I'm clicking show and destroy links with Capybara that should be in the first table row in an employees table. The table should sort so that the most recently modified employee is on the top, based on the updated_at timestamp.
Before the example a valid employee must be created that passes authentication. Then at the beginning of the example an employee must be created to test with. This is the employee that should always be at the top of the table because it's supposed to have been modified most recently. Sometimes it is and sometimes it isn't. Adding a sleep call fixes this, and I'm wondering if that's valid or if I've got it wrong. I thought adding a sleep call in a test was a Bad Thing. I also thought if the authentication employee is created before the example then even if my spec is running really fast then it should still have an earlier updated_at timestamp.
The authentication macro:
module AuthenticationMacros
def login_confirmed_employee
# create a valid employee for access
Factory :devise_confirmed_employee,
:username => 'confirmed.employee',
:password => 'password',
:password_confirmation =>'password'
# sign in with valid credentials
visit '/employees/sign_in'
fill_in 'Username', :with => 'confirmed.employee'
fill_in 'Password', :with => 'password'
click_on 'Sign In'
end
end
The request spec in question:
require 'spec_helper'
include AuthenticationMacros
describe "Employees" do
before do
login_confirmed_employee
end
# shows employees
it "shows employees" do
sleep 1.seconds
Factory :employee_with_all_attributes,
:username => 'valid.employee',
:email => 'valid.employee#example.com',
visit '/employees'
within 'tbody tr:first-child td:last-child' do; click_on 'Show', end
page.should have_content 'valid.employee'
page.should have_content 'valid.employee#example.com'
end
# destroys employees
it "destroys employees" do
sleep 1.seconds
Factory(:employee)
visit '/employees'
within 'tbody tr:first-child td:last-child' do; click_on 'Delete', end
page.should have_content 'Employee was successfully deleted.'
end
end
And for good measure here's my spec_helper:
require 'spork'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
ActiveSupport::Dependencies.clear
require 'email_spec'
RSpec.configure do |config|
config.include EmailSpec::Helpers
config.include EmailSpec::Matchers
end
end
Spork.each_run do
require 'rspec/rails'
require 'factory_girl_rails'
require 'capybara/rspec'
require 'capybara/rails'
require 'shoulda'
RSpec.configure do |config|
config.mock_with :rspec
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
end
Sometimes I end up on the show page or destroying the authentication-required employee instead of the example employee.It never happens though if I add the 1 second sleep call.
Nope, it fact it's a very bad solution because it increases tests execution time.
You could mock Time.now method call using one of the following solutions:
https://github.com/bebanjo/delorean
https://github.com/jtrupiano/timecop
Related
I am facing a wired issue, factoryBot is creating a record in Db, but when capybara try to access it, there is no record in HTML.
I tried debugging with "byebug", on prompt, when I say
#topics => It gives me Nil data. (#topic is instance variable in topics_controller.rb -> index method )
If I do "Topic.all.first" it will show me correct record of Topic with an expected random name that is -> "Toys & Garden"
If I do "random_topic.name" -> "Toys & Garden"
I have somewhat similar setup in other feature i.e "account creation feature", it is working fine in there. Any pointer or help would be highly appreciated.
My factory file is
FactoryBot.define do
factory :topic do
name { Faker::Commerce.department(2, true) }
archived false
end
end
My Feature spec file looks like below
require 'rails_helper'
describe "topics" do
let(:user) {create(:user)}
before do
sign_user_in(user) #support fuction to sign user in
end
it "allows topics to be edited" do
random_topic = create(:topic)
visit topics_path # /topics/
expect(page).to have_text random_topic.name # Error1
click_edit_topic_button random_topic.name # Another support fuction
random_topic_name_2 = Faker::Commerce.department(2, true)
fill_in "Name", with: random_topic_name_2
check "Archived"
click_button "Update Topic"
expect(page).to have_text "Topic updated!"
expect(page).to have_text random_topic_name_2
end
end
I get the error on line marked as "Error 1" , please note that "Toys & Garden" is sample name generated by Faker Gem.
Failure/Error: expect(page).to have_text random_topic.name
expected #has_text?("Toys & Garden") to return true, got false
my Rails helper(rails_helper.rb) file setup is as below.
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
require 'database_cleaner'
require 'capybara/rspec'
require 'shoulda/matchers'
require 'email_spec'
require "email_spec/rspec"
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
# This is for setting up Capybara right host.
# https://stackoverflow.com/questions/6536503/capybara-with-subdomains-default-host
def set_host (host)
default_url_options[:host] = host
Capybara.app_host = "http://" + host
end
RSpec.configure do |config|
config.include Capybara::DSL
config.include Rails.application.routes.url_helpers
config.include FactoryBot::Syntax::Methods
config.include EmailSpec::Helpers
config.include EmailSpec::Matchers
config.order = "random"
config.use_transactional_fixtures = false
config.before(:each) do
set_host "lvh.me:3000"
end
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
My Topics Controller file is something like below
class TopicsController < ApplicationController
layout 'dashboard'
before_action :authenticate_user!
def index
#topics = Topic.all
end
end
Updated with #smallbutton.com comments, but issue continues.
SOLVED
I am using apartment gem and hence topic was getting created in public schema while test was looking into a respective tenant.
As per #thomas suggestion, I modified the code:
before do
set_subdomain(account.subdomain)
sign_user_in(user) #support fuction to sign user in
Apartment::Tenant.switch!(account.subdomain)
end
When this happens it's generally caused by one of a few things
The record isn't actually being created
From your code it doesn't appear to be that
The record is being created in one transaction while the app is running in a different transaction.
You appear to have database_cleaner configured correctly, and this shouldn't be an issue in your case, however you should be using - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example - rather than the configuration you have (which depends on the :js metadata rather than checking which driver is actually being used)
The user has configured Capybara to hit a different server than the one the test is actually running on.
Here we appear to have an issue, since you're configuring Capybara.app_host to be 'lvh.me:3000'. Port 3000 is what your dev app is generally run on, while Capybara (by default) starts your app on a random port for tests. This probably means your tests are actually running against your dev app/db instance which has nothing to do with the test app/db instance, and therefore the tests won't see anything you create in your tests. Remove the setting of Capybara.app_host unless you have an actual need for its setting (in which case remove the port from your app_host setting and enable Capybara.always_include_server_port)
This all being said, since you're using Rails 5.1+ database_cleaner should not be needed anymore. You should be able to remove all of database_cleaner, reenable use_transactional_fixtures, and set Capybara.server = :puma and have things work fine (still would need to fix the app_host setting)
Your record isn't persisted when you visit the page, so it's normal that it return false.
Try the following :
require 'rails_helper'
describe "topics" do
let(:user) {create(:user)}
let!(:random_topic) {create(:topic)}
before do
sign_user_in(user) #support fuction to sign user in
visit topics_path # /topics/
end
it "allows topics to be edited" do
expect(page).to have_text random_topic.name # Error1
click_edit_topic_button random_topic.name # Another support fuction
random_topic_name_2 = Faker::Commerce.department(2, true)
fill_in "Name", with: random_topic_name_2
check "Archived"
click_button "Update Topic"
expect(page).to have_text "Topic updated!"
expect(page).to have_text random_topic_name_2
end
end
Note that random_topic is extracted in a let! (more info about the difference between let and let! : https://relishapp.com/rspec/rspec-core/v/2-5/docs/helper-methods/let-and-let !
You should create the record before you visit the page. Currently you do it the other way around so your record cannot appear.
People having this kind of issue should definitly try this:
instance.reload after clicking and before using "expect".
This solved my issue I've been stuck on for a whole day ...
I was writing test for registeration form and i got error "Email has already been taken"
I have googled this problem and come up this gem
gem 'database_cleaner', git: 'https://github.com/DatabaseCleaner/database_cleaner.git'
But it still didn't fixed the bug
I may messed up with the database_cleaner setup
spec_helper.rb
require 'database_cleaner'
Dir["./spec/support/**/*.rb"].sort.each { |f| require f}
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
expectations.syntax = :should
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.before(:suite) do
DatabaseCleaner[:active_record].strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
rails_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'capybara/rspec'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
end
factories.rb
FactoryGirl.define do
factory :identity do |f|
f.name Faker::Name.name
f.email Faker::Internet.email
f.password Faker::Internet.password(4,40)
end
end
identity_spec.rb
it "Registration successfully" do
user = FactoryGirl.create(:identity)
visit(new_identity_path)
fill_in('Name', :with => user.name)
fill_in('Email', :with => user.email)
fill_in('Password', :with => user.password)
fill_in('Password confirmation', :with => user.password)
click_button 'Register'
page.should have_content("You'r successfully logged in")
end
UPDATE:
it "Invalid password" do
user = FactoryGirl.create(:identity)
puts "USER Email: #{user.email}"
visit('/login')
fill_in('Email', :with => user.email)
fill_in('Password', :with => "incorrect")
click_button 'Login'
page.should have_content("Invalid info")
end
it "Registration successfully" do
puts "IDENTITY COUNT: #{Identity.count}"
user = FactoryGirl.create(:identity)
puts "USER Email: #{user.email}"
# visit(new_identity_path)
# fill_in('Name', :with => user.name)
# fill_in('Email', :with => user.email)
# fill_in('Password', :with => user.password)
# fill_in('Password confirmation', :with => user.password)
# click_button 'Register'
# page.should have_content("You'r successfully logged in")
end
Output
USER Email: litzy.legros#rogahnskiles.net
.IDENTITY COUNT: 0
USER Email: litzy.legros#rogahnskiles.net
.
.
Looks like you might have it slightly misconfigured.
Try putting require 'database_cleaner' in your spec_helper.rb file.
And then include require 'spec_helper' in your rails_helper.rb file.
If that doesn't fix it, then please include the rest of your spec_helper.rb and rails_helper.rb files in your question.
UPDATE
As far as I can tell, everything looks good in your helper files. The only difference I see between your implementation and my own is that you've got the strategy defined with:
DatabaseCleaner[:active_record].strategy = :transaction
whereas mine is simply:
DatabaseCleaner.strategy = :transaction
I don't think that would be the issue but it's worth a shot.
If that doesn't fix it, can you throw a couple of puts statements in your spec tests and let us know the output? Like so:
puts "IDENTITY COUNT: #{Identity.count}"
user = FactoryGirl.create(:identity)
puts "USER EMAIL: #{user.email}"
This will let us know two things:
is database_cleaner actually not working (count should be 0 if it is working)
is Faker using the same exact email address every time it's used.
Capybara tests should not use transactions. Turn off transactions in rails_helper.rb with:
config.use_transactional_fixtures = false
The database_cleaner docs explain why:
You'll typically discover a feature spec is incorrectly using transaction instead of truncation strategy when the data created in the spec is not visible in the app-under-test.
A frequently occurring example of this is when, after creating a user in a spec, the spec mysteriously fails to login with the user. This happens because the user is created inside of an uncommitted transaction on one database connection, while the login attempt is made using a separate database connection. This separate database connection cannot access the uncommitted user data created over the first database connection due to transaction isolation.
I have a feature spec with Capybara for a login page, and I am using FactoryGirl + DatabaseCleaner
require 'rails_helper'
feature 'Admin signs in' do
background do
FactoryGirl.create(:user)
end
scenario 'with valid credentials' do
visit admin_root_path
fill_in 'user_email', :with => 'email#email.com'
fill_in 'user_password', :with => 'testpassword'
click_button 'Sign in'
expect(page).to have_content('Dashboard')
end
scenario 'with invalid credentials' do
visit admin_root_path
fill_in 'user_email', :with => 'email#email.com'
fill_in 'user_password', :with => 'wrongpassword'
click_button 'Sign in'
expect(page).to have_content('Admin Login')
end
end
running the test, I get the following error:
1) Admin signs in test with invalid credentials
Failure/Error: FactoryGirl.create(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
I thought DatabaseCleaner would revert the changes, but it looks like the user record persist in the database till the second scenario block.
How can I make sure that the database is cleaned after the first scenario?
I configured Database cleaner following this post
# support/database_cleaner_spec.rb
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
I have also updated the spec helper file with:
config.use_transactional_fixtures = false
I was wrongly assuming that configuration files in spec/support folder were automatically loaded, but it turns out that I had to uncomment the following line in spec/rails_helper.rb
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
The DatabaseCleaner config file was correct, it just wasn't loaded at all.
Make sure you have the following configuration in spec/rails_helper.rb
RSpec.configure do |config|
config.use_transactional_fixtures = true
end
The idea is to start each example with a clean database, create whatever data is necessary for that example, and then remove that data by simply rolling back the transaction at the end of the example.
use these settings:
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
If by any chance you are using MySQL and altering tables (reset auto increments or whatever DDL operation) within a method within a test, the transaction strategy will fail and your database will not be cleaned.
In order to fix, you have to declare a config block like this:
config.before(:each, :altering_database => true) do
DatabaseCleaner.strategy = :truncation
end
And add this config to your test context:
context "when you alter the DB", :altering_database => true do...
Note: this will slow down your tests, so be careful not to abuse it.
config.before(:example) do
DatabaseCleaner.clean_with(:truncation)
end
worked for me!
I'm using rspec to perform feature tests and I can't save the user in the DB before the log in.
I'm using factory girl to build the object.
fixture are saved in db at the beginning of the test but are not deleted at the end.(maybe because the test fail. I don't know)
So I can not save the user before clicking on logIn and I get this errror message
--
DEPRECATION WARNING: an empty resource was given to Devise::Strategies::DatabaseAuthenticatable#validate. Please ensure the resource is not nil. (called from set_required_vars at app/controllers/application_controller.rb:43)
spec/features/login_to_mainpage_spec.rb (no error are rescued)
require "rails_helper"
feature 'Navigating to homepage' do
let(:user) { create(:user) }
let(:login_page) { MainLoginPage.new }
scenario "login" do
login_page.visit_page.login(user)
sleep(20)
end
end
A simple page object: spec/features/pages_objects/main_login_page.rb
class MainLoginPage
include Capybara::DSL
def login(user)
fill_in 'email', with: user.email
fill_in 'password', with: "password"
click_on 'logIn'
end
def visit_page
visit '/'
self
end
end
my rails_helper
require 'spec_helper'
require 'capybara/rspec'
require 'capybara/poltergeist'
require "selenium-webdriver"
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
Dir[Rails.root.join("spec/features/page_objects/**/*.rb")].each { |f| require f }
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false
config.before :each do
DatabaseCleaner.start
end
config.after :each do
DatabaseCleaner.clean
end
config.infer_spec_type_from_file_location!
config.include Devise::TestHelpers, :type => :controller
end
Capybara.default_driver = :selenium
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, :browser => :firefox)
end
in spec helper:
require 'simplecov'
require 'factory_girl'
require 'rspec/autorun'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
ENV["RAILS_ENV"] ||= 'test'
RSpec.configure do |config|
include ActionDispatch::TestProcess
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.disable_monkey_patching!
if config.files_to_run.one?
config.default_formatter = 'doc'
end
config.profile_examples = 10
config.order = :random
Kernel.srand config.seed
end
EDIT 1
I switch "gem 'factory_girl'" to "gem 'factory_girl_rails'"
and add this to application.rb
config.generators do
|g|
g.test_framework :rspec,
:fixtures => true,
:view_specs => false,
:helper_specs => false,
:routing_specs => false,
:controller_specs => true,
:request_specs => true
g.fixture_replacement :factory_girl, :dir => "spec/factories"
end
I still can not save the user in DB.
Everything pass but I put some sleep(10) in by code to refresh my DB and see te records and user is never saved
EDIT 3
My problem is actually very simple. FactoryGirl.create never save the data in DB if I put in my rails_helper:
config.use_transactional_fixtures = true
or
config.before :each do
DatabaseCleaner.start
end
config.after :each do
DatabaseCleaner.clean
end
/spec/factories
FactoryGirl.define do
factory :user do
email 'pierre#tralala.com'
password 'password'
password_confirmation 'password'
end
/spec/support/factory_girl.rb
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
spec/features/login_to_mainpage_spec.rb
let(:user) { create(:user) }
scenario "login" do
login_page.visit_page.login(create(:user))
sleep(5)
end
User will not be saved because of the config I cited before.
I need to have data reseted between tests.
EDIT 4
If I'm using the console
RAILS_ENV=test rails c
FactoryGirl.create(:user) it is saved in db.
I don't understand why it does not work in my tests.
Try using let! to create your user.
From the rSpec documentation:
Note that let is lazy-evaluated: it is not evaluated until the first time
the method it defines is invoked. You can use let! to force the method's
invocation before each example.
You said that you are using FactoryGirl but I do not see this in your test. To create my Users with FactoryGirl I always do something like this:
FactoryGirl.create(:user, password: 'test', password_confirmation: 'test', name: 'test')
If setup correctly in your Factory you can just write:
FactoryGirl.create(:user)
To solve your problem with the unique fields FactoryGirl provides you sequences:
sequence :email do |n|
"person#{n}#example.com"
end
factory :user do
email { generate(:email }
end
This will start with "person1#example.com" and add 1 to the number each time FactoryGirl.create(:user) is called.
It's definitely best to divide specs up so you have specs pertaining to each aspect of the MVC architecture, but I think there is a slight crossover with controller specs and view specs.
With view specs, you should only be concerned with the view, but with controller specs I still think it would be a good idea to test that the correct view is rendered, and maybe even test the content of the view, although more in-depth testing of the content should take place in the view spec.
Despite this clear article, https://www.relishapp.com/rspec/rspec-rails/v/2-1/docs/controller-specs/render-views, describing how to do this, I just cannot integrate my view and controller specs.
I keep getting the error undefined method 'contain'!
Here's my spec_helper:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
require 'capybara/rails'
require 'factory_girl_rails'
require 'ap'
def set(factory)
#user = FactoryGirl.create(factory)
end
def sign_up(first_name, last_name, profile_name, email, password)
visit "/"
click_link "Register"
fill_in('First name', with: first_name)
fill_in('Last name', with: last_name)
fill_in('Profile name', with: profile_name)
fill_in('Email', with: email)
fill_in('Password', with: password)
fill_in('Password confirmation', with: password)
click_button 'Sign up'
end
def sign_in(email, password)
visit "/"
click_link "Sign In"
fill_in('Email', with: email)
fill_in('Password', with: password)
click_button 'Sign in'
end
def sign_out
visit "/"
click_link "Sign Out"
end
#Webrat.configure do |config|
# config.mode = :rails
#end
#webrat
require 'capybara/poltergeist'
# Capybara.javascript_driver = :poltergeist
Capybara.javascript_driver = :selenium
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
# true means 'yes, filter these specs'
config.filter_run_excluding stress: true
# config.current_driver = :webkit
# config.use_transactional_fixtures = false
# config.include Capybara::DSL
DatabaseCleaner.strategy = :truncation
config.after(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
# config.before(:suite) do
# DatabaseCleaner.strategy = :transaction
# DatabaseCleaner.clean_with(:truncation)
# DatabaseCleaner.start
# end
# config.after(:each) do
# DatabaseCleaner.clean
# end
#config.after(:suite) do
# DatabaseCleaner.strategy = :transaction
# DatabaseCleaner.clean_with(:truncation)
# DatabaseCleaner.clean
# end
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
# config.include RSpec::Rails::RequestExampleGroup, type: :feature
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
I18n.enforce_available_locales = true
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
end
Here's my controller spec:
require "spec_helper"
describe UserFriendshipsController, type: :controller do
render_views
let (:user_1) { FactoryGirl.create(:user_1)}
before {
sign_in user_1
get :index
}
it "renders the :index view" do
response.should render_template(:index)
end
it "view contains expected html" do
# a sanity test more than anything
response.should contain("Welcome to the home page")
end
end
Upon running this spec I get this:
.F
Failures:
1) UserFriendshipsController view contains expected html
Failure/Error: response.should contain("Listing widgets")
NoMethodError:
undefined method `contain' for #<RSpec::Core::ExampleGroup::Nested_1:0x00000008632268>
# ./spec/controllers/user_friendships_spec.rb:18:in `block (2 levels) in <top (required)>'
Finished in 0.1835 seconds
2 examples, 1 failure
Why is this happening? How can I get this to work?
If you look at the relish documentation for the current 2.14 version of Rspec you'll see that they're using match now instead:
expect(response.body).to match /Listing widgets/m
Using the should syntax, this should work:
response.body.should match(/Welcome to the home page/)
Right, it was a very unclear article from Rspec that caused this error. It was using webrat in its example and didn't think to tell you. If anyone else gets here, you can add webrat to your gemfile to use the contain method:
Gemfile
group :test do
gem 'webrat'
end
However, it makes a lot more sense to use rspec's native match method:
expect(response.body).to match /Listing widgets/m