Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document the assert_turbo_stream helpers #462

Merged
merged 1 commit into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ You can watch [the video introduction to Hotwire](https://hotwired.dev/#screenca

Turbo can coexist with Rails UJS, but you need to take a series of upgrade steps to make it happen. See [the upgrading guide](https://github.com/hotwired/turbo-rails/blob/main/UPGRADING.md).

## Testing


The [`Turbo::TestAssertions`](./lib/turbo/test_assertions.rb) concern provides Turbo Stream test helpers that assert the presence or absence of `<turbo-stream>` elements in a rendered fragment of HTML. `Turbo::TestAssertions` are automatically included in [`ActiveSupport::TestCase`](https://edgeapi.rubyonrails.org/classes/ActiveSupport/TestCase.html) and depend on the presence of [`rails-dom-testing`](https://github.com/rails/rails-dom-testing/) assertions.

The [`Turbo::TestAssertions::IntegrationTestAssertions`](./lib/turbo/test_assertions/integration_test_assertions.rb) are built on top of `Turbo::TestAssertions`, and add support for passing a `status:` keyword. They are automatically included in [`ActionDispatch::IntegrationTest`](https://edgeguides.rubyonrails.org/testing.html#integration-testing).


## Development

Expand Down
9 changes: 8 additions & 1 deletion lib/turbo/engine.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
require "rails/engine"
require "turbo/test_assertions"

module Turbo
class Engine < Rails::Engine
Expand Down Expand Up @@ -69,8 +68,16 @@ class Engine < Rails::Engine

initializer "turbo.test_assertions" do
ActiveSupport.on_load(:active_support_test_case) do
require "turbo/test_assertions"

include Turbo::TestAssertions
end

ActiveSupport.on_load(:action_dispatch_integration_test) do
require "turbo/test_assertions/integration_test_assertions"

include Turbo::TestAssertions::IntegrationTestAssertions
end
end

initializer "turbo.integration_test_request_encoding" do
Expand Down
62 changes: 58 additions & 4 deletions lib/turbo/test_assertions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,71 @@ module TestAssertions
delegate :dom_id, :dom_class, to: ActionView::RecordIdentifier
end

def assert_turbo_stream(action:, target: nil, targets: nil, status: :ok, &block)
assert_response status
assert_equal Mime[:turbo_stream], response.media_type
# Assert that the rendered fragment of HTML contains a `<turbo-stream>`
# element.
#
# === Options
#
# * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
# attribute
# * <tt>:target</tt> [String, #to_key] matches the element's
# <tt>[target]</tt> attribute. If the value responds to <tt>#to_key</tt>,
# the value will be transformed by calling <tt>dom_id</tt>
# * <tt>:targets</tt> [String] matches the element's <tt>[targets]</tt>
# attribute
#
# Given the following HTML fragment:
#
# <turbo-stream action="remove" target="message_1"></turbo-stream>
#
# The following assertion would pass:
#
# assert_turbo_stream action: "remove", target: "message_1"
#
# You can also pass a block make assertions about the contents of the
# element. Given the following HTML fragment:
#
# <turbo-stream action="replace" target="message_1">
# <template>
# <p>Hello!</p>
# <template>
# </turbo-stream>
#
# The following assertion would pass:
#
# assert_turbo_stream action: "replace", target: "message_1" do
# assert_select "template p", text: "Hello!"
# end
#
def assert_turbo_stream(action:, target: nil, targets: nil, &block)
selector = %(turbo-stream[action="#{action}"])
selector << %([target="#{target.respond_to?(:to_key) ? dom_id(target) : target}"]) if target
selector << %([targets="#{targets}"]) if targets
assert_select selector, count: 1, &block
end

# Assert that the rendered fragment of HTML does not contain a `<turbo-stream>`
# element.
#
# === Options
#
# * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
# attribute
# * <tt>:target</tt> [String, #to_key] matches the element's
# <tt>[target]</tt> attribute. If the value responds to <tt>#to_key</tt>,
# the value will be transformed by calling <tt>dom_id</tt>
# * <tt>:targets</tt> [String] matches the element's <tt>[targets]</tt>
# attribute
#
# Given the following HTML fragment:
#
# <turbo-stream action="remove" target="message_1"></turbo-stream>
#
# The following assertion would fail:
#
# assert_no_turbo_stream action: "remove", target: "message_1"
#
def assert_no_turbo_stream(action:, target: nil, targets: nil)
assert_equal Mime[:turbo_stream], response.media_type
selector = %(turbo-stream[action="#{action}"])
selector << %([target="#{target.respond_to?(:to_key) ? dom_id(target) : target}"]) if target
selector << %([targets="#{targets}"]) if targets
Expand Down
76 changes: 76 additions & 0 deletions lib/turbo/test_assertions/integration_test_assertions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
module Turbo
module TestAssertions
module IntegrationTestAssertions
# Assert that the Turbo Stream request's response body's HTML contains a
# `<turbo-stream>` element.
#
# === Options
#
# * <tt>:status</tt> [Integer, Symbol] the HTTP response status
# * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
# attribute
# * <tt>:target</tt> [String, #to_key] matches the element's
# <tt>[target]</tt> attribute. If the value responds to <tt>#to_key</tt>,
# the value will be transformed by calling <tt>dom_id</tt>
# * <tt>:targets</tt> [String] matches the element's <tt>[targets]</tt>
# attribute
#
# Given the following HTML response body:
#
# <turbo-stream action="remove" target="message_1"></turbo-stream>
#
# The following assertion would pass:
#
# assert_turbo_stream action: "remove", target: "message_1"
#
# You can also pass a block make assertions about the contents of the
# element. Given the following HTML response body:
#
# <turbo-stream action="replace" target="message_1">
# <template>
# <p>Hello!</p>
# <template>
# </turbo-stream>
#
# The following assertion would pass:
#
# assert_turbo_stream action: "replace", target: "message_1" do
# assert_select "template p", text: "Hello!"
# end
#
def assert_turbo_stream(status: :ok, **attributes, &block)
assert_response status
assert_equal Mime[:turbo_stream], response.media_type
super(**attributes, &block)
end

# Assert that the Turbo Stream request's response body's HTML does not
# contain a `<turbo-stream>` element.
#
# === Options
#
# * <tt>:status</tt> [Integer, Symbol] the HTTP response status
# * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
# attribute
# * <tt>:target</tt> [String, #to_key] matches the element's
# <tt>[target]</tt> attribute. If the value responds to <tt>#to_key</tt>,
# the value will be transformed by calling <tt>dom_id</tt>
# * <tt>:targets</tt> [String] matches the element's <tt>[targets]</tt>
# attribute
#
# Given the following HTML response body:
#
# <turbo-stream action="remove" target="message_1"></turbo-stream>
#
# The following assertion would fail:
#
# assert_no_turbo_stream action: "remove", target: "message_1"
#
def assert_no_turbo_stream(status: :ok, **attributes)
assert_response status
assert_equal Mime[:turbo_stream], response.media_type
super(**attributes)
end
end
end
end
2 changes: 1 addition & 1 deletion test/streams/streams_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Turbo::StreamsControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to message_path(id: 1)

post messages_path, as: :turbo_stream
assert_no_turbo_stream action: :update, target: "messages"
assert_no_turbo_stream status: :created, action: :update, target: "messages"
assert_turbo_stream status: :created, action: :append, target: "messages" do |selected|
assert_equal "<template>message_1</template>", selected.children.to_html
end
Expand Down