rspec-rails 3.7.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/Capybara.md +5 -54
- data/Changelog.md +259 -70
- data/README.md +265 -496
- data/lib/generators/rspec/channel/channel_generator.rb +12 -0
- data/lib/generators/rspec/{observer/templates/observer_spec.rb → channel/templates/channel_spec.rb.erb} +1 -1
- data/lib/generators/rspec/controller/controller_generator.rb +21 -4
- data/lib/generators/rspec/controller/templates/request_spec.rb +14 -0
- data/lib/generators/rspec/controller/templates/routing_spec.rb +13 -0
- data/lib/generators/rspec/feature/feature_generator.rb +4 -4
- data/lib/generators/rspec/generator/generator_generator.rb +24 -0
- data/lib/generators/rspec/generator/templates/generator_spec.rb +6 -0
- data/lib/generators/rspec/helper/helper_generator.rb +1 -1
- data/lib/generators/rspec/install/install_generator.rb +4 -4
- data/lib/generators/rspec/install/templates/spec/rails_helper.rb +25 -12
- data/lib/generators/rspec/integration/integration_generator.rb +4 -4
- data/lib/generators/rspec/integration/templates/request_spec.rb +1 -1
- data/lib/generators/rspec/mailbox/mailbox_generator.rb +14 -0
- data/lib/generators/rspec/mailbox/templates/mailbox_spec.rb.erb +7 -0
- data/lib/generators/rspec/mailer/mailer_generator.rb +2 -1
- data/lib/generators/rspec/mailer/templates/preview.rb +1 -1
- data/lib/generators/rspec/model/model_generator.rb +6 -5
- data/lib/generators/rspec/model/templates/fixtures.yml +1 -1
- data/lib/generators/rspec/request/request_generator.rb +1 -1
- data/lib/generators/rspec/scaffold/scaffold_generator.rb +43 -23
- data/lib/generators/rspec/scaffold/templates/api_controller_spec.rb +2 -38
- data/lib/generators/rspec/scaffold/templates/api_request_spec.rb +131 -0
- data/lib/generators/rspec/scaffold/templates/controller_spec.rb +17 -17
- data/lib/generators/rspec/scaffold/templates/edit_spec.rb +1 -1
- data/lib/generators/rspec/scaffold/templates/index_spec.rb +2 -2
- data/lib/generators/rspec/scaffold/templates/new_spec.rb +1 -1
- data/lib/generators/rspec/scaffold/templates/request_spec.rb +133 -0
- data/lib/generators/rspec/scaffold/templates/routing_spec.rb +10 -13
- data/lib/generators/rspec/scaffold/templates/show_spec.rb +1 -1
- data/lib/generators/rspec/system/system_generator.rb +26 -0
- data/lib/generators/rspec/system/templates/system_spec.rb +9 -0
- data/lib/generators/rspec/view/view_generator.rb +2 -2
- data/lib/generators/rspec.rb +0 -6
- data/lib/rspec/rails/adapters.rb +11 -76
- data/lib/rspec/rails/configuration.rb +47 -36
- data/lib/rspec/rails/example/channel_example_group.rb +93 -0
- data/lib/rspec/rails/example/controller_example_group.rb +4 -4
- data/lib/rspec/rails/example/feature_example_group.rb +6 -26
- data/lib/rspec/rails/example/helper_example_group.rb +2 -9
- data/lib/rspec/rails/example/mailbox_example_group.rb +80 -0
- data/lib/rspec/rails/example/mailer_example_group.rb +1 -1
- data/lib/rspec/rails/example/rails_example_group.rb +1 -1
- data/lib/rspec/rails/example/system_example_group.rb +96 -60
- data/lib/rspec/rails/example/view_example_group.rb +47 -28
- data/lib/rspec/rails/example.rb +3 -3
- data/lib/rspec/rails/extensions/active_record/proxy.rb +1 -9
- data/lib/rspec/rails/feature_check.rb +12 -29
- data/lib/rspec/rails/fixture_file_upload_support.rb +40 -0
- data/lib/rspec/rails/fixture_support.rb +37 -31
- data/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb +170 -0
- data/lib/rspec/rails/matchers/action_cable/have_streams.rb +58 -0
- data/lib/rspec/rails/matchers/action_cable.rb +65 -0
- data/lib/rspec/rails/matchers/action_mailbox.rb +64 -0
- data/lib/rspec/rails/matchers/active_job.rb +180 -22
- data/lib/rspec/rails/matchers/base_matcher.rb +179 -0
- data/lib/rspec/rails/matchers/be_a_new.rb +1 -1
- data/lib/rspec/rails/matchers/be_new_record.rb +1 -1
- data/lib/rspec/rails/matchers/be_valid.rb +1 -1
- data/lib/rspec/rails/matchers/have_enqueued_mail.rb +198 -0
- data/lib/rspec/rails/matchers/have_http_status.rb +34 -13
- data/lib/rspec/rails/matchers/have_rendered.rb +2 -1
- data/lib/rspec/rails/matchers/redirect_to.rb +1 -1
- data/lib/rspec/rails/matchers/routing_matchers.rb +14 -14
- data/lib/rspec/rails/matchers.rb +11 -0
- data/lib/rspec/rails/tasks/rspec.rake +7 -17
- data/lib/rspec/rails/vendor/capybara.rb +10 -15
- data/lib/rspec/rails/version.rb +1 -1
- data/lib/rspec/rails/view_path_builder.rb +1 -1
- data/lib/rspec/rails/view_rendering.rb +16 -5
- data/lib/rspec/rails.rb +1 -0
- data/lib/rspec-rails.rb +13 -10
- data.tar.gz.sig +0 -0
- metadata +55 -33
- metadata.gz.sig +0 -0
- data/lib/generators/rspec/observer/observer_generator.rb +0 -13
data/README.md
CHANGED
@@ -1,600 +1,369 @@
|
|
1
|
-
# rspec-rails [![Build Status]
|
2
|
-
**rspec-rails** is a testing framework for Rails 3.x, 4.x and 5.0.
|
1
|
+
# rspec-rails [![Build Status][]][travis-ci] [![Code Climate][]][code-climate] [![Gem Version][]](gem-version)
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
`rspec-rails` brings the [RSpec][] testing framework to [Ruby on Rails][]
|
4
|
+
as a drop-in alternative to its default testing framework, Minitest.
|
6
5
|
|
7
|
-
|
6
|
+
In RSpec, tests are not just scripts that verify your application code.
|
7
|
+
They’re also specifications (or _specs,_ for short):
|
8
|
+
detailed explanations of how the application is supposed to behave,
|
9
|
+
expressed in plain English.
|
8
10
|
|
9
|
-
|
10
|
-
`Gemfile`:
|
11
|
+
Use **[`rspec-rails` 1.x][]** for Rails 2.x.
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
[Build Status]: https://secure.travis-ci.org/rspec/rspec-rails.svg?branch=master
|
14
|
+
[travis-ci]: https://travis-ci.org/rspec/rspec-rails
|
15
|
+
[Code Climate]: https://codeclimate.com/github/rspec/rspec-rails.svg
|
16
|
+
[code-climate]: https://codeclimate.com/github/rspec/rspec-rails
|
17
|
+
[Gem Version]: https://badge.fury.io/rb/rspec-rails.svg
|
18
|
+
[gem-version]: https://badge.fury.io/rb/rspec-rails
|
19
|
+
[RSpec]: https://rspec.info/
|
20
|
+
[Ruby on Rails]: https://rubyonrails.org/
|
21
|
+
[`rspec-rails` 1.x]: https://github.com/dchelimsky/rspec-rails
|
17
22
|
|
18
|
-
|
19
|
-
RSpec repos as well. Add the following to your `Gemfile`:
|
23
|
+
## Installation
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'master'
|
24
|
-
end
|
25
|
-
```
|
25
|
+
1. Add `rspec-rails` to **both** the `:development` and `:test` groups
|
26
|
+
of your app’s `Gemfile`:
|
26
27
|
|
27
|
-
|
28
|
+
```ruby
|
29
|
+
# Run against the latest stable release
|
30
|
+
group :development, :test do
|
31
|
+
gem 'rspec-rails', '~> 4.0'
|
32
|
+
end
|
28
33
|
|
29
|
-
|
30
|
-
|
31
|
-
|
34
|
+
# Or, run against the master branch
|
35
|
+
# (requires master-branch versions of all related RSpec libraries)
|
36
|
+
group :development, :test do
|
37
|
+
%w[rspec-core rspec-expectations rspec-mocks rspec-rails rspec-support].each do |lib|
|
38
|
+
gem lib, git: "https://github.com/rspec/#{lib}.git", branch: 'master'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
```
|
32
42
|
|
33
|
-
|
43
|
+
(Adding it to the `:development` group is not strictly necessary,
|
44
|
+
but without it, generators and rake tasks must be preceded by `RAILS_ENV=test`.)
|
34
45
|
|
35
|
-
|
36
|
-
rails generate rspec:install
|
37
|
-
```
|
46
|
+
2. Then, in your project directory:
|
38
47
|
|
39
|
-
|
48
|
+
```sh
|
49
|
+
# Download and install
|
50
|
+
$ bundle install
|
40
51
|
|
41
|
-
|
42
|
-
|
43
|
-
|
52
|
+
# Generate boilerplate configuration files
|
53
|
+
# (check the comments in each generated file for more information)
|
54
|
+
$ rails generate rspec:install
|
55
|
+
create .rspec
|
56
|
+
create spec
|
57
|
+
create spec/spec_helper.rb
|
58
|
+
create spec/rails_helper.rb
|
59
|
+
```
|
44
60
|
|
45
|
-
|
61
|
+
## Upgrading
|
46
62
|
|
47
|
-
|
63
|
+
If your project is already using an older version of `rspec-rails`,
|
64
|
+
upgrade to the latest version with:
|
48
65
|
|
49
|
-
```
|
50
|
-
bundle
|
66
|
+
```sh
|
67
|
+
$ bundle update rspec-rails
|
51
68
|
```
|
52
69
|
|
53
|
-
|
54
|
-
|
55
|
-
|
70
|
+
RSpec follows [semantic versioning](https://semver.org/),
|
71
|
+
which means that “major version” upgrades (_e.g.,_ 2.x → 3.x)
|
72
|
+
come with **breaking changes**.
|
73
|
+
If you’re upgrading from version 2.x or below,
|
74
|
+
read the [`rspec-rails` upgrade notes][] to find out what to watch out for.
|
56
75
|
|
57
|
-
|
76
|
+
Be sure to check the general [RSpec upgrade notes][] as well.
|
58
77
|
|
59
|
-
|
60
|
-
|
61
|
-
bundle exec rspec spec/models
|
78
|
+
[`rspec-rails` upgrade notes]: https://www.relishapp.com/rspec/rspec-rails/docs/upgrade
|
79
|
+
[RSpec upgrade notes]: https://relishapp.com/rspec/docs/upgrade
|
62
80
|
|
63
|
-
|
64
|
-
bundle exec rspec spec/controllers/accounts_controller_spec.rb
|
81
|
+
## Usage
|
65
82
|
|
66
|
-
|
67
|
-
bundle exec rspec spec/controllers/accounts_controller_spec.rb:8
|
68
|
-
```
|
83
|
+
### Creating boilerplate specs with `rails generate`
|
69
84
|
|
70
|
-
|
71
|
-
|
85
|
+
```sh
|
86
|
+
# RSpec hooks into built-in generators
|
87
|
+
$ rails generate model user
|
88
|
+
invoke active_record
|
89
|
+
create db/migrate/20181017040312_create_users.rb
|
90
|
+
create app/models/user.rb
|
91
|
+
invoke rspec
|
92
|
+
create spec/models/user_spec.rb
|
72
93
|
|
73
|
-
|
74
|
-
|
94
|
+
# RSpec also provides its own spec file generators
|
95
|
+
$ rails generate rspec:model user
|
96
|
+
create spec/models/user_spec.rb
|
75
97
|
|
98
|
+
# List all RSpec generators
|
99
|
+
$ rails generate --help | grep rspec
|
76
100
|
```
|
77
|
-
bundle binstubs rspec-core
|
78
|
-
```
|
79
|
-
|
80
|
-
### Upgrade Note
|
81
|
-
|
82
|
-
For detailed information on the general RSpec 3.x upgrade process see the
|
83
|
-
[RSpec Upgrade docs](https://relishapp.com/rspec/docs/upgrade).
|
84
|
-
|
85
|
-
There are three particular `rspec-rails` specific changes to be aware of:
|
86
|
-
|
87
|
-
1. [The default helper files created in RSpec 3.x have changed](https://www.relishapp.com/rspec/rspec-rails/docs/upgrade#default-helper-files)
|
88
|
-
2. [File-type inference disabled by default](https://www.relishapp.com/rspec/rspec-rails/docs/upgrade#file-type-inference-disabled)
|
89
|
-
3. [Rails 4.x `ActiveRecord::Migration` pending migration checks](https://www.relishapp.com/rspec/rspec-rails/docs/upgrade#pending-migration-checks)
|
90
|
-
4. Extraction of `stub_model` and `mock_model` to
|
91
|
-
[`rspec-activemodel-mocks`](https://github.com/rspec/rspec-activemodel-mocks)
|
92
|
-
5. In Rails 5.x, controller testing has been moved to its own gem which is [rails-controller-testing](https://github.com/rails/rails-controller-testing). Using `assigns` in your controller specs without adding this gem will no longer work.
|
93
|
-
6. `rspec-rails` now includes two helpers, `spec_helper.rb` and `rails_helper.rb`.
|
94
|
-
`spec_helper.rb` is the conventional RSpec configuration helper, whilst the
|
95
|
-
Rails specific loading and bootstrapping has moved to the `rails_helper.rb`
|
96
|
-
file. Rails specs now need this file required beforehand either at the top
|
97
|
-
of the specific file (recommended) or a common configuration location such
|
98
|
-
as your `.rspec` file.
|
99
101
|
|
100
|
-
|
101
|
-
docs](https://www.relishapp.com/rspec/rspec-rails/docs/upgrade) for full
|
102
|
-
details.
|
102
|
+
### Running specs
|
103
103
|
|
104
|
-
|
105
|
-
|
104
|
+
```sh
|
105
|
+
# Default: Run all spec files (i.e., those matching spec/**/*_spec.rb)
|
106
|
+
$ bundle exec rspec
|
106
107
|
|
107
|
-
|
108
|
+
# Run all spec files in a single directory (recursively)
|
109
|
+
$ bundle exec rspec spec/models
|
108
110
|
|
109
|
-
|
110
|
-
|
111
|
-
used.
|
111
|
+
# Run a single spec file
|
112
|
+
$ bundle exec rspec spec/controllers/accounts_controller_spec.rb
|
112
113
|
|
113
|
-
|
114
|
-
|
115
|
-
information, see [list of all
|
116
|
-
generators](https://www.relishapp.com/rspec/rspec-rails/docs/generators).
|
114
|
+
# Run a single example from a spec file (by line number)
|
115
|
+
$ bundle exec rspec spec/controllers/accounts_controller_spec.rb:8
|
117
116
|
|
118
|
-
|
119
|
-
|
120
|
-
Once you've set up the environment, you'll need to cd into the working
|
121
|
-
directory of whichever repo you want to work in. From there you can run the
|
122
|
-
specs and cucumber features, and make patches.
|
123
|
-
|
124
|
-
NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You
|
125
|
-
can treat each RSpec repo as an independent project.
|
126
|
-
Please see the following files:
|
127
|
-
|
128
|
-
For `rspec-rails`-specific development information, see
|
129
|
-
|
130
|
-
- [Build details](BUILD_DETAIL.md)
|
131
|
-
- [Code of Conduct](CODE_OF_CONDUCT.md)
|
132
|
-
- [Detailed contributing guide](CONTRIBUTING.md)
|
133
|
-
- [Development setup guide](DEVELOPMENT.md)
|
134
|
-
|
135
|
-
|
136
|
-
## Model Specs
|
137
|
-
|
138
|
-
Use model specs to describe behavior of models (usually ActiveRecord-based) in
|
139
|
-
the application.
|
140
|
-
|
141
|
-
Model specs default to residing in the `spec/models` folder. Tagging any
|
142
|
-
context with the metadata `:type => :model` treats its examples as model
|
143
|
-
specs.
|
144
|
-
|
145
|
-
For example:
|
146
|
-
|
147
|
-
```ruby
|
148
|
-
require "rails_helper"
|
149
|
-
|
150
|
-
RSpec.describe User, :type => :model do
|
151
|
-
it "orders by last name" do
|
152
|
-
lindeman = User.create!(first_name: "Andy", last_name: "Lindeman")
|
153
|
-
chelimsky = User.create!(first_name: "David", last_name: "Chelimsky")
|
154
|
-
|
155
|
-
expect(User.ordered_by_last_name).to eq([chelimsky, lindeman])
|
156
|
-
end
|
157
|
-
end
|
117
|
+
# See all options for running specs
|
118
|
+
$ bundle exec rspec --help
|
158
119
|
```
|
159
120
|
|
160
|
-
|
161
|
-
|
121
|
+
**Optional:** If `bundle exec rspec` is too verbose for you,
|
122
|
+
you can generate a binstub at `bin/rspec` and use that instead:
|
162
123
|
|
163
|
-
|
124
|
+
```sh
|
125
|
+
$ bundle binstubs rspec-core
|
126
|
+
```
|
164
127
|
|
165
|
-
|
166
|
-
specifically, the HTTP response to be issued for a given request (a.k.a.
|
167
|
-
integration tests). Since such client-facing behavior encompasses controller
|
168
|
-
actions, this is the type of spec to use for controller testing.
|
128
|
+
## RSpec DSL Basics (or, how do I write a spec?)
|
169
129
|
|
170
|
-
|
171
|
-
|
172
|
-
:request` treats its examples as request specs.
|
173
|
-
|
174
|
-
Request specs mix in behavior from
|
175
|
-
[ActionDispatch::Integration::Runner](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Runner.html),
|
176
|
-
which is the basis for [Rails' integration
|
177
|
-
tests](http://guides.rubyonrails.org/testing.html#integration-testing).
|
130
|
+
In RSpec, application behavior is described
|
131
|
+
**first in (almost) plain English, then again in test code**, like so:
|
178
132
|
|
179
133
|
```ruby
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
user = User.create!(:username => "jdoe", :password => "secret")
|
185
|
-
get "/login"
|
186
|
-
assert_select "form.login" do
|
187
|
-
assert_select "input[name=?]", "username"
|
188
|
-
assert_select "input[name=?]", "password"
|
189
|
-
assert_select "input[type=?]", "submit"
|
134
|
+
RSpec.describe 'Post' do #
|
135
|
+
context 'before publication' do # (almost) plain English
|
136
|
+
it 'cannot have comments' do #
|
137
|
+
expect { Post.create.comments.create! }.to raise_error(ActiveRecord::RecordInvalid) # test code
|
190
138
|
end
|
191
|
-
|
192
|
-
post "/login", :username => "jdoe", :password => "secret"
|
193
|
-
assert_select ".header .username", :text => "jdoe"
|
194
139
|
end
|
195
140
|
end
|
196
141
|
```
|
197
142
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
```ruby
|
204
|
-
require 'rails_helper'
|
205
|
-
|
206
|
-
RSpec.describe "home page", :type => :request do
|
207
|
-
it "displays the user's username after successful login" do
|
208
|
-
user = FactoryGirl.create(:user, :username => "jdoe", :password => "secret")
|
209
|
-
visit "/login"
|
210
|
-
fill_in "Username", :with => "jdoe"
|
211
|
-
fill_in "Password", :with => "secret"
|
212
|
-
click_button "Log in"
|
143
|
+
Running `rspec` will execute this test code,
|
144
|
+
and then use the plain-English descriptions
|
145
|
+
to generate a report of where the application
|
146
|
+
conforms to (or fails to meet) the spec:
|
213
147
|
|
214
|
-
expect(page).to have_selector(".header .username", :text => "jdoe")
|
215
|
-
end
|
216
|
-
end
|
217
148
|
```
|
149
|
+
$ rspec --format documentation spec/models/post_spec.rb
|
218
150
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
Among other benefits, Capybara binds the form post to the generated HTML, which
|
224
|
-
means we don't need to specify them separately. Note that Capybara's DSL as
|
225
|
-
shown is, by default, only available in specs in the spec/features directory.
|
226
|
-
For more information, see the [Capybara integration
|
227
|
-
docs](http://rubydoc.info/gems/rspec-rails/file/Capybara.md).
|
228
|
-
|
229
|
-
There are several other Ruby libs that implement the factory pattern or provide
|
230
|
-
a DSL for request specs (a.k.a. acceptance or integration specs), but
|
231
|
-
FactoryGirl and Capybara seem to be the most widely used. Whether you choose
|
232
|
-
these or other libs, we strongly recommend using something for each of these
|
233
|
-
roles.
|
234
|
-
|
235
|
-
For more information, see [cucumber scenarios for request
|
236
|
-
specs](https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec).
|
151
|
+
Post
|
152
|
+
before publication
|
153
|
+
cannot have comments
|
237
154
|
|
238
|
-
|
155
|
+
Failures:
|
239
156
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
supported until at least version 4.0 (see the [release
|
245
|
-
notes](http://rspec.info/blog/2016/07/rspec-3-5-has-been-released/#rails-support-for-rails-5)
|
246
|
-
for details).
|
157
|
+
1) Post before publication cannot have comments
|
158
|
+
Failure/Error: expect { Post.create.comments.create! }.to raise_error(ActiveRecord::RecordInvalid)
|
159
|
+
expected ActiveRecord::RecordInvalid but nothing was raised
|
160
|
+
# ./spec/models/post.rb:4:in `block (3 levels) in <top (required)>'
|
247
161
|
|
248
|
-
|
249
|
-
|
162
|
+
Finished in 0.00527 seconds (files took 0.29657 seconds to load)
|
163
|
+
1 example, 1 failure
|
250
164
|
|
251
|
-
|
165
|
+
Failed examples:
|
252
166
|
|
253
|
-
|
254
|
-
[`capybara`](https://github.com/jnicklas/capybara) is used to manage the
|
255
|
-
simulated browser.
|
256
|
-
|
257
|
-
Feature specs default to residing in the `spec/features` folder. Tagging any
|
258
|
-
context with the metadata `:type => :feature` treats its examples as feature
|
259
|
-
specs.
|
260
|
-
|
261
|
-
Feature specs mix in functionality from the capybara gem, thus they require
|
262
|
-
`capybara` to use. To use feature specs, add `capybara` to the `Gemfile`:
|
263
|
-
|
264
|
-
```ruby
|
265
|
-
gem "capybara"
|
167
|
+
rspec ./spec/models/post_spec.rb:3 # Post before publication cannot have comments
|
266
168
|
```
|
267
169
|
|
268
|
-
For
|
269
|
-
|
170
|
+
For an in-depth look at the RSpec DSL, including lots of examples,
|
171
|
+
read the official Cucumber documentation for [RSpec Core][].
|
270
172
|
|
271
|
-
|
173
|
+
[RSpec Core]: https://relishapp.com/rspec/rspec-core/docs
|
272
174
|
|
273
|
-
|
274
|
-
`:type => :mailer` to any context makes its examples be treated as mailer specs.
|
175
|
+
### Helpful Rails Matchers
|
275
176
|
|
276
|
-
|
177
|
+
In RSpec, assertions are called _expectations,_
|
178
|
+
and every expectation is built around a _matcher._
|
179
|
+
When you `expect(a).to eq(b)`, you’re using the `eq` matcher.
|
277
180
|
|
278
|
-
|
279
|
-
|
181
|
+
In addition to [the matchers that come standard in RSpec][],
|
182
|
+
here are some extras that make it easier
|
183
|
+
to test the various parts of a Rails system:
|
280
184
|
|
281
|
-
RSpec
|
282
|
-
|
283
|
-
|
185
|
+
| RSpec matcher | Delegates to | Available in | Notes |
|
186
|
+
| ------------------------ | ----------------- | ------------------------------- | -------------------------------------------------------- |
|
187
|
+
| [`be_a_new`][] | | all | primarily intended for controller specs |
|
188
|
+
| [`render_template`][] | `assert_template` | request / controller / view | use with `expect(response).to` |
|
189
|
+
| [`redirect_to`][] | `assert_redirect` | request / controller | use with `expect(response).to` |
|
190
|
+
| [`route_to`] | `assert_routing` | routing / controller | replaces `route_for` from version 1.x |
|
191
|
+
| [`be_routable`] | | routing / controller | usu. for `expect(...).not_to be_routable` |
|
192
|
+
| [`have_http_status`][] | | request / controller / feature | |
|
193
|
+
| [`match_array`][] | | all | for comparing arrays of ActiveRecord objects |
|
194
|
+
| [`have_been_enqueued`][] | | all | requires config: `ActiveJob::Base.queue_adapter = :test` |
|
195
|
+
| [`have_enqueued_job`][] | | all | requires config: `ActiveJob::Base.queue_adapter = :test` |
|
284
196
|
|
285
|
-
|
286
|
-
expect(mail.subject).to eq("Signup")
|
287
|
-
expect(mail.to).to eq(["to@example.org"])
|
288
|
-
expect(mail.from).to eq(["from@example.com"])
|
289
|
-
end
|
197
|
+
Follow the links above for examples of how each matcher is used.
|
290
198
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
199
|
+
[the matchers that come standard in RSpec]: https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
|
200
|
+
[`be_a_new`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/be-a-new-matcher
|
201
|
+
[`render_template`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/render-template-matcher
|
202
|
+
[`redirect_to`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/redirect-to-matcher
|
203
|
+
[`route_to`]: https://relishapp.com/rspec/rspec-rails/docs/routing-specs/route-to-matcher
|
204
|
+
[`be_routable`]: https://relishapp.com/rspec/rspec-rails/docs/routing-specs/be-routable-matcher
|
205
|
+
[`have_http_status`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/have-http-status-matcher
|
206
|
+
[`match_array`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/activerecord-relation-match-array
|
207
|
+
[`have_been_enqueued`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/have-been-enqueued-matcher
|
208
|
+
[`have_enqueued_job`]: https://relishapp.com/rspec/rspec-rails/docs/matchers/have-enqueued-job-matcher
|
297
209
|
|
298
|
-
|
299
|
-
](https://relishapp.com/rspec/rspec-rails/v/3-4/docs/mailer-specs).
|
210
|
+
### What else does RSpec Rails add?
|
300
211
|
|
301
|
-
|
212
|
+
For a comprehensive look at RSpec Rails’ features,
|
213
|
+
read the [official Cucumber documentation][].
|
302
214
|
|
303
|
-
|
304
|
-
specs. Typically these specs will live in `spec/jobs`.
|
215
|
+
[official Cucumber documentation]: https://relishapp.com/rspec/rspec-rails/docs
|
305
216
|
|
306
|
-
|
307
|
-
require 'rails_helper'
|
308
|
-
|
309
|
-
RSpec.describe UploadBackupsJob, :type => :job do
|
310
|
-
describe "#perform_later" do
|
311
|
-
it "uploads a backup" do
|
312
|
-
ActiveJob::Base.queue_adapter = :test
|
313
|
-
UploadBackupsJob.perform_later('backup')
|
314
|
-
expect(UploadBackupsJob).to have_been_enqueued
|
315
|
-
end
|
316
|
-
end
|
317
|
-
end
|
318
|
-
```
|
217
|
+
## What tests should I write?
|
319
218
|
|
320
|
-
|
321
|
-
|
219
|
+
RSpec Rails defines ten different _types_ of specs
|
220
|
+
for testing different parts of a typical Rails application.
|
221
|
+
Each one inherits from one of Rails’ built-in `TestCase` classes,
|
222
|
+
meaning the helper methods provided by default in Rails tests
|
223
|
+
are available in RSpec, as well.
|
322
224
|
|
323
|
-
|
225
|
+
| Spec type | Corresponding Rails test class |
|
226
|
+
| -------------- | -------------------------------- |
|
227
|
+
| [model][] | |
|
228
|
+
| [controller][] | [`ActionController::TestCase`][] |
|
229
|
+
| [mailer][] | `ActionMailer::TestCase` |
|
230
|
+
| [job][] | |
|
231
|
+
| [view][] | `ActionView::TestCase` |
|
232
|
+
| [routing][] | |
|
233
|
+
| [helper][] | `ActionView::TestCase` |
|
234
|
+
| [request][] | [`ActionDispatch::IntegrationTest`][] |
|
235
|
+
| [feature][] | |
|
236
|
+
| [system][] | [`ActionDispatch::SystemTestCase`][] |
|
324
237
|
|
325
|
-
|
326
|
-
|
238
|
+
Follow the links above to see examples of each spec type,
|
239
|
+
or for official Rails API documentation on the given `TestCase` class.
|
327
240
|
|
328
|
-
|
241
|
+
> **Note: This is not a checklist.**
|
242
|
+
>
|
243
|
+
> Ask a hundred developers how to test an application,
|
244
|
+
> and you’ll get a hundred different answers.
|
245
|
+
>
|
246
|
+
> RSpec Rails provides thoughtfully selected features
|
247
|
+
> to encourage good testing practices, but there’s no “right” way to do it.
|
248
|
+
> Ultimately, it’s up to you to decide how your test suite will be composed.
|
249
|
+
|
250
|
+
When creating a spec file,
|
251
|
+
assign it a type in the top-level `describe` block, like so:
|
329
252
|
|
330
253
|
```ruby
|
331
|
-
|
254
|
+
# spec/models/user_spec.rb
|
332
255
|
|
333
|
-
RSpec.describe
|
334
|
-
|
335
|
-
assign(:events, [double(Event), double(Event)])
|
336
|
-
render
|
337
|
-
expect(view).to render_template(:partial => "_event", :count => 2)
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
RSpec.describe "events/show", :type => :view do
|
342
|
-
it "displays the event location" do
|
343
|
-
assign(:event, Event.new(:location => "Chicago"))
|
344
|
-
render
|
345
|
-
expect(rendered).to include("Chicago")
|
346
|
-
end
|
347
|
-
end
|
256
|
+
RSpec.describe User, type: :model do
|
257
|
+
...
|
348
258
|
```
|
349
259
|
|
350
|
-
|
351
|
-
|
260
|
+
[request]: https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec
|
261
|
+
[feature]: https://www.relishapp.com/rspec/rspec-rails/docs/feature-specs/feature-spec
|
262
|
+
[system]: https://relishapp.com/rspec/rspec-rails/docs/system-specs/system-spec
|
263
|
+
[model]: https://www.relishapp.com/rspec/rspec-rails/docs/model-specs
|
264
|
+
[controller]: https://www.relishapp.com/rspec/rspec-rails/docs/controller-specs
|
265
|
+
[mailer]: https://relishapp.com/rspec/rspec-rails/docs/mailer-specs
|
266
|
+
[job]: https://relishapp.com/rspec/rspec-rails/docs/job-specs/job-spec
|
267
|
+
[view]: https://www.relishapp.com/rspec/rspec-rails/docs/view-specs/view-spec
|
268
|
+
[routing]: https://www.relishapp.com/rspec/rspec-rails/docs/routing-specs
|
269
|
+
[helper]: https://www.relishapp.com/rspec/rspec-rails/docs/helper-specs/helper-spec
|
270
|
+
[`ActionDispatch::IntegrationTest`]: https://api.rubyonrails.org/classes/ActionDispatch/IntegrationTest.html
|
271
|
+
[`ActionDispatch::SystemTestCase`]: https://api.rubyonrails.org/classes/ActionDispatch/SystemTestCase.html
|
272
|
+
[`ActionController::TestCase`]: https://api.rubyonrails.org/classes/ActionController/TestCase.html
|
273
|
+
[in the appropriate folder]: https://relishapp.com/rspec/rspec-rails/docs/directory-structure
|
352
274
|
|
353
|
-
|
354
|
-
controller.controller_path == "events"
|
355
|
-
controller.request.path_parameters[:controller] == "events"
|
356
|
-
```
|
275
|
+
### System specs, feature specs, request specs–what’s the difference?
|
357
276
|
|
358
|
-
|
359
|
-
|
360
|
-
need to override these values before rendering the view.
|
277
|
+
RSpec Rails provides some end-to-end (entire application) testing capability
|
278
|
+
to specify the interaction with the client.
|
361
279
|
|
362
|
-
|
363
|
-
and the layout explicitly. For example:
|
280
|
+
#### System specs
|
364
281
|
|
365
|
-
|
366
|
-
|
367
|
-
|
282
|
+
Also called **acceptance tests**, **browser tests**, or **end-to-end tests**,
|
283
|
+
system specs test the application from the perspective of a _human client._
|
284
|
+
The test code walks through a user’s browser interactions,
|
368
285
|
|
369
|
-
|
286
|
+
* `visit '/login'`
|
287
|
+
* `fill_in 'Name', with: 'jdoe'`
|
370
288
|
|
371
|
-
|
289
|
+
and the expectations revolve around page content.
|
372
290
|
|
373
|
-
|
374
|
-
assign(:widget, Widget.new)
|
375
|
-
render
|
376
|
-
```
|
291
|
+
* `expect(page).to have_text('Welcome')`
|
377
292
|
|
378
|
-
|
379
|
-
|
293
|
+
Because system specs are a wrapper around Rails’ built-in `SystemTestCase`,
|
294
|
+
they’re only available on Rails 5.1+.
|
295
|
+
(Feature specs serve the same purpose, but without this dependency.)
|
380
296
|
|
381
|
-
|
382
|
-
instance variables you set will be transparently propagated into your views
|
383
|
-
(similar to how instance variables you set in controller actions are made
|
384
|
-
available in views). For example:
|
297
|
+
#### Feature specs
|
385
298
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
299
|
+
Before Rails introduced system testing facilities,
|
300
|
+
feature specs were the only spec type for end-to-end testing.
|
301
|
+
While the RSpec team now [officially recommends system specs][] instead,
|
302
|
+
feature specs are still fully supported, look basically identical,
|
303
|
+
and work on older versions of Rails.
|
390
304
|
|
391
|
-
|
392
|
-
|
393
|
-
|
305
|
+
On the other hand, feature specs require non-trivial configuration
|
306
|
+
to get some important features working,
|
307
|
+
like JavaScript testing or making sure each test runs with a fresh DB state.
|
308
|
+
With system specs, this configuration is provided out-of-the-box.
|
394
309
|
|
395
|
-
|
310
|
+
Like system specs, feature specs require the [Capybara][] gem.
|
311
|
+
Rails 5.1+ includes it by default as part of system tests,
|
312
|
+
but if you don’t have the luxury of upgrading,
|
313
|
+
be sure to add it to the `:test` group of your `Gemfile` first:
|
396
314
|
|
397
315
|
```ruby
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
# rspec-rails-2.x+
|
402
|
-
assign(key, value)
|
403
|
-
```
|
404
|
-
|
405
|
-
### `rendered`
|
406
|
-
|
407
|
-
This represents the rendered view.
|
408
|
-
|
409
|
-
```ruby
|
410
|
-
render
|
411
|
-
expect(rendered).to match /Some text expected to appear on the page/
|
412
|
-
```
|
413
|
-
|
414
|
-
#### Upgrade note
|
415
|
-
|
416
|
-
```ruby
|
417
|
-
# rspec-rails-1.x
|
418
|
-
render
|
419
|
-
response.should xxx
|
420
|
-
|
421
|
-
# rspec-rails-2.x+
|
422
|
-
render
|
423
|
-
rendered.should xxx
|
424
|
-
|
425
|
-
# rspec-rails-2.x+ with expect syntax
|
426
|
-
render
|
427
|
-
expect(rendered).to xxx
|
428
|
-
```
|
429
|
-
|
430
|
-
## Routing specs
|
431
|
-
|
432
|
-
Routing specs default to residing in the `spec/routing` folder. Tagging any
|
433
|
-
context with the metadata `:type => :routing` treats its examples as routing
|
434
|
-
specs.
|
435
|
-
|
436
|
-
```ruby
|
437
|
-
require 'rails_helper'
|
438
|
-
|
439
|
-
RSpec.describe "routing to profiles", :type => :routing do
|
440
|
-
it "routes /profile/:username to profile#show for username" do
|
441
|
-
expect(:get => "/profiles/jsmith").to route_to(
|
442
|
-
:controller => "profiles",
|
443
|
-
:action => "show",
|
444
|
-
:username => "jsmith"
|
445
|
-
)
|
446
|
-
end
|
447
|
-
|
448
|
-
it "does not expose a list of profiles" do
|
449
|
-
expect(:get => "/profiles").not_to be_routable
|
450
|
-
end
|
316
|
+
group :test do
|
317
|
+
gem "capybara"
|
451
318
|
end
|
452
319
|
```
|
453
320
|
|
454
|
-
|
455
|
-
|
456
|
-
`route_for` from rspec-rails-1.x is gone. Use `route_to` and `be_routable`
|
457
|
-
instead.
|
458
|
-
|
459
|
-
## Helper specs
|
460
|
-
|
461
|
-
Helper specs default to residing in the `spec/helpers` folder. Tagging any
|
462
|
-
context with the metadata `:type => :helper` treats its examples as helper
|
463
|
-
specs.
|
464
|
-
|
465
|
-
Helper specs mix in ActionView::TestCase::Behavior. A `helper` object is
|
466
|
-
provided which mixes in the helper module being spec'd, along with
|
467
|
-
`ApplicationHelper` (if present).
|
468
|
-
|
469
|
-
```ruby
|
470
|
-
require 'rails_helper'
|
471
|
-
|
472
|
-
RSpec.describe EventsHelper, :type => :helper do
|
473
|
-
describe "#link_to_event" do
|
474
|
-
it "displays the title, and formatted date" do
|
475
|
-
event = Event.new("Ruby Kaigi", Date.new(2010, 8, 27))
|
476
|
-
# helper is an instance of ActionView::Base configured with the
|
477
|
-
# EventsHelper and all of Rails' built-in helpers
|
478
|
-
expect(helper.link_to_event).to match /Ruby Kaigi, 27 Aug, 2010/
|
479
|
-
end
|
480
|
-
end
|
481
|
-
end
|
482
|
-
```
|
483
|
-
|
484
|
-
## Matchers
|
485
|
-
|
486
|
-
Several domain-specific matchers are provided to each of the example group
|
487
|
-
types. Most simply delegate to their equivalent Rails' assertions.
|
488
|
-
|
489
|
-
### `be_a_new`
|
490
|
-
|
491
|
-
- Available in all specs
|
492
|
-
- Primarily intended for controller specs
|
493
|
-
|
494
|
-
```ruby
|
495
|
-
expect(object).to be_a_new(Widget)
|
496
|
-
```
|
497
|
-
|
498
|
-
Passes if the object is a `Widget` and returns true for `new_record?`
|
321
|
+
[officially recommends system specs]: https://rspec.info/blog/2017/10/rspec-3-7-has-been-released/#rails-actiondispatchsystemtest-integration-system-specs
|
322
|
+
[Capybara]: https://github.com/teamcapybara/capybara
|
499
323
|
|
500
|
-
|
324
|
+
#### Request specs
|
501
325
|
|
502
|
-
|
503
|
-
|
326
|
+
Request specs are for testing the application
|
327
|
+
from the perspective of a _machine client._
|
328
|
+
They begin with an HTTP request and end with the HTTP response,
|
329
|
+
so they’re faster than feature specs,
|
330
|
+
but do not examine your app’s UI or JavaScript.
|
504
331
|
|
505
|
-
|
332
|
+
Request specs provide a high-level alternative to controller specs.
|
333
|
+
In fact, as of RSpec 3.5, both the Rails and RSpec teams
|
334
|
+
[discourage directly testing controllers][]
|
335
|
+
in favor of functional tests like request specs.
|
506
336
|
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
In view specs, apply to the `view` object:
|
512
|
-
|
513
|
-
```ruby
|
514
|
-
expect(view).to render_template(:partial => "_form", :locals => { :widget => widget } )
|
515
|
-
```
|
516
|
-
|
517
|
-
### `redirect_to`
|
518
|
-
|
519
|
-
- Delegates to `assert_redirect`
|
520
|
-
- Available in request and controller specs
|
521
|
-
|
522
|
-
```ruby
|
523
|
-
expect(response).to redirect_to(widgets_path)
|
524
|
-
```
|
525
|
-
|
526
|
-
### `route_to`
|
527
|
-
|
528
|
-
- Delegates to Rails' `assert_routing`
|
529
|
-
- Available in routing and controller specs
|
530
|
-
|
531
|
-
```ruby
|
532
|
-
expect(:get => "/widgets").to route_to(:controller => "widgets", :action => "index")
|
533
|
-
```
|
534
|
-
|
535
|
-
### `be_routable`
|
536
|
-
|
537
|
-
Passes if the path is recognized by Rails' routing. This is primarily intended
|
538
|
-
to be used with `not_to` to specify standard CRUD routes which should not be
|
539
|
-
routable.
|
540
|
-
|
541
|
-
```ruby
|
542
|
-
expect(:get => "/widgets/1/edit").not_to be_routable
|
543
|
-
```
|
544
|
-
|
545
|
-
### `have_http_status`
|
546
|
-
|
547
|
-
- Passes if `response` has a matching HTTP status code
|
548
|
-
- The following symbolic status codes are allowed:
|
549
|
-
- `Rack::Utils::SYMBOL_TO_STATUS_CODE`
|
550
|
-
- One of the defined `ActionDispatch::TestResponse` aliases:
|
551
|
-
- `:error`
|
552
|
-
- `:missing`
|
553
|
-
- `:redirect`
|
554
|
-
- `:success`
|
555
|
-
- Available in controller, feature, and request specs.
|
556
|
-
|
557
|
-
In controller and request specs, apply to the `response` object:
|
337
|
+
When writing them, try to answer the question,
|
338
|
+
“For a given HTTP request (verb + path + parameters),
|
339
|
+
what HTTP response should the application return?”
|
558
340
|
|
559
|
-
|
560
|
-
expect(response).to have_http_status(201)
|
561
|
-
expect(response).not_to have_http_status(:created)
|
562
|
-
```
|
563
|
-
|
564
|
-
In feature specs, apply to the `page` object:
|
341
|
+
[discourage directly testing controllers]: https://rspec.info/blog/2016/07/rspec-3-5-has-been-released/#rails-support-for-rails-5
|
565
342
|
|
566
|
-
|
567
|
-
expect(page).to have_http_status(:success)
|
568
|
-
```
|
569
|
-
|
570
|
-
## `rake` tasks
|
571
|
-
|
572
|
-
Several rake tasks are provided as a convenience for working with RSpec. To run
|
573
|
-
the entire spec suite use `rake spec`. To run a subset of specs use the
|
574
|
-
associated type task, for example `rake spec:models`.
|
575
|
-
|
576
|
-
A full list of the available rake tasks can be seen by running `rake -T | grep
|
577
|
-
spec`.
|
343
|
+
## Contributing
|
578
344
|
|
579
|
-
|
345
|
+
- [Build details](BUILD_DETAIL.md)
|
346
|
+
- [Code of Conduct](CODE_OF_CONDUCT.md)
|
347
|
+
- [Detailed contributing guide](CONTRIBUTING.md)
|
580
348
|
|
581
|
-
|
582
|
-
|
583
|
-
project](https://www.relishapp.com/rspec/rspec-core/docs/command-line/rake-task).
|
584
|
-
However, you must first clear the task that rspec-rails defined:
|
349
|
+
Once you’ve cloned the repo and [set up the environment](DEVELOPMENT.md),
|
350
|
+
you can run the specs and Cucumber features, or submit a pull request.
|
585
351
|
|
586
|
-
|
587
|
-
task("spec").clear
|
588
|
-
```
|
352
|
+
## See Also
|
589
353
|
|
354
|
+
### RSpec base libraries
|
590
355
|
|
591
|
-
|
356
|
+
* <https://github.com/rspec/rspec>
|
357
|
+
* <https://github.com/rspec/rspec-core>
|
358
|
+
* <https://github.com/rspec/rspec-expectations>
|
359
|
+
* <https://github.com/rspec/rspec-mocks>
|
592
360
|
|
593
|
-
|
594
|
-
* [https://github.com/rspec/rspec-core](https://github.com/rspec/rspec-core)
|
595
|
-
* [https://github.com/rspec/rspec-expectations](https://github.com/rspec/rspec-expectations)
|
596
|
-
* [https://github.com/rspec/rspec-mocks](https://github.com/rspec/rspec-mocks)
|
361
|
+
### Recommended third-party extensions
|
597
362
|
|
598
|
-
|
363
|
+
* [FactoryBot](https://github.com/thoughtbot/factory_bot)
|
364
|
+
* [Capybara](https://github.com/teamcapybara/capybara)
|
365
|
+
(Included by default in Rails 5.1+.
|
366
|
+
Note that [additional configuration is required][] to use the Capybara DSL
|
367
|
+
anywhere other than system specs and feature specs.)
|
599
368
|
|
600
|
-
|
369
|
+
[additional configuration is required]: https://rubydoc.info/gems/rspec-rails/file/Capybara.md
|