Capybara & minitest - sessions aren't working - ruby-on-rails

I want Capybara to fill out a login form, click on 'Login', and redirect me to the root path like this: (example). This app is your classic blog app with Devise for authentication - I can't think of anything else that would affect the test.
I only get a 'failed assertion' test error so I checked the spelling of my button, experimented with Warden, and still couldn't figure it out. For a solution, I'd like to be able to exactly mimic how a user would navigate through a page.
Integration test:
require 'test_helper'
require 'database_cleaner'
class PostsTest < ActionDispatch::IntegrationTest
# for setup and tear down each time we run tests
self.use_transactional_fixtures = false
setup do
DatabaseCleaner.start
end
teardown do
DatabaseCleaner.clean
end
def setup
#post = posts(:valid_post)
#admin = users(:james)
#regular = users(:steve)
end
test 'display comments' do
assert #post.comments.first.body == 'hello'
end
test 'visit contact page' do
visit '/contact'
assert page.has_text?('jamesyoun710')
end
test 'login as admin' do
visit new_user_session_path
assert page.has_field?('Email', type: 'email')
fill_in('Email', with: 'jamesyoun710#gmail.com')
fill_in('Password', with: 'gooneen44')
click_on('Log in') # this doesn't redirect me into the page
# login_as(#admin) # I need to do this to execute the line above
visit root_path
assert page.has_link?('Logout')
assert page.has_link?('New Post')
end
end
test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require "minitest/reporters"
require 'minitest/rails'
require 'capybara/rails'
require 'minitest/rails/capybara'
Minitest::Reporters.use!
# for creating sessions in tests
include Warden::Test::Helpers
Warden.test_mode!
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
end
class ActionController::TestCase
include Devise::TestHelpers
end
class ActionDispatch::IntegrationTest
include Capybara::DSL
end
gemfile:
group :development, :test do
gem 'database_cleaner'
gem 'hirb'
gem 'byebug'
gem 'annotate'
gem 'web-console', '~> 2.0'
gem 'spring'
gem 'better_errors', '~> 2.1.1'
gem 'binding_of_caller', '~> 0.7.2'
end
group :test do
gem 'minitest-reporters', '1.0.5'
gem 'minitest-rails-capybara'
# gem 'mini_backtrace'
gem 'guard-minitest', '2.3.1'
end

Found the solution - I should have been using login info from my fixtures (test db) but instead I was using login info from my development db.

Related

undefined method `test_get_index' for class `Minitest::Result'

I'm trying to run this integration test. For some reason, it isn't accepting minitest syntax and I have no clue why.
test_helper.rb
require File.expand_path("../../config/environment", __FILE__)
require "rails/test_help"
require "minitest/rails"
require 'minitest/reporters'
require "minitest/rails/capybara"
Minitest::Reporters.use!
class ActiveSupport::TestCase
fixtures :all
end
gemfile.rb
group :test do
gem "minitest-rails"
gem 'minitest-rails-capybara'
gem 'minitest-reporters'
gem 'guard'
gem 'guard-minitest'
gem "selenium-webdriver"
gem "chromedriver-helper"
gem "shoulda-matchers", require: false
end
integration_controller_test
require 'test_helper'
class MovieControllerTest < ActionDispatch::IntegrationTest
setup do
#movie = movies(:movie_1)
end
describe "integration testing" do
test 'get index' do
get movies_path
assert_response :success
end
end
end

Execution expired on rails feature spec testing a download using capybara/selenium/firefox

