-
-
Notifications
You must be signed in to change notification settings - Fork 175
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tests for targets and target collections
- Loading branch information
1 parent
8cfba5d
commit 4ab5b60
Showing
2 changed files
with
226 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { html, fixture, assert } from '@open-wc/testing' | ||
|
||
import { extractTargets } from '../attributes' | ||
import Schema, { defaultSchema } from '../schema' | ||
|
||
Schema.set(defaultSchema) | ||
|
||
describe('extractTargets', () => { | ||
it('should extract no targets by default', async () => { | ||
const dom = await fixture( | ||
html`<div data-reflex-target="post">Post</div>` | ||
) | ||
const targets = extractTargets(undefined, null) | ||
assert.deepStrictEqual(targets, {}) | ||
}) | ||
|
||
it('should extract multiple targets from page', async () => { | ||
const dom = await fixture( | ||
html` | ||
<div data-reflex-target="post">Post</div> | ||
<div data-reflex-target="comment" class="comment-1">Comment 1</div> | ||
<div data-reflex-target="comment" class="comment-2">Comment 2</div> | ||
` | ||
) | ||
const targets = extractTargets("page", null) | ||
|
||
assert.equal(targets["post"][0]["name"], "post") | ||
assert.equal(targets["post"][0]["selector"], "/html/body/div[1]/div[1]") | ||
assert.equal(targets["post"][0]["attrs"]["data-reflex-target"], "post") | ||
|
||
assert.equal(targets["comment"][0]["name"], "comment") | ||
assert.equal(targets["comment"][0]["selector"], "/html/body/div[1]/div[2]") | ||
assert.equal(targets["comment"][0]["attrs"]["data-reflex-target"], "comment") | ||
assert.equal(targets["comment"][0]["attrs"]["class"], "comment-1") | ||
|
||
assert.equal(targets["comment"][1]["name"], "comment") | ||
assert.equal(targets["comment"][1]["selector"], "/html/body/div[1]/div[3]") | ||
assert.equal(targets["comment"][1]["attrs"]["data-reflex-target"], "comment") | ||
assert.equal(targets["comment"][1]["attrs"]["class"], "comment-2") | ||
}) | ||
|
||
it('should limit targets to parent controller if specified', async () => { | ||
const controller = await fixture( // Note: fixture() returns the first element in the DOM | ||
html` | ||
<div data-controller="test"> | ||
<div data-reflex-target="included">In</div> | ||
</div> | ||
<div data-reflex-target="not_included">Out</div> | ||
` | ||
) | ||
|
||
const targets = extractTargets("controller", controller) | ||
|
||
assert.equal(targets["included"][0]["name"], "included") | ||
assert.equal(targets["included"][0]["selector"], "/html/body/div[1]/div[1]/div[1]") | ||
assert.equal(targets["not_included"], undefined) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative "test_helper" | ||
require "mocha/minitest" | ||
|
||
class StimulusReflex::ReflexTargetsTest < ActionCable::Channel::TestCase | ||
tests StimulusReflex::Channel | ||
|
||
attr_reader :reflex | ||
delegate :post_targets, :button_target, :absent_target, :unicorn_targets, :cable_ready, to: :reflex | ||
|
||
setup do | ||
stub_connection(session_id: SecureRandom.uuid) | ||
def connection.env | ||
@env ||= {} | ||
end | ||
|
||
@element = StimulusReflex::Element.new({}, selector: "/html/body/button[1]") | ||
@reflex = build_with_targets | ||
end | ||
|
||
def build_with_targets(targets_data: nil, target_scope: "page") | ||
targets_data ||= { | ||
"post" => [ | ||
{ "name" => "post", "selector" => "/html/body/div[1]", "attrs" => { "class" => "" } }, | ||
{ "name" => "post", "selector" => "/html/body/div[2]", "attrs" => { "class" => "special" } }, | ||
{ "name" => "post", "selector" => "/html/body/div[3]", "attrs" => { "class" => "special" } } | ||
], | ||
"button" => [ | ||
{ "name" => "button", "selector" => "/html/body/button[1]", "dataset" => {} } | ||
] | ||
} | ||
|
||
reflex_data = StimulusReflex::ReflexData.new( | ||
element: @element, | ||
url: "https://test.stimulusreflex.com", | ||
targets: targets_data, | ||
id: "123", | ||
version: StimulusReflex::VERSION, | ||
reflex_controller: "stimulus-reflex", | ||
target_scope: target_scope | ||
) | ||
|
||
StimulusReflex::Reflex.new(subscribe, reflex_data: reflex_data) | ||
end | ||
|
||
def build_payload(operations = []) | ||
{ | ||
"cableReady" => true, | ||
"operations" => Array.wrap(operations), | ||
"version" => CableReady::VERSION | ||
} | ||
end | ||
|
||
test "shares a cable_ready instance with targets and target collections" do | ||
assert_equal reflex.cable_ready, button_target.cable_ready | ||
assert_equal reflex.cable_ready, post_targets.cable_ready | ||
assert_equal reflex.cable_ready, post_targets.first.cable_ready | ||
end | ||
|
||
test "builds chainable operations on a (singular) target" do | ||
expected = build_payload( | ||
[ | ||
{"selector" => "/html/body/button[1]", "xpath" => true, "name" => "updated", "reflexId" => "123", "operation" => "addCssClass"}, | ||
{"selector" => "/html/body/button[1]", "xpath" => true, "text" => "Button", "reflexId" => "123", "operation" => "textContent"} | ||
] | ||
) | ||
|
||
assert_broadcast_on(reflex.stream_name, expected) do | ||
button_target.add_css_class(name: "updated").text_content(text: "Button") | ||
|
||
reflex.cable_ready.broadcast | ||
end | ||
end | ||
|
||
test "builds chainable operations on (plural) multi-target collection using select_all" do | ||
expected = build_payload( | ||
[ | ||
{"selector" => "[data-reflex-target='post']", "selectAll" => true, "name" => "updated", "reflexId" => "123", "operation" => "addCssClass"}, | ||
{"selector" => "[data-reflex-target='post']", "selectAll" => true, "text" => "Post", "reflexId" => "123", "operation" => "textContent"} | ||
] | ||
) | ||
|
||
assert_broadcast_on(reflex.stream_name, expected) do | ||
post_targets.add_css_class(name: "updated").text_content(text: "Post") | ||
|
||
reflex.cable_ready.broadcast | ||
end | ||
end | ||
|
||
test "target collections respond to array-like interface" do | ||
assert_equal post_targets.any?, true | ||
assert_equal post_targets.many?, true | ||
assert_equal post_targets.count, 3 | ||
assert_equal post_targets.first.selector, "/html/body/div[1]" | ||
assert_equal post_targets.last.selector, "/html/body/div[3]" | ||
|
||
special_targets = post_targets.select{ |target| target.attrs[:class].include?("special") } | ||
|
||
assert_equal special_targets.count, 2 | ||
assert_equal special_targets.first.selector, "/html/body/div[2]" | ||
assert_equal special_targets.last.selector, "/html/body/div[3]" | ||
end | ||
|
||
test "doesn't raise an exception / halt execution if operation(s) are called on a missing target" do | ||
expected = build_payload( | ||
[ | ||
{"selector" => "/html/body/button[1]", "xpath" => true, "name" => "success", "reflexId" => "123", "operation" => "addCssClass"}, | ||
{"selector" => "/html/body/button[1]", "xpath" => true, "text" => "I'm still updated!", "reflexId" => "123", "operation" => "textContent"} | ||
] | ||
) | ||
|
||
assert_broadcast_on(reflex.stream_name, expected) do | ||
absent_target.add_css_class(name: "nope").text_content(text: "I'm not even here!") | ||
button_target.add_css_class(name: "success").text_content(text: "I'm still updated!") | ||
|
||
reflex.cable_ready.broadcast | ||
end | ||
end | ||
|
||
test "missing/undefined targets that *might* exist but are currently not in the DOM still respond to inspection" do | ||
assert_equal absent_target.any?, false | ||
assert_equal absent_target.present?, false | ||
assert_equal unicorn_targets.count, 0 | ||
assert_equal unicorn_targets.first.present?, false | ||
assert_equal unicorn_targets.any?, false | ||
end | ||
|
||
test "targets in a multi-target collection can also be operated on individually" do | ||
expected = build_payload( | ||
[ | ||
{"selector" => "/html/body/div[2]", "xpath" => true, "name" => "upgrade", "reflexId" => "123", "operation" => "addCssClass"}, | ||
{"selector" => "/html/body/div[3]", "xpath" => true, "name" => "upgrade", "reflexId" => "123", "operation" => "addCssClass"}, | ||
{"selector" => "/html/body/div[1]", "xpath" => true, "name" => "downgrade", "reflexId" => "123", "operation" => "addCssClass"} | ||
] | ||
) | ||
|
||
assert_broadcast_on(reflex.stream_name, expected) do | ||
post_targets | ||
.select{ |target| target.attrs[:class].include?("special") } | ||
.each{ |target| target.add_css_class(name: "upgrade") } | ||
|
||
post_targets | ||
.find{ |target| target.attrs[:class].blank? } | ||
.add_css_class(name: "downgrade") | ||
|
||
reflex.cable_ready.broadcast | ||
end | ||
end | ||
|
||
test "plays nicely with other operations interspersed" do | ||
expected = build_payload( | ||
[ | ||
{"selector" => "[data-reflex-target='post']", "selectAll" => true, "name" => "hey", "reflexId" => "123", "operation" => "addCssClass"}, | ||
{"selector" => "#other", "name" => "thing", "reflexId" => "123", "operation" => "addCssClass"}, | ||
{"selector" => "[data-reflex-target='post']", "selectAll" => true, "text" => "I'm a Post", "reflexId" => "123", "operation" => "textContent"} | ||
] | ||
) | ||
|
||
assert_broadcast_on(reflex.stream_name, expected) do | ||
post_targets.add_css_class(name: "hey") | ||
cable_ready.add_css_class(selector: "#other", name: "thing") | ||
post_targets.text_content(text: "I'm a Post") | ||
|
||
reflex.cable_ready.broadcast | ||
end | ||
end | ||
end |