Skip to content

Commit f9872c3

Browse files
authored
Improve upon test suite flakiness (#327)
* Make `turbo_test.rb` with Rails' generated `test_helper.rb` > Something in the test suite configuration is preventing the database > from being wiped between test runs. This results in state leaking > between tests. As a result, our Continuous Integration tests are flaky. > > - [#248][] As a follow-up to the [short-term solution][] shipped in [#248][], this commit attempts to make the `test/turbo_test.rb` file's setup consistent with the test harness setup generated by Rails' [engine generator][] code. To that end, this commit: * renames the `test/turbo_test.rb` file to `test/test_helper.rb` * omits one-off `require` calls for particular dependencies * re-orders the require calls so that the `../test/dummy/config/environment` file is required ahead of the `rails/test_help` file [engine generator]: https://github.com/rails/rails/blob/3c48b4030adbded21bebaa0d78254216cca48a6e/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt [#248]: #248 [short-term solution]: c2dc5b1 * Use Ruby 2.7 argument forwarding Switching to argument forwarding addresses deprecation warnings like: ``` hotwired/turbo-rails/test/streams/streams_channel_test.rb:140: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call hotwired/turbo-rails/test/turbo_test.rb:14: warning: The called method `render' is defined here ``` * Tests: Load 6.1 defaults in Dummy Application Resolve deprecation warnings like: ``` Preparing test database DEPRECATION WARNING: Non-URL-safe CSRF tokens are deprecated. Use 6.1 defaults or above. (called from <top (required)> at /home/runner/work/turbo-rails/turbo-rails/test/dummy/config/initializers/inspect_helpers.rb:1) DEPRECATION WARNING: Using legacy connection handling is deprecated. Please set `legacy_connection_handling` to `false` in your application. The new connection handling does not support `connection_handlers` getter and setter. Read more about how to migrate at: https://guides.rubyonrails.org/active_record_multiple_databases.html#migrate-to-the-new-connection-handling (called from <top (required)> at /home/runner/work/turbo-rails/turbo-rails/test/test_helper.rb:6) ``` Since our GitHub CI matrix includes `6.1`, `7.0`, and `main`, CI's tests should run with at least the `6.1` defaults. * CI: Continue other executions on error Remove the `continue-on-error` configuration and instead allow other jobs complete in spite of failures. * Improve Flaky Test: Clear fields before filling in Resolve a flaky System Test by ensuring that an input is clear before filling in a new value. * Improve flaky tests: Broadcasts First, don't render HTML with the `<turbo-stream-source>` element. Instead, append the element when clicking a `<button>`.
1 parent 5040246 commit f9872c3

20 files changed

+77
-63
lines changed

.github/workflows/ci.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ jobs:
1111
- "6.1"
1212
- "7.0"
1313
- "main"
14-
continue-on-error: [ false ]
1514

1615
# Disabled until minitest relaxes its upper bound: https://github.com/seattlerb/minitest/pull/862
1716
# > minitest-5.14.2 requires ruby version < 3.1, >= 2.2, which is incompatible with the current version, ruby 3.1.0p-1
@@ -25,7 +24,7 @@ jobs:
2524

2625
name: ${{ format('Tests (Ruby {0}, Rails {1})', matrix.ruby-version, matrix.rails-version) }}
2726
runs-on: ubuntu-latest
28-
continue-on-error: ${{ matrix.continue-on-error }}
27+
continue-on-error: true
2928

3029
steps:
3130
- uses: actions/checkout@v1

test/application_system_test_case.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require "turbo_test"
1+
require "test_helper"
22

33
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
44
driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400]

test/drive/drive_helper_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require "turbo_test"
1+
require "test_helper"
22

33
class Turbo::DriveHelperTest < ActionDispatch::IntegrationTest
44
test "opting out of the default cache" do
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<button type="button">
2+
<%= content %>
3+
4+
<script>
5+
document.currentScript.parentElement.addEventListener("click", ({ currentTarget }) => {
6+
for (const template of currentTarget.querySelectorAll("template")) {
7+
currentTarget.parentElement.insertBefore(template.content, currentTarget)
8+
}
9+
currentTarget.remove()
10+
})
11+
</script>
12+
13+
<template><%= yield %></template>
14+
</button>
+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<h1>Echo Messages</h1>
22

