stimulus_reflex 3.5.0.pre2 → 3.5.0.pre3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of stimulus_reflex might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +56 -11
- data/Gemfile.lock +71 -66
- data/README.md +4 -3
- data/app/channels/stimulus_reflex/channel.rb +11 -11
- data/lib/generators/stimulus_reflex/stimulus_reflex_generator.rb +5 -4
- data/lib/generators/stimulus_reflex/templates/config/initializers/stimulus_reflex.rb +5 -0
- data/lib/stimulus_reflex/broadcasters/broadcaster.rb +18 -17
- data/lib/stimulus_reflex/broadcasters/nothing_broadcaster.rb +6 -1
- data/lib/stimulus_reflex/broadcasters/page_broadcaster.rb +1 -3
- data/lib/stimulus_reflex/broadcasters/selector_broadcaster.rb +2 -6
- data/lib/stimulus_reflex/configuration.rb +2 -1
- data/lib/stimulus_reflex/dataset.rb +34 -0
- data/lib/stimulus_reflex/element.rb +12 -46
- data/lib/stimulus_reflex/reflex.rb +7 -2
- data/lib/stimulus_reflex/utils/attribute_builder.rb +17 -0
- data/lib/stimulus_reflex/utils/logger.rb +6 -2
- data/lib/stimulus_reflex/version.rb +1 -1
- data/lib/tasks/stimulus_reflex/install.rake +1 -1
- data/test/broadcasters/broadcaster_test.rb +0 -1
- data/test/broadcasters/broadcaster_test_case.rb +24 -0
- data/test/broadcasters/nothing_broadcaster_test.rb +14 -22
- data/test/broadcasters/page_broadcaster_test.rb +30 -32
- data/test/broadcasters/selector_broadcaster_test.rb +82 -88
- data/test/element_test.rb +73 -0
- data/test/generators/stimulus_reflex_generator_test.rb +8 -0
- data/test/reflex_test.rb +11 -0
- data/test/test_helper.rb +3 -1
- data/test/tmp/app/reflexes/demo_reflex.rb +0 -1
- metadata +36 -20
- data/package.json +0 -58
- data/stimulus_reflex.gemspec +0 -42
- data/yarn.lock +0 -4680
| @@ -17,9 +17,7 @@ module StimulusReflex | |
| 17 17 | 
             
                          payload: payload,
         | 
| 18 18 | 
             
                          children_only: true,
         | 
| 19 19 | 
             
                          permanent_attribute_name: permanent_attribute_name,
         | 
| 20 | 
            -
                          stimulus_reflex: data.merge( | 
| 21 | 
            -
                            morph: to_sym
         | 
| 22 | 
            -
                          })
         | 
| 20 | 
            +
                          stimulus_reflex: data.merge(morph: to_sym)
         | 
| 23 21 | 
             
                        )
         | 
| 24 22 | 
             
                      else
         | 
| 25 23 | 
             
                        operations << [update.selector, :inner_html]
         | 
| @@ -27,9 +25,7 @@ module StimulusReflex | |
| 27 25 | 
             
                          selector: update.selector,
         | 
| 28 26 | 
             
                          html: fragment.to_html,
         | 
| 29 27 | 
             
                          payload: payload,
         | 
| 30 | 
            -
                          stimulus_reflex: data.merge( | 
| 31 | 
            -
                            morph: to_sym
         | 
| 32 | 
            -
                          })
         | 
| 28 | 
            +
                          stimulus_reflex: data.merge(morph: to_sym)
         | 
| 33 29 | 
             
                        )
         | 
| 34 30 | 
             
                      end
         | 
| 35 31 | 
             
                    end
         | 
| @@ -14,7 +14,7 @@ module StimulusReflex | |
| 14 14 | 
             
              end
         | 
| 15 15 |  | 
| 16 16 | 
             
              class Configuration
         | 
| 17 | 
            -
                attr_accessor :on_failed_sanity_checks, :on_new_version_available, :on_missing_default_urls, :parent_channel, :logging, :middleware
         | 
