I'm writing a spec for a form page which uses DragonFly gem to handle attachments, here is my spec (relevant part of it)
fill_in "Subject", :with => 'My message'
fill_in "Title", :with => 'My image title'
fill_in "Content", :with => 'Message content'
attach_file 'Title image', Rails.root.join('spec', 'factories', 'test-image.png')
click_button "Create Message"
page.should have_content("Message was successfully created.")
However it fails on the click_button step with the following error
Failure/Error: click_button "Create Message"
ArgumentError:
Dragonfly::TempObject must be initialized with a String, a Pathname, a File, a Tempfile, another TempObject, something that responds to .tempfile, or something that responds to .path
I tracked down this error and I've found that it's raised in this line; I've put some debug instruction before that line and I found out that obj is an Array which contains binary data of the image, here are the first data returned by p obj.inspect
"[\"\\x89PNG\\r\\n\", \"\\u001A\\n\", \"\\u0000\\u0000\\u0000\\rIHDR\\u0000\\u0000\\u0003s\
What I'm doing wrong? Is it my fault or there is some incompatibility with Capybara and Dragonfly?
P.S. When I access the application using a real browser it works like a charm.
I was using an old version of Capybara, I've updated it to version 1.1.2 with bundle update capybara and the problem is gone.
Related
I have the problem with a simple script:
Given(/^I am on the main home page$/) do
visit 'xxx.se'
end
When(/^I search for "(.*?)"$/) do
|search_term|
fill_in 'q', :with => search_term
click_on 'search'
end
Then(/^videos of large rodents are returned$/) do
expect(page).to have_content 'Samsung'
but I got an error
Capybara::ElementNotFound: Unable to find link or button "search"
./features/step_definitions/steps.rb:7:in `/^I search for "(.*?)"$/'
link to inspect element here:
http://imgur.com/GLbbg7e
try find("button[aria-label='Search']") it probably can help
you can read about clicks here
http://www.rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Actions
As click on does not support css selectors you can use find instead
find(:css, "button.search-form-button").click
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 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).
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)
I am trying to test a sinatra app using minitest and capybara but get several errors on all tests using capybara features like fill_in or visit.
test_index gives:
undefined local variable or method `app' for #
test_create_user gives:
Invalid expression: .////form[#id = 'register']
test_same_email gives:
Unable to find css "#register"
test_login gives:
cannot fill in, no text field, text area or password field with id,
name, or label 'email' found
Any suggestions on what may be wrong?
test.rb
require "test/unit"
require "minitest/autorun"
require "capybara"
require "capybara/dsl"
require "rack/test"
require_relative "../lib/kimsin.rb"
ENV["RACK_ENV"] = "test"
class KimsinTests < Test::Unit::TestCase
include Rack::Test::Methods
include Capybara::DSL
Capybara.app = Sinatra::Application
def test_index
visit "/"
assert stuff..
end
def test_create_user
visit "/user/new"
within "//form#register" do
fill_in :username, :with => "first#company.com"
fill_in :password, :with => "abC123?*"
fill_in :confirm_password, :with => "abC123?*"
click_link "Register"
end
assert stuff..
end
end
I'm using cygwin 1.7.15-1 on windows 7, rvm -v 1.14.1 (stable) and ruby -v 1.9.2p320.
----UPDATE----
Finally I got the tests work by incorporating Steve's suggestions:
within "form#register" do
fill_in "email", :with => "first#company.com"
click_button "Register"
and asserting the response by using capybara_minitest_spec:
page.must_have_content "Password"
page.must_have_button "Register"
I just answered a more recent question you posted about Sintra with Webrat.
Acceptance testing of sinatra app using webrat fails
I think the problem here is the same. Try replacing:
Capybara.app = Sinatra::Application
with:
Capybara.app = Kimsin
Personally I would choose Capybara over Webrat.