how to run capybara commands once, then run some tests - ruby

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)

Related

How to run all examples except one in Ruby using Rspec

config.before(:example,) do
visit '/'
find('a[class=btn').click
fill_in 'username', with: $email
fill_in 'password', with: $password
find('input[class=btn]').click
end
I want to log in to the website in all tests except one, how do i do that?
I tried this:
config.before(:example,) |test| do
visit '/'
find('a[class=btn').click
fill_in 'username', with: $email
fill_in 'password', with: $password
find('input[class=btn]').click
unless test.metadata[:notrun]
end
end
I was expecting all test run except the one with the tag :notrun, but it runs anyway
Your unless block is just
unless test.metadata[:notrun]
end
so it's not doing anything. If you wanted the code in the before to not run then you could wrap it all in the unless
config.before(:example) |test| do
unless test.metadata[:notrun]
visit '/'
find('a[class=btn').click
fill_in 'username', with: $email
fill_in 'password', with: $password
find('input[class=btn]').click
end
end
but that will just stop the before hook from doing anything on the tagged test(s), it won't actually prevent the test from being run. Easiest way to prevent a specific example from being run is just to tag it with skip (instead of your notrun)
it 'blah blah', skip: true do
....
end
If I understand correctly, the OP wants to login before every test except one. Using skip: true will actually skip the test, not the before block.
There is a way to configure a before block to only execute on certain tests using metadata. It works like this:
RSpec.configure do |config|
config.before(:each, login: true) do
visit '/'
find('a[class=btn').click
fill_in 'username', with: $email
fill_in 'password', with: $password
find('input[class=btn]').click
end
end
RSpec.describe 'MyController' do
describe '#index' do
it 'does something while logged out'
context 'logged in', login: true do
it 'does something while logged in'
it 'does something else while logged in'
end
end
end
You can place the metadata on any describe, context, or example/it block. So, if you had a file full of tests that should be logged in, you'd just put the metadata on the outermost describe at the top of the file.

Session sometimes not persisting in Capybara Selenium test

I have a number of remote: true forms in my Rails 4 application to make up a wizard.
At each post, the action adds keys to the session object in my controller.
#post :some_action
def some_action
current_form_indetifier = params[:current_form_indetifier]
session[current_form_indetifier] = 'some_data'
end
This works fine in development and production.
It also SOMETIMES works perfectly in my Capybara Selenium test.
#step 1
fill_in 'My name is', with: 'Andy Smith'
fill_in 'I work at', with: 'Coca Cola'
find('.signup-form-next-button').click
#session key set in this post
wait_for_ajax
#step 2
fill_in 'Your Email', with: 'andy#smith.com'
fill_in 'Password', with: 'some-super-long-password'
find('.signup-form-next-button').click
#session key from last request is gone :-(
wait_for_ajax
It's super important to note that this does work sometimes.
However, for the majority (70%) of the time it does not working during testing.
By logging, I can see that the key/values are being added to the session in each request, but then in the next request the key is no longer in the session.
#first request
puts session.keys => "['form_1']"
#second request
puts session.keys => "[]"
Again, this works sometimes.
What I've tried so far to no avail:
enabling config.action_controller.allow_forgery_protection = true in environments/test.rb (it's false by default)
commenting out protect_from_forgery with: :exception in the application_controller.rb
It's important to remember that this does sometimes work.
Any ideas?
Update
For now I've worked around this by using the ActiveRecord SessionStore, so it seems the issue is around the cookies.

Factory_girl/Capybara and Cucumber

In my Rails projects I normally use factory_girl to build/create users in my app. I want to know if I can use factory_girl when using Cucumber, Capybara to test the user interaction with my app. There is no database to save them to, I am only looking to store their credentials
I can have many users so wanted to create factories for each user (unless there is a better way of doing this with Cucumber).
Within my support folder could I create a factories folder and then a .rb file holding each user.
FactoryGirl.define do
factory :user_1 do
username "username"
password "password"
end
end
Within my env.rb file I am requiring Factory Girl but this is not enough
require 'factory_girl'
As if in my feature I try
Then(/^I will enter my credentials$/) do
fill_in 'username', :with => user_1.email
fill_in 'password', :with => user_2.password
click_button 'login-button'
end
I get
uninitialized constant user_1
I also have a feeling that if this is to work I need a before hook that will build the factory user but I'm unsure on the whole setup at the moment.
Does anyone use factory_girl in this way or, as I mentioned earlier, is there a better way to do this?
You should be able to do seething like this
Given(/^I will enter my credentials$/) do
#user = user = FactoryGirl.create(:user)
end
you can read more on this question https://stackoverflow.com/a/16841999/4421094 it was really helpful
Thanks to #MarshallCap for the answer, I had come up with a workable solution and wanted to share, maybe its right or maybe there is a better way but this is what I have ended up doing, if this helps someone else then great.
Firstly I created a class for my factory_users
class Users
FactoryGirl.define do
factory :user_1, :class => :users do |u|
u.skip_create
u.username "username1"
u.password "password"
end
end
FactoryGirl.define do
factory :user_2, :class => :users do |u|
u.skip_create
u.username "username2"
u.password "password2"
end
end
end
require factory_girl in env.rb
require 'factory_girl'
And within my login script within step_definitions assigned an instance variable a hash of the users attributes
Then(/^I will enter my credentials$/) do
#user = FactoryGirl.attributes_for(:user_1)
fill_in 'username', :with => #user[:username]
end

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

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).