| 17 | 
            +
                attr_accessor :on_failed_sanity_checks, :on_new_version_available, :on_missing_default_urls, :parent_channel, :logging, :logger, :middleware
         | 
| 18 18 |  | 
| 19 19 | 
             
                DEFAULT_LOGGING = proc { "[#{session_id}] #{operation_counter.magenta} #{reflex_info.green} -> #{selector.cyan} via #{mode} Morph (#{operation.yellow})" }
         | 
| 20 20 |  | 
| @@ -24,6 +24,7 @@ module StimulusReflex | |
| 24 24 | 
             
                  @on_missing_default_urls = :warn
         | 
| 25 25 | 
             
                  @parent_channel = "ApplicationCable::Channel"
         | 
| 26 26 | 
             
                  @logging = DEFAULT_LOGGING
         | 
| 27 | 
            +
                  @logger = Rails.logger
         | 
| 27 28 | 
             
                  @middleware = ActionDispatch::MiddlewareStack.new
         | 
| 28 29 | 
             
                end
         | 
| 29 30 | 
             
              end
         | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "stimulus_reflex/utils/attribute_builder"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class StimulusReflex::Dataset < OpenStruct
         | 
| 6 | 
            +
              include StimulusReflex::AttributeBuilder
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              attr_accessor :attrs, :data_attrs
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def initialize(data = {})
         | 
| 11 | 
            +
                datasets = data["dataset"] || {}
         | 
| 12 | 
            +
                regular_dataset = datasets["dataset"] || {}
         | 
| 13 | 
            +
                @attrs = build_data_attrs(regular_dataset, datasets["datasetAll"] || {})
         | 
| 14 | 
            +
                @data_attrs = @attrs.transform_keys { |key| key.delete_prefix "data-" }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                super build_underscored(@data_attrs)
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def signed
         | 
| 20 | 
            +
                @signed ||= ->(accessor) { GlobalID::Locator.locate_signed(self[accessor]) }
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def unsigned
         | 
| 24 | 
            +
                @unsigned ||= ->(accessor) { GlobalID::Locator.locate(self[accessor]) }
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              def boolean
         | 
| 28 | 
            +
                @boolean ||= ->(accessor) { ActiveModel::Type::Boolean.new.cast(self[accessor]) || self[accessor].blank? }
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              def numeric
         | 
| 32 | 
            +
                @numeric ||= ->(accessor) { Float(self[accessor]) }
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
            end
         | 
| @@ -1,66 +1,32 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 3 | 
            +
            require "stimulus_reflex/dataset"
         | 
| 4 | 
            +
            require "stimulus_reflex/utils/attribute_builder"
         | 
| 5 5 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
                @inner_html = data["inner_html"]
         | 
| 9 | 
            -
                @text_content = data["text_content"]
         | 
| 6 | 
            +
            class StimulusReflex::Element < OpenStruct
         | 
| 7 | 
            +
              include StimulusReflex::AttributeBuilder
         | 
| 10 8 |  | 
| 11 | 
            -
             | 
| 12 | 
            -
                regular_dataset = datasets["dataset"] || {}
         | 
| 13 | 
            -
                @data_attrs = build_data_attrs(regular_dataset, datasets["datasetAll"] || {})
         | 
| 9 | 
            +
              attr_reader :attrs, :dataset
         | 
| 14 10 |  | 
| 15 | 
            -
             | 
| 11 | 
            +
              alias_method :data_attributes, :dataset
         | 
| 16 12 |  | 
| 17 | 
            -
             | 
| 18 | 
            -
              end
         | 
| 13 | 
            +
              delegate :signed, :unsigned, :numeric, :boolean, :data_attrs, to: :dataset
         | 
| 19 14 |  | 
| 20 | 
            -
              def  | 
| 21 | 
            -
                @ | 
| 22 | 
            -
             | 
| 15 | 
            +
              def initialize(data = {})
         | 
| 16 | 
            +
                @attrs = HashWithIndifferentAccess.new(data["attrs"] || {})
         | 
| 17 | 
            +
                @dataset = StimulusReflex::Dataset.new(data)
         | 
| 23 18 |  | 
| 24 | 
            -
             | 