Update: After burning too many hours, decided to opt for the easy way out and use rack-test. This works straight out of the box and at least verifies that the content-type is a pdf.
scenario 'document can be downloaded' do
visit my_documents_path
click_on 'Download'
expect(page.response_headers['Content-Type']).to eq "application/pdf"
end
I am trying to write a feature spec to test the contents of my downloaded pdf, and I have followed the directions found here: https://stackoverflow.com/a/29544674/2464546
I am running Ruby 2.3, Rails 4.2.5.2, RSpec 3.4, Capybara 2.7.
In the code from the SO link above, there's a line that supposedly suppresses the Firefox Save popup, with this, adjusted to pdf from csv:
# Suppress "open with" dialog
profile['browser.helperApps.neverAsk.saveToDisk'] = 'application/pdf'
This doesn't seem to work because the dialog box still pops up, and then my test errors out.
My feature spec:
scenario 'document can be downloaded', js: true do
visit my_documents_path
click_on 'Download'
expect(DownloadHelpers::download_content).to have_content('Thingy')
end
Every time I run this spec, it errors out saying execution expired with a different error each time. For example the latest one had the following:
1) My documents home page document can be downloaded
Failure/Error: Dir[PATH.join("*")]
Timeout::Error:
execution expired
# ./spec/features/shared/download_helper.rb:8:in `downloads'
# ./spec/features/shared/download_helper.rb:31:in `downloading?'
# ./spec/features/shared/download_helper.rb:27:in `downloaded?'
# ./spec/features/shared/download_helper.rb:22:in `block in wait_for_download'
# ./spec/features/shared/download_helper.rb:21:in `wait_for_download'
# ./spec/features/shared/download_helper.rb:16:in `download_content'
# ./spec/features/my_documents/index_spec.rb:42:in `block (2 levels) in <top (required)>'
In the DownloadHelpers module, I've changed the sleep from 0.1 to 1 to 3, and occasionally I'll get the following error, with the sleep count changing w/ whatever I've set it to:
Failure/Error: sleep 3 until downloaded?
Timeout::Error:
execution expired
# ./spec/features/shared/download_helper.rb:22:in `sleep'
# ./spec/features/shared/download_helper.rb:22:in `block in wait_for_download'
# ./spec/features/shared/download_helper.rb:21:in `wait_for_download'
# ./spec/features/shared/download_helper.rb:16:in `download_content'
# ./spec/features/my_documents/index_spec.rb:42:in `block (2 levels) in <top (required)>'
I have also changed the TIMEOUT count with no change in failure result from the above. Ultimately, the dialog box still pops up and does not go away/doesn't look like it downloads the file.
My controller behind the Download button:
def download
pdf = #document.pdf_file_name
send_file pdf
end
The created document is not large, as all it has is a name and a few lines, so I don't suspect it'd need more than a few seconds to download and read the file.
Why is the execution expiring? How do I get Capybara/Feature spec to download the file so my expectation passes?
The view document.haml using angular tho I don't think that matters.
%li.col-xs-6
%li.col-xs-6= link_to 'Download', download_document_path(id: document.id), "ng-click" => "logAnalytics('#{document.document_template_id}', 'download')"
Also, my feature spec has require 'rails_helper' at the top, and my rails_helper has the code from the SO post (in full, w/ relevant bits):
require 'features/shared/download_helper'
RSpec.configure do |config|
Capybara.register_driver :selenium do |app|
profile = Selenium::WebDriver::Firefox::Profile.new
profile['browser.download.dir'] = DownloadHelpers::PATH.to_s
profile['browser.download.folderList'] = 2
profile['browser.helperApps.neverAsk.saveToDisk'] = 'application/pdf'
Capybara::Selenium::Driver.new(app, browser: :firefox, profile: profile)
end
config.before( :each ) do
DownloadHelpers::clear_downloads
end
end
I think any of the following will work:
page.driver.browser.switch_to.alert.accept
# or
page.driver.browser.switch_to.alert.dismiss
# or
page.driver.browser.switch_to.alert.text
Check the mime type your pdf download is returning, odds are it's not actually 'application/pdf' and is most likely being returned as 'application/octet-stream'. You should fix the return type to be correct, but in the short term you can try changing to profile['browser.helperApps.neverAsk.saveToDisk'] = 'application/pdf,application/octet-stream'
I got the 'execution expired' error too. I followed all the steps above, but the error remained. It turned out to be the download directory was missing in the filesystem (DownloadHelpers::PATH).
Creating that one made the message disappear and the test pass.
I was experiencing this same error. The solution for me was to increase the timeout. So where ever you are doing the sleeping until timeout, increase the timeout. Of course it depends on your business logic but 5 seconds works for me consistently whereas 2 seconds failed consistently.
I have tried to implement something similar and spend lots of hours. Finally I have some solution, maybe it fit for you as well.
Gemfile:
#source 'https://rubygems.org'
gem 'rails', '4.2.2'
gem 'bcrypt', '3.1.7'
gem 'bootstrap-sass', '3.2.0.0'
gem 'faker', '1.4.2'
gem 'carrierwave', '0.10.0'
gem 'mini_magick', '3.8.0'
gem 'fog', '1.36.0'
gem 'will_paginate', '3.0.7'
gem 'bootstrap-will_paginate', '0.0.10'
gem 'sass-rails', '5.0.2'
gem 'uglifier', '2.5.3'
gem 'coffee-rails', '4.1.0'
gem 'jquery-rails', '4.0.3'
gem 'turbolinks', '2.3.0'
gem 'jbuilder', '2.2.3'
gem 'sdoc', '0.4.0', group: :doc
gem 'rename'
gem 'sprockets', '3.6.3'
gem 'responders', '~> 2.0'
gem 'inherited_resources'
group :development, :test do
gem 'sqlite3', '1.3.9'
gem 'byebug', '3.4.0'
gem 'web-console', '2.0.0.beta3'
gem 'spring', '1.1.3'
end
group :test do
gem 'minitest-reporters', '1.0.5'
gem 'mini_backtrace', '0.1.3'
gem 'guard-minitest', '2.3.1'
gem 'capybara', '2.8.1'
gem 'rspec', '3.5.0'
gem 'rspec-rails', '~> 3.4'
gem 'cucumber-rails', :require => false
gem 'shoulda-matchers', '~> 3.0', require: false
gem 'database_cleaner'
gem 'factory_girl_rails', '~> 4.5.0'
end
spec/rails_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'shoulda/matchers'
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
config.use_transactional_fixtures = false
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
end
spec/spec_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
require 'capybara/rails'
require 'download_helper'
Capybara.register_driver :selenium do |app|
profile = Selenium::WebDriver::Firefox::Profile.new
profile['browser.download.dir'] = DownloadHelpers::PATH.to_s
profile['browser.download.folderList'] = 2
profile['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv'
Capybara::Selenium::Driver.new(app, :browser => :firefox, :profile => profile)
end
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.shared_context_metadata_behavior = :apply_to_host_groups
config.include Capybara::DSL
=begin
config.filter_run_when_matching :focus
config.example_status_persistence_file_path = "spec/examples.txt"
config.disable_monkey_patching!
if config.files_to_run.one?
config.default_formatter = 'doc'
end
config.profile_examples = 10
config.order = :random
Kernel.srand config.seed
=end
end
test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'capybara/rails'
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
include ApplicationHelper
def is_logged_in?
!session[:user_id].nil?
end
# Logs in a test user.
def log_in_as(user, options = {})
password = options[:password] || 'password'
remember_me = options[:remember_me] || '1'
if integration_test?
post login_path, session: { email:user.email, password: password, remember_me: remember_me }
else
session[:user_id] = user.id
end
end
private
# Returns true inside an integration test.
def integration_test?
defined?(post_via_redirect)
end
end
class ActionDispatch::IntegrationTest
# Make the Capybara DSL available in all integration tests
include Capybara::DSL
# Reset sessions and driver between tests
# Use super wherever this method is redefined in your individual test classes
def teardown
Capybara.reset_sessions!
Capybara.use_default_driver
end
end
spec/download_helper.rb
module DownloadHelpers
TIMEOUT = 1
PATH = Rails.root.join("tmp/downloads")
extend self
def downloads
Dir[PATH.join("*")]
end
def download
downloads.first
end
def download_content
wait_for_download
File.read(download)
end
def wait_for_download
Timeout.timeout(TIMEOUT) do
sleep 0.1 until downloaded?
end
end
def downloaded?
!downloading? && downloads.any?
end
def downloading?
downloads.grep(/\.part$/).any?
end
def clear_downloads
FileUtils.rm_f(downloads)
end
end
spec/mpodels/spec.rb
describe 'Download file' do
specify do
visit '/createfile'
click_on 'create file'
page.response_headers['Content-Type'].should == "text/csv"
header = page.response_headers['Content-Disposition']
header.should match /^attachment/
header.should match /filename=\"temp.csv\"$/
end
end

minitest not picking up describe blocks

I am having an issue using the describe syntax in minitest. When I run: ruby -Itest test/elasticsearch/es_record_test.rb
Its only picking up 1 test, and not picking up the one in the describe block.
pass: 1, fail: 0, error: 0, skip: 0
total: 1 tests with 1 assertions in 0.075147 seconds
Below is my current code:
require "test_helper"
class EsRecordTest < Minitest::Spec
let(:id) { '123' }
let(:invalid_id) { '456' }
let(:index_name) { 'es' }
let(:index_type) { 'test' }
let(:body) {{ :body => 'data' }}
before do
Elasticsearch::EsRecord.stub(:index_name, index_name) do
Elasticsearch::EsRecord.stub(:index_type, index_type) do
Elasticsearch::EsRecord.index(id, body)
end
end
end
it "should raise an error for unimplemented methods" do
assert_raises NotImplementedError do
Elasticsearch::EsRecord.index_name
Elasticsearch::EsRecord.index_type
end
end
describe "::delete_index_type" do
it 'should be able to delete an index type if the type exists' do
assert Elasticsearch::EsRecord.delete_index_type(index_name, index_type)
end
end
My test_helper.rb is:
ENV["RAILS_ENV"] ||= "test"
require File.expand_path("../../config/environment", __FILE__)
require "rails/test_help"
require "minitest/rails"
require 'webmock/minitest'
require 'sidekiq/testing'
require 'typhoeus/adapters/faraday'
WebMock.disable_net_connect!(:allow_localhost => true)
Turn.config.format = :outline
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
fixtures :all
# Add more helper methods to be used by all tests here...
extend MiniTest::Spec::DSL
register_spec_type self do |desc|
desc < ActiveRecord::Base if desc.is_a? Class
end
end
My gemfile:
gem "byebug", group: [:development, :test]
gem 'http_logger', require: true, group: [:development]
gem "minitest-rails", '~> 0.9', group: [:development, :test]
group :test do
gem 'cucumber-rails', :require => false, group: [:test]
gem 'selenium-webdriver', "~> 2.40.0"
gem 'vcr'
gem 'database_cleaner'
gem 'webmock'
gem 'elasticsearch-extensions'
gem 'rspec-rails'
gem 'turn'
gem 'pickle', :git => "https://github.com/zgchurch/pickle.git"
end
Both RSpec and Minitest define the describe method. Since you have rspec-rails added in your Gemfile it is using RSpec. I don't know of a way to have both RSpec and Minitest's Spec DSL activated at the same time.

Capybara/rspec configuration issue

When I try to run my feature specs with Capybara, I get a
undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_1:0x007fdc629c6d28>
error. I know it's an issue of not having capybara configured correctly because otherwise, it would have a visit method.
Here's the relevant part of my gemfile:
group :test, :development do
gem 'rspec-rails', '~> 2.0'
gem 'factory_girl_rails', ">= 4.2.0"
gem 'guard-rspec', "~> 0.7.0"
end
group :test do
gem 'faker', '~> 1.0.1'
gem 'capybara', git: 'https://github.com/jnicklas/capybara', ref: '7fa75e55420e'
gem 'database_cleaner', '~> 0.7.2'
gem 'launchy', '~> 2.1.0'
gem 'shoulda-matchers'
end
Using that ref for capybara I got from this article on upgrading to Capybara 2.0.
And here's my spec:
# spec/features/create_user_spec.rb
require 'spec_helper'
feature 'Creating a user' do
scenario 'adds a new user' do
visit new_user_registration_path
fill_in 'Email', :with => 'me#me.com'
[ 'Password', 'Password confirmation' ].each { |p| fill_in p, :with => '12345678' }
page.should have_content 'User successfully created'
current_path.should == recipes_path
end
end
And here's my spec_helper.rb:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rspec'
require 'capybara/rails'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.include Capybara::DSL
config.order = "random"
end
What I've tried
Manually including Capybara::DSL
Adding require_relative to give the right routing to the spec_helper file
Please tell me what I'm overlooking.
Do you have multiple spec_helper.rb files
try giving
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
or giving the full path...
the underscores were not getting rendered.

Why cant I get selenium to kick in with capybara

Im trying to test a user clicking on a button which makes an ajax call. When i click it manuallly in my browser it behaves as expected i.e. default behaviour of the button is ignored and instead it gets the results via ajax which are then added to the page.
But when i run my tests using capybara, after clicking on the button it redirects to the buttons action. It seems selenium isnt kicking in. I cant figure out why.
Is it my config? Since it works in development mode Im assuming this isnt due to my jquery code so for brevity not displaying that.
Gemfile
source 'http://rubygems.org'
gem 'rails', '3.1.0.rc4'
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'sqlite3'
gem 'omniauth', '~>0.2.0'
gem 'pusher'
gem 'youtube_it'
gem 'simple_form'
# Asset template engines
gem 'sass-rails', "~> 3.1.0.rc"
gem 'coffee-script'
gem 'uglifier'
gem 'jquery-rails'
# Use unicorn as the web server
# gem 'unicorn'
# Deploy with Capistrano
# gem 'capistrano'
# To use debugger
# gem 'ruby-debug19', :require => 'ruby-debug'
group :test do
gem "shoulda"
gem "factory_girl_rails"
# Pretty printed test output
gem 'turn', :require => false
gem 'mocha'
end
group :development do
gem 'rails3-generators'
gem "autotest"
end
group :development, :test do
gem "capybara", :git => 'git://github.com/jnicklas/capybara.git'
gem "launchy"
gem "haml-rails"
gem "database_cleaner"
end
or my test_helper
ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'shoulda/rails'
require "capybara/rails"
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
OmniAuth.config.test_mode = true
# Add more helper methods to be used by all tests here...
def login_in(user)
#request.session[:user_id] = user.id
end
def should_redirect_unauthorized
assert_redirected_to root_path
assert_match /you need to login/i, flash[:alert]
end
end
module ActionController
class IntegrationTest
include Capybara::DSL
self.use_transactional_fixtures = false
setup do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.start #workaround for capybara / selenium. See capybara docs
end
teardown do
DatabaseCleaner.clean #workaround for capybara / selenium. See capybara docs
end
#signup using twitter, facebook for authentication
def signup_using(provider)
OmniAuth.config.add_mock(provider.to_sym, {'uid' => "123456"})
visit '/'
page.click_link("#{provider}_auth")
assert_match /\/users\/\d+\/edit/, current_path
assert page.find("#flash").has_content?("Welcome to")
end
#login into existing account using twitter, facebook
def login_using(service)
OmniAuth.config.add_mock(service.provider.to_sym, {'uid' => service.uid})
visit '/'
page.click_link("#{service.provider}_auth")
assert page.find("#flash").has_content?("Welcome back")
assert_equal rooms_path, current_path
end
def login_and_visit_room(service, room)
login_using(service)
visit_room(room)
end
def visit_room(room)
visit room_path(room)
assert_equal room_path(#room.id), current_path
end
end
end
or the setup blocks in my integration test
require 'test_helper'
class PlaylistStoriesTestTest < ActionDispatch::IntegrationTest
fixtures :all
setup do
Capybara.current_driver = :selenium
#user = Factory(:user)
#service = #user.services.create(:provider => "twitter", :uid => "123456")
#room = Factory(:room)
end
....
teardown do
Capybara.use_default_driver
DatabaseCleaner.clean #workaround for capybara / selenium. See capybara docs
end
end
With Capybara, you should not get confused with the difference between a link (even if it looks like a button) and a button (like "submit"). You did not provide the view file contents, but I guess, you are using a button, not a link.
With capybara, you have to differentiate
visit '/'
click_button 'Login'
or
visit '/'
click_link 'Home'
See also the Capybara-Documentation at GitHub

Resources