Why do I get the error in my acceptance test? - ruby-on-rails

Tell me please,why does it happen?
I can't understand, if I write:
feature "Article Creation" do
#here i write (:all)
before(:all) do
sign_up_helper
end
I get the error:
Article Creation allows user to visit to creating article page
Failure/Error: fill_in :article_title, :with => 'test_title'
Capybara::ElementNotFound:
Unable to find field :article_title
or
1) Article Creation allows user to visit to article page
Failure/Error: expect(page).to have_content I18n.t('articles.articles_new')
expected to find text "New Article:" in "Toggle navigation Blog Rails New Contacts Sign in --- !ruby/hash:ActionController::Parameters controller: devise/sessions action: new {\"controller\"=>\"devise/sessions\", \"action\"=>\"new\"} nil You need to sign in or sign up before continuing. Sign in: Email Password Remember me Sign up Forgot your password?"
but, if I write:
feature "Article Creation" do
#here i write(:each)
before(:each) do
sign_up_helper
end
It's Ok. All tests works. My question -WHY?
This is my test:
*#before all test visitor signs up
#here I've changed :all and :each*
feature "Article Creation" do
before(:all) do
sign_up_helper
end
scenario "allows user to visit to article page" do
visit new_article_path
expect(page).to have_content I18n.t('articles.articles_new')
end
scenario "allows user to visit to created article page" do
visit new_article_path
fill_in :article_title, :with => 'test_title'
fill_in :article_text, :with => 'example_text'
click_button 'Save Article'
expect(page).to have_content 'example_text'
end
This is sign_up_helper method:
#spec/support/session_helper.rb
def sign_up_helper
visit new_user_registration_path
fill_in :user_email, :with => 'user#example.com'
fill_in :user_username, :with => 'mike'
fill_in :user_password, :with => 'secure123!##'
fill_in :user_password_confirmation, :with => 'secure123!##'
click_button 'Sign up'
end
This is html form:
<p>
<label for="article_title">Title</label><br/>
<input type="text" name="article[title]" id="article_title" />
</p>
<p>
<label for="article_text">Text</label><br/>
<textarea name="article[text]" id="article_text">
</textarea>
</p>

Environment for each test is set anew, I think. New session, cookies, etc. In many cases, even brand new users are generated. So one "global" login is not possible.
Even if it were possible, it would still be a problem, as it introduces spec order dependency which is bad. Imagine that one of your specs logs user out. Then each subsequent spec would fail, because user is not logged in anymore.
To prevent this, make sure that each spec sets its own environment as it needs it (user logins, method stubs, etc.), without relying on side-effects from previously executed specs (which may or may not persist).

Related

Capybara::ElementNotFound: Unable to find button "Log in" that is not disabled

I'm running an acceptance test that includes logging in via /users/sign_in.
How do I set up the test so I can "click" the submit button within a Rspec Capybara test?
Seems that Devise disables the Login submit button and runs javascript to make things work.
<%= f.submit "Log in" %>
produces:
<input type="submit" name="commit" value="Log In" tabindex="4" data-disable-with="Log In" />
The data-disable-with, which devise needs, seems to be breaking capybara testing. I would just like to click the button as per my acceptance test below.
it "logs in and shows success message" do
visit '/users/sign_in'
login_as(user, :scope => :user)
within(".login-details") do
fill_in 'Email', with: user.email
fill_in 'Password', with: 'fakepassword'
end
click_button 'Log in'
expect(page).to have_content 'Success'
end
Is producing:
Capybara::ElementNotFound: Unable to find button "Log in" that is not disabled
Note: I have multiple pages that logging in can send a user to, this example is the simplest test that reveals this bug. So no my goal is not to 'make sure devise works', incase you were wondering 'why do they need this?'
The data-disable-with attribute is used by Rails UJS to change the buttons text after it's been clicked so wouldn't be affecting this test. Looking at the HTML element you posted the value of the button is 'Log In' so, since case matters, you'd need to do
click_button 'Log In'
rather than 'Log in'
I do wonder why you have login_as(user, :scope => :user) in the same code where you're filling in the username and password though, you'd normally only use login_as when you wanted to bypass actually filling in the form and logging in.

