Reputation: 973
Context: I set up a new system using rails-new into a devcontainer. So the dev environment is running inside docker. I'm using a dockerised Selenium Chromium to run my tests. I'm using Devise for authentication, and Cucumber for BDD.
Basic login is working when running manually, but not working when the Cucumber tests run. The user is set up correctly and first_user.valid_password?(password) is true inside the test steps. But Devise returns a 401 and the user is not logged in.
The logs show the email and password are coming through correctly. So I'm guessing that it must be something to do with CSRF tokens or something to do with the session.
Since this is a standard setup and thousands of people must have tested this and got over this problem, what's the solution?
Here's features/support/config.rb
require "capybara/cucumber"
require "selenium-webdriver"
Capybara.register_driver :selenium_remote_chrome do |app|
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument("--window-size=1400,1400")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
Capybara::Selenium::Driver.new(
app,
browser: :remote,
url: "http://#{ENV.fetch("SELENIUM_HOST")}:4444/wd/hub",
options: options
)
end
Capybara.configure do |config|
config.run_server = true
config.server_port = ENV.fetch("CAPYBARA_SERVER_PORT", 3015).to_i
config.server_host = "0.0.0.0"
config.default_driver = :selenium_remote_chrome
config.app_host = "http://rails-app:#{config.server_port}"
end
The feature file ;-
Background:
Given a user exists with email "[email protected]" and password "password123"
Rule: A user can login with the correct email and password
Scenario: User logs in successfully
When I go to the login page
And I fill in "Email" with "[email protected]"
And I fill in "Password" with "password123"
And I press "Log in"
And I wait for the page to load
Then I should see "Dashboard"
And I should see "Log out"
the steps;-
Given("a user exists with email {string} and password {string}") do |email, password|
User.create!(email: email, password: password, password_confirmation: password)
expect(User.count).to eq(1) # Ensure that the user was created
u = User.first
expect(u.valid_password?(password)).to be true # Ensure that the password is correct
end
When("I go to the login page") do
visit new_user_session_path
end
When("I fill in {string} with {string}") do |field, value|
fill_in field, with: value
end
When("I press {string}") do |button|
click_button button
end
Then("I should see {string}") do |text|
expect(page).to have_content(text)
end
And("I wait for the page to load") do
sleep 1
end
And("I wait for {int} seconds") do |seconds|
sleep seconds
end
And log/test.log ;-
Completed 401 Unauthorized in 2ms (ActiveRecord: 0.2ms (1 query, 0 cached) | GC: 0.0ms)
Processing by Devise::SessionsController#new as TURBO_STREAM
Parameters: {"user"=>{"email"=>"[email protected]", "password"=>"password123"}, "commit"=>"Log in"}
Rendering layout layouts/application.html.haml
Rendering devise/sessions/new.html.haml within layouts/application
Rendered devise/shared/_links.html.haml (Duration: 0.3ms | GC: 0.0ms)
Rendered devise/sessions/new.html.haml within layouts/application (Duration: 2.5ms | GC: 0.0ms)
Rendered layout layouts/application.html.haml (Duration: 3.3ms | GC: 0.0ms)
Note that I removed email and password from log filtering so that I can see the values being passed in.
Login works when run manually
Any ideas what could be causing this problem ?
Upvotes: 0
Views: 20
Reputation: 973
Solved it. I needed to use ```DatabaseCleaner.strategy = :truncation`` instead of :transaction
In the past I've been running Cucumber tests inside rack with the browser being controlled locally so that records created are visible to the browser.
But I can't do that when running inside a docker container. So I have to use a dockerised selenium which runs remotely. Therefore the default database cleaner strategy, :transaction won't work because records would be created inside a transaction, are are therefore invisible to remote selenium.
Once I switched to :truncation it all worked.
Upvotes: 0