| 25 | 
            -
                 | 
| 19 | 
            +
                all_attributes = @attrs.merge(@dataset.attrs)
         | 
| 20 | 
            +
                super build_underscored(all_attributes)
         | 
| 26 21 | 
             
              end
         | 
| 27 22 |  | 
| 28 23 | 
             
              def attributes
         | 
| 29 24 | 
             
                @attributes ||= OpenStruct.new(build_underscored(attrs))
         | 
| 30 25 | 
             
              end
         | 
| 31 26 |  | 
| 32 | 
            -
              def dataset
         | 
| 33 | 
            -
                @dataset ||= OpenStruct.new(build_underscored(data_attrs))
         | 
| 34 | 
            -
              end
         | 
| 35 | 
            -
             | 
| 36 27 | 
             
              def to_dom_id
         | 
| 37 28 | 
             
                raise NoIDError.new "The element `morph` is called on must have a valid DOM ID" if id.blank?
         | 
| 38 29 |  | 
| 39 30 | 
             
                "##{id}"
         | 
| 40 31 | 
             
              end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
              alias_method :data_attributes, :dataset
         | 
| 43 | 
            -
             | 
| 44 | 
            -
              private
         | 
| 45 | 
            -
             | 
| 46 | 
            -
              def all_attributes
         | 
| 47 | 
            -
                @attrs.merge(@data_attrs)
         | 
| 48 | 
            -
              end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
              def build_data_attrs(dataset, dataset_all)
         | 
| 51 | 
            -
                dataset_all.transform_keys! { |key| "data-#{key.delete_prefix("data-").pluralize}" }
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                dataset.each { |key, value| dataset_all[key]&.prepend(value) }
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                data_attrs = dataset.merge(dataset_all)
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                HashWithIndifferentAccess.new(data_attrs || {})
         | 
| 58 | 
            -
              end
         | 
| 59 | 
            -
             | 
| 60 | 
            -
              def build_underscored(attrs)
         | 
| 61 | 
            -
                attrs.merge(attrs.transform_keys(&:underscore))
         | 
| 62 | 
            -
              end
         | 
| 63 | 
            -
             | 
| 64 | 
            -
              class NoIDError < StandardError
         | 
| 65 | 
            -
              end
         | 
| 66 32 | 
             
            end
         | 
| @@ -8,14 +8,14 @@ class StimulusReflex::Reflex | |
| 8 8 | 
             
              include ActionView::Helpers::TagHelper
         | 
| 9 9 | 
             
              include CableReady::Identifiable
         | 
| 10 10 |  | 
| 11 | 
            -
              attr_accessor :payload
         | 
| 11 | 
            +
              attr_accessor :payload, :headers
         | 
| 12 12 | 
             
              attr_reader :cable_ready, :channel, :url, :element, :selectors, :method_name, :broadcaster, :client_attributes, :logger
         | 
| 13 13 |  | 
| 14 14 | 
             
              alias_method :action_name, :method_name # for compatibility with controller libraries like Pundit that expect an action name
         | 
| 15 15 |  | 
| 16 16 | 
             
              delegate :connection, :stream_name, to: :channel
         | 
| 17 17 | 
             
              delegate :controller_class, :flash, :session, to: :request
         | 
| 18 | 
            -
              delegate :broadcast, : | 
| 18 | 
            +
              delegate :broadcast, :halted, :error, to: :broadcaster
         | 
| 19 19 | 
             
              delegate :reflex_id, :tab_id, :reflex_controller, :xpath_controller, :xpath_element, :permanent_attribute_name, to: :client_attributes
         | 
| 20 20 |  | 
| 21 21 | 
             
              def initialize(channel, url: nil, element: nil, selectors: [], method_name: nil, params: {}, client_attributes: {})
         | 
| @@ -41,6 +41,7 @@ class StimulusReflex::Reflex | |
| 41 41 | 
             
                @client_attributes = ClientAttributes.new(client_attributes)
         | 
| 42 42 | 
             
                @cable_ready = StimulusReflex::CableReadyChannels.new(stream_name, reflex_id)
         | 
