stimulus_reflex 3.4.0.pre5 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of stimulus_reflex might be problematic. Click here for more details.

Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +78 -2
  3. data/Gemfile.lock +76 -73
  4. data/README.md +5 -8
  5. data/Rakefile +5 -5
  6. data/app/channels/stimulus_reflex/channel.rb +22 -0
  7. data/bin/console +1 -0
  8. data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/%file_name%_controller.js.tt +14 -2
  9. data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/application_controller.js.tt +10 -2
  10. data/lib/generators/stimulus_reflex/templates/app/reflexes/%file_name%_reflex.rb.tt +19 -9
  11. data/lib/generators/stimulus_reflex/templates/app/reflexes/application_reflex.rb.tt +2 -2
  12. data/lib/generators/stimulus_reflex/templates/config/initializers/stimulus_reflex.rb +10 -1
  13. data/lib/stimulus_reflex.rb +2 -1
  14. data/lib/stimulus_reflex/broadcasters/broadcaster.rb +2 -4
  15. data/lib/stimulus_reflex/broadcasters/page_broadcaster.rb +2 -1
  16. data/lib/stimulus_reflex/broadcasters/selector_broadcaster.rb +2 -2
  17. data/lib/stimulus_reflex/cable_ready_channels.rb +21 -0
  18. data/lib/stimulus_reflex/configuration.rb +2 -1
  19. data/lib/stimulus_reflex/reflex.rb +16 -6
  20. data/lib/stimulus_reflex/sanity_checker.rb +18 -4
  21. data/lib/stimulus_reflex/version.rb +1 -1
  22. data/lib/tasks/stimulus_reflex/install.rake +8 -3
  23. data/package.json +3 -3
  24. data/stimulus_reflex.gemspec +3 -1
  25. data/tags +95 -37
  26. data/test/broadcasters/broadcaster_test.rb +3 -6
  27. data/test/broadcasters/broadcaster_test_case.rb +15 -0
  28. data/test/broadcasters/nothing_broadcaster_test.rb +27 -26
  29. data/test/broadcasters/page_broadcaster_test.rb +56 -50
  30. data/test/broadcasters/selector_broadcaster_test.rb +57 -83
  31. data/test/reflex_test.rb +32 -0
  32. data/test/test_helper.rb +43 -2
  33. data/test/tmp/app/reflexes/application_reflex.rb +2 -2
  34. data/test/tmp/app/reflexes/demo_reflex.rb +34 -0
  35. data/yarn.lock +199 -226
  36. metadata +13 -8
  37. data/test/tmp/app/reflexes/posts_reflex.rb +0 -24
@@ -1,11 +1,8 @@
1
- require_relative "../test_helper"
1
+ # frozen_string_literal: true
2
2
 
3
- class StimulusReflex::BroadcasterTest < ActiveSupport::TestCase
4
- setup do
5
- @reflex = Minitest::Mock.new
6
- @reflex.expect :stream_name, "TestStream"
7
- end
3
+ require_relative "broadcaster_test_case"
8
4
 
5
+ class StimulusReflex::BroadcasterTest < StimulusReflex::BroadcasterTestCase
9
6
  test "raises a NotImplementedError if called directly" do
10
7
  broadcaster = StimulusReflex::Broadcaster.new(@reflex)
11
8
 
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../test_helper"
4
+
5
+ class StimulusReflex::BroadcasterTestCase < ActionCable::Channel::TestCase
6
+ tests StimulusReflex::Channel
7
+
8
+ setup do
9
+ stub_connection(session_id: SecureRandom.uuid)
10
+ def connection.env
11
+ @env ||= {}
12
+ end
13
+ @reflex = StimulusReflex::Reflex.new(subscribe, url: "https://test.stimulusreflex.com")
14
+ end
15
+ end
@@ -1,34 +1,35 @@
1
- require_relative "../test_helper"
1
+ # frozen_string_literal: true
2
2
 
