My system tests are experiencing a race condition leading to inconsistent test results. Sometimes the turbo frame is updated before my assertion (test passes) and sometimes afterward (test fails).
View:
<div data-controller="filter">
<%= form_with url: root_path, method: :get, data: { turbo_frame: "intakes", filter_target: "form", action: "change->filter#submit" } do %>
<%= select_tag "country", options_for_select(@countries) %>
<% end %>
<%= turbo_frame_tag "intakes" do %>
<table>
<% @family_intakes.each do |family_intake| %>
<tr>
<td><%= family_intake.full_name %></td>
</tr>
<% end %>
</table>
<% end %>
</div>
This Stimulus controller submits my form on change event (ultimately updating the turbo frame):
export default class extends Controller {
static targets = ["form"];
submit(event) {
this.formTarget.requestSubmit();
}
}
Test:
class FamilyIntakesTest < ApplicationSystemTestCase
test "Only intakes from selected country are displayed" do
login
select "Afghanistan", from: "country"
assert_selector "td", text: family_intakes(:manizha).first
assert_selector "td", text: family_intakes(:sayed).first
refute_selector "td", text: family_intakes(:mohammad).first
end
end
Error:
Failure:
FamilyIntakesTest#test_Only_intakes_from_selected_country_are_displayed [/home/eric/<redacted>/test/system/family_intakes_test.rb:31]:
expected not to find visible css "td" with text "Mohammad", found 1 match: "Mohammad Ahmad". Also found "Manizha Ahmadi", "Sayed Shinwari", which matched the selector but not all filters.
CodePudding user response:
My current solution is to add a turbo-response
class to the table being updated inside my turbo frame and to scope my test assertions to that css class. That way I can't get a false negative if my assertion runs before before the frame is updated.
View update
<table turbo-response" if turbo_frame_request? %>">
Helper:
module ApplicationHelper
def turbo_frame_request?
request.headers["Turbo-Frame"]
end
end
Test:
class FamilyIntakesTest < ApplicationSystemTestCase
test "Only intakes from selected country are displayed" do
login
select "Afghanistan", from: "country"
within('.turbo-response') do
assert_selector "td", text: family_intakes(:manizha).first
assert_selector "td", text: family_intakes(:sayed).first
refute_selector "td", text: family_intakes(:mohammad).first
end
end
end
Also, during the debugging process, to prevent any "accidental" success of my tests caused by the turbo frame just "happening" to load first, I intentionally slowed down my JavaScript form submission:
submit(event) {
setTimeout(() => this.formTarget.requestSubmit(), 1500);
}
The slowdown should be less than Capybara.default_max_wait_time
which is typically 2 seconds or else Capybara really will give up. I went with 1.5 seconds or 1500 milliseconds. Just make sure to remove the setTimout
later! Getting my tests to pass with or without that slowdown gives me way more confidence that they are passing for the right reasons!