everydayrails / rails-4-1-rspec-3-0 Goto Github PK
View Code? Open in Web Editor NEWCode samples for Everyday Rails Testing with RSpec, Rails 4.1/RSpec 3.0 edition
Code samples for Everyday Rails Testing with RSpec, Rails 4.1/RSpec 3.0 edition
In Simplifying our syntax section in chapter 4, the sample code is described as "is has a valid factory". It should be "has a valid factory".
I found http://ruby.railstutorial.org is now redirected to https://www.railstutorial.org/ . You may want to update the link URL.
In sample code, you wrote "describe "admin access to contacts" do", but document output is "administrator access". Same as user access.
In chapter 8, you write "We also need to configure Database Cleaner", but it should be "DatabaseCleaner" for consistency. (Very trivial point, I admit.)
In chapter 3, you wrote "We'll fill in the details in a moment, but if we ran the specs right now from the command line (by typing bin/rspec
or just rspec
on the command line) the output would be similar to the following:" However bin/rspec
and rspec
are not always interchangeable. (bin/rspec
and bundle exec rspec
are usually interchangeable, I think.)
rbenv executes the latest version of RSpec in specific Ruby version. If it differs the one in Gemfile.lock, you may not be able to run tests.
The following scenario shows such case (3.1.7 vs 3.0.0):
➜ cb git:(master) rspec -v
3.0.0
➜ cb git:(master) gem update rspec
Updating installed gems
Updating rspec-core
Fetching: rspec-support-3.1.2.gem (100%)
Successfully installed rspec-support-3.1.2
Fetching: rspec-core-3.1.7.gem (100%)
Successfully installed rspec-core-3.1.7
Updating rspec-expectations
Fetching: rspec-expectations-3.1.2.gem (100%)
Successfully installed rspec-expectations-3.1.2
Updating rspec-mocks
Fetching: rspec-mocks-3.1.3.gem (100%)
Successfully installed rspec-mocks-3.1.3
Updating rspec-rails
Fetching: rspec-rails-3.1.0.gem (100%)
Successfully installed rspec-rails-3.1.0
Updating spring-commands-rspec
Fetching: spring-commands-rspec-1.0.4.gem (100%)
Successfully installed spring-commands-rspec-1.0.4
Gems updated: rspec-core rspec-support rspec-expectations rspec-mocks rspec-rails spring-commands-rspec
➜ cb git:(master) rspec -v
3.1.7
➜ cb git:(master) bin/rspec -v
3.0.0
➜ cb git:(master) bundle exec rspec -v
3.0.0
➜ cb git:(master) rspec
/Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/bundler-1.7.6/lib/bundler/runtime.rb:34:in `block in setup': You have already activated rspec-support 3.1.2, but your Gemfile requires rspec-support 3.0.0. Prepending `bundle exec` to your command may solve this. (Gem::LoadError)
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/bundler-1.7.6/lib/bundler/runtime.rb:19:in `setup'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/bundler-1.7.6/lib/bundler.rb:121:in `setup'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/bundler-1.7.6/lib/bundler/setup.rb:7:in `<top (required)>'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:135:in `require'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:135:in `rescue in require'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:144:in `require'
from /Users/jit/dev/private/cb/config/boot.rb:4:in `<top (required)>'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/jit/dev/private/cb/config/application.rb:1:in `<top (required)>'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/jit/dev/private/cb/config/environment.rb:2:in `<top (required)>'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/jit/dev/private/cb/spec/spec_helper.rb:3:in `<top (required)>'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/jit/dev/private/cb/spec/features/admin_spec.rb:2:in `<top (required)>'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/lib/rspec/core/configuration.rb:1105:in `load'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/lib/rspec/core/configuration.rb:1105:in `block in load_spec_files'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/lib/rspec/core/configuration.rb:1105:in `each'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/lib/rspec/core/configuration.rb:1105:in `load_spec_files'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/lib/rspec/core/runner.rb:96:in `setup'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/lib/rspec/core/runner.rb:84:in `run'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/lib/rspec/core/runner.rb:69:in `run'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/lib/rspec/core/runner.rb:37:in `invoke'
from /Users/jit/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/exe/rspec:4:in `<top (required)>'
from /Users/jit/.rbenv/versions/2.1.4/bin/rspec:23:in `load'
from /Users/jit/.rbenv/versions/2.1.4/bin/rspec:23:in `<main>'
➜ cb git:(master) bin/rspec
......
Finished in 0.62278 seconds (files took 0.39209 seconds to load)
6 examples, 0 failures
Randomized with seed 63723
➜ cb git:(master) bin/rspec -v
3.0.0
➜ cb git:(master) be rspec
......
Finished in 0.62967 seconds (files took 2.6 seconds to load)
6 examples, 0 failures
Randomized with seed 49959
Phone class has phone attribute. I think it could lead confusing.
E.g.
contact = Contact.find params[:id]
phones = contact.phones # Phone instances
phones = phones.map{|phone| phone.phone } # Phone attributes
It would be better if it has different attribute name. For example:
contact = Contact.find params[:id]
phones = contact.phones
phone_numbers = phones.map{|phone| phone.phone_number }
$ rails g scaffold news_release title released_on:date body:text
$ rake db:migrate
In chapter 11, the commands above could use binstub, like bin/rails
or bin/rake
. Don't you replace with them?
Now, if we run RSpec from the command line again (via
rspec
orbundle exec rspec
, depending on whether you installed therspec
binstub in the previous chapter) we see one passing example!
In the sentence above, you wrote "via rspec
or bundle exec rspec
" but I think "via bin/rspec
or bundle exec rspec
" would be better because readers can easily understand they are using the installed binstub.
As you know, pending
behavior has been changed since RSpec 3. So the code below should use skip
rather than pending
in this context:
it "loads a lot of data" do
pending "no longer necessary"
# your spec's code; it will not be run
end
And I think it is worth mentioning about the difference between skip
and pending
.
page 34, line 23 should say in my view:
expect(Contact.by_letter("J")).not_to include @smith
instead of:
expect(Contact.by_letter("J")).not_to include smith
In chapter 9, you wrote specify { should be_named 'John Doe' }
but it is not readable. It would be better to write as it { is_expected.to be_named 'John Doe' }
. Other sample codes like it { should ... }
should be changed to it { is_expected.to ...}
too, because you can write without "should" with RSpec 3.
In the API test, you use PUT method to update a contact. But isn't it PATCH? As for API design, I am not sure about that, though.
In exercises in chapter 2, you wrote "if you haven’t already, with bundle exec rake db:create:all.", but it bin/rake
would be better for this use case.
In chapter 7, "PUT" still exists:
describe 'PUT #update' do
it "requires login"
end
PUT #update
requires login
The implementation of title_with_date
is view-specific, so it should be implemented as helper method rather than model instance method. And I18n.l
is preferable to strftime
for internationalization purpose. For example:
module NewsReleasesHelper
def title_with_date(news_release)
"#{l news_release.released_on}: #{news_release.title}"
end
end
Other solution is using decorator gem like Draper. (It would be overkill here, though.)
I was getting the following error after adding js: true to features/user_spec.rb
Selenium::WebDriver::Error::JavascriptError: arguments[0] is undefined
I was running Firefox 35. The solution was to uninstall Firefox 35 and install Firefox 34 instead.
After that the specs were passing again. I'm not sure why it doesn't work with 35.
I found the solution on StackOverflow, which also suggests disabling automatic updates of Firefox, otherwise it will update to 35 and the spec may fail again.
In the third chapter Model specs of kindle edition in the testing validations section inthe secon paragraph code snippet is written as plain text
As you might know, Rails Tutorial 3rd edition is out now.
The news release says, it is using MiniTest and Lighter-weight testing approach:
http://news.railstutorial.org/rails_tutorial_3rd_ed_screencast_access
I have not read it yet, but the description in "More testing resources for Rails" might need to be changed.
In chapter 2, you wrote "That said, there are times when it makes sense to test a specific view. See chapter 12 for more details.", but I could not understand what you mean. In chapter 12, I am not sure which one is written about view test.
In the section titled "it{} and specify{}", there is no sample code using specify
. (I requested to do so, though...)
It may be hard to understand "Read your specs aloud as you write them, and use the term that makes the most sense--there are not hard rules about when to use one or the other." too.
I found an example spec which is written in normal text, the code doesn't even contain line breaks so it's very hard to read
I found the issue existing in the PDF and mobi versions, so I assume it also exists in the epub version.
It's under the Testing Validations
in chapter 3, highlighted in gray in the screenshot
In this repository .rspec
file has --warnings
option, but this is very noisy. When I git-cloned and ran RSpec, I was surprised at too many warnings. I guess beginners would be surprised too.
As for chapter 9 - Tags, a reader commented it might be worth mentioning about run_all_when_everything_filtered option:
https://www.relishapp.com/rspec/rspec-core/v/3-1/docs/configuration/run-all-when-everything-filtered
With this option, you don't have to remove config.filter_run focus: true
.
In chapater 9, you introduced Guard + Spring, but in branches for chapter 9, 11 and master, bin/rspec
does not use Spring. It is very confusing.
In addition, I think bin/rails
and bin/rake
should use Spring from the start, because this is Rails 4.1 application.
spec/controllers/contacts_controller_spec.rb:199
fails with
Failures:
1) ContactsController administrator access behaves like full access to contacts PATCH #update invalid attributes does not change the contact's attributes
Failure/Error: expect(assigns(:contact).reload.attributes).to eq contact.attributes
expected: {"id"=>2, "firstname"=>"Lawrence", "lastname"=>"Smith", "email"=>"[email protected]", "created_at"=>Thu, 08 Jan 2015 06:18:40 UTC +00:00, "updated_at"=>Thu, 08 Jan 2015 06:18:40 UTC +00:00, "hidden"=>false}
got: {"id"=>2, "firstname"=>"Lawrence", "lastname"=>"Smith", "email"=>"[email protected]", "created_at"=>Thu, 08 Jan 2015 06:18:40 UTC +00:00, "updated_at"=>Thu, 08 Jan 2015 06:18:40 UTC +00:00, "hidden"=>false}
(compared using ==)
Diff:
Shared Example Group: "full access to contacts" called from ./spec/controllers/contacts_controller_spec.rb:233
# ./spec/controllers/contacts_controller_spec.rb:199:in `block (5 levels) in <top (required)>'
# ./spec/rails_helper.rb:38:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:37:in `block (2 levels) in <top (required)>'
2) ContactsController user access behaves like full access to contacts PATCH #update invalid attributes does not change the contact's attributes
Failure/Error: expect(assigns(:contact).reload.attributes).to eq contact.attributes
expected: {"id"=>2, "firstname"=>"Lawrence", "lastname"=>"Smith", "email"=>"[email protected]", "created_at"=>Thu, 08 Jan 2015 06:18:41 UTC +00:00, "updated_at"=>Thu, 08 Jan 2015 06:18:41 UTC +00:00, "hidden"=>false}
got: {"id"=>2, "firstname"=>"Lawrence", "lastname"=>"Smith", "email"=>"[email protected]", "created_at"=>Thu, 08 Jan 2015 06:18:41 UTC +00:00, "updated_at"=>Thu, 08 Jan 2015 06:18:41 UTC +00:00, "hidden"=>false}
(compared using ==)
Diff:
Shared Example Group: "full access to contacts" called from ./spec/controllers/contacts_controller_spec.rb:242
# ./spec/controllers/contacts_controller_spec.rb:199:in `block (5 levels) in <top (required)>'
# ./spec/rails_helper.rb:38:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:37:in `block (2 levels) in <top (required)>'
in branch https://github.com/everydayrails/rails-4-1-rspec-3-0/tree/09_speedup
As you may be able to spot, we’re creating an outline of examples here to help us sort similar examples together. This makes for a more readable spec. Now let’s finish cleaning up our reorganized spec with the help of a before hook:
Sample code after the sentence above still require spec_helper. And I found some 'spec_helper's in other chapters. Please grep and fix them.
Your mailer spec has expect(mail.body.encoded).to match edit_friendship_path(user, friend)
but mail message usually has url rather than path. So I feel expect(mail.body.encoded).to match edit_friendship_url(user, friend)
is better. (edit_friendship_url
includes edit_friendship_path
, though.)
In addition, such a test case usually requires default_url_options
in test.rb
. Beginners might get in trouble (like I used to).
I found bundle exec rake db:create:all
command in exercises in chapter 2. Other chapters seem to have bundle exec
too. Please grep and fix them.
Naked command might execute unexpected version, so I think you should specify bin/xxx
or bundle exec xxx
.
For example:
guard init rspec
=> bundle exec guard init rspec
guard
=> Run bundle exec guard
spring binstub rspec
= > bundle exec spring binstub rspec
spring stop
=> bin/spring stop
rspec --tag focus
=> bin/rspec --tag focus
But I am not fully confident about which to use. Probably I am misunderstaindig. Please review and investigate by yourself.
In chapter 10, you wrote attach_file 'Avatar', File.new(...)
but that did not work for me. I used string file path instead of File object, like this:
Could you check it please?
In chapter 7, you write shared_examples_for 'public access to contacts' do
. I wonder why you use shared_examples_for
instead of shared_examples
. I think it should be shared_examples
for consistency.
Unnecessary block is used in phone attribute:
FactoryGirl.define do
factory :phone do
association :contact
phone { '123-555-1234' }
factory :home_phone do
phone_type 'home'
end
factory :work_phone do
phone_type 'work'
end
factory :mobile_phone do
phone_type 'mobile'
end
end
end
Notice the require 'rails_helper' at the top, and get used to typing it–all of your specs will include this line moving forward.
I actually like to add --require rails_helper
to a .rspec
file in my project root. This has the effect that all my specs are automatically run with rails_helper pre-required. You can do this with other parameters you'd like to use when running rspec as well. My full .rspec
file reads:
--color
--format documentation
--require rails_helper
As you mentioned in chapter 8, Launchy is installed with Capybara. So you can remove it from Gemfile. Actually I have never added Launchy to Gemfile explicitly.
In chapter 10, you suggest creating custom matcher called have_status_code
, but I found the same matcher called have_http_status
in rspec-rails.
You wrote "RSpec requires eq
or eql
, not ==
, to indicate an expectation of equality.". However, eq
and eql
are not interchangeable. This expression might lead misunderstanding. I think you don't have to mention eql
here.
https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers
it "is equal to a float of the same value" do
expect(5).to eq(5.0)
end
it "is not equal to a float of the same value" do
expect(5).not_to eql(5.0)
end
You wrote "RSpec prefers eq
over ==
to indicate an expectation of equality". I feel it is allowed to write as expect(x).to == y
, but it isn't. I think you should explicitly explain "==" is not allowed.
When you introduce Faker on page 54 there is this code example:
FactoryGirl.define do
factory :contact do
firstname { Faker::Name.first_name }
lastname { Faker::Name.last_name }
email { Faker::Internet.email }
end
end
but I think the curly brackets aren't needed.
You're saying “We’re testing not just for ideal results–the user selects a letter with results–but also for letters with no results.”, but this test is the really the same as the first test. There are results if you pass in 'J'.
I think you should change the letter being passed in to something like 'M' so there are no matching results. Maybe even change the expectation to something like:
expect(Contact.by_letter('K')).to be_empty
You might know, but generator config can be used to skip creating JS, SCSS and helper:
config.generators do |g|
# ...
g.assets false
g.helper false
g.javascripts false
g.stylesheets false
end
However, this is technique about Rails, not RSpec, so I am not sure if it is worth mentioning.
A reader reported bin/rspec
cannot run in "Applying your database schema to test". He or she checked out 01_untested branch and found rspec binstub did not exist in bin directory:
https://github.com/everydayrails/rails-4-1-rspec-3-0/tree/01_untested/bin
Could you check it?
Hello.
First I want to say "Thank you!!!" for creating this book!!! I will recommend this book for the Thinkful.com training site. I'm having problems with the Capybara testing. Rspec doesn't like when I type 'visit root_path'. When I create the Module, it still doesn't like the login aspect.
my github is https://github.com/vdogamer/rpsec1
(forgive my misspelling)
In the code below, user: create(:user_with_avatar)
should be user: attributes_for(:user_with_avatar)
, correct?
it "uploads an avatar" do
post :create, user: create(:user_with_avatar)
expect(assigns(:user).avatar_file_name).to eq 'avatar.png'
end
Hi Aaron, I've just finished to read your book and it was very useful to clarify some doubts I had on rails testing.
I have few remaining questions for you:
Thank you!
You are using selenium-webdriver, but I don't use Selenium-webdriver day-to-day development. Recently I use Poltergeist.
Selenium-webdriver takes active window, so I don't like it so much. I think using headless browsers like Poltergeist is more practical approach. Do you have any plans to switch JS driver?
I found you use not_to
instead of to_not
from RSpec 3 edition and I am wondering why.
But anyway I think it is worth mentioning about not_to
and to_not
. Readers should know they can use both. If there is any rule to determine which to use, I would like to know it.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.