3-
<%= turbo_stream_from "messages", channel: EchoChannel, data: {message: "Hello, world!"} %>
3+
<%= render "template_button", content: "Start listening for broadcasts" do %>
4+
<%= turbo_stream_from "messages", channel: EchoChannel, data: {message: "Hello, world!"} %>
5+
<% end %>
6+
47
<div id="messages">
58
</div>
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
<h1>Messages</h1>
22

3-
<span id="message-count">
4-
<%= @messages.count %> messages sent
5-
</span>
3+
<%= render "template_button", content: "Start listening for broadcasts" do %>
4+
<%= turbo_stream_from "messages" %>
5+
<% end %>
66

7-
<%= turbo_stream_from "messages" %>
87
<div id="messages">
98
</div>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
<h1>Users::Profiles</h1>
22

3-
<%= turbo_stream_from "users_profiles" %>
4-
<div id="users_profiles"></div>
3+
<%= render "template_button", content: "Start listening for broadcasts" do %>
4+
<%= turbo_stream_from "users_profiles" %>
5+
<% end %>
6+
7+
<div id="users_profiles">
8+
</div>

test/dummy/config/application.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
module Dummy
1313
class Application < Rails::Application
1414
# Initialize configuration defaults for originally generated Rails version.
15-
config.load_defaults 6.0
15+
config.load_defaults 6.1
1616

1717
# Settings in config/environments/* take precedence over those specified here.
1818
# Application configuration can go into files in config/initializers

test/dummy/config/cable.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ development:
22
adapter: async
33

44
test:
5-
adapter: async
5+
adapter: inline
66

77
production:
88
adapter: redis

test/frames/frame_request_controller_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require "turbo_test"
1+
require "test_helper"
22

33
class Turbo::FrameRequestControllerTest < ActionDispatch::IntegrationTest
44
test "frame requests are rendered without a layout" do

test/frames/frames_helper_test.rb

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
require "turbo_test"
1+
require "test_helper"
22

33
class Turbo::FramesHelperTest < ActionView::TestCase
4-
setup { Message.delete_all }
5-
64
test "frame with src" do
75
assert_dom_equal %(<turbo-frame src="/trays/1" id="tray"></turbo-frame>), turbo_frame_tag("tray", src: "/trays/1")
86
end

test/initializers/helpers_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require "turbo_test"
1+
require "test_helper"
22

33
class Turbo::HelpersInInitializersTest < ActionDispatch::IntegrationTest
44
test "AC::Base has the helpers in place when initializers run" do

test/native/navigation_controller_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require "turbo_test"
1+
require "test_helper"
22

33
class Turbo::Native::NavigationControllerTest < ActionDispatch::IntegrationTest
44
test "recede, resume, or refresh when native or redirect when not" do

test/streams/broadcastable_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require "turbo_test"
1+
require "test_helper"
22
require "action_cable"
33

44
class Turbo::BroadcastableTest < ActionCable::Channel::TestCase

test/streams/streams_channel_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require "turbo_test"
1+
require "test_helper"
22
require "action_cable"
33

44
class Turbo::StreamsChannelTest < ActionCable::Channel::TestCase

test/streams/streams_controller_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require "turbo_test"
1+
require "test_helper"
22

33
class Turbo::StreamsControllerTest < ActionDispatch::IntegrationTest
44
test "create with respond to" do

test/streams/streams_helper_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require "turbo_test"
1+
require "test_helper"
22

33
class TestChannel < ApplicationCable::Channel; end
44

test/system/broadcasts_test.rb

+30-31
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,70 @@
11
require "application_system_test_case"
22

33
class BroadcastsTest < ApplicationSystemTestCase
4-
setup { Message.delete_all }
5-
6-
include ActionCable::TestHelper
7-
84
test "Message broadcasts Turbo Streams" do
95
visit messages_path
10-
wait_for_subscriber
6+
subscribe_to_broadcasts
117

12-
assert_text "Messages"
13-
assert_broadcasts_text "Message 1" do |text|
14-
Message.create(content: text).broadcast_append_to(:messages)
8+
assert_broadcasts_text "Message 1", to: :messages do |text, target|
9+
Message.create(content: text).broadcast_append_to(target)
1510
end
1611
end
1712

