I have a helper method which outputs a greeting #{greet(Time.now.hour)} in the view pending the time of day:
users_helper.rb:
def greet(hour_of_clock)
if hour_of_clock >= 1 && hour_of_clock <= 11
"Morning"
elsif hour_of_clock >= 12 && hour_of_clock <= 16
"Afternoon"
else
"Evening"
end
end
And I am trying to test this unsuccessfully as below:
users_feature_spec.rb
describe 'greeting a newly registered user' do
before do
#fake_time = Time.parse("11:00")
Time.stub(:now) { #fake_time }
end
it 'tailors the greeting to the time of day' do
visit '/'
fill_in 'Name here...', with: 'test name'
fill_in 'Your email here...', with: 'test#test.com'
click_button 'Notify me'
expect(page).to have_content 'Morning'
end
end
The test fails as the Time.now.hour is not being stubbed as intended above.
I've now tried all sorts of variations thanks to various advice, the two main reformats which it at least seemed were syntactically correct were:
describe 'greeting a newly registered user' do
before do
#fake_time = Time.parse("11:00")
allow(Time).to receive(:now).and_return(#fake_time)
end
it 'tailors the greeting to the time of day' do
visit '/'
fill_in 'Name here...', with: 'test name'
fill_in 'Your email here...', with: 'test#test.com'
click_button 'Notify me'
expect(page).to have_content 'Morning'
end
end
and using the new ActiveSupport::Testing::TimeHelpers method #travel_to:
describe 'greeting a newly registered user' do
it 'tailors the greeting to the time of day' do
travel_to Time.new(2013, 11, 24, 01, 04, 44) do
visit '/'
fill_in 'Name here...', with: 'test name'
fill_in 'Your email here...', with: 'test#test.com'
click_button 'Notify me'
expect(page).to have_content 'Morning'
end
end
But still I'm doing something wrong which means that #greet is still taking the live output of Time.now.hour and not using my stubbed or travel_to Time value. Any help please?
You can try this :
let!(:fake_hour) { '11' }
before do
allow(Time).to receive_message_chain(:now, :hour).and_return(fake_hour)
end
Another approach would be to use Timecop (or the new Rails replacement travel_to) to stub out your time for you. With Timecop you can have super readable specs with no need for manual stubbing:
# spec setup
Timecop.freeze(Time.now.beginning_of_day + 11.hours) do
visit root_path
do_other_stuff!
end
I gave up trying to either stub out myself or use the ::TimeHelpers method #travel_to :( and used the Timecop gem, worked first time as below:
before do
Timecop.freeze(Time.now.beginning_of_day + 11.hours)
end
it 'tailors the greeting to the time of day' do
visit '/'
fill_in 'Name here...', with: 'test name'
fill_in 'Your email here...', with: 'test#test.com'
click_button 'Notify me'
expect(page).to have_content 'Morning'
end
I would really like to understand what was failing with my original approach though, does anyone see what was going wrong?
Related
I have a feature test for user registration. How do I test that Devise confirmation instructions are sent correctly? I don't need to test the content of the email, only that the mailer has been called.
I am sending mails in the background.
#user.rb
def send_devise_notification(notification, *args)
devise_mailer.send(notification, self, *args).deliver_later
end
I have tried a few approaches that work for other mailers, including
it "sends the confirmation email" do
expect(Devise.mailer.deliveries.count).to eq 1
end
and
it "sends the confirmation email" do
message_delivery = instance_double(ActionMailer::MessageDelivery)
expect(Devise::Mailer).to receive(:confirmation_instructions).and_return(message_delivery)
expect(message_delivery).to receive(:deliver_later)
end
none of which are working as expected for Devise messages.
What am I doing wrong?
Edit
The feature spec looks like this:
feature "User signs up" do
before :each do
visit '/'
click_link 'Sign up'
fill_in 'user_email', with: valid_attributes[:email]
fill_in 'user_password', with: valid_attributes[:password]
fill_in 'user_password_confirmation', with: valid_attributes[:password]
click_button 'Sign up'
end
it "sends the confirmation email" ...
end
Since you're doing a high level feature spec, I would wager that as a result of clicking the 'Sign up' button, what you want to confirm is that an email job has been added to the queue.
In order to do that, you may have to slightly change your spec set up:
feature "User signs up" do
before :each do
visit '/'
click_link 'Sign up'
fill_in 'user_email', with: valid_attributes[:email]
fill_in 'user_password', with: valid_attributes[:password]
fill_in 'user_password_confirmation', with: valid_attributes[:password]
end
it "queues up a confirmation email job" do
expect { click_button 'Sign up' }.to \
have_enqueued_job(ActionMailer::DeliveryJob)
end
end
You can have a look at the have_enqueued_job matcher for more options if the above one doesn't quite suit your use case.
Hello dear Stackoverflowers.
I'm having some seriously insanely annoying trouble with my capybara test. It seems to have a mind of its own and will sometimes decide to run with zero issue and sometimes decide to not find elements, click anything and generally just suck. I have no idea why this is.
I've been researching for days trying to find sure up my logic, find the 'best' ways of finding and clicking elements or filling in fields and haven't gotten any further. Please help, if I still had hair I would be pulling it out.
Also I'm using the Selenium Web Driver. All gems are up to date.
Thanks in advance.
It will randomly decide to not click on 'Amtrak 1234' and sometimes entirely miss the find('#atedrop4').click or will decide to click elements not even close being specified in my test. I'm very confused, and in desperate need of some help.
it 'can view the itinerary print and export', js: true do
visit '/admin/login'
fill_in 'Email', with: "evan#tripwing.com"
fill_in 'Password', with: "guest"
click_button 'Login'
click_link 'Trips'
expect(page).to have_content 'Trips'
click_link('View Trip Page', match: :first)
new_window=windows.last
page.within_window new_window do
expect(page).to have_content 'A Test To Forget'
find('.showItinerary').click
expect(page).to have_content "DAY 1, AMSTERDAM"
find(:xpath, "//a[#href='#flight1day1']").click
expect(page).to have_content "SINGAPORE AIRLINES FLIGHT 326"
click_link 'Add to Calendar'
find('.ategoogle').click
new_window=page.driver.browser.window_handles.last
page.driver.browser.switch_to.window(new_window) do
fill_in "Email", with: "evan#tripwing.com"
fill_in "Password", with: "boarder1"
find("#signIn").click
expect(page).to have_content "evan#tripwing.com"
page.driver.browser.close
end
find(:xpath, "//a[#href='#flight1day1']").click
find(:xpath, "//a[#href='#train1Day1']").click
click_link('Export to Calendar', match: :first)
find('.ategoogle').click
new_window=page.driver.browser.window_handles.last
page.driver.browser.switch_to.window(new_window) do
expect(page).to have_content "evan#tripwing.com"
page.driver.browser.close
end
find(:xpath, "//a[#href='#train1Day1']").click
find(:xpath, "//a[#href='#carRentalDay1']").click
click_link('Export to Calendar', match: :first)
find('.ategoogle').click
new_window=page.driver.browser.window_handles.last
page.driver.browser.switch_to.window(new_window) do
expect(page).to have_content "evan#tripwing.com"
page.driver.browser.close
end
find(:xpath, "//a[#href='#carRentalDay1']").click
find(:xpath, "//a[#href='#hotelDay1']").click
click_link('Export to Calendar', match: :first)
find('.ategoogle').click
new_window=page.driver.browser.window_handles.last
page.driver.browser.switch_to.window(new_window) do
expect(page).to have_content "evan#tripwing.com"
page.driver.browser.close
end
find(:xpath, "//a[#href='#hotelDay1']").click
find(:xpath, "//a[#href='#carTransfer1Day1']").click
click_link('Export to Calendar', match: :first)
find('.ategoogle').click
new_window=page.driver.browser.window_handles.last
page.driver.browser.switch_to.window(new_window) do
expect(page).to have_content "evan#tripwing.com"
page.driver.browser.close
end
find(:xpath, "//a[#href='#carTransfer1Day1']").click
One thing that helps is to use the save_and_open_page in your capybara tests. This way you can open up the html source of the test page and verify if your html id's and classes actually exist / are rendering the way you think they are. This has especially been the case for me when I'm doing nested forms and adding html to the page dynamically.
I'm trying requests tests with Capybara and it doesnt seem to work. This is my test file:
describe "Sessions", :type => :request do
let(:company) { FactoryGirl.create(:company) }
let(:user) { FactoryGirl.create(:admin, company_id: company.id ) }
describe "login page" do
it "signs me in" do
visit '/users/sign_in'
within("#new_user") do
fill_in 'Email', :with => user.email
fill_in 'Password', :with => user.password
end
click_button 'Sign in'
expect(page).to have_content 'Agenda'
end
end
end
Throws the following Error:
Failure/Error: expect(page).to have_content 'Agenda'
expected #has_content?("Agenda") to return true, got false
Im not sure if the problem is at logging in or at redirecting. But if i change the last line in the test for this:
expect(page).to have_content 'Invalid email'
I get the same Error.
Thanks in advance.
UPDATE:
i'm using devise for login
Simplest thing is to use screenshot_and_save_page to take a screenshot of the page just before the failing test, maybe you can determine what the problem is there.
I am writing some integration test cases for an existing application. My test works fine if there is only one 'it' block. However, If I add more than one 'it' block it throws an error. Below is my code that works:
require 'spec_helper'
describe 'Group' do
before do
visit 'http://groups.caremonkey.com/users/sign_in'
fill_in "Email", :with => "email#example.com"
fill_in "Password", :with => "password"
click_button "Login"
page.should have_link('Account')
end
it 'Should check all the links and functionality of groups' do
#add new subgroup with valid data should save a new group
find("#group-squares").click_link("Add")
fill_in "Group Name", :with => "Melbourne futsal"
click_on("Save")
page.should_not have_content("can't be blank")
page.execute_script("parent.$.fancybox.close();")
page.should have_link('Account')
#test edit group: should be able to update group info provided valid data are given
first(".actual img").click
page.should have_content("Group")
page.should have_link("Cancel")
fill_in "Group name", :with => "Futsal club"
page.execute_script("$('#sub-group-color-options').find('.color23').click()")
click_button "Save"
click_on("Cancel")
page.should have_link('Account')
end
end
It works perfectly fine when I put all the 'it' block together in a single 'it' block. But when I split them in different 'it' block, it stops working. For example if I split this ("test edit group: should be able to update group info provided valid data are given") test case into separate 'it' block as follows
require 'spec_helper'
describe 'Group' do
before do
visit 'http://groups.caremonkey.com/users/sign_in'
fill_in "Email", :with => "email#example.com"
fill_in "Password", :with => "password"
click_button "Login"
page.should have_link('Account')
end
it 'add new subgroup with valid data should save a new group' do
find("#group-squares").click_link("Add")
fill_in "Group Name", :with => "Melbourne futsal"
click_on("Save")
page.should_not have_content("can't be blank")
page.execute_script("parent.$.fancybox.close();")
page.should have_link('Account')
end
it 'should be able to update group info provided valid data are given' do
first(".actual img").click
page.should have_content("Group")
page.should have_link("Cancel")
fill_in "Group name", :with => "Futsal club"
page.execute_script("$('#sub-group-color-options').find('.color23').click()")
click_button "Save"
click_on("Cancel")
page.should have_link('Account')
end
end
then rspec fails, it passes the first test, however second test gets failed throwing following error.
Failure/Error: visit 'http://groups.caremonkey.com/users/sign_in'
ActionController::RoutingError:
No route matches [GET] "/users/sign_in"
One more thing, I have to test all the features in remote(url: http://groups.caremonkey.com/). Because, I am writing integration tests for an existing application. In addition, I need to login to the system before I test rest of the features of my application. Thanks in advance for your help.
Have you followed the Capybara documentation for calling remote servers? It says you should have the following:
Capybara.current_driver = :selenium # Or anything but rack_test, probably
Capybara.run_server = false # Don't run your app in-process
Capybara.app_host = 'http://groups.caremonkey.com/'
My guess is that when you have visited the site once, future visit calls are trying to use relative routes, which then is routed to the default server. I can't think why you would get a ActionController::RoutingError if you don't have some kind of Rack server running. Are you running these tests in some other Rails application?
I guess something like this:
require 'spec_helper'
describe 'Group' do
before do
visit 'http://groups.caremonkey.com/users/sign_in'
fill_in "Email", :with => "email#example.com"
fill_in "Password", :with => "password"
click_button "Login"
page.should have_link('Account')
find("#group-squares").click_link("Add") #apperently both specs are "scoped" to this page
end
it 'Should check all the links and functionality of groups' do
fill_in "Group Name", :with => "Melbourne futsal"
click_on("Save")
page.should_not have_content("can't be blank")
page.execute_script("parent.$.fancybox.close();")
page.should have_link('Account')
end
it "test edit group: should be able to update group info provided valid data are given"
first(".actual img").click
page.should have_content("Group")
page.should have_link("Cancel")
fill_in "Group name", :with => "Futsal club"
page.execute_script("$('#sub-group-color-options').find('.color23').click()")
click_button "Save"
click_on("Cancel")
page.should have_link('Account')
end
end
My gut feeling tells me both test need the follow this: find("#group-squares").click_link("Add") so I added it to the before block This test however is cryptic, what is first(".actual img")?
I would have thought this test would have passed. Any ideas why it isnt?
it 'should create an account' do
visit new_user_registration_path
fill_in 'user_email', with: 'newtest#test.com'
fill_in 'user_password', with: 'testing123'
fill_in 'user_password_confirmation', with: 'testing123'
expect{
click_button 'Sign Up'
}.to change{User.count}.by(1)
end
I just get
result should have been changed by 1, but was changed by 0
It is a counter cache problem, see this:
Rails counter_cache not updating correctly
Silly mistake. I had a validation on user for name!