rspec before context without js

In a feature test I have 2 feature macros: sign_in and add_to_cart. User logs in without JS, but for add_to_cart a JS macros is needed.
spec:
describe 'User add product in cart' do
before { sign_in(user) }
scenario 'and view cart stuff' do
add_to_cart(product, 2)
visit cart_path
end
end
feature macros
module FeaturesMacros
def sign_in(user)
visit sign_in_path
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
click_button 'Sign in'
end
def add_to_cart(product, quantity)
visit product_path(id: product.id)
fill_in 'line_item_quantity', with: quantity
click_button 'Add to Cart'
end
end
When I run test without JS, error is
ActionController::UnknownFormat: LineItemsController#create is missing a template for this request format and variant.
If I add JS for scenario 'and view cart stuff', js: true do, I have error in user login:
Failure/Error: visit sign_in_path.
How to add JS in scenario, but remove it from before context? Maybe there are better methods?

Visiting More than one Page in a Describe Block Via Capybara

I'm writing some super simple integration specs, and while Capybara does simulate the browser/user interaction, I suspect that changing through several pages in one test causes issues. Mainly that the variable page doesn't get changed if you visit a few pages in a row. Here's what I mean:
require "rails_helper"
describe "The Initial Experience", :type => :feature do
it "User visits Narrowcontent" do
visit root_path
expect(page).to have_content "Sign In" && "Register"
click_on "Sign In"
expect(page).to have_content("Login Access")
within(".middle-login") do
fill_in "user_email", :with => ENV["admin_username"]
fill_in "user_password", :with => ENV["admin_pw"]
end
click_button 'Sign in'
save_and_open_page
#expect(page).to have_content("Dashboard")
end
end
I had to comment out the last expectation because it causes the test to fail. The keyword "Dashboard" DOES exist, but the problem is that after running click_button 'Sign In', the variable page still represents the old one, as if click_button 'Sign In'has no impact whatsoever.
Any tips?

Rspec/Capybara test cases are not working for multiple 'it' blocks

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")?

Cucumber + Webrat doesn't submit forms?

I'm new to Cucumber and totally lost as to why this integration test is failing. I have the following scenarios:
Scenario: User changes profile
Given I have an account
When I change my profile
Then my profile should be saved
Scenario: User changes login
Given I have an account
When I change my login information
Then my account should be changed
And these step definitions:
Given /^I have an account$/ do
#user = Factory.create(:user)
visit login_path
fill_in "Email", :with => #user.email
fill_in "Password", :with => 'secret'
click_button "Sign in"
end
When /^I change my profile$/ do
visit edit_user_profile_path(#user)
fill_in "First name", :with => "John"
fill_in "Last name", :with => "Doe"
click_button "Update Profile"
end
Then /^my profile should be saved$/ do
#user.profile.first_name.should == "John"
#user.profile.last_name.should == "Doe"
end
When /^I change my login information$/ do
visit edit_user_path(#user)
fill_in "Email", :with => "foo#example.com"
click_button "Update Login Information"
end
Then /^my account should be changed$/ do
#user.email.should == "foo#example.com"
end
And I fail the "Then" condition on both scenarios with this message:
# Scenario 1
expected: "John"
got: "Test1" (using ==) (RSpec::Expectations::ExpectationNotMetError)
# Scenario 1
expected: "foo#example.com"
got: "test2#example.com" (using ==) (RSpec::Expectations::ExpectationNotMetError)
So, in both cases the factory information is still present after submitting the form to update the user login or profile. However, if I test this in a real browser it works perfectly. So, why is this test failing???
Thanks for the help!
#user is just a variable which lives inside your cucumber code block. It will not be changed. What will be changed in the test is the database record. To check that it was changed indeed you have to visit some page where user name is displayed.
(Just as you do in your real life test)

Resources