Capybara and Rails have_content failing in spec to test to see if a messages partial appears - ruby

I have a request spec which passes up until the point where I need to check to see if content is present on the page, which I am using page.should have_content to do. The content is actually a message which appears on successful form submission, which is rendered from a messages partial. The test fails even though If I test through the browser, functionality works as expected and the content appears as it should. I'm also using FactoryGirl to generate the users to use for the form submission.
Here's the error I get after running the spec with the --format d option:
UserSignup
shows a thank you message on successful form submission (FAILED - 1)
Failures:
1) UserSignup shows a thank you message on successful form submission
Failure/Error: page.should have_content("Thank you. You will be notified of our launch at #{user.email}.")
expected #has_content?("Thank you. You will be notified of our launch at quinn.purdy#casperzboncak.org.") to return true, got false
# ./spec/requests/user_signup_spec.rb:21:in `block (2 levels) in <top (required)>'
user_signup_spec.rb:
require 'spec_helper'
describe "UserSignup" do
it "shows a thank you message on successful form submission" do
user = FactoryGirl.create(:user)
visit sign_up_path
fill_in "user_fullname", with: user.fullname
fill_in "user_email", with: user.email
click_button "Sign up"
current_path.should eq(sign_up_path)
page.should have_content("Thank you. You will be notified of our launch at #{user.email}.")
end
end
users_controller.rb:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(secure_params)
if #user.valid?
#user.subscribe
flash[:notice] = "Thank you. You will be notified of our launch at #{#user.email}."
redirect_to sign_up_path
else
render :new
end
end
private
def secure_params
params.require(:user).permit(:fullname, :email)
end
end
I'm wondering if it could be because I render the messages partial from the application layout, but when it gets outputted in the users view, the message appears inside the body of the source, but outside the main class.

So I seem to have got the tests passing by adding the line , :js => true do beside 'it' and using the selenium web driver. There's got to be a way to do it without selenium I'm thinking, because you have to sit and wait while it actually runs it in a browser which is the downside.
Maybe I'm going about it the wrong way, and I should actually be checking for the partial in a view spec (currently it was just part of the feature test).

Related

How to hook after example has execution result and status with :aggregated_failures flag

I'm maintaining a standalone test automation suite written in Rspec & Capybara and SitePrism (No Rails).
Recently I started integrating it with Testrail for reporting - I used rspec-testrail gem for that but I had to modify it a bit, because I also wanted to send Slack notifications with test progress and report.
Anyway, the integration works smoothly, except the fact that example processing is relying on example having an exception and lack of exception causes setting the test status as Passed on Testrail.
As it appears, after :each nor after :example in Rspec.configure doesn't guarantee that the example has finished running.
I also tried around :example and around :each as described here, but to no avail.
I inspected contents of example.metadata and it looks that example.metadata[:execution_result] has only started_at variable, but a finished example would have also finished_at and status variables, according to the docs
My suspicion (after reading the relish docs) is that :aggregated_failures is the cause of different metadata structure and multiple expects running in threads that are later merged into one backtrace.
Do you know how can I wait for the example to finish or how to hook into the state where it's finished?
Or maybe I should create a custom formatter where I would hook after example notifications printed to the console (I would like to keep the stacktrace there).
My code is as follows:
Test (both assertions are failing):
require 'spec_helper'
feature 'Sign in' do
let(:login_page) { LoginPage.new }
let(:user) { { email: ENV['ADMIN_EMAIL'], password: ENV['ADMIN_PASSWORD'] } }
scenario 'is successful and user is redirected to dashboard for user with correct credentials', testrail_id: 5694 do
login_page.load
login_page.form.email.set(user[:email])
login_page.form.password.set(user[:password])
login_page.form.submit_btn.click
expect(login_page.sidebar).to have_jobs(text: "some_nonexistenttext")
login_page.logout
expect(current_url).to have_content "google.com"
end
end
Console output from the above test:
Failures:
1) Sign in is successful and user is redirected to dashboard for user with correct credentials
Got 2 failures:
1.1) Failure/Error: expect(login_page.sidebar).to have_jobs(text: "blala")
expected #has_jobs?({:text=>"some_nonexistenttext"}) to return true, got false
# ./spec/auth/login_spec.rb:13:in `block (3 levels) in <top (required)>'
1.2) Failure/Error: expect(current_url).to have_content "google.com"
expected to find text "google.com" in "https://example.com/"
# ./spec/auth/login_spec.rb:15:in `block (3 levels) in <top (required)>'
Finished in 53.91 seconds (files took 1.45 seconds to load)
4 examples, 1 failure
Failed examples:
rspec ./spec/auth/login_spec.rb:8 # Sign in is successful and user is redirected to dashboard for user with correct credentials
Spec helper:
require 'rubygems'
require 'capybara/rspec'
require 'selenium-webdriver'
require 'site_prism'
require 'slack-notifier'
require_relative '../config'
require_relative '../lib/testrail'
...
RSpec.configure do |config|
config.define_derived_metadata do |meta|
meta[:aggregate_failures] = true
end
config.example_status_persistence_file_path = 'examples.txt'
config.before :all do
testrail_initialize_test_run!
end
config.after :example, testrail_id: proc { |value| !value.nil? } do |example|
RSpec::Testrail.process(example)
end
end
processing method (slightly modified from original)
def process(example)
if example.exception
status = 5
message = example.exception.message
slack_notifier.publish(message_text "Failed")
elsif example.skipped? || example.pending?
puts 'Example skipped or pending'
status = 10
message = 'Pending or not implemented'
else
status = 1
message = ''
end
client.send_post("add_result_for_case/#{testrun['id']}/#{example.metadata[:testrail_id]}",
status_id: status,
comment: message)
end
So basically all I had to was to use a reporter listener and process notifications inside it :)
config.reporter.register_listener RSpec::Testrail::Listener.new, :start, :example_failed, :example_passed, :example_pending, :stop

