everydayrails / everydayrails-rspec-2017 Goto Github PK
View Code? Open in Web Editor NEWSample source for the 2017 edition of Everyday Rails Testing with RSpec.
Home Page: http://rspectutorial.com
Sample source for the 2017 edition of Everyday Rails Testing with RSpec.
Home Page: http://rspectutorial.com
So, the following should be amended from
context "as a guest" do
before do
@project = FactoryGirl.create(:project)
end
it "returns a 302 response" do
delete :destroy, params: { id: @project.id }
expect(response).to have_http_status "302"
end
it "redirects to the sign-in page" do
delete :destroy, params: { id: @project.id }
expect(response).to redirect_to "/users/sign_in"
end
end
it "does not delete the project" do
expect {
delete :destroy, params: { id: @project.id }
}.to_not change(Project, :count)
end
to
context "as a guest" do
before do
@project = FactoryGirl.create(:project)
end
it "returns a 302 response" do
delete :destroy, params: { id: @project.id }
expect(response).to have_http_status "302"
end
it "redirects to the sign-in page" do
delete :destroy, params: { id: @project.id }
expect(response).to redirect_to "/users/sign_in"
end
it "does not delete the project" do
expect {
delete :destroy, params: { id: @project.id }
}.to_not change(Project, :count)
end
end
There is already an example for "does not delete the project" on p. 86, so the following code is redundant:
it "does not delete the project" do
expect {
delete :destroy, params: { id: @project.id }
}.to_not change(Project, :count)
end
In Chapter 2, page 17,
Now that we’ve got RSpec installed, Rails’ stock generators will no longer generate the default Test::Unit files in the test directory
I think Rails generates Minitest files, not Test::Unit.
Chapter 8, page 138-139,
- TasksController#show responds with JSON formatted output
Failure/Error: expect(response).to_not have_content_type :json
Expected "unknown content type (application/json)" to
not be Content Type "application/json" (json)
The message "unknown content type (application/json)" is very confusing. I could not understand what happened for a moment. The actual content type is not "unknown" but "application/json".
content_type
method expects short name like :html
or :json
as a parameter, so it can't be used for actual content type. I think failure_message
or failure_message_when_negated
should be implemented like this:
failure_message do |actual|
"Expected \"#{actual.content_type}\" to be Content Type " +
"\"#{content_type(expected)}\" (#{expected})"
end
Just so people know, I'm aware that FactoryGirl has been renamed to FactoryBot. I will update all references the next time I do a maintenance update to the book.
Think you skipped a spec for user_spec.rb
: "is invalid without an email address". See page 33 to page 34.
Here is my version:
it "is invalid without an email address" do
user = User.new(
first_name: "Joe",
last_name: "Tester",
password: "dottle-nouveau-pavillion-tights-furze",
)
user.valid?
expect(user.errors[:email]).to include("can't be blank")
end
Also will need to update bottom of page 46.
In Chapter 2, page 20,
Optionally, configure Rails’ generators to use RSpec, so that as you add new models and controllers to your application, you’ll be able to use the generators in your development workflow, and automatically be given starter files for
your specs and factories.
At this point, factories is not described in details, so readers might be confused.
Most worker related examples I have seen, seems to abandon "Arrange, Act, Assert" (3A). So, just out of curiosity, can you come up with a way to follow 3A in:
everydayrails-rspec-2017/spec/jobs/geocode_user_job_spec.rb
Lines 5 to 7 in 3a001f9
The filename should be Gemfile
instead of config/application.rb
click_button
has no guarantee that any actions triggered by it will have completed when it returns. Because of this you should have an expectation after it that verifies/waits until the action has completed. In the example on page 98 that means moving at least one of the expectations inside the change
block. Without that change the test will be flaky with some drivers.
expect {
click_link "New Project"
fill_in "Name", with: "Test Project"
fill_in "Description", with: "Trying out Capybara"
click_button "Create Project"
expect(page).to have_content "Project was successfully created"
expect(page).to have_content "Test Project"
expect(page).to have_content "Owner: #{user.name}"
}.to change(user.projects, :count).by(1)
In the code block for projects_apis_spec.rb
, on line 6:
get projects_apis_path
Should be:
get api_projects_path
In Chapter 4, page 61,
alias we added to the User model
I think "alias we added to the User factory" would be easy to understand.
In Chapter 5,
You used change matcher for the first time, but there is no description about it. It should be described for beginners.
In Chapter 3, page 47
we used
@note1
and@note1
as test notes
@note1 and @note1
should be @note1 and @note2
or anything, right?
In Chapter 3, page 34,
bin/rails g rspec:model project
$
might be required for consistency.
Chapter 10, page 169,
First, include the matchers near the top of the file:
I think "require the matchers" is easier to understand the following code.
Chapter 10, page 177,
expect(mail.body).to match(/Hello #{user.first_name},/)
I am not sure why you used regexp here. I think using string is simpler:
expect(mail.body).to match "Hello #{user.first_name},"
Chapter 8, page 141,
But in version 3.3, RSpec gained the ability to aggregate failures, so that additional examples can continue to run and, perhaps, provide some extra context for the failure.
Perhaps "additional examples" should be "additional expectations".
I implemented the model specs testing the late status of a project on p.64. I cloned the first chapter and followed along for chapter 2,3 and 4. But when I run the spec "is late when the due date is past today" I get this failure message:
Failure/Error: expect(project).to be_late │
expected #<Project id: 1, name: "Project 2", description:
"Sample project for testing purposes", due_on: "2017-07-04", created_at: "2017-07-05 07:30:40", updated_at: "2017-07-05 07:30:40", user_id: 1> to respond to late?
I suppose these test should pass, but I not sure why they are failing.
Chapter 8, page 123,
on of my favorite ways
It should be "one of my favorite ways".
If you enable warnings in spec output, you'll see numerous warnings from the Paperclip gem. These are not caused by specs, but are noisy and can cause confusion for people beginning to learn testing. I think they're caused by changes in either Rails or Ruby. I opted to move forward with Paperclip in spite of the warnings, and will review its status to see if the warnings have been addressed.
I couldn't get :selenium_chrome to work at all with the given instructions. It kept saying the driver couldn't be found. I finally came across the chromedriver-helper gem. Followed their instructions and it worked great. Maybe it was just my setup on macOS Sierra, but thought I'd share anyhow.
Everyday Rails Testing with RSpec: September 18th, 2017
format: mobi
8th paragraph, last sentence:
"In other Words, we’re testing project-specific functionality here, not user or login-specific functionality.”
4th word has unicode characters in place of the apostrophe
2nd and 3rd code block after 8th paragraph (1st code block being spec/rails_helper.rb)
spec/features/projects_feature.spec
should be spec/features/projects_spec.rb
3rd paragraph, 1st sentence:
“To demonstrate, let’s create a model spec for the Task model, since we haven’t done that yet.”
another case of apostrophe being replaced with unicode charcters in haven't
This can just be done with
Capybara.javascript_driver = :selenium_chrome
or for headless
Capybara.javascript_driver = :selenium_chrome_headless
The text used as selector should "RSpec Tutorial"
instead of "RSpec tutorial"
(capital T), otherwise the test will fail.
i.e. the code should change from
require 'rails_helper'
RSpec.feature "Tasks", type: :feature do
scenario "user toggles a task", js: true do
user = FactoryGirl.create(:user)
project = FactoryGirl.create(:project,
name: "RSpec tutorial",
owner: user)
task = project.tasks.create!(name: "Finish RSpec tutorial")
visit root_path
click_link "Sign in"
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
click_link "RSpec tutorial"
check "Finish RSpec tutorial"
expect(page).to have_css "label#task_#{task.id}.completed"
expect(task.reload).to be_completed
uncheck "Finish RSpec tutorial"
expect(page).to_not have_css "label#task_#{task.id}.completed"
expect(task.reload).to_not be_completed
end
end
to
require 'rails_helper'
RSpec.feature "Tasks", type: :feature do
scenario "user toggles a task", js: true do
user = FactoryGirl.create(:user)
project = FactoryGirl.create(:project,
name: "RSpec tutorial",
owner: user)
task = project.tasks.create!(name: "Finish RSpec tutorial")
visit root_path
click_link "Sign in"
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Log in"
click_link "RSpec Tutorial"
check "Finish RSpec tutorial"
expect(page).to have_css "label#task_#{task.id}.completed"
expect(task.reload).to be_completed
uncheck "Finish RSpec tutorial"
expect(page).to_not have_css "label#task_#{task.id}.completed"
expect(task.reload).to_not be_completed
end
end
Changing the default_max_wait_time
for a single test should be done with using_wait_time(time) do ... end
Chapter 9, page 152,
group :test do
gem 'capybara', '~> 2.15.4'
gem 'selenium-webdriver'
gem 'launchy', '~> 2.4.3'
gem 'shoulda-matchers',
git: 'https://github.com/thoughtbot/shoulda-matchers.git',
branch: 'rails-5'
end
It should be:
group :test do
gem 'capybara', '~> 2.15.4'
gem 'selenium-webdriver'
gem 'launchy', '~> 2.4.3'
gem 'shoulda-matchers',
git: 'https://github.com/thoughtbot/shoulda-matchers.git',
branch: 'rails-5'
end
Not to spam you, but found another slight error.
In note.rb
, the search scope is case sensitive:
scope :search, ->(term) {
where("message LIKE ?", "%#{term}%")
}
Which breaks the search term spec, since note3
has a capital F:
note3 = project.notes.create(
message: "First, preheat the oven.",
user: user
)
Perhaps change the scope in note.rb
to:
scope :search, ->(term) {
where("LOWER(message) LIKE ?", "%#{term}%")
}
Chapter 10, page 167
expect(page).to have_content "attachment.jpg (image/jpeg"
I thought it should be "attachment.jpg (image/jpeg)"
but the actual string was attachment.jpg (image/jpeg, 14.5 KB)
.
However, it is still confusing, so I suggest:
expect(page).to have_content "attachment.jpg"
or
expect(page).to have_content /attachment\.jpg \(image\/jpeg, [\d\w\s.]+\)/
args
is deprecated.
Instead of
args: ["headless"],
we can use
options: Selenium::WebDriver::Chrome::Options.new(args: %w[headless])
The examples in the describe #create
block do not need id: @task.id
to be passed along. For example, the first example should look like
it "responds with JSON formatted output" do
new_task = { name: "New test task" }
sign_in @user
post :create, format: :json,
params: { project_id: @project.id, task: new_task }
expect(response.content_type).to eq "application/json"
end
I'll include the fixed versions in the next release.
In Chapter 4, page 66
Let’s add a callback to automatically create tasks on a new project.
"create tasks" should be "create notes", correct?
The text and example appear to imply that only the find
methods will wait for elements to appear. The actions methods like click_button
will also wait since they are implemented as find(...).click
. Therefore recommending find_button('Close').click
over click_button('Close')
doesn't make sense.
spec/factories/notes.rb
should be
app/models/project.rb
by setting you're application
should be your
.
Specifically discussing the test environment is there anything to be aware of aside from the usual use of procs? In the feature spec chapter, they are referred to as “the expect{} Proc we checked out in chapter 5” (controller specs), but they are not discussed in that chapter, just used obscurely.
Huge thanks for this book!
In Chapter 4, page 53
## more specs ...
It should be # more specs ...
Chapter 8, page 135,
CONTENT_TYPES hash
Why is CONTENT_TYPES
written in uppercase? Maybe it should be content_types
.
In Chapter 3, page 24,
$bin/railsgrspec:modeluser
It should be $ bin/railsgrspec:modeluser
.
The directory should be spec/support
instead of spec_support
I'm very curious to hear your thoughts on testing data that changes outside of the database, but is used above the model level. I know with request tests this would go against your practice of the skinny controller layout, but surely I'm not the only dev that has been put in front of a project where this is the case.
Along the same lines, Services are always easy as they can be included and tested in their own model/unit-tests, but request tests when working with such services where the return values come back to the frontend and not that obvious. I guess as long as there was a good known way to corner the data with a proc, that would be a great start.
EDIT: Just to give an idea of what I'm doing now for these cases, I'm using the rails-controller-testing gem to have access to the assigns method so that I can grab the instance variable and test against the data going in with the data being returned (in the assigns). I don't like to do this, since they are depreciated, and why I ask what can be done instead.
Thanks for everything, and I hope you consider this request!
Chapter 10, page 173,
You could also experiment with DRY testing techniques from chapter 8, should you have tests across multiple files requiring the test queue.
I am not sure what "DRY testing techniques from chapter 8" is. You mean using shared_context
, right?
As of chapter 9, group :development, :test
includes
group :development, :test do
gem 'rspec-rails', '~> 3.6.0'
gem 'factory_girl_rails', '~> 4.8.0'
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'capybara', '~> 2.14.0'
gem 'selenium-webdriver'
# Or use poltergeist and PhantomJS as an alternative to Selenium/Chrome
# gem 'poltergeist', '~> 1.15.0'
gem 'launchy', '~> 2.4.3'
gem 'shoulda-matchers',
git: 'https://github.com/thoughtbot/shoulda-matchers.git',
branch: 'rails-5'
end
Everything after byebug should be able to go in a standalone group :test
, but I need to confirm. This will be addressed in a future release.
The header for the spec file on the page is wrong.
spec/models/user_spec.rb
should be
spec/models/note_spec.rb
From project_spec.rb
:
it "allows two users to share a project name" do
user = User.create(
first_name: "Joe",
last_name: "Tester",
email: "[email protected]",
password: "dottle-nouveau-pavillion-tights-furze",
)
user.projects.create(
name: "Test Project",
)
other_user = User.create(
first_name: "Jane",
last_name: "Tester",
email: "[email protected]",
password: "dottle-nouveau-pavillion-tights-furze",
)
other_project = other_user.projects.build(
name: "Test Project"
)
expect(other_project).to be_valid
end
I get:
1) Project allows two users to share a project name
Failure/Error: expect(other_project).to be_valid
expected #<Project id: nil, name: "Test Project", description: nil, due_on: nil, created_at: nil, updated_at: nil, user_id: nil> to be valid, but got errors: Owner must exist
Code matches the book. Guess we're missing a user_id
, although calling projects
on other_user
should have done the trick.
All instances of Capybara.default_wait_time
should be replaced with Capybara.default_max_wait_time
Solution: See shoulda-matchers#1057 for full discussion
Solution Text
Yes, we rebased rails-5 and then merged it into master. Sorry for the mess -- it won't happen again!
For anyone else who found this, we fixed this by deleting the revision sha from our Gemfile.lock and re-ran bundle install.
Be advised that we will remove rails-5 at a certain point, so I would recommend switching to master now if you really want to continue being on the bleeding edge :)
It fails with following error log
Fetching https://github.com/thoughtbot/shoulda-matchers.git
fatal: Could not parse object '0b2e0da6035b9c45b0430bc6eb9a8bab4aeba50e'.
Git error: command `git reset --hard 0b2e0da6035b9c45b0430bc6eb9a8bab4aeba50e`
in directory
C:/Ruby24-x64/lib/ruby/gems/2.4.0/bundler/gems/shoulda-matchers-0b2e0da6035b has
failed.
If this error persists you could try removing the cache directory
'C:/Ruby24-x64/lib/ruby/gems/2.4.0/cache/bundler/git/shoulda-matchers-e04e9ade87805b3667f97d976fd84556605e66f8'
Process finished with exit code 11
The code should be
expect(json[0]["name"]).to eq "Second Sample Project"
instead of
expect(json["name"]).to eq "Second Sample Project"
FactoryGirl.definedo factory :note do
message "My important note."
association :project
association :note
end end
should be
FactoryGirl.definedo factory :note do
message "My important note."
association :project
association :user
end end
otherwise, we will get this validation error:
FactoryGirl::AssociationDefinitionError:
Self-referencing association 'note' in 'note'
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.