| 43 43 | 
             
                @payload = {}
         | 
| 44 | 
            +
                @headers = {}
         | 
| 44 45 | 
             
                self.params
         | 
| 45 46 | 
             
              end
         | 
| 46 47 |  | 
| @@ -97,6 +98,7 @@ class StimulusReflex::Reflex | |
| 97 98 |  | 
| 98 99 | 
             
              def controller
         | 
| 99 100 | 
             
                @controller ||= controller_class.new.tap do |c|
         | 
| 101 | 
            +
                  request.headers.merge!(headers)
         | 
| 100 102 | 
             
                  c.instance_variable_set :@stimulus_reflex, true
         | 
| 101 103 | 
             
                  c.set_request! request
         | 
| 102 104 | 
             
                  c.set_response! controller_class.make_response!(request)
         | 
| @@ -111,6 +113,9 @@ class StimulusReflex::Reflex | |
| 111 113 | 
             
              end
         | 
| 112 114 |  | 
| 113 115 | 
             
              def render(*args)
         | 
| 116 | 
            +
                options = args.extract_options!
         | 
| 117 | 
            +
                (options[:locals] ||= {}).reverse_merge!(params: params)
         | 
| 118 | 
            +
                args << options.reverse_merge(layout: false)
         | 
| 114 119 | 
             
                controller_class.renderer.new(connection.env.merge("SCRIPT_NAME" => "")).render(*args)
         | 
| 115 120 | 
             
              end
         | 
| 116 121 |  | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module StimulusReflex::AttributeBuilder
         | 
| 4 | 
            +
              def build_data_attrs(dataset, dataset_all)
         | 
| 5 | 
            +
                dataset_all.transform_keys! { |key| "data-#{key.delete_prefix("data-").pluralize}" }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                dataset.each { |key, value| dataset_all[key]&.prepend(value) }
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                data_attrs = dataset.merge(dataset_all)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                HashWithIndifferentAccess.new(data_attrs || {})
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def build_underscored(attrs)
         | 
| 15 | 
            +
                attrs.merge(attrs.transform_keys(&:underscore))
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -2,18 +2,22 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module StimulusReflex
         | 
| 4 4 | 
             
              class Logger
         | 
| 5 | 
            +
                attr_reader :logger
         | 
| 5 6 | 
             
                attr_accessor :reflex, :current_operation
         | 
| 6 7 |  | 
| 8 | 
            +
                delegate :debug, :info, :warn, :error, :fatal, :unknown, to: :logger
         | 
| 9 | 
            +
             | 
| 7 10 | 
             
                def initialize(reflex)
         | 
| 8 11 | 
             
                  @reflex = reflex
         | 
| 9 12 | 
             
                  @current_operation = 1
         | 
| 13 | 
            +
                  @logger = StimulusReflex.config.logger
         | 
| 10 14 | 
             
                end
         | 
| 11 15 |  | 
| 12 | 
            -
                def  | 
| 16 | 
            +
                def log_all_operations
         | 
| 13 17 | 
             
                  return unless config_logging.instance_of?(Proc)
         | 
| 14 18 |  | 
| 15 19 | 
             
                  reflex.broadcaster.operations.each do
         | 
| 16 | 
            -
                     | 
| 20 | 
            +
                    logger.info instance_eval(&config_logging) + "\e[0m"
         | 
| 17 21 | 
             
                    @current_operation += 1
         | 
| 18 22 | 
             
                  end
         | 
| 19 23 | 
             
                end
         | 
| @@ -96,7 +96,7 @@ namespace :stimulus_reflex do | |
| 96 96 | 
             
                puts
         | 
| 97 97 | 
             
                system "bundle exec rails generate stimulus_reflex:initializer"
         | 
| 98 98 | 
             
                system "bundle exec rails generate cable_ready:initializer"
         | 
| 99 | 
            -
                system "bundle exec rails generate cable_ready: | 
| 99 | 
            +
                system "bundle exec rails generate cable_ready:helpers"
         | 
| 100 100 |  | 
| 101 101 | 
             
                puts
         | 