Acceptance testing of sinatra app using webrat fails

I am trying to test a ruby authentication app using minitest and webrat but get errors.
Tests like visit '/' fail with an error Status 200 expected but was 404.
Tests containing code like fill_in :email, :with => "first#company.com" fail with error Could not find field: :email.
I read several sinatra, testing and webrat documents and forums. Some of them were old and suggested stuff like Sinatra::Default, but github.com/brynary/webrat/wiki/sinatra, Building a Sinatra App Driven By Webrat Tests and Learning From the Masters: Sinatra Internals are new, yet they still fail.
Basically, I didn't like sentence-like syntax of rspec, cucumber etc but do want to do behaviour driven development. I really like the minitest syntax, both tests and output and that is why I choose webrat for BDD. If I'm wrong about expecting webrat to fulfill acceptance testing requirements, please simply tell me that I should use this framework or that one.
Apart from that, the first parts of the main file and test file are below. I hope someone can explain me, what I am missing?
test_file
require "test/unit"
require "minitest/autorun"
require "rack/test"
require 'webrat'
require_relative "../lib/kimsin.rb"
Webrat.configure do |config|
config.mode = :rack
end
ENV["RACK_ENV"] = "test"
class KimsinTests < Test::Unit::TestCase
include Rack::Test::Methods
include Webrat::Methods
include Webrat::Matchers
def app
Sinatra::Application.new
end
def test_create_user
visit "/user/new"
fill_in :username, :with => "first#company.com"
fill_in :password, :with => "abC123?*"
fill_in :confirm_password, :with => "abC123?*"
click_link "Register"
assert 201, last_response.status, "Status 201 expected but was #{last_response.status}.\n#{error}"
assert_contain /Logged in as first#company.com./, "No user created"
assert_contain /Logout/, "Logout link not present"
end
main_file
require "sinatra"
require "erb"
require_relative "../lib/kimsin/version"
require_relative "../lib/kimsin/user"
class Kimsin < Sinatra::Application
use Rack::Session::Pool, :expire_after => 2592000
set :session_secret, BCrypt::Engine.generate_salt
configure :development do
DataMapper.auto_migrate!
end
get "/" do
if session[:user_id]
user = User.get session[:user_id]
email = user.email
erb :index, :locals => { :email => email }
else
email = nil
erb :index, :locals => { :email => email }
end
end
Using Sinatra with Webrat should work fine. I think that the errors that you are seeing are caused by the following method (around line 18 in your test file):
def app
Sinatra::Application.new
end
This is setting up the Sinatra::Application base class to run your tests against when you really need to set up your own subclass Kimsin (because you are creating a modular style Sinatra app), i.e.
def app
Kimsin.new
end
The 404 errors and missing fields are happening because Sinatra::Application doesn't define any of the routes you are testing.
You might also like to take a look at Capybara if you are looking for similar alternatives to Webrat.

Resources