Mechanize (Ruby gem) not recognizing a form from a saved HTML file, but it recognizes the form when accessing the actual website?

I'm trying to write Rspec tests for my Mechanize agent.
My agent is supposed to go to a website, log into the form, then scrape some data off the website. I also downloaded FakeWeb to stub the HTTP requests, and make my tests faster.
Here is my account_spec.spec file:
require 'spec_helper'
describe Account do
before(:each) { #account = Account.new('bob', '1234') }
describe '#login' do
before(:each) do
home_page = File.read('spec/html/home_page.html')
login_page = File.read('spec/html/login_page.html')
FakeWeb.register_uri(:get,
"https://www.example.com/",
body: home_page,
status: ["200", "Success"],
content_type: "text/html")
FakeWeb.register_uri(:get,
"https://www.example.com/account/login",
body: login_page,
status: ["200", "Success"],
content_type: "text/html")
#web_crawler = Mechanize.new
#home_page = #web_crawler.get("https://www.example.com/")
#login_page = #web_crawler.get("https://www.example.com/account/login")
end # -- before :each
it 'finds the login form' do
login_form = #login_page.form_with(:class => "form login")
puts login_form.class # ==> nil:NilClass
end
end # -- #login
end # -- Account
However, when I comment out the FakeWeb uri for example/account/login (it then accesses the real server), it actually returns the correct form. Basically, if I am searching for the form in my locally saved HTML file, Mechanize can not find it, but if I check the actual website, it does find it. I would like to know if there is a way around this, and why this happens.
Any help would be greatly appreciated.

Ruby on Rails - Redirect/render via action does not work

I have the following code:
def isLoggedIn
if session[:username].nil?
puts "Not logged in!"
return render :controller=>"admin", :action=>"login"
end
end
And the following code which calls this action at the top to check the status of the user.
def view_gallery
isLoggedIn
.
.
.
.
\/
return render "view_gallery"
end
The problem I am having is that the code continues to execute past isLoggedIn although the console is logging "Not logged in!" because as expected the user isn't logged in. This should then render an alternative layout which it doesn't do. If I mispell the action (say "logib") then it complains about a missing template - so I can see it running the render function.
The same occurs if I change render to redirect_to and/or if I move the return statement to the end of the line.
Any idea's?
Many thanks
The Rails Guides says to do this in the following way:
render :controller=>"admin", :action=>"login" and return

how to run capybara commands once, then run some tests

I have the given testing code:
describe 'A new user', js: true do
before do
#new_user = Fabricate.build(:user)
end
it 'should sign up' do
#login code
visit '/'
click_link 'Login'
fill_in 'user[email]', :with => #new_user.email
fill_in 'user[password]', :with => #new_user.password
click_button 'Login now'
#login code end
page.should have_content("Hello #{#new_user.first_name}!")
current_path.should == dashboard_path
end
it 'should receive a confirmation mail' do
#same login code again
visit '/'
click_link 'Login'
fill_in 'user[email]', :with => #new_user.email
fill_in 'user[password]', :with => #new_user.password
click_button 'Login now'
mail = ActionMailer::Base.deliveries.last
assert_equal #new_user.email, mail['to'].to_s
end
end
Now I want to add more tests.
To avoid code doubling, how can I run the capybara login code once before all tests?
One solution would be to put the login code in the before method. Another would be to create a method do_login, put the code in it and run every test like this:
it 'should do something after login' do
do_login
#test code here
end
But for both solutions, the code is run for every test and thats not what I want. Putting the login code in a before(:all) doesn't work, too.
How can I run some capybara code once and then do all the tests after this?
You can't run capybara code once and then run all the tests. You always start from scratch. Your proposed solution with before(:each) or helper method is the only posibility. (It's possible to run some ruby before(:all) e.g. create objects outside the transaction check here but not Capybara)
To speed up your specs you can test login feature in separate spec and then somehow stub the authentication but it depends on your implementation.
If you are using Devise check devise wiki: https://github.com/plataformatec/devise/wiki/How-To:-Controllers-tests-with-Rails-3-(and-rspec)