| 102 102 | 
             
                puts "✨ Generating ApplicationReflex class and Stimulus controllers, plus an example Reflex class and controller"
         | 
| @@ -7,6 +7,5 @@ class StimulusReflex::BroadcasterTest < StimulusReflex::BroadcasterTestCase | |
| 7 7 | 
             
                broadcaster = StimulusReflex::Broadcaster.new(@reflex)
         | 
| 8 8 |  | 
| 9 9 | 
             
                assert_raises(NotImplementedError) { broadcaster.broadcast }
         | 
| 10 | 
            -
                assert_raises(NotImplementedError) { broadcaster.broadcast_message(subject: "Test") }
         | 
| 11 10 | 
             
              end
         | 
| 12 11 | 
             
            end
         | 
| @@ -5,6 +5,30 @@ require_relative "../test_helper" | |
| 5 5 | 
             
            class StimulusReflex::BroadcasterTestCase < ActionCable::Channel::TestCase
         | 
| 6 6 | 
             
              tests StimulusReflex::Channel
         | 
| 7 7 |  | 
| 8 | 
            +
              def assert_broadcast_on(stream, data, &block)
         | 
| 9 | 
            +
                serialized_msg = ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(data))
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                new_messages = broadcasts(stream)
         | 
| 12 | 
            +
                if block
         | 
| 13 | 
            +
                  old_messages = new_messages
         | 
| 14 | 
            +
                  clear_messages(stream)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  yield
         | 
| 17 | 
            +
                  new_messages = broadcasts(stream)
         | 
| 18 | 
            +
                  clear_messages(stream)
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  (old_messages + new_messages).each { |m| pubsub_adapter.broadcast(stream, m) }
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                message = new_messages.find { |msg| ActiveSupport::JSON.decode(msg) == serialized_msg }
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                unless message
         | 
| 26 | 
            +
                  puts "\n\n#{ActiveSupport::JSON.decode(new_messages.first)}\n#{data}\n\n"
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                assert message, "No messages sent with #{data} to #{stream}"
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 8 32 | 
             
              setup do
         | 
| 9 33 | 
             
                stub_connection(session_id: SecureRandom.uuid)
         | 
| 10 34 | 
             
                def connection.env
         | 
| @@ -3,35 +3,27 @@ | |
| 3 3 | 
             
            require_relative "broadcaster_test_case"
         | 
| 4 4 |  | 
| 5 5 | 
             
            class StimulusReflex::NothingBroadcasterTest < StimulusReflex::BroadcasterTestCase
         | 
| 6 | 
            -
              test "broadcasts a  | 
| 6 | 
            +
              test "broadcasts a nothing morph when called" do
         | 
| 7 7 | 
             
                broadcaster = StimulusReflex::NothingBroadcaster.new(@reflex)
         | 
| 8 8 |  | 
| 9 9 | 
             
                expected = {
         | 
| 10 10 | 
             
                  "cableReady" => true,
         | 
| 11 | 
            -
                  "operations" =>  | 
| 12 | 
            -
                     | 
| 13 | 
            -
                       | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
                              "body" => nil
         | 
| 24 | 
            -
                            }
         | 
| 25 | 
            -
                          }
         | 
| 26 | 
            -
                        },
         | 
| 27 | 
            -
                        "reflexId" => "666"
         | 
| 28 | 
            -
                      }
         | 
| 29 | 
            -
                    ]
         | 
| 30 | 
            -
                  }
         | 
| 11 | 
            +
                  "operations" => [
         | 
| 12 | 
            +
                    {
         | 
| 13 | 
            +
                      "name" => "stimulus-reflex:morph-nothing",
         | 
| 14 | 
            +
                      "payload" => {},
         | 
| 15 | 
            +
                      "stimulusReflex" => {
         | 
| 16 | 
            +
                        "some" => "data",
         | 
| 17 | 
            +
                        "morph" => "nothing"
         | 
| 18 | 
            +
                      },
         | 
| 19 | 
            +
                      "reflexId" => "666",
         | 
| 20 | 
            +
                      "operation" => "dispatchEvent"
         | 
| 21 | 
            +
                    }
         | 
| 22 | 
            +
                  ]
         | 
