-
-
Notifications
You must be signed in to change notification settings - Fork 755
Specify shared_context used with conditions in example group #2775
Conversation
The following works: RSpec.describe "polling" do
let(:voter_status) { nil }
let(:poll_open) { false }
# DECLARE DIMENSIONS IN THE TEST MATRIX AS SHARED CONTEXTS
shared_context "is registered", registered: true do
let(:voter_status) { :registered }
end
shared_context "is early", early: true do
let(:poll_open) { true }
end
# TEST MATRIX
context "as a good citizen", :registered, :early do
specify "vote counted" do
expect(voter_status).to eq :registered
expect(poll_open).to eq true
end
end
context "late citizen" do
specify "vote not counted" do
expect(voter_status).to be_nil
expect(poll_open).to eq false
end
end
end Do you find it counter-intuitive? |
Not sure I understand. It is included globally with |
The following looks like a bug, or at least it's confusing RSpec.describe "polling" do
let(:open) { false }
shared_context "is early" do
let(:open) { true }
end
# Works fine with `it_behaves_like` with metadata
it_behaves_like "is early", early: true
# Fails with `include_context`/`include_examples`
# it_behaves_like "is early", early: true
context "early", :early do
specify "yeah" do
expect(open).to eq true
end
end
context "late" do
specify "oops" do
expect(open).to eq false
end
end
end The reason that I find this confusing is that without metadata the shared context gets included. @JonRowe What is the expected behaviour? Is this by design and we should emphasize this in the documentation? @avit Would you like to hack on it?
rspec-core/lib/rspec/core/example_group.rb Line 343 in 5d87c28
|
That's the way I've been writing RSpec for years. I think it's great, but sometimes I think flatter contexts by inclusion are easier to reason about than nesting. The nesting often means related examples (with just one changed condition) end up being specified very far apart, and the stack of nested contexts must be decided carefully to get the best grouping of examples together. Wider contexts like "when logged in" or "as an admin" make sense to set up outermost, or else you end up repeating them a lot. A conflict arises when 2 or more intersecting contexts are equally common and no stacking is clearly "better". Nesting also means that outer contexts are implicitly inherited. I would rather see the error that something like |
It's specifically the difference in usage with metadata conditions that I'm interested in here. The unconditional (I really think the intersection of shared examples with including different shared contexts could be useful.)
According to the docs, is this passing metadata to the context, or yielded parameters to the block? It's not clear. The differences between
|
Please disregard my above code examples. It slipped my mind the implicit inclusion with the matching metadata was discouraged, and will be removed in RSpec 4. There is an interesting conversation here regarding this. It seems that metadata specified in example group RSpec.describe "polling" do
shared_examples "vote counted" do
it 'is counted' do
expect(poll_open).to be(true)
end
end
shared_context "is early" do
let(:poll_open) { true }
end
include_context "is early", early: 'early'
context "as a good citizen", early: 'early' do
it_behaves_like "vote counted"
end
context "as a BAD citizen", early: 'LATE' do # This passes, but should not
it_behaves_like "vote counted"
end
end |
@JonRowe We still have this (I didn't remove this line in #2834):
but this doesn't work: RSpec.describe do
shared_examples "conditionally included", :cond do
it 'runs' do
expect(true).to be(true)
end
end
context "cond group", :cond do
end
end
PS It works with |
There is one more example that confuses me: RSpec.describe do
shared_examples "conditionally included", cond: '1' do
it 'runs' do |example|
expect(example.metadata[:cond]).to eq('1')
end
end
context "cond group" do
include_examples 'conditionally included', cond: '2'
it_behaves_like 'conditionally included', cond: '2'
end
end Both of the examples pass. It doesn't seem that the metadata passed to |
@myronmarston I resort to summoning you to express your opinion on |
To clarify, are you referring to this example you posted above? RSpec.describe do
shared_examples "conditionally included", cond: '1' do
it 'runs' do |example|
expect(example.metadata[:cond]).to eq('1')
end
end
context "cond group" do
include_examples 'conditionally included', cond: '2'
it_behaves_like 'conditionally included', cond: '2'
end
end
In this case, RSpec.describe do
shared_examples "conditionally included", cond: '1' do |cond:|
it 'runs' do |example|
expect(example.metadata[:cond]).to eq('1')
expect(cond).to eq '2'
end
end
context "cond group" do
include_examples 'conditionally included', cond: '2'
it_behaves_like 'conditionally included', cond: '2'
end
end This passes, because when you pass |
@myronmarston Please accept my apologies for the very late response. Thanks for getting right to the gist of my confusion. Your explanation helped me to finally wrap my head around the current design and describe it in #2878. @avit I clearly understand your proposal. Probably metadata is not the best way to approach the problem. I won't let myself to come with more examples and alternative solutions to this. Sorry for all the confusion dealt. |
Fixes rspec/rspec-core#2775 Related: - rspec/rspec-core#2834 - rspec/rspec-core#2832 - rspec/rspec-core#1762 --- This commit was imported from rspec/rspec-core@361e521.
This is not a fully realized example, but some kind of functionality similar to this could help make it easier to use shared contexts.
Currently, calling
include_context
within an example group, and globalRSpec.configuration.include_context
have a subtle but major difference that is not documented:It's not exactly clear that this happens from reading the docs, and there is no warning where the filters are ignored. (There is also no example in the docs that shows how a
shared_context
can be declared locally within a group.)Ultimately, I would like a way to more easily scope shared contexts with metadata filters, and combine them with shared examples to write a test matrix. Maybe this fictional example will show what I'm after:
The obvious workaround is to manually
include_context
repeatedly where each one applies. It just seems like there could be a way to use filters to make things more readable & easier to spot that all the permutations are covered.