Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit 9139c61

Browse files
committed
Add new config.include_context API for including shared contexts.
1 parent 157e20f commit 9139c61

File tree

4 files changed

+89
-7
lines changed

4 files changed

+89
-7
lines changed

Changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ Enhancements:
1313
others in a one-off manner. For example, `rspec spec/unit
1414
spec/acceptance --order defined` will run unit specs before acceptance
1515
specs. (Myron Marston, #2253)
16+
* Add new `config.include_context` API for configuring global or
17+
filtered inclusion of shared contexts in example groups.
18+
(Myron Marston, #2256)
1619

1720
Bug Fixes:
1821

features/example_groups/shared_context.feature

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
Feature: shared context
22

3-
Use `shared_context` to define a block that will be evaluated in the context
4-
of example groups either explicitly, using `include_context`, or implicitly by
5-
matching metadata.
3+
Use `shared_context` to define a block that will be evaluated in the context of example groups either locally, using `include_context` in an example group, or globally using `config.include_context`.
64

75
When implicitly including shared contexts via matching metadata, the normal way is to define matching metadata on an example group, in which case the context is included in the entire group. However, you also have the option to include it in an individual example instead. RSpec treats every example as having a singleton example group (analogous to Ruby's singleton classes) containing just the one example.
86

97
Background:
108
Given a file named "shared_stuff.rb" with:
119
"""ruby
12-
RSpec.shared_context "shared stuff", :a => :b do
10+
RSpec.shared_context "shared stuff" do
1311
before { @some_var = :some_value }
1412
def shared_method
1513
"it works"
@@ -19,6 +17,10 @@ Feature: shared context
1917
'this is the subject'
2018
end
2119
end
20+
21+
RSpec.configure do |rspec|
22+
rspec.include_context "shared stuff", :include_shared => true
23+
end
2224
"""
2325

2426
Scenario: Declare a shared context and include it with `include_context`
@@ -72,7 +74,7 @@ Feature: shared context
7274
"""ruby
7375
require "./shared_stuff.rb"
7476
75-
RSpec.describe "group that includes a shared context using metadata", :a => :b do
77+
RSpec.describe "group that includes a shared context using metadata", :include_shared => true do
7678
it "has access to methods defined in shared context" do
7779
expect(shared_method).to eq("it works")
7880
end
@@ -103,7 +105,7 @@ Feature: shared context
103105
expect(self).not_to respond_to(:shared_method)
104106
end
105107
106-
it "has access to shared methods from examples with matching metadata", :a => :b do
108+
it "has access to shared methods from examples with matching metadata", :include_shared => true do
107109
expect(shared_method).to eq("it works")
108110
end
109111
end

lib/rspec/core/configuration.rb

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1153,7 +1153,7 @@ def exclusion_filter
11531153
# end
11541154
#
11551155
# RSpec.configure do |config|
1156-
# config.include(UserHelpers) # included in all modules
1156+
# config.include(UserHelpers) # included in all groups
11571157
# config.include(AuthenticationHelpers, :type => :request)
11581158
# end
11591159
#
@@ -1172,6 +1172,7 @@ def exclusion_filter
11721172
# example has a singleton example group containing just the one
11731173
# example.
11741174
#
1175+
# @see #include_context
11751176
# @see #extend
11761177
# @see #prepend
11771178
def include(mod, *filters)
@@ -1180,6 +1181,42 @@ def include(mod, *filters)
11801181
end
11811182
end
11821183

1184+
# Tells RSpec to include the named shared example group in example groups.
1185+
# Use `filters` to constrain the groups or examples in which to include
1186+
# the example group.
1187+
#
1188+
# @example
1189+
#
1190+
# RSpec.shared_context "example users" do
1191+
# let(:admin_user) { create_user(:admin) }
1192+
# let(:guest_user) { create_user(:guest) }
1193+
# end
1194+
#
1195+
# RSpec.configure do |config|
1196+
# config.include_context "example users", :type => :request
1197+
# end
1198+
#
1199+
# describe "admin page", :type => :request do
1200+
# it "can be viewed by admins" do
1201+
# login_with admin_user
1202+
# get "/admin"
1203+
# expect(response).to be_ok
1204+
# end
1205+
# end
1206+
#
1207+
# @note Filtered context inclusions can also be applied to
1208+
# individual examples that have matching metadata. Just like
1209+
# Ruby's object model is that every object has a singleton class
1210+
# which has only a single instance, RSpec's model is that every
1211+
# example has a singleton example group containing just the one
1212+
# example.
1213+
#
1214+
# @see #include
1215+
def include_context(shared_group_name, *filters)
1216+
block = world.shared_example_group_registry.find([:main], shared_group_name)
1217+
include SharedExampleGroupModule.new(shared_group_name, block), *filters
1218+
end
1219+
11831220
# Tells RSpec to extend example groups with `mod`. Methods defined in
11841221
# `mod` are exposed to example groups (not examples). Use `filters` to
11851222
# constrain the groups to extend.

spec/rspec/core/configuration_spec.rb

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,46 @@ def file_at(relative_path)
914914
end
915915
end
916916

917+
describe "#include_context" do
918+
context "with no metadata filters" do
919+
it 'includes the named shared example group in all groups' do
920+
RSpec.shared_examples "shared group" do
921+
let(:foo) { 17 }
922+
end
923+
RSpec.configuration.include_context "shared group"
924+
925+
expect(RSpec.describe.new.foo).to eq 17
926+
end
927+
end
928+
929+
context "with metadata filters" do
930+
it 'includes the named shared example group in matching groups' do
931+
RSpec.shared_examples "shared group" do
932+
let(:foo) { 18 }
933+
end
934+
RSpec.configuration.include_context "shared group", :include_it
935+
936+
expect(RSpec.describe.new).not_to respond_to(:foo)
937+
expect(RSpec.describe("", :include_it).new.foo).to eq 18
938+
end
939+
940+
it 'includes the named shared example group in the singleton class of matching examples' do
941+
RSpec.shared_examples "shared group" do
942+
let(:foo) { 19 }
943+
end
944+
RSpec.configuration.include_context "shared group", :include_it
945+
946+
foo_value = nil
947+
describe_successfully do
948+
it { expect { self.foo }.to raise_error(NoMethodError) }
949+
it("", :include_it) { foo_value = foo }
950+
end
951+
952+
expect(foo_value).to eq 19
953+
end
954+
end
955+
end
956+
917957
describe "#include" do
918958
include_examples "warning of deprecated `:example_group` during filtering configuration", :include, Enumerable
919959

0 commit comments

Comments
 (0)