| 31 23 | 
             
                }
         | 
| 32 24 |  | 
| 33 25 | 
             
                assert_broadcast_on @reflex.stream_name, expected do
         | 
| 34 | 
            -
                  broadcaster.broadcast nil, {: | 
| 26 | 
            +
                  broadcaster.broadcast nil, {some: :data}
         | 
| 35 27 | 
             
                end
         | 
| 36 28 | 
             
              end
         | 
| 37 29 | 
             
            end
         | 
| @@ -20,22 +20,21 @@ class StimulusReflex::PageBroadcasterTest < StimulusReflex::BroadcasterTestCase | |
| 20 20 |  | 
| 21 21 | 
             
                expected = {
         | 
| 22 22 | 
             
                  "cableReady" => true,
         | 
| 23 | 
            -
                  "operations" =>  | 
| 24 | 
            -
                     | 
| 25 | 
            -
                       | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
                        " | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
                  }
         | 
| 23 | 
            +
                  "operations" => [
         | 
| 24 | 
            +
                    {
         | 
| 25 | 
            +
                      "selector" => "body",
         | 
| 26 | 
            +
                      "html" => "<div>New Content</div><div>Another Content</div>",
         | 
| 27 | 
            +
                      "payload" => {},
         | 
| 28 | 
            +
                      "childrenOnly" => true,
         | 
| 29 | 
            +
                      "permanentAttributeName" => nil,
         | 
| 30 | 
            +
                      "stimulusReflex" => {
         | 
| 31 | 
            +
                        "some" => :data,
         | 
| 32 | 
            +
                        "morph" => :page
         | 
| 33 | 
            +
                      },
         | 
| 34 | 
            +
                      "reflexId" => "666",
         | 
| 35 | 
            +
                      "operation" => "morph"
         | 
| 36 | 
            +
                    }
         | 
| 37 | 
            +
                  ]
         | 
| 39 38 | 
             
                }
         | 
| 40 39 |  | 
| 41 40 | 
             
                assert_broadcast_on @reflex.stream_name, expected do
         | 
| @@ -54,22 +53,21 @@ class StimulusReflex::PageBroadcasterTest < StimulusReflex::BroadcasterTestCase | |
| 54 53 |  | 
| 55 54 | 
             
                expected = {
         | 
| 56 55 | 
             
                  "cableReady" => true,
         | 
| 57 | 
            -
                  "operations" =>  | 
| 58 | 
            -
                     | 
| 59 | 
            -
                       | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
                        " | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
                  }
         | 
| 56 | 
            +
                  "operations" => [
         | 
| 57 | 
            +
                    {
         | 
| 58 | 
            +
                      "selector" => "#foo",
         | 
| 59 | 
            +
                      "html" => "New Content",
         | 
| 60 | 
            +
                      "payload" => {},
         | 
| 61 | 
            +
                      "childrenOnly" => true,
         | 
| 62 | 
            +
                      "permanentAttributeName" => nil,
         | 
| 63 | 
            +
                      "stimulusReflex" => {
         | 
| 64 | 
            +
                        "some" => :data,
         | 
| 65 | 
            +
                        "morph" => :page
         | 
| 66 | 
            +
                      },
         | 
| 67 | 
            +
                      "reflexId" => "666",
         | 
| 68 | 
            +
                      "operation" => "morph"
         | 
| 69 | 
            +
                    }
         | 
| 70 | 
            +
                  ]
         | 
| 73 71 | 
             
                }
         | 
| 74 72 |  | 
| 75 73 | 
             
                assert_broadcast_on @reflex.stream_name, expected do
         | 
| @@ -10,22 +10,21 @@ module StimulusReflex | |
| 10 10 |  | 
| 11 11 | 
             
                  expected = {
         | 
| 12 12 | 
             
                    "cableReady" => true,
         | 
| 13 | 
            -
                    "operations" =>  | 
| 14 | 
            -
                       | 
| 15 | 
            -
                         | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
                          " | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
                    }
         | 