18-
test "New messages update the message count with html" do
13+
test "Message broadcasts with html: render option" do
1914
visit messages_path
20-
wait_for_subscriber
21-
22-
assert_text "Messages"
23-
message = Message.create(content: "A new message")
15+
subscribe_to_broadcasts
2416

25-
message.broadcast_update_to(:messages, target: "message-count",
26-
html: "#{Message.count} messages sent")
27-
assert_selector("#message-count", text: Message.count, wait: 10)
17+
assert_broadcasts_text "Hello, with html: option", to: :messages do |text, target|
18+
Message.create(content: "Ignored").broadcast_append_to(target, html: text)
19+
end
2820
end
2921

3022
test "Users::Profile broadcasts Turbo Streams" do
3123
visit users_profiles_path
32-
wait_for_subscriber
24+
subscribe_to_broadcasts
3325

34-
assert_text "Users::Profiles"
35-
assert_broadcasts_text "Profile 1" do |text|
36-
Users::Profile.new(id: 1, name: text).broadcast_append_to(:users_profiles)
26+
assert_broadcasts_text "Profile 1", to: :users_profiles do |text, target|
27+
Users::Profile.new(id: 1, name: text).broadcast_append_to(target)
3728
end
3829
end
3930

4031
test "passing extra parameters to channel" do
4132
visit echo_messages_path
42-
wait_for_subscriber
4333

44-
assert_text "Hello, world!", wait: 100
34+
assert_broadcasts_text "Hello, world!", to: :messages do
35+
subscribe_to_broadcasts
36+
end
4537
end
4638

4739
private
4840

49-
def assert_broadcasts_text(text, wait: 5, &block)
50-
assert_no_text text
51-
perform_enqueued_jobs { block.call(text) }
52-
assert_text text, wait: wait
41+
def subscribe_to_broadcasts
42+
click_on "Start listening for broadcasts"
43+
44+
assert_no_button "Start listening for broadcasts"
45+
46+
Timeout.timeout(Capybara.default_max_wait_time) { wait_for_subscriber }
47+
end
48+
49+
def assert_broadcasts_text(text, to:, &block)
50+
within(:element, id: to) { assert_no_text text }
51+
52+
[text, to].yield_self(&block)
53+
54+
within(:element, id: to) { assert_text text }
5355
end
5456

55-
def wait_for_subscriber(timeout: 10)
56-
time = Time.now
57+
def wait_for_subscriber
5758
loop do
58-
subscriber_map = pubsub_adapter.instance_variable_get(:@subscriber_map)
59+
subscriber_map = ActionCable.server.pubsub.instance_variable_get(:@subscriber_map)
5960
if subscriber_map.is_a?(ActionCable::SubscriptionAdapter::SubscriberMap)
6061
subscribers = subscriber_map.instance_variable_get(:@subscribers)
6162
sync = subscriber_map.instance_variable_get(:@sync)
6263
sync.synchronize do
6364
return unless subscribers.empty?
6465
end
6566
end
66-
assert_operator(Time.now - time, :<, timeout, "subscriber waiting timed out")
6767
sleep 0.1
6868
end
6969
end
70-
7170
end

test/system/form_submissions_test.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ class FormSubmissionsTest < ApplicationSystemTestCase
1515
article = Article.create! body: "My article"
1616

1717
visit edit_article_path(article.id)
18-
fill_in("Body", with: "My edit").then { click_on "Submit as PATCH" }
18+
fill_in "Body", with: "My edit", fill_options: { clear: :backspace }
19+
click_on "Submit as PATCH"
1920

2021
assert_text "Articles"
2122
assert_text "My edit", count: 1

test/turbo_test.rb test/test_helper.rb

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1+
# Configure Rails Environment
12
ENV["RAILS_ENV"] = "test"
23

3-
require "minitest/autorun"
4-
require "rails"
4+
require_relative "../test/dummy/config/environment"
5+
ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)]
56
require "rails/test_help"
6-
require "byebug"
7-
8-
require_relative "dummy/config/environment"
97

10-
ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)]
118
ActionCable.server.config.logger = Logger.new(STDOUT) if ENV["VERBOSE"]
129

1310
module ActionViewTestCaseExtensions
14-
def render(*arguments, **options, &block)
15-
ApplicationController.renderer.render(*arguments, **options, &block)
11+
def render(...)
12+
ApplicationController.renderer.render(...)
1613
end
1714
end
1815

0 commit comments

Comments
 (0)