forked from rspec/rspec-rails
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdirectory_structure.feature
204 lines (172 loc) · 6.5 KB
/
directory_structure.feature
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
Feature: Directory Structure
Specs are usually placed in a canonical directory structure that describes
their purpose:
- Model specs reside in the `spec/models` directory
- Controller specs reside in the `spec/controllers` directory
- Request specs reside in the `spec/requests` directory. The directory
can also be named `integration` or `api`.
- Feature specs reside in the `spec/features` directory
- View specs reside in the `spec/views` directory
- Helper specs reside in the `spec/helpers` directory
- Mailer specs reside in the `spec/mailers` directory
- Routing specs reside in the `spec/routing` directory
Application developers are free to use a different directory structure. In
order to include the correct `rspec-rails` support functions, the specs need
to have the appropriate corresponding metadata `:type` value:
- Model specs: `type: :model`
- Controller specs: `type: :controller`
- Request specs: `type: :request`
- Feature specs: `type: :feature`
- View specs: `type: :view`
- Helper specs: `type: :helper`
- Mailer specs: `type: :mailer`
- Routing specs: `type: :routing`
For example, say the spec for the `ThingsController` is located in
`spec/legacy/things_controller_spec.rb`. Simply tag the spec's
`RSpec.describe` block with the `type: :controller` metadata:
```ruby
# spec/legacy/things_controller_spec.rb
RSpec.describe ThingsController, type: :controller do
describe "GET index" do
# Examples
end
end
```
**Note:** Standard RSpec specs do not require any additional metadata by
default.
Check out the [`rspec-core`](/rspec/rspec-core/docs) documentation on [using metadata](/rspec/rspec-core/docs/metadata) for more details.
Automatically Adding Metadata
-----------------------------
RSpec versions before 3.0.0 automatically added metadata to specs based on
their location on the filesystem. This was both confusing to new users and not
desirable for some veteran users.
In RSpec 3, this behavior must be explicitly enabled:
```ruby
# spec/rails_helper.rb
RSpec.configure do |config|
config.infer_spec_type_from_file_location!
end
```
Since this assumed behavior is so prevalent in tutorials, the default
configuration generated by `rails generate rspec:install` enables this.
If you follow the above listed canonical directory structure and have
configured `infer_spec_type_from_file_location!`, RSpec will automatically
include the correct support functions for each type.
If you want to set metadata for a custom directory that doesn't follow fit the canonical structure above, you can do the following:
```ruby
# set `:type` for serializers directory
RSpec.configure do |config|
config.define_derived_metadata(:file_path => Regexp.new('/spec/serializers/')) do |metadata|
metadata[:type] = :serializer
end
end
```
Tips on Spec Location
---------------------
It is suggested that the `spec/` directory structure generally mirror both
`app/` and `lib/`. This makes it easy to locate corresponding code and spec
files.
**Example:**
app
├── controllers
│ ├── application_controller.rb
│ └── books_controller.rb
├── helpers
│ ├── application_helper.rb
│ └── books_helper.rb
├── models
│ ├── author.rb
│ ├── book.rb
└── views
├── books
├── layouts
lib
├── country_map.rb
├── development_mail_interceptor.rb
├── enviroment_mail_interceptor.rb
└── tasks
├── irc.rake
spec
├── controllers
│ ├── books_controller_spec.rb
├── country_map_spec.rb
├── features
│ ├── tracking_book_delivery_spec.rb
├── helpers
│ └── books_helper_spec.rb
├── models
│ ├── author_spec.rb
│ ├── book_spec.rb
├── rails_helper.rb
├── requests
│ ├── books_spec.rb
├── routing
│ └── books_routing_spec.rb
├── spec_helper.rb
└── tasks
│ ├── irc_spec.rb
└── views
├── books
Scenario: Standard Rails specs must specify the `:type` metadata
Given a file named "spec/functional/widgets_controller_spec.rb" with:
"""ruby
require "rails_helper"
RSpec.describe WidgetsController, :type => :controller do
it "responds successfully" do
get :index
expect(response.status).to eq(200)
end
end
"""
When I run `rspec spec`
Then the example should pass
Scenario: Non-rails related specs do not require `:type` metadata by default
Given a file named "spec/ledger/entry_spec.rb" with:
"""ruby
require "spec_helper"
Entry = Struct.new(:description, :us_cents)
RSpec.describe Entry do
it "has a description" do
is_expected.to respond_to(:description)
end
end
"""
When I run `rspec spec`
Then the example should pass
Scenario: Inferring spec type from the file location adds the appropriate metadata
Given a file named "spec/controllers/widgets_controller_spec.rb" with:
"""ruby
require "rails_helper"
RSpec.configure do |config|
config.infer_spec_type_from_file_location!
end
RSpec.describe WidgetsController do
it "responds successfully" do
get :index
expect(response.status).to eq(200)
end
end
"""
When I run `rspec spec`
Then the example should pass
Scenario: Specs in canonical directories can override their inferred types
Given a file named "spec/routing/duckduck_routing_spec.rb" with:
"""ruby
require "rails_helper"
Rails.application.routes.draw do
get "/example" => redirect("http://example.com")
end
RSpec.configure do |config|
config.infer_spec_type_from_file_location!
end
# Due to limitations in the Rails routing test framework, routes that
# perform redirects must actually be tested via request specs
RSpec.describe "/example", :type => :request do
it "redirects to example.com" do
get "/example"
expect(response).to redirect_to("http://example.com")
end
end
"""
When I run `rspec spec`
Then the example should pass