| 13 | 
            +
                    "operations" => [
         | 
| 14 | 
            +
                      {
         | 
| 15 | 
            +
                        "selector" => "#foo",
         | 
| 16 | 
            +
                        "html" => "<div>bar</div><div>baz</div>",
         | 
| 17 | 
            +
                        "payload" => {},
         | 
| 18 | 
            +
                        "childrenOnly" => true,
         | 
| 19 | 
            +
                        "permanentAttributeName" => nil,
         | 
| 20 | 
            +
                        "stimulusReflex" => {
         | 
| 21 | 
            +
                          "some" => "data",
         | 
| 22 | 
            +
                          "morph" => "selector"
         | 
| 23 | 
            +
                        },
         | 
| 24 | 
            +
                        "reflexId" => "666",
         | 
| 25 | 
            +
                        "operation" => "morph"
         | 
| 26 | 
            +
                      }
         | 
| 27 | 
            +
                    ]
         | 
| 29 28 | 
             
                  }
         | 
| 30 29 |  | 
| 31 30 | 
             
                  assert_broadcast_on @reflex.stream_name, expected do
         | 
| @@ -39,20 +38,19 @@ module StimulusReflex | |
| 39 38 |  | 
| 40 39 | 
             
                  expected = {
         | 
| 41 40 | 
             
                    "cableReady" => true,
         | 
| 42 | 
            -
                    "operations" =>  | 
| 43 | 
            -
                       | 
| 44 | 
            -
                         | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
                          " | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
                    }
         | 
| 41 | 
            +
                    "operations" => [
         | 
| 42 | 
            +
                      {
         | 
| 43 | 
            +
                        "selector" => "#foo",
         | 
| 44 | 
            +
                        "html" => '<div id="baz"><span>bar</span></div>',
         | 
| 45 | 
            +
                        "payload" => {},
         | 
| 46 | 
            +
                        "stimulusReflex" => {
         | 
| 47 | 
            +
                          "some" => "data",
         | 
| 48 | 
            +
                          "morph" => "selector"
         | 
| 49 | 
            +
                        },
         | 
| 50 | 
            +
                        "reflexId" => "666",
         | 
| 51 | 
            +
                        "operation" => "innerHtml"
         | 
| 52 | 
            +
                      }
         | 
| 53 | 
            +
                    ]
         | 
| 56 54 | 
             
                  }
         | 
| 57 55 |  | 
| 58 56 | 
             
                  assert_broadcast_on @reflex.stream_name, expected do
         | 
| @@ -66,20 +64,19 @@ module StimulusReflex | |
| 66 64 |  | 
| 67 65 | 
             
                  expected = {
         | 
| 68 66 | 
             
                    "cableReady" => true,
         | 
| 69 | 
            -
                    "operations" =>  | 
| 70 | 
            -
                       | 
| 71 | 
            -
                         | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
                          " | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
                    }
         | 
| 67 | 
            +
                    "operations" => [
         | 
| 68 | 
            +
                      {
         | 
| 69 | 
            +
                        "selector" => "#foo",
         | 
| 70 | 
            +
                        "html" => "",
         | 
| 71 | 
            +
                        "payload" => {},
         | 
| 72 | 
            +
                        "stimulusReflex" => {
         | 
| 73 | 
            +
                          "some" => "data",
         | 
| 74 | 
            +
                          "morph" => "selector"
         | 
| 75 | 
            +
                        },
         | 
| 76 | 
            +
                        "reflexId" => "666",
         | 
| 77 | 
            +
                        "operation" => "innerHtml"
         | 
| 78 | 
            +
                      }
         | 
| 79 | 
            +
                    ]
         | 
| 83 80 | 
             
                  }
         | 
| 84 81 |  | 
| 85 82 | 
             
                  assert_broadcast_on @reflex.stream_name, expected do
         | 
| @@ -93,20 +90,19 @@ module StimulusReflex | |
| 93 90 |  | 
| 94 91 | 
             
                  expected = {
         | 
| 95 92 | 
             
                    "cableReady" => true,
         | 
| 96 | 
            -
                    "operations" =>  | 
| 97 | 
            -
                       | 
| 98 | 
            -
                         | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
                          " | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
                    }
         | 