What is the best way to mock a 3rd party object in ruby?

I'm writing a test app using the twitter gem and I'd like to write an integration test but I can't figure out how to mock the objects in the Twitter namespace. Here's the function that I want to test:
def build_twitter(omniauth)
Twitter.configure do |config|
config.consumer_key = TWITTER_KEY
config.consumer_secret = TWITTER_SECRET
config.oauth_token = omniauth['credentials']['token']
config.oauth_token_secret = omniauth['credentials']['secret']
end
client = Twitter::Client.new
user = client.current_user
self.name = user.name
end
and here's the rspec test that I'm trying to write:
feature 'testing oauth' do
before(:each) do
#twitter = double("Twitter")
#twitter.stub!(:configure).and_return true
#client = double("Twitter::Client")
#client.stub!(:current_user).and_return(#user)
#user = double("Twitter::User")
#user.stub!(:name).and_return("Tester")
end
scenario 'twitter' do
visit root_path
login_with_oauth
page.should have_content("Pages#home")
end
end
But, I'm getting this error:
1) testing oauth twitter
Failure/Error: login_with_oauth
Twitter::Error::Unauthorized:
GET https://api.twitter.com/1/account/verify_credentials.json: 401: Invalid / expired Token
# ./app/models/user.rb:40:in `build_twitter'
# ./app/models/user.rb:16:in `build_authentication'
# ./app/controllers/authentications_controller.rb:47:in `create'
# ./spec/support/integration_spec_helper.rb:3:in `login_with_oauth'
# ./spec/integration/twit_test.rb:16:in `block (2 levels) in <top (required)>'
The mocks above are using rspec but I'm open to trying mocha too. Any help would be greatly appreciated.
OK, I managed to figure this out thanks to everyone's help. Here's the final test:
feature 'testing oauth' do
before(:each) do
#client = double("Twitter::Client")
#user = double("Twitter::User")
Twitter.stub!(:configure).and_return true
Twitter::Client.stub!(:new).and_return(#client)
#client.stub!(:current_user).and_return(#user)
#user.stub!(:name).and_return("Tester")
end
scenario 'twitter' do
visit root_path
login_with_oauth
page.should have_content("Pages#home")
end
end
The trick was figuring out that I needed to stub :configure and :new on the real objects and stub :current_user and :name on a dobuled object instance.
I think the problem is just the way you are using the mock, you created the mock #twitter, but you never actually use it. I think you may be under the impression that any calls to Twitter will use the stubbed methods you specified, but that's not how it works, only calls made to #twitter are stubbed.
I use double ruby, not rspec mocks, but i believe you want to do something like this instead:
Twitter.stub!(:configure).and_return true
...
Twitter::Client.stub!(:current_user).and_return #user
This ensures that anytime the methods you stubbed on Twitter, Twitter::Client are called, they respond how you want.
Also, it seems strange that this is tested as part of a view, should really be part of a controller test instead unless i'm missing something.
You can try using something like http://jondot.github.com/moxy/ . Mock Web Requests

Resources