3
- class StimulusReflex::NothingBroadcasterTest < ActiveSupport::TestCase
4
- setup do
5
- @reflex = Minitest::Mock.new
6
- @reflex.expect :stream_name, "TestStream"
7
- end
3
+ require_relative "broadcaster_test_case"
8
4
 
5
+ class StimulusReflex::NothingBroadcasterTest < StimulusReflex::BroadcasterTestCase
9
6
  test "broadcasts a server message when called" do
10
7
  broadcaster = StimulusReflex::NothingBroadcaster.new(@reflex)
11
8
 
12
- cable_ready_channels = Minitest::Mock.new
13
- cable_ready_channel = Minitest::Mock.new
14
- CableReady::Channels.stub :instance, cable_ready_channels do
15
- cable_ready_channel.expect(:dispatch_event, nil, [{name: "stimulus-reflex:server-message",
16
- detail: {
17
- reflexId: nil,
18
- stimulus_reflex: {
19
- some: :data,
20
- morph: :nothing,
21
- server_message: {
22
- subject: "nothing", body: nil
23
- }
24
- }
25
- }}])
26
- cable_ready_channels.expect(:[], cable_ready_channel, ["TestStream"])
27
- cable_ready_channels.expect(:broadcast, nil)
28
- broadcaster.broadcast(nil, {some: :data})
29
- end
9
+ expected = {
10
+ "cableReady" => true,
11
+ "operations" => {
12
+ "dispatchEvent" => [
13
+ {
14
+ "name" => "stimulus-reflex:server-message",
15
+ "detail" => {
16
+ "reflexId" => nil,
17
+ "stimulusReflex" => {
18
+ "some" => :data,
19
+ "morph" => :nothing,
20
+ "serverMessage" => {
21
+ "subject" => "nothing",
22
+ "body" => nil
23
+ }
24
+ }
25
+ }
26
+ }
27
+ ]
28
+ }
29
+ }
30
30
 
31
- assert_mock cable_ready_channels
32
- assert_mock cable_ready_channel
31
+ assert_broadcast_on @reflex.stream_name, expected do
32
+ broadcaster.broadcast nil, some: :data
33
+ end
33
34
  end
34
35
  end
@@ -1,69 +1,75 @@
1
- require_relative "../test_helper"
1
+ # frozen_string_literal: true
2
2
 
3
- class StimulusReflex::PageBroadcasterTest < ActiveSupport::TestCase
4
- setup do
5
- @reflex = Minitest::Mock.new
6
- @reflex.expect :params, {action: "show"}
7
- @reflex.expect :stream_name, "TestStream"
8
- @reflex.expect :permanent_attribute_name, "some-attribute"
9
- end
3
+ require_relative "broadcaster_test_case"
10
4
 
5
+ class StimulusReflex::PageBroadcasterTest < StimulusReflex::BroadcasterTestCase
11
6
  test "returns if the response html is empty" do
12
- controller = Minitest::Mock.new
13
- controller.expect(:process, nil, ["show"])
14
- @reflex.expect :controller, controller
15
- @reflex.expect :controller, controller
7
+ broadcaster = StimulusReflex::PageBroadcaster.new(@reflex)
8
+ broadcaster.broadcast(["#foo"], {some: :data})
9
+ # TODO: figure out how to refute_broadcast_on
10
+ end
16
11
 
17
- # stub the controller response with a struct responding to :body
18
- controller.expect(:response, Struct.new(:body).new(nil))
12
+ test "performs a page morph on body" do
13
+ class << @reflex.controller.response
14
+ def body
15
+ "<html><head></head><body>New Content</body></html>"
16
+ end
17
+ end
19
18
 
20
19
  broadcaster = StimulusReflex::PageBroadcaster.new(@reflex)
21
20
 
22
- cable_ready_channels = Minitest::Mock.new
23
- cable_ready_channels.expect(:broadcast, nil)
24
-
25
- broadcaster.broadcast(["#foo"], {some: :data})
21
+ expected = {
22
+ "cableReady" => true,
23
+ "operations" => {
24
+ "morph" => [
25
+ {
26
+ "selector" => "body",
27
+ "html" => "New Content",
28
+ "childrenOnly" => true,
29
+ "permanentAttributeName" => nil,
30
+ "stimulusReflex" => {
31
+ "some" => :data,
32
+ "morph" => :page
33
+ }
34
+ }
35
+ ]
36
+ }
37
+ }
26
38
 
