RspecInContext

Gem Version Codacy Badge Test and Release badge

This gem is here to help you write better shared_examples in Rspec.

Ever been bothered by the fact that they don't really behave like methods and that you can't pass it a block ? There you go: rspec_in_context

Installation

Add this line to your application's Gemfile:

gem 'rspec_in_context'

And then execute:

$ bundle

Or install it yourself as:

$ gem install rspec_in_context

Usage

Add this into Rspec

You must require the gem on top of your spec_helper:

require 'rspec_in_context'

Then include it into Rspec:

RSpec.configure do |config|
  [...]

  config.include RspecInContext
end

Define a new in_context

You can define in_context block that are reusable almost anywhere. They completely look like normal Rspec.

Inside a Rspec block (scoped)
# A in_context can be named with a symbol or a string
define_context :context_name do
  it 'works' do
    expect(true).to be_truthy
  end
end

Those in_context will be scoped to their current describe/context block.

Outside a Rspec block (globally)

Outside of a test you have to use RSpec.define_context. Those in_context will be defined globally in your tests.

Use the context

Anywhere in your test description, use a in_context block to use a predefined in_context.

Important: in_context are scoped to their current describe/context block. If you need globally defined context see RSpec.define_context

# A in_context can be named with a symbol or a string
RSpec.define_context :context_name do
  it 'works' do
    expect(true).to be_truthy
  end
end

[...]
Rspec.describe MyClass do
  in_context :context_name # => will execute the 'it works' test here
end

Things to know

Inside block execution

  • You can chose exactly where your inside test will be used: By using execute_tests in your define context, the test passed when you use the context will be executed here
define_context :context_name do
  it 'works' do
    expect(true).to be_truthy
  end
  context "in this context pomme exists" do
    let(:pomme) { "abcd" }

    execute_tests
  end
end

[...]

in_context :context_name do
  it 'will be executed at execute_tests place' do
    expect(pomme).to eq("abcd") # => true
  end
end
  • You can add variable instantiation relative to your test where you exactly want:

instanciate_context is an alias of execute_tests so you can't use both. But it let you describe what the block will do better.

Variable usage

  • You can use variable in the in_context definition
define_context :context_name do |name|
  it 'works' do
    expect(true).to be_truthy
  end
  context "in this context #{name} exists" do
    let(name) { "abcd" }

    execute_tests
  end
end

[...]

in_context :context_name, :poire do
  it 'the right variable will exists' do
    expect(poire).to eq("abcd") # => true
  end
end

Scoping

  • In_contexts can be scope inside one another
define_context :context_name do |name|
  it 'works' do
    expect(true).to be_truthy
  end
  context "in this context #{name} exists" do
    let(name) { "abcd" }

    execute_tests
  end
end

define_context "second in_context" do
  context 'and tree also' do
    let(:tree) { 'abcd' }

    it 'will scope correctly' do
      expect(tree).to eq(poire)
    end
  end
end

[...]

in_context :context_name, :poire do
  it 'the right variable will exists' do
    expect(poire).to eq("abcd") # => true
  end

  in_context "second in_context" # => will work
end
  • in_context are bound to their current scope

Namespacing

  • You can add a namespace to a in_context definition
define_context "this is a namespaced context", namespace: "namespace name"

Or

define_context "this is a namespaced context", ns: "namespace name"

Or

RSpec.define_context "this is a namespaced context", ns: "namespace name"
  • When you want to use a namespaced in_context, you have two choice:

Ignore any namespace and it will try to find a corresponding in_context in any_namespace (the ones defined without namespace have the priority);

define_context "namespaced context", ns: "namespace name" do
  [...]
end

in_context "namespaced context"

Pass a namespace and it will look only in this context.

define_context "namespaced context", ns: "namespace name" do
  [...]
end

in_context "namespaced context", namespace: "namespace name"
in_context "namespaced context", ns: "namespace name"

Making in_context adverstise itself

The fact that a in_context block is used inside the test is silent and invisible by default. in_context will still wrap its own execution inside a anonymous context.

But, there's some case where it helps to make the in_context to wrap its execution in a named context block. For example:

define_context "with my_var defined" do
  before do
    described_class.set_my_var(true)
  end

  it "works"
end

define_context "without my_var defined" do
  it "doesn't work"
end

RSpec.describe MyNiceClass do
  in_context "with my_var defined"
  in_context "without my_var defined"
end

Using a rspec -f doc will only print "MyNiceClass works" and "MyNiceClass doesn't work" which is not really a good documentation.

So, you can define a context specifying it not to be silent or to print_context. For example :

define_context "with my_var defined", silent: false do
  before do
    described_class.set_my_var(true)
  end

  it "works"
end

define_context "without my_var defined", print_context: true do
  it "doesn't work"
end

RSpec.describe MyNiceClass do
  in_context "with my_var defined"
  in_context "without my_var defined"
end

Will print "MyNiceClass with my_var defined works" and "MyNiceClass without my_var defined doesn't work". Which is valid and readable documentation.

Development

After checking out the repo, run bin/setup to install dependencies. You can also run bin/console for an interactive prompt that will allow you to experiment.

After setuping the repo, you should run overcommit --install to install the different hooks.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/denispasin/rspec_in_context.