0
votes

I have an RSpec feature spec that tests the login for my app. It passes when I run it in RSpec with Capybara, but when I try to run it flagged with js: true using Capybara-webkit, it fails. This is a problem because my entire app is behind the login, and if I can't get this bit to run I don't know how to do feature specs for the rest of the app.

Here's what I have tried:

  • Installing all the Capybara-webkit dependencies listed here. I'm running my app in a Docker container built on the ruby:2.3 image, which is built on Jessie.
  • Setting up DatabaseCleaner per this blog post. My database_cleaner.rb file is below.
  • Using the Headless gem (headless.rb below)
  • Running RSpec like so: xvfb-run -a bin/rspec spec/features/log_in_spec.rb (seems no different than running it normally with Headless)

How do I get my login specs to work under Capybara-webkit? Some of my specs will need to be flagged for JS and some won't, but they'll all need the user to be logged in. Thank you.

log_in_spec.rb

require 'rails_helper'

RSpec.feature "Log in", type: :feature do

  scenario "as admin" do
    user = create(:admin)

    # Tried this instead of with Capybara, works with Capybara but not capybara-webkit    
    # login_as user, scope: :user, run_callbacks: false

    visit root_path
    fill_in 'Email', with: user.email
    fill_in 'Password', with: user.password
    find('.btn-primary').click
    expect(page).to have_content('Admin')
  end
end

spec_helper.rb

require 'capybara/rspec'
require 'paperclip/matchers'

RSpec.configure do |config|

  Capybara.javascript_driver = :webkit
  Capybara.app_host = 'https://192.168.99.101'

  config.include Paperclip::Shoulda::Matchers

  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
    mocks.verify_doubled_constant_names = true
  end

  config.filter_run :focus
  config.run_all_when_everything_filtered = true

  config.disable_monkey_patching!

  if config.files_to_run.one?
    config.default_formatter = 'doc'
  end

end

rails_helper.rb

ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)

# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'

require 'capybara/rails'
require 'devise'
require 'support/controller_macros'

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!

RSpec.configure do |config|
  config.use_transactional_fixtures = false

  config.filter_rails_from_backtrace!

  config.include Warden::Test::Helpers
  config.before :suite do
    Warden.test_mode!
  end

  config.after :each do
    Warden.test_reset!
  end

end

# Added headless gem and this code thanks to this post: http://stackoverflow.com/a/28706535/3043668
if ENV['HEADLESS']
  require 'headless'
  headless = Headless.new
  headless.start
  at_exit { headless.stop }
end

spec/support/database_cleaner.rb

RSpec.configure do |config|
  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, js: true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end
end

spec/support/headless.rb

RSpec.configure do |config|
  config.around type: :feature do |example|
    Headless.ly do
      example.run
    end
  end
end

spec/support/capybara.rb

Capybara::Webkit.configure do |config|
  config.debug = true
  config.allow_unknown_urls
  config.timeout = 5
  config.ignore_ssl_errors
  config.skip_image_loading
end

Here is a gist of the debug output from Capybara-webkit when I run the test. It looks like it's trying the same thing over and over.

UPDATE I removed my Capybara.app_host setting, and the non-JS test still passes, but when I run it under capybara-webkit, I see this in the debig output:

Received 0 from "https://127.0.0.1:37193/login"
Page finished with false
Load finished
Page load from command finished
Wrote response false "{"class":"InvalidResponseError","message":"Unable to load URL: http://127.0.0.1:37193/login because of error loading https://127.0.0.1:37193/login: Unknown error"}"
Received "Reset()"
Started "Reset()"
undefined|1|SecurityError: DOM Exception 18: An attempt was made to break through the security policy of the user agent.

It's trying to visit("/login") and it is being redirected to the https version, and this is making it fail. How do I make it succeed?

2
Your use_transactional_fixtures and database_cleaner config look right for out-of-process testing to me, so I don't think the connection-sharing hack should be necessary. That said I don't know what the problem is. I'd try save_and_open_page and save_and_open_screenshot.Dave Schweisguth

2 Answers

1
votes
  1. The first reason is that the record after save procedure c=keep not the password in plain view, but seems that it is good in this case:

    user = create(:admin)
    # ...
    user = User.first # wrong way
    #...
    fill_in 'Password', with: 'password'
    
  2. The second reason in fail to login is that factory girl and capybara uses separate connections, so and data created in one session isn't available in another. To fix it use single connection patch (put it to spec/support) as described here.

0
votes

This was a hard one. But the issue was that I had set force_ssl = true in my application.rb, stupidly, instead of putting it in production.rb and development.rb like a normal person.

I also had set Capybara-webkit's app_host, which, as it turned out, I did not need to do. After removing that, and running capybara-webkit with debug on, I saw that it was trying to redirect from http://localhost:45362/login (or whatever port) to https://localhost:45362/login (note the https!) and that this was causing a DOM 18 security error or whatever, and this was making it choke. I turned off force_ssl and now it works like a champ. Hope this helps you not tear your hair out.