| 93 | 
            +
                    "operations" => [
         | 
| 94 | 
            +
                      {
         | 
| 95 | 
            +
                        "selector" => "#foo",
         | 
| 96 | 
            +
                        "html" => "",
         | 
| 97 | 
            +
                        "payload" => {},
         | 
| 98 | 
            +
                        "stimulusReflex" => {
         | 
| 99 | 
            +
                          "some" => "data",
         | 
| 100 | 
            +
                          "morph" => "selector"
         | 
| 101 | 
            +
                        },
         | 
| 102 | 
            +
                        "reflexId" => "666",
         | 
| 103 | 
            +
                        "operation" => "innerHtml"
         | 
| 104 | 
            +
                      }
         | 
| 105 | 
            +
                    ]
         | 
| 110 106 | 
             
                  }
         | 
| 111 107 |  | 
| 112 108 | 
             
                  assert_broadcast_on @reflex.stream_name, expected do
         | 
| @@ -120,20 +116,19 @@ module StimulusReflex | |
| 120 116 |  | 
| 121 117 | 
             
                  expected = {
         | 
| 122 118 | 
             
                    "cableReady" => true,
         | 
| 123 | 
            -
                    "operations" =>  | 
| 124 | 
            -
                       | 
| 125 | 
            -
                         | 
| 126 | 
            -
             | 
| 127 | 
            -
             | 
| 128 | 
            -
             | 
| 129 | 
            -
                          " | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 136 | 
            -
                    }
         | 
| 119 | 
            +
                    "operations" => [
         | 
| 120 | 
            +
                      {
         | 
| 121 | 
            +
                        "selector" => "#foo",
         | 
| 122 | 
            +
                        "html" => "",
         | 
| 123 | 
            +
                        "payload" => {},
         | 
| 124 | 
            +
                        "stimulusReflex" => {
         | 
| 125 | 
            +
                          "some" => "data",
         | 
| 126 | 
            +
                          "morph" => "selector"
         | 
| 127 | 
            +
                        },
         | 
| 128 | 
            +
                        "reflexId" => "666",
         | 
| 129 | 
            +
                        "operation" => "innerHtml"
         | 
| 130 | 
            +
                      }
         | 
| 131 | 
            +
                    ]
         | 
| 137 132 | 
             
                  }
         | 
| 138 133 |  | 
| 139 134 | 
             
                  assert_broadcast_on @reflex.stream_name, expected do
         | 
| @@ -147,22 +142,21 @@ module StimulusReflex | |
| 147 142 |  | 
| 148 143 | 
             
                  expected = {
         | 
| 149 144 | 
             
                    "cableReady" => true,
         | 
| 150 | 
            -
                    "operations" =>  | 
| 151 | 
            -
                       | 
| 152 | 
            -
                         | 
| 153 | 
            -
             | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
                          " | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
                    }
         | 
| 145 | 
            +
                    "operations" => [
         | 
| 146 | 
            +
                      {
         | 
| 147 | 
            +
                        "selector" => "#foo",
         | 
| 148 | 
            +
                        "html" => "<div>bar</div><div>baz</div>",
         | 
| 149 | 
            +
                        "payload" => {},
         | 
| 150 | 
            +
                        "childrenOnly" => true,
         | 
| 151 | 
            +
                        "permanentAttributeName" => nil,
         | 
| 152 | 
            +
                        "stimulusReflex" => {
         | 
| 153 | 
            +
                          "some" => "data",
         | 
| 154 | 
            +
                          "morph" => "selector"
         | 
| 155 | 
            +
                        },
         | 
| 156 | 
            +
                        "reflexId" => "666",
         | 
| 157 | 
            +
                        "operation" => "morph"
         | 
| 158 | 
            +
                      }
         | 
| 159 | 
            +
                    ]
         | 
| 166 160 | 
             
                  }
         | 
| 167 161 |  | 
| 168 162 | 
             
                  assert_broadcast_on @reflex.stream_name, expected do
         |