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