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.
Related
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.
I am using Rspec 3.2 and Capybara 2.4 in a non RoR project. I am trying to test with feature mode provided by Capybara gem.
$ cat .rspec
--color
--require spec_helper
$ cat spec/features/test_spec.rb
feature 'login' do
username ="rspec#{Time.now.to_i}"
valid_email = "#{username}#gmail.com"
scenario 'with valid email' do
sign_up_with valid_email, 'pwd', 'pwd', username
expect(page).to have_content('LOGOUT')
end
end
$ cat spec/support/session_helper.rb
module SessionHelper
def sign_up_with(email, password, confirm_password, username)
visit '/signup'
fill_in 'email', with: email
fill_in 'password', with: password
fill_in 'passconf', with: confirm_password
fill_in 'username', with: username
click_button 'submit'
end
end
$ cat spec/spec_helper.rb
require 'capybara/rspec'
Capybara.default_driver = :selenium
RSpec.configure do |config|
...
config.include SessionHelper, type: :feature
...
end
This is a non RoR project, when I run the test I have this error:
$ rspec
spec/spec_helper.rb:26:in `block in <top (required)>': uninitialized constant SessionHelper (NameError)
In online documentation there are many examples, I have structured my files like the examples but it not works.
The way I handle this in all of my projects is like this:
Require all the support files:
In spec_helper.rb
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
And then your spec/support/session_helper.rb should look like this:
module SessionHelper
def sign_up_with(email, password, confirm_password, username)
visit '/signup'
fill_in 'email', with: email
fill_in 'password', with: password
fill_in 'passconf', with: confirm_password
fill_in 'username', with: username
click_button 'submit'
end
end
RSpec.configure do |config|
# Remove the equivalent line from spec_helper.rb
config.include(SessionHelper)
end
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
Is there a way to call a ruby script a within another ruby script b? I have a ruby script which performs the website login (login.rb) and another script order_create.rb. I want to call login.rb first and then execute order_create.rb next. Please suggest.
Order_Created.rb:-
##order_data = YAML.load(File.open'C:\Users\order_details.yaml') def fill_order_form(order_data)
fill_in 'Firstname', :with => order_data['firstname']
fill_in 'Lastname', :with => order_data['lastname']
fill_in 'ZIP', :with => order_data['zip']
click_button 'Continue'
end
order_detail.yaml :-
firstname: "Order"
lastname: "Test"
zip: "90341"
login.rb:-
require './order_create.rb'
def login
#login code here
fill_order_form(##order_data)
end
Error on running login.rb :- undefined method `fill_order_form' for #<#<Class:0x3e344e0>:0x4248ba0>
A similar (although different) question already been answered at : Running another ruby script from a ruby script
You can include the script that you want to call in your script with:
require './b.rb' #if b.rb is in the same directory
and call it with:
b(args)
for your example, you can do the following:
login.rb
require './order_create.rb'
def login
#login code here
order_create()
end
Assuming that your create_order.rb contains def create_order()
Even though you can execute any shell command using backticks or %x
`ruby yourscript.rb`
%x(ruby yourscript.rb)
In this case it isn't good idea, since you have conventional ways of solving this, create third script, say login_and_order.rb and put following code inside:
require_relative 'login.rb'
require_relative 'order_create.rb'
# run your methods from both scripts in sequence you need
# or if they are just set of commands, nothing else needed
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)