I'm running into an error with an end-to-end Capybara spec in my Rails application.
Here is the relevant part of my view:
#show.html.erb
...
<%= button_to 'Cancel',
cancel_subscription_path,
class: 'button button--danger',
data: {
turbo_confirm: 'Are you sure you want to cancel?',
turbo_method: 'post'
}
%>
<div id="cancel_message"></div>
...
# cancel_subscription_spec.rb
require 'rails_helper'
RSpec.describe 'CancelSubscriptions', js: true do
it 'cancels an active subscription' do
email = sign_up_and_subscribe
visit subscription_path
accept_confirm do
click_button 'Cancel'
end
subscription = User.find_by(email:).current_subscription
expect(subscription.cancelled?).to be(true)
end
end
sign_up_and_subscribe is just a simple helper method that signs up to the application and fills in the Stripe form to create a subscription - it works in other tests and I also see the subscription created in the Stripe dashboard, this isn't the issue.
When the spec reaches visit subscription_path and attempts to click the cancel button, I get the following error:
Selenium::WebDriver::Error::UnexpectedAlertOpenError:
unexpected alert open: {Alert text : }
(Session info: chrome-headless-shell=123.0.6312.87)
I figured I was misusing the accept_confirm method, but from what I found in the documentation, this is the correct usage.
What I found strange was that commenting out the accept_confirm in the spec and the turbo_confirm in the view didn't actually change the error message. Is Capybara caching the page in between test runs?
I would consider changing the behaviour to make the spec pass at this point, I prefer to have a well-tested user flow even if that means a small change in the user experience, but I can't even do that, the issue remains the same.
In case it's helpful, the relevant part of the rails_helper.rb is:
Capybara.register_driver :chrome do |app|
Capybara::Selenium::Driver.new app, browser: :chrome,
options: Selenium::WebDriver::Chrome::Options.new(args: %w[headless disable-gpu])
end
Capybara.javascript_driver = :chrome
I can post the rest if it might be useful, but it's mostly unrelated as far as I can see.
My cancel action in the controller looks like this:
def cancel
@subscription = current_user.current_subscription
SubscriptionCanceller.new(subscription_id: @subscription.provider_id).call
rescue SubscriptionCancellationError => _e
render :cancellation_error
end
where I have turbo_stream views for cancellation_error and cancel itself, both of which work in the browser when I test them manually.
Just in case that affects it, here is the cancel.turbo_stream.erb
<%= turbo_stream.replace 'cancel_message' do %>
<div>We are cancelling your subscription.</div>
<% end %>
If there is any further detail/code required, let me know and I'll post it.
I've figured out the issue, and it wasn't an issue with the spec in question, although the behaviour was unexpected.
The underlying data that the page under tests relies on was not present. That's because in other specs I tested the same Stripe form-filling functionality and the assertions made in those tests made the application wait until they were true. In this test, however, the page was redirected with
visit subscription_pathbefore the result from the Stripe API were saved, thus causing an error.The error raised in the test threw me off because it led me to believe that there was a dialogue box open that should not have been, whereas the actual issue was that no dialogue box was open even though it was expecting one to be. The cancel button was not present on the page because the subscription page was showing empty.
The test now looks like:
Takeaway: make sure the page is rendered as expected before making assertions on accepting confirmation or prompt dialogue boxes with Capybara/Selenium. Not doing can cause unexpected errors.