27
- assert_raises { cable_ready_channels.verify }
39
+ assert_broadcast_on @reflex.stream_name, expected do
40
+ broadcaster.broadcast(["body"], {some: :data})
41
+ end
28
42
  end
29
43
 
30
44
  test "performs a page morph given an array of reflex root selectors" do
31
- controller = Minitest::Mock.new
32
- controller.expect(:process, nil, ["show"])
33
- @reflex.expect :controller, controller
34
- @reflex.expect :controller, controller
35
-
36
- # stub the controller response with a struct responding to :body
37
- controller.expect(:response, Struct.new(:body).new("<html></html>"))
45
+ class << @reflex.controller.response
46
+ def body
47
+ "<html><head></head><body><div id=\"foo\">New Content</div></body></html>"
48
+ end
49
+ end
38
50
 
39
51
  broadcaster = StimulusReflex::PageBroadcaster.new(@reflex)
40
52
 
41
- cable_ready_channels = Minitest::Mock.new
42
- cable_ready_channel = Minitest::Mock.new
43
- document = Minitest::Mock.new
44
- Nokogiri::HTML.stub :parse, document do
45
- document.expect(:css, "something that is present", ["#foo"])
46
- document.expect(:css, Struct.new(:inner_html).new("<span>bar</span>"), ["#foo"])
47
-
48
- CableReady::Channels.stub :instance, cable_ready_channels do
49
- cable_ready_channel.expect(:morph, nil, [{
50
- selector: "#foo",
51
- html: "<span>bar</span>",
52
- children_only: true,
53
- permanent_attribute_name: "some-attribute",
54
- stimulus_reflex: {
55
- some: :data,
56
- morph: :page
53
+ expected = {
54
+ "cableReady" => true,
55
+ "operations" => {
56
+ "morph" => [
57
+ {
58
+ "selector" => "#foo",
59
+ "html" => "New Content",
60
+ "childrenOnly" => true,
61
+ "permanentAttributeName" => nil,
62
+ "stimulusReflex" => {
63
+ "some" => :data,
64
+ "morph" => :page
65
+ }
57
66
  }
58
- }])
59
- cable_ready_channels.expect(:[], cable_ready_channel, ["TestStream"])
60
- cable_ready_channels.expect(:broadcast, nil)
67
+ ]
68
+ }
69
+ }
61
70
 
62
- broadcaster.broadcast(["#foo"], {some: :data})
63
- end
71
+ assert_broadcast_on @reflex.stream_name, expected do
72
+ broadcaster.broadcast(["#foo"], {some: :data})
64
73
  end
65
-
66
- assert_mock cable_ready_channels
67
- assert_mock cable_ready_channel
68
74
  end
69
75
  end
@@ -1,83 +1,57 @@
1
- require_relative "../test_helper"
2
-
3
- class StimulusReflex::SelectorBroadcasterTest < ActiveSupport::TestCase
4
- setup do
5
- @reflex = Minitest::Mock.new
6
- @reflex.expect :stream_name, "TestStream"
7
- @reflex.expect :permanent_attribute_name, "some-attribute"
8
- end
9
-
10
- test "morphs the contents of an element if the selector(s) are present in both original and morphed html fragments" do
11
- broadcaster = StimulusReflex::SelectorBroadcaster.new(@reflex)
12
-
13
- cable_ready_channels = Minitest::Mock.new
14
- cable_ready_channel = Minitest::Mock.new
15
- fragment = Minitest::Mock.new
16
- match = Minitest::Mock.new
17
- Nokogiri::HTML.stub :fragment, fragment do
18
- fragment.expect(:at_css, match, ["#foo"])
19
- match.expect(:present?, true)
20
-
21
- # we need to mock `!`, because `blank?` returns
22
- # respond_to?(:empty?) ? !!empty? : !self
23
- match.expect(:!, false)
24
- match.expect(:inner_html, "<span>bar</span>")
25
- CableReady::Channels.stub :instance, cable_ready_channels do
26
- broadcaster.append_morph("#foo", "<div id=\"foo\"><span>bar</span></div>")
27
- cable_ready_channel.expect(:morph, nil, [{
28
- selector: "#foo",
29
- html: "<span>bar</span>",
30
- children_only: true,
31
- permanent_attribute_name: "some-attribute",
32
- stimulus_reflex: {
33
- some: :data,
34
- morph: :selector
35
- }
36
- }])
37
- cable_ready_channels.expect(:[], cable_ready_channel, ["TestStream"])
38
- cable_ready_channels.expect(:broadcast, nil)
39
-
40
- broadcaster.broadcast(nil, {some: :data})
41
- end
42
- end
43
-
44
- assert_mock cable_ready_channels
45
- assert_mock cable_ready_channel
46
- end
47
-
48
- test "replaces the contents of an element and ignores permanent-attributes if the selector(s) aren't present in the replacing html fragment" do
49
- broadcaster = StimulusReflex::SelectorBroadcaster.new(@reflex)
50
-
51
- cable_ready_channels = Minitest::Mock.new
52
- cable_ready_channel = Minitest::Mock.new
53
- fragment = Minitest::Mock.new
54
- match = Minitest::Mock.new
55
- Nokogiri::HTML.stub :fragment, fragment do
56
- fragment.expect(:at_css, match, ["#foo"])
57
- fragment.expect(:to_html, "<div id=\"baz\"><span>bar</span></div>")
58
- match.expect(:present?, false)
59
-
60
- # we need to mock `!`, because `blank?` returns
61
- # respond_to?(:empty?) ? !!empty? : !self
62
- match.expect(:!, true)
63
- CableReady::Channels.stub :instance, cable_ready_channels do
64
- broadcaster.append_morph("#foo", "<div id=\"baz\"><span>bar</span></div>")
65
- cable_ready_channel.expect(:inner_html, nil, [{
66
- selector: "#foo",
67
- html: "<div id=\"baz\"><span>bar</span></div>",
68
- stimulus_reflex: {
69
- some: :data,
70
- morph: :selector
71
- }
72
- }])
73
- cable_ready_channels.expect(:[], cable_ready_channel, ["TestStream"])
74
- cable_ready_channels.expect(:broadcast, nil)
75
-
76
- broadcaster.broadcast(nil, {some: :data})
77
- end
78
- end
79
-
80
- assert_mock cable_ready_channels
81
- assert_mock cable_ready_channel
82
- end
83
- end
1
+ # frozen_string_literal: true
2
+
3
+ # require_relative "broadcaster_test_case"
4
+
5
+ # class StimulusReflex::SelectorBroadcasterTest < StimulusReflex::BroadcasterTestCase
6
+ # test "morphs the contents of an element if the selector(s) are present in both original and morphed html fragments" do
7
+ # broadcaster = StimulusReflex::SelectorBroadcaster.new(@reflex)
8
+ # broadcaster.append_morph("#foo", "<div id=\"foo\"><span>bar</span></div>")
9
+
10
+ # expected = {
11
+ # "cableReady" => true,
12
+ # "operations" => {
13
+ # "morph" => [
14
+ # {
15
+ # "selector" => "#foo",
16
+ # "html" => "<span>bar</span>",
17
+ # "childrenOnly" => true,
18
+ # "permanentAttributeName" => nil,
19
+ # "stimulusReflex" => {
20
+ # "some" => :data,
21
+ # "morph" => :selector
22
+ # }
23
+ # }
24
+ # ]
25
+ # }
26
+ # }
27
+
28
+ # assert_broadcast_on @reflex.stream_name, expected do
29
+ # broadcaster.broadcast nil, some: :data
30
+ # end
31
+ # end
32
+
33
+ # test "replaces the contents of an element and ignores permanent-attributes if the selector(s) aren't present in the replacing html fragment" do
34
+ # broadcaster = StimulusReflex::SelectorBroadcaster.new(@reflex)
35
+ # broadcaster.append_morph("#foo", "<div id=\"baz\"><span>bar</span></div>")
36
+
37
+ # expected = {
38
+ # "cableReady" => true,
39
+ # "operations" => {
40
+ # "innerHtml" => [
41
+ # {
42
+ # "selector" => "#foo",
43
+ # "html" => "<div id=\"baz\"><span>bar</span></div>",
44
+ # "stimulusReflex" => {
45
+ # "some" => :data,
46
+ # "morph" => :selector
47
+ # }
48
+ # }
49
+ # ]
50
+ # }
51
+ # }
52
+
53
+ # assert_broadcast_on @reflex.stream_name, expected do
54
+ # broadcaster.broadcast nil, some: :data
55
+ # end
56
+ # end
57
+ # end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+
5
+ class StimulusReflex::ReflexTest < ActionCable::Channel::TestCase
6
+ tests StimulusReflex::Channel
7
+
8
+ setup do
9
+ stub_connection(session_id: SecureRandom.uuid)
10
+ def connection.env
11
+ @env ||= {}
12
+ end
13
+ @reflex = StimulusReflex::Reflex.new(subscribe, url: "https://test.stimulusreflex.com")
14
+ @reflex.controller_class.view_paths << Rails.root.join("test/views")
15
+ end
16
+
17
+ test "render plain" do
18
+ assert @reflex.render(plain: "Some text") == "Some text"
19
+ end
20
+
21
+ test "render template" do
22
+ assert @reflex.render("/hello_template", assigns: {message: "Testing 123"}) == "<p>Hello from template! Testing 123</p>\n"
23
+ end
24
+
25
+ test "render partial" do
26
+ assert @reflex.render(partial: "/hello_partial", assigns: {message: "Testing 123"}) == "<p>Hello from partial! Testing 123</p>\n"
27
+ end
28
+
29
+ test "dom_id" do
30
+ assert @reflex.dom_id(TestModel.new(id: 123)) == "test_model_123"
31
+ end
32
+ end
@@ -1,6 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "minitest/mock"
4
-
5
3
  ENV["RAILS_ENV"] ||= "test"
4
+
5
+ require "minitest/mock"
6
+ require "rails"
7
+ require "active_model"
8
+ require "action_controller"
9
+ require "pry"
6
10
  require_relative "../lib/stimulus_reflex"
11
+
12
+ class TestApp < Rails::Application
13
+ routes.draw { root to: "test#index" }
14
+ end
15
+
16
+ class ApplicationController < ActionController::Base; end
17
+
18
+ class TestController < ApplicationController
19
+ include Rails.application.routes.url_helpers
20
+
21
+ def index
22
+ head :ok
23
+ end
24
+ end
25
+
26
+ class SessionMock
27
+ def load!
28
+ nil
29
+ end
30
+ end
31
+
32
+ class ActionDispatch::Request
33
+ def session
34
+ @session ||= SessionMock.new
35
+ end
36
+ end
37
+
38
+ class TestModel
39
+ include ActiveModel::Model
40
+ attr_accessor :id
41
+ end
42
+
43
+ StimulusReflex.configuration.parent_channel = "ActionCable::Channel::Base"
44
+ ActionCable::Server::Base.config.cable = {adapter: "test"}
45
+ ActionCable::Server::Base.config.logger = Logger.new(nil)
46
+
47
+ require_relative "../app/channels/stimulus_reflex/channel"
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ApplicationReflex < StimulusReflex::Reflex
4
- # Put application wide Reflex behavior in this file.
4
+ # Put application-wide Reflex behavior and callbacks in this file.
5
5
  #
6
6
  # Example:
7
7
  #
8
8
  # # If your ActionCable connection is: `identified_by :current_user`
9
9
  # delegate :current_user, to: :connection
10
10
  #
11
- # Learn more at: https://docs.stimulusreflex.com
11
+ # Learn more at: https://docs.stimulusreflex.com/reflexes#reflex-classes
12
12
  end