Skip to content

Commit 6a8cc7f

Browse files
committed
Merge pull request #807 from rspec/issue-801-overridding-spec-types
Allows metadata to override the type of Rails spec
2 parents 652a77d + eb9b98b commit 6a8cc7f

File tree

3 files changed

+127
-24
lines changed

3 files changed

+127
-24
lines changed

features/.nav

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- Changelog.md
55
- Upgrade.md
66
- RailsVersions.md (Rails versions)
7+
- directory_structure.feature
78
- model_specs:
89
- errors_on.feature
910
- records.feature

features/directory_structure.feature

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
Feature: Directory Structure
2+
3+
Specs are usually placed in a canonical directory structure that describes
4+
their purpose.
5+
6+
* Model specs reside in the `spec/models` directory
7+
* Controller specs reside in the `spec/controllers` directory
8+
* Request specs reside in the `spec/requests` directory
9+
* Feature specs reside in the `spec/features` directory
10+
* View specs reside in the `spec/views` directory
11+
* Helper specs reside in the `spec/helpers` directory
12+
* Mailer specs reside in the `spec/mailers` directory
13+
* Routing specs reside in the `spec/routing` directory
14+
15+
If you follow this directory structure, RSpec will automatically include the
16+
correct test support functions for each type of test.
17+
18+
Application developers are free to use a different directory structure, but
19+
will need to specify the types manually by adding a `:type` metadata key (for
20+
example, `describe WidgetsController, :type => :controller`)
21+
22+
Scenario: Specs in the `spec/controllers` directory automatically tagged as controller specs
23+
Given a file named "spec/controllers/widgets_controller_spec.rb" with:
24+
"""ruby
25+
require "spec_helper"
26+
27+
describe WidgetsController do
28+
it "responds successfully" do
29+
get :index
30+
expect(response.status).to eq(200)
31+
end
32+
end
33+
"""
34+
When I run `rspec spec`
35+
Then the example should pass
36+
37+
Scenario: Specs in other directories must have their types specified manually
38+
Given a file named "spec/functional/widgets_controller_spec.rb" with:
39+
"""ruby
40+
require "spec_helper"
41+
42+
describe WidgetsController, :type => :controller do
43+
it "responds successfully" do
44+
get :index
45+
expect(response.status).to eq(200)
46+
end
47+
end
48+
"""
49+
When I run `rspec spec`
50+
Then the example should pass
51+
52+
Scenario: Specs in canonical directories can override their types
53+
Given a file named "spec/routing/duckduck_routing_spec.rb" with:
54+
"""ruby
55+
require "spec_helper"
56+
57+
Rails.application.routes.draw do
58+
get "/example" => redirect("http://example.com")
59+
end
60+
61+
# Due to limitations in the Rails routing test framework, routes that
62+
# perform redirects must actually be tested via request specs
63+
describe "/example", :type => :request do
64+
it "redirects to example.com" do
65+
get "/example"
66+
expect(response).to redirect_to("http://example.com")
67+
end
68+
end
69+
"""
70+
When I run `rspec spec`
71+
Then the example should pass

lib/rspec/rails/example.rb

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,61 @@ def c.escaped_path(*parts)
1313
Regexp.compile(parts.join('[\\\/]') + '[\\\/]')
1414
end
1515

16-
c.include RSpec::Rails::ControllerExampleGroup, :type => :controller, :example_group => {
17-
:file_path => c.escaped_path(%w[spec controllers])
18-
}
19-
c.include RSpec::Rails::HelperExampleGroup, :type => :helper, :example_group => {
20-
:file_path => c.escaped_path(%w[spec helpers])
21-
}
22-
if defined?(RSpec::Rails::MailerExampleGroup)
23-
c.include RSpec::Rails::MailerExampleGroup, :type => :mailer, :example_group => {
24-
:file_path => c.escaped_path(%w[spec mailers])
16+
controller_path_regex = c.escaped_path(%w[spec controllers])
17+
c.include RSpec::Rails::ControllerExampleGroup,
18+
:type => :controller,
19+
:example_group => lambda { |example_group, metadata|
20+
metadata[:type].nil? && controller_path_regex =~ example_group[:file_path]
21+
}
22+
23+
helper_path_regex = c.escaped_path(%w[spec helpers])
24+
c.include RSpec::Rails::HelperExampleGroup,
25+
:type => :helper,
26+
:example_group => lambda { |example_group, metadata|
27+
metadata[:type].nil? && helper_path_regex =~ example_group[:file_path]
2528
}
29+
30+
mailer_path_regex = c.escaped_path(%w[spec mailers])
31+
if defined?(RSpec::Rails::MailerExampleGroup)
32+
c.include RSpec::Rails::MailerExampleGroup,
33+
:type => :mailer,
34+
:example_group => lambda { |example_group, metadata|
35+
metadata[:type].nil? && mailer_path_regex =~ example_group[:file_path]
36+
}
2637
end
27-
c.include RSpec::Rails::ModelExampleGroup, :type => :model, :example_group => {
28-
:file_path => c.escaped_path(%w[spec models])
29-
}
30-
c.include RSpec::Rails::RequestExampleGroup, :type => :request, :example_group => {
31-
:file_path => c.escaped_path(%w[spec (requests|integration|api)])
32-
}
33-
c.include RSpec::Rails::RoutingExampleGroup, :type => :routing, :example_group => {
34-
:file_path => c.escaped_path(%w[spec routing])
35-
}
36-
c.include RSpec::Rails::ViewExampleGroup, :type => :view, :example_group => {
37-
:file_path => c.escaped_path(%w[spec views])
38-
}
39-
c.include RSpec::Rails::FeatureExampleGroup, :type => :feature, :example_group => {
40-
:file_path => c.escaped_path(%w[spec features])
41-
}
38+
39+
model_path_regex = c.escaped_path(%w[spec models])
40+
c.include RSpec::Rails::ModelExampleGroup,
41+
:type => :model,
42+
:example_group => lambda { |example_group, metadata|
43+
metadata[:type].nil? && model_path_regex =~ example_group[:file_path]
44+
}
45+
46+
request_path_regex = c.escaped_path(%w[spec (requests|integration|api)])
47+
c.include RSpec::Rails::RequestExampleGroup,
48+
:type => :request,
49+
:example_group => lambda { |example_group, metadata|
50+
metadata[:type].nil? && request_path_regex =~ example_group[:file_path]
51+
}
52+
53+
routing_path_regex = c.escaped_path(%w[spec routing])
54+
c.include RSpec::Rails::RoutingExampleGroup,
55+
:type => :routing,
56+
:example_group => lambda { |example_group, metadata|
57+
metadata[:type].nil? && routing_path_regex =~ example_group[:file_path]
58+
}
59+
60+
view_path_regex = c.escaped_path(%w[spec views])
61+
c.include RSpec::Rails::ViewExampleGroup,
62+
:type => :view,
63+
:example_group => lambda { |example_group, metadata|
64+
metadata[:type].nil? && view_path_regex =~ example_group[:file_path]
65+
}
66+
67+
feature_example_regex = c.escaped_path(%w[spec features])
68+
c.include RSpec::Rails::FeatureExampleGroup,
69+
:type => :feature,
70+
:example_group => lambda { |example_group, metadata|
71+
metadata[:type].nil? && feature_example_regex =~ example_group[:file_path]
72+
}
4273
end

0 commit comments

Comments
 (0)