cable_ready 4.4.6 → 5.0.0.pre2

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +228 -161
  3. data/Gemfile.lock +146 -99
  4. data/LATEST +1 -0
  5. data/README.md +13 -13
  6. data/Rakefile +8 -2
  7. data/app/channels/cable_ready/stream.rb +12 -0
  8. data/app/helpers/cable_ready_helper.rb +11 -0
  9. data/app/jobs/cable_ready_broadcast_job.rb +14 -0
  10. data/bin/standardize +1 -1
  11. data/cable_ready.gemspec +4 -2
  12. data/lib/cable_ready.rb +44 -0
  13. data/lib/cable_ready/broadcaster.rb +3 -4
  14. data/lib/cable_ready/cable_car.rb +17 -0
  15. data/lib/cable_ready/channel.rb +14 -36
  16. data/lib/cable_ready/channels.rb +22 -68
  17. data/lib/cable_ready/compoundable.rb +11 -0
  18. data/lib/cable_ready/config.rb +78 -0
  19. data/lib/cable_ready/identifiable.rb +30 -0
  20. data/lib/cable_ready/operation_builder.rb +83 -0
  21. data/lib/cable_ready/sanity_checker.rb +151 -0
  22. data/lib/cable_ready/stream_identifier.rb +13 -0
  23. data/lib/cable_ready/version.rb +1 -1
  24. data/lib/generators/cable_ready/channel_generator.rb +71 -0
  25. data/lib/generators/cable_ready/initializer_generator.rb +14 -0
  26. data/lib/generators/cable_ready/stream_from_generator.rb +43 -0
  27. data/lib/generators/cable_ready/templates/config/initializers/cable_ready.rb +18 -0
  28. data/package.json +10 -5
  29. data/tags +58 -35
  30. data/test/lib/cable_ready/cable_car_test.rb +50 -0
  31. data/test/lib/cable_ready/identifiable_test.rb +75 -0
  32. data/test/lib/cable_ready/operation_builder_test.rb +211 -0
  33. data/test/lib/generators/cable_ready/channel_generator_test.rb +157 -0
  34. data/test/support/generator_test_helpers.rb +28 -0
  35. data/test/test_helper.rb +15 -0
  36. data/yarn.lock +134 -124
  37. metadata +66 -11
data/tags CHANGED
@@ -9,49 +9,72 @@ CableReady lib/cable_ready.rb /^module CableReady$/;" m
9
9
  CableReady lib/cable_ready/broadcaster.rb /^module CableReady$/;" m
10
10
  CableReady lib/cable_ready/channel.rb /^module CableReady$/;" m
11
11
  CableReady lib/cable_ready/channels.rb /^module CableReady$/;" m
12
+ CableReady lib/cable_ready/config.rb /^module CableReady$/;" m
12
13
  CableReady lib/cable_ready/version.rb /^module CableReady$/;" m
14
+ CableReady lib/generators/cable_ready/channel_generator.rb /^class CableReady::ChannelGenerator < Rails::Generators::NamedBase$/;" c
15
+ CableReady test/lib/generators/cable_ready/channel_generator_test.rb /^class CableReady::ChannelGeneratorTest < Rails::Generators::TestCase$/;" c
13
16
  Channel lib/cable_ready/channel.rb /^ class Channel$/;" c class:CableReady
14
17
  Channels lib/cable_ready/channels.rb /^ class Channels$/;" c class:CableReady
18
+ ClassMethods test/support/generator_test_helpers.rb /^ module ClassMethods$/;" m class:GeneratorTestHelpers
19
+ Config lib/cable_ready/config.rb /^ class Config$/;" c class:CableReady
15
20
  Engine lib/cable_ready.rb /^ class Engine < Rails::Engine$/;" c class:CableReady
21
+ GeneratorTestHelpers test/support/generator_test_helpers.rb /^module GeneratorTestHelpers$/;" m
16
22
  [] lib/cable_ready/channels.rb /^ def [](identifier)$/;" f class:CableReady.Channels
17
- add_operation lib/cable_ready/channels.rb /^ def add_operation(operation, &implementation)$/;" f class:CableReady.Channels
18
- broadcast lib/cable_ready/channel.rb /^ def broadcast(clear = true)$/;" f class:CableReady.Channel
23
+ add_operation_method lib/cable_ready/channel.rb /^ def add_operation_method(name)$/;" f class:CableReady.Channel
24
+ add_operation_name lib/cable_ready/config.rb /^ def add_operation_name(name)$/;" f class:CableReady.Config
25
+ broadcast lib/cable_ready/channel.rb /^ def broadcast(clear: true)$/;" f class:CableReady.Channel
19
26
  broadcast lib/cable_ready/channels.rb /^ def broadcast(*identifiers, clear: true)$/;" f class:CableReady.Channels
20
- broadcast_to lib/cable_ready/channel.rb /^ def broadcast_to(model, clear = true)$/;" f class:CableReady.Channel
27
+ broadcast_to lib/cable_ready/channel.rb /^ def broadcast_to(model, clear: true)$/;" f class:CableReady.Channel
21
28
  broadcast_to lib/cable_ready/channels.rb /^ def broadcast_to(model, *identifiers, clear: true)$/;" f class:CableReady.Channels
29
+ broadcastable_operations lib/cable_ready/channel.rb /^ def broadcastable_operations$/;" f class:CableReady.Channel
22
30
  cable_ready lib/cable_ready/broadcaster.rb /^ def cable_ready$/;" f class:CableReady.Broadcaster
23
- channel_broadcast lib/cable_ready/channel.rb /^ def channel_broadcast(clear)$/;" f class:CableReady.Channel
24
- channel_broadcast_to lib/cable_ready/channel.rb /^ def channel_broadcast_to(model, clear)$/;" f class:CableReady.Channel
25
- configure lib/cable_ready/channels.rb /^ def self.configure$/;" F class:CableReady.Channels
26
- const.bubbles javascript/cable_ready.js /^ const init = { bubbles: true, cancelable: true, detail: detail }$/;" p
27
- const.cancelable javascript/cable_ready.js /^ const init = { bubbles: true, cancelable: true, detail: detail }$/;" p
28
- const.color javascript/cable_ready.js /^ color: true,$/;" p
29
- const.date javascript/cable_ready.js /^ date: true,$/;" p
30
- const.datetime javascript/cable_ready.js /^ datetime: true,$/;" p
31
- const.datetime-local javascript/cable_ready.js /^ 'datetime-local': true,$/;" p
32
- const.detail javascript/cable_ready.js /^ const init = { bubbles: true, cancelable: true, detail: detail }$/;" p
33
- const.email javascript/cable_ready.js /^ email: true,$/;" p
34
- const.month javascript/cable_ready.js /^ month: true,$/;" p
35
- const.number javascript/cable_ready.js /^ number: true,$/;" p
36
- const.password javascript/cable_ready.js /^ password: true,$/;" p
37
- const.pushState javascript/cable_ready.js /^ pushState: config => {$/;" p
38
- const.range javascript/cable_ready.js /^ range: true,$/;" p
39
- const.search javascript/cable_ready.js /^ search: true,$/;" p
40
- const.select-multiple javascript/cable_ready.js /^ 'select-multiple': true,$/;" p
41
- const.select-one javascript/cable_ready.js /^ 'select-one': true,$/;" p
42
- const.tel javascript/cable_ready.js /^ tel: true,$/;" p
43
- const.text javascript/cable_ready.js /^ text: true,$/;" p
44
- const.textarea javascript/cable_ready.js /^ textarea: true,$/;" p
45
- const.time javascript/cable_ready.js /^ time: true,$/;" p
46
- const.url javascript/cable_ready.js /^ url: true,$/;" p
47
- const.value javascript/cable_ready.js /^ const ignore = { value: true }$/;" p
48
- const.week javascript/cable_ready.js /^ week: true$/;" p
31
+ check_options lib/generators/cable_ready/channel_generator.rb /^ def check_options$/;" f class:CableReady
32
+ config lib/cable_ready.rb /^ def self.config$/;" F class:CableReady
33
+ configure lib/cable_ready.rb /^ def self.configure$/;" F class:CableReady
34
+ const.bubbles javascript/utils.js /^ const init = { bubbles: true, cancelable: true, detail: detail }$/;" p
35
+ const.cancelable javascript/utils.js /^ const init = { bubbles: true, cancelable: true, detail: detail }$/;" p
36
+ const.detail javascript/utils.js /^ const init = { bubbles: true, cancelable: true, detail: detail }$/;" p
37
+ const.value javascript/morph_callbacks.js /^ const ignore = { value: true }$/;" p
38
+ create_channel lib/generators/cable_ready/channel_generator.rb /^ def create_channel$/;" f class:CableReady
39
+ create_sample_app test/support/generator_test_helpers.rb /^ def create_sample_app$/;" f class:GeneratorTestHelpers.ClassMethods
40
+ default_operation_names lib/cable_ready/config.rb /^ def default_operation_names$/;" f class:CableReady.Config
49
41
  dom_id lib/cable_ready/broadcaster.rb /^ def dom_id(record, prefix = nil)$/;" f class:CableReady.Broadcaster
50
- enqueue_operation lib/cable_ready/channel.rb /^ def enqueue_operation(key, options)$/;" f class:CableReady.Channel
51
- import.INPUT javascript/cable_ready.js /^ INPUT: true,$/;" p
52
- import.SELECT javascript/cable_ready.js /^ SELECT: true$/;" p
53
- import.TEXTAREA javascript/cable_ready.js /^ TEXTAREA: true,$/;" p
54
- initialize lib/cable_ready/channel.rb /^ def initialize(identifier, available_operations)$/;" f class:CableReady.Channel
42
+ enhance_channels lib/generators/cable_ready/channel_generator.rb /^ def enhance_channels$/;" f class:CableReady
43
+ export.INPUT javascript/enums.js /^ INPUT: true,$/;" p
44
+ export.OPTION javascript/enums.js /^ OPTION: true$/;" p
45
+ export.SELECT javascript/enums.js /^ SELECT: true$/;" p
46
+ export.TEXTAREA javascript/enums.js /^ TEXTAREA: true,$/;" p
47
+ export.color javascript/enums.js /^ color: true,$/;" p
48
+ export.date javascript/enums.js /^ date: true,$/;" p
49
+ export.datetime javascript/enums.js /^ datetime: true,$/;" p
50
+ export.datetime-local javascript/enums.js /^ 'datetime-local': true,$/;" p
51
+ export.email javascript/enums.js /^ email: true,$/;" p
52
+ export.month javascript/enums.js /^ month: true,$/;" p
53
+ export.number javascript/enums.js /^ number: true,$/;" p
54
+ export.password javascript/enums.js /^ password: true,$/;" p
55
+ export.range javascript/enums.js /^ range: true,$/;" p
56
+ export.search javascript/enums.js /^ search: true,$/;" p
57
+ export.select-multiple javascript/enums.js /^ 'select-multiple': true,$/;" p
58
+ export.select-one javascript/enums.js /^ 'select-one': true,$/;" p
59
+ export.tel javascript/enums.js /^ tel: true,$/;" p
60
+ export.text javascript/enums.js /^ text: true,$/;" p
61
+ export.textarea javascript/enums.js /^ textarea: true,$/;" p
62
+ export.time javascript/enums.js /^ time: true,$/;" p
63
+ export.url javascript/enums.js /^ url: true,$/;" p
64
+ export.week javascript/enums.js /^ week: true$/;" p
65
+ finalizer_for lib/cable_ready/channel.rb /^ def self.finalizer_for(identifier)$/;" F class:CableReady.Channel
66
+ identifier lib/generators/cable_ready/channel_generator.rb /^ def identifier$/;" f class:CableReady
67
+ included test/support/generator_test_helpers.rb /^ def self.included(base)$/;" F class:GeneratorTestHelpers
68
+ initialize lib/cable_ready/channel.rb /^ def initialize(identifier)$/;" f class:CableReady.Channel
55
69
  initialize lib/cable_ready/channels.rb /^ def initialize$/;" f class:CableReady.Channels
56
- mutex lib/cable_ready/channels.rb /^ def mutex$/;" f class:CableReady.Channels
70
+ initialize lib/cable_ready/config.rb /^ def initialize$/;" f class:CableReady.Config
71
+ observers lib/cable_ready/config.rb /^ def observers$/;" f class:CableReady.Config
72
+ operation_names lib/cable_ready/config.rb /^ def operation_names$/;" f class:CableReady.Config
73
+ option_given? lib/generators/cable_ready/channel_generator.rb /^ def option_given?$/;" f class:CableReady
74
+ prepare_destination test/support/generator_test_helpers.rb /^ def prepare_destination$/;" f class:GeneratorTestHelpers.ClassMethods
75
+ remove_sample_app test/support/generator_test_helpers.rb /^ def remove_sample_app$/;" f class:GeneratorTestHelpers.ClassMethods
57
76
  reset lib/cable_ready/channel.rb /^ def reset$/;" f class:CableReady.Channel
77
+ resource lib/generators/cable_ready/channel_generator.rb /^ def resource$/;" f class:CableReady
78
+ sample_app_path test/support/generator_test_helpers.rb /^ def sample_app_path$/;" f class:GeneratorTestHelpers.ClassMethods
79
+ using_broadcast_to? lib/generators/cable_ready/channel_generator.rb /^ def using_broadcast_to?$/;" f class:CableReady
80
+ using_stimulus? lib/generators/cable_ready/channel_generator.rb /^ def using_stimulus?$/;" f class:CableReady
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+ require_relative "../../../lib/cable_ready"
5
+
6
+ class CableReady::CableCarTest < ActiveSupport::TestCase
7
+ setup do
8
+ @cable_car = CableReady::CableCar.instance
9
+ end
10
+
11
+ test "dispatch should return json-ifiable payload" do
12
+ CableReady::CableCar.instance.reset!
13
+ dispatch = CableReady::CableCar.instance.inner_html(selector: "#users", html: "<span>winning</span>").dispatch
14
+ assert_equal({"innerHtml" => [{"selector" => "#users", "html" => "<span>winning</span>"}]}, dispatch)
15
+ end
16
+
17
+ test "dispatch should clear operations" do
18
+ CableReady::CableCar.instance.reset!
19
+ CableReady::CableCar.instance.inner_html(selector: "#users", html: "<span>winning</span>").dispatch
20
+ assert_equal({}, CableReady::CableCar.instance.instance_variable_get(:@enqueued_operations))
21
+ end
22
+
23
+ test "dispatch should maintain operations if clear is false" do
24
+ CableReady::CableCar.instance.reset!
25
+ CableReady::CableCar.instance.inner_html(selector: "#users", html: "<span>winning</span>").dispatch(clear: false)
26
+ assert_equal({"inner_html" => [{"selector" => "#users", "html" => "<span>winning</span>"}]}, CableReady::CableCar.instance.instance_variable_get(:@enqueued_operations))
27
+ end
28
+
29
+ test "selectors should accept any object which respond_to? to_dom_selector" do
30
+ CableReady::CableCar.instance.reset!
31
+ my_object = Struct.new(:id) do
32
+ def to_dom_selector
33
+ ".#{id}"
34
+ end
35
+ end.new("users")
36
+ dispatch = CableReady::CableCar.instance.inner_html(selector: my_object, html: "<span>winning</span>").dispatch
37
+ assert_equal({"innerHtml" => [{"selector" => ".users", "html" => "<span>winning</span>"}]}, dispatch)
38
+ end
39
+
40
+ test "selectors should accept any object which respond_to? to_dom_id" do
41
+ CableReady::CableCar.instance.reset!
42
+ my_object = Struct.new(:id) do
43
+ def to_dom_id
44
+ id
45
+ end
46
+ end.new("users")
47
+ dispatch = CableReady::CableCar.instance.inner_html(selector: my_object, html: "<span>winning</span>").dispatch
48
+ assert_equal({"innerHtml" => [{"selector" => "#users", "html" => "<span>winning</span>"}]}, dispatch)
49
+ end
50
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+ require_relative "../../../lib/cable_ready"
5
+
6
+ class User
7
+ include ActiveModel::Model
8
+
9
+ attr_accessor :id
10
+ end
11
+
12
+ class CableReady::IdentifiableTest < ActiveSupport::TestCase
13
+ include CableReady::Identifiable
14
+
15
+ test "should handle nil" do
16
+ assert_equal "#", dom_id(nil)
17
+ end
18
+
19
+ test "should work with strings" do
20
+ assert_equal "#users", dom_id("users")
21
+ assert_equal "#users", dom_id("users ")
22
+ assert_equal "#users", dom_id(" users ")
23
+ end
24
+
25
+ test "should work with symbols" do
26
+ assert_equal "#users", dom_id(:users)
27
+ assert_equal "#active_users", dom_id(:active_users)
28
+ end
29
+
30
+ test "should just return one hash" do
31
+ assert_equal "#users", dom_id("users")
32
+ assert_equal "#users", dom_id("#users")
33
+ assert_equal "#users", dom_id("##users")
34
+ end
35
+
36
+ test "should strip prefixes" do
37
+ assert_equal "#active_users", dom_id(" users ", " active ")
38
+ assert_equal "#all_active_users", dom_id(" users ", " all_active ")
39
+ end
40
+
41
+ test "should not include provided prefix if prefix is nil" do
42
+ assert_equal "#users", dom_id("users", nil)
43
+ end
44
+
45
+ test "should work with ActiveRecord::Relation" do
46
+ relation = mock("ActiveRecord::Relation")
47
+
48
+ relation.stubs(:is_a?).with(ActiveRecord::Relation).returns(true).at_least_once
49
+ relation.stubs(:is_a?).with(ActiveRecord::Base).never
50
+ relation.stubs(:model_name).returns(OpenStruct.new(plural: "users"))
51
+
52
+ assert_equal "#users", dom_id(relation)
53
+ assert_equal "#users", dom_id(relation, nil)
54
+ assert_equal "#active_users", dom_id(relation, "active")
55
+ end
56
+
57
+ test "should work with ActiveRecord::Base" do
58
+ User.any_instance.stubs(:is_a?).with(ActiveRecord::Relation).returns(false)
59
+ User.any_instance.stubs(:is_a?).with(ActiveRecord::Base).returns(true)
60
+
61
+ assert_equal "#new_user", dom_id(User.new(id: nil))
62
+
63
+ user = User.new(id: 42)
64
+
65
+ assert_equal "#user_42", dom_id(user)
66
+ assert_equal "#user_42", dom_id(user, nil)
67
+ assert_equal "#all_active_user_42", dom_id(user, "all_active")
68
+
69
+ user = User.new(id: 99)
70
+
71
+ assert_equal "#user_99", dom_id(user)
72
+ assert_equal "#user_99", dom_id(user, nil)
73
+ assert_equal "#all_active_user_99", dom_id(user, "all_active")
74
+ end
75
+ end
@@ -0,0 +1,211 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+ require_relative "../../../lib/cable_ready"
5
+
6
+ class Death
7
+ def to_html
8
+ "I rock"
9
+ end
10
+
11
+ def to_dom_id
12
+ "death"
13
+ end
14
+
15
+ def to_operation_options
16
+ [:html, :dom_id, :spaz]
17
+ end
18
+ end
19
+
20
+ class Life
21
+ def to_operation_options
22
+ {
23
+ html: "You go, girl",
24
+ dom_id: "life"
25
+ }
26
+ end
27
+ end
28
+
29
+ class CableReady::OperationBuilderTest < ActiveSupport::TestCase
30
+ setup do
31
+ @operation_builder = CableReady::OperationBuilder.new("test")
32
+ end
33
+
34
+ test "should create enqueued operations" do
35
+ assert_not_nil @operation_builder.instance_variable_get(:@enqueued_operations)
36
+ end
37
+
38
+ test "should add observer to cable ready" do
39
+ assert_not_nil CableReady.config.instance_variable_get(:@observer_peers)[@operation_builder]
40
+ end
41
+
42
+ test "should remove observer when destroyed" do
43
+ @operation_builder = nil
44
+ assert_nil CableReady.config.instance_variable_get(:@observer_peers)[@operation_builder]
45
+ end
46
+
47
+ test "should add operation method" do
48
+ @operation_builder.add_operation_method("foobar")
49
+ assert @operation_builder.respond_to?(:foobar)
50
+ end
51
+
52
+ test "added operation method should add keys" do
53
+ @operation_builder.add_operation_method("foobar")
54
+ @operation_builder.foobar({name: "passed_option"})
55
+
56
+ operations = @operation_builder.instance_variable_get(:@enqueued_operations)
57
+
58
+ assert_equal 1, operations["foobar"].size
59
+ assert_equal({"name" => "passed_option"}, operations["foobar"].first)
60
+ end
61
+
62
+ test "should json-ify operations" do
63
+ @operation_builder.add_operation_method("foobar")
64
+ @operation_builder.foobar({name: "passed_option"})
65
+ assert_equal("{\"foobar\":[{\"name\":\"passed_option\"}]}", @operation_builder.to_json)
66
+ end
67
+
68
+ test "should apply! many operations" do
69
+ @operation_builder.apply!(foobar: [{name: "passed_option"}])
70
+
71
+ operations = @operation_builder.instance_variable_get(:@enqueued_operations)
72
+ assert_equal 1, operations["foobar"].size
73
+ assert_equal({"name" => "passed_option"}, operations["foobar"].first)
74
+ end
75
+
76
+ test "should apply! many operations from a string" do
77
+ @operation_builder.apply!(JSON.generate({foobar: [{name: "passed_option"}]}))
78
+
79
+ operations = @operation_builder.instance_variable_get(:@enqueued_operations)
80
+ assert_equal 1, operations["foobar"].size
81
+ assert_equal({"name" => "passed_option"}, operations["foobar"].first)
82
+ end
83
+
84
+ test "operations payload should omit empty operations" do
85
+ @operation_builder.add_operation_method("foobar")
86
+ payload = @operation_builder.operations_payload
87
+ assert_equal({}, payload)
88
+ end
89
+
90
+ test "operations payload should camelize keys" do
91
+ @operation_builder.add_operation_method("foo_bar")
92
+ @operation_builder.foo_bar({beep_boop: "passed_option"})
93
+ assert_equal({"fooBar" => [{"beepBoop" => "passed_option"}]}, @operation_builder.operations_payload)
94
+ end
95
+
96
+ test "should take first argument as selector" do
97
+ @operation_builder.add_operation_method("inner_html")
98
+
99
+ @operation_builder.inner_html("#smelly", html: "<span>I rock</span>")
100
+
101
+ operations = {
102
+ "innerHtml" => [{"html" => "<span>I rock</span>", "selector" => "#smelly"}]
103
+ }
104
+
105
+ assert_equal(operations, @operation_builder.operations_payload)
106
+ end
107
+
108
+ test "should use previously passed selector in next operation" do
109
+ @operation_builder.add_operation_method("inner_html")
110
+ @operation_builder.add_operation_method("set_focus")
111
+
112
+ @operation_builder.set_focus("#smelly").inner_html(html: "<span>I rock</span>")
113
+
114
+ operations = {
115
+ "setFocus" => [{"selector" => "#smelly"}],
116
+ "innerHtml" => [{"html" => "<span>I rock</span>", "selector" => "#smelly"}]
117
+ }
118
+
119
+ assert_equal(operations, @operation_builder.operations_payload)
120
+ end
121
+
122
+ test "should clear previous_selector after calling reset!" do
123
+ @operation_builder.add_operation_method("inner_html")
124
+ @operation_builder.inner_html(selector: "#smelly", html: "<span>I rock</span>")
125
+
126
+ @operation_builder.reset!
127
+
128
+ @operation_builder.inner_html(html: "<span>winning</span>")
129
+
130
+ assert_equal({"innerHtml" => [{"html" => "<span>winning</span>"}]}, @operation_builder.operations_payload)
131
+ end
132
+
133
+ test "should use previous_selector if present and should use `selector` if explicitly provided" do
134
+ @operation_builder.add_operation_method("inner_html")
135
+ @operation_builder.add_operation_method("set_focus")
136
+
137
+ @operation_builder.set_focus("#smelly").inner_html(html: "<span>I rock</span>").inner_html(html: "<span>I rock too</span>", selector: "#smelly2")
138
+
139
+ operations = {
140
+ "setFocus" => [
141
+ {"selector" => "#smelly"}
142
+ ],
143
+ "innerHtml" => [
144
+ {"html" => "<span>I rock</span>", "selector" => "#smelly"},
145
+ {"html" => "<span>I rock too</span>", "selector" => "#smelly2"}
146
+ ]
147
+ }
148
+
149
+ assert_equal(operations, @operation_builder.operations_payload)
150
+ end
151
+
152
+ test "should pull html option from Death object" do
153
+ @operation_builder.add_operation_method("inner_html")
154
+ death = Death.new
155
+
156
+ @operation_builder.inner_html(html: death)
157
+
158
+ operations = {
159
+ "innerHtml" => [
160
+ {"html" => "I rock"}
161
+ ]
162
+ }
163
+
164
+ assert_equal(operations, @operation_builder.operations_payload)
165
+ end
166
+
167
+ test "should pull html option with selector from Death object" do
168
+ @operation_builder.add_operation_method("inner_html")
169
+ death = Death.new
170
+
171
+ @operation_builder.inner_html(death, html: death)
172
+
173
+ operations = {
174
+ "innerHtml" => [
175
+ {"html" => "I rock", "selector" => "#death"}
176
+ ]
177
+ }
178
+
179
+ assert_equal(operations, @operation_builder.operations_payload)
180
+ end
181
+
182
+ test "should pull html and dom_id options from Death object" do
183
+ @operation_builder.add_operation_method("inner_html")
184
+ death = Death.new
185
+
186
+ @operation_builder.inner_html(death)
187
+
188
+ operations = {
189
+ "innerHtml" => [
190
+ {"html" => "I rock", "domId" => "death"}
191
+ ]
192
+ }
193
+
194
+ assert_equal(operations, @operation_builder.operations_payload)
195
+ end
196
+
197
+ test "should pull html and dom_id options from Life object" do
198
+ @operation_builder.add_operation_method("inner_html")
199
+ life = Life.new
200
+
201
+ @operation_builder.inner_html(life)
202
+
203
+ operations = {
204
+ "innerHtml" => [
205
+ {"html" => "You go, girl", "domId" => "life"}
206
+ ]
207
+ }
208
+
209
+ assert_equal(operations, @operation_builder.operations_payload)
210
+ end
211
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+ require "generators/cable_ready/channel_generator"
5
+
6
+ class CableReady::ChannelGeneratorTest < Rails::Generators::TestCase
7
+ include ::GeneratorTestHelpers
8
+
9
+ tests CableReady::ChannelGenerator
10
+ destination File.expand_path("../../../../tmp/dummy", __dir__)
11
+
12
+ prepare_destination
13
+ create_sample_app
14
+
15
+ MiniTest.after_run do
16
+ remove_sample_app
17
+ end
18
+
19
+ test "should generate channel with the same resource name and stimulus controller" do
20
+ run_generator ["user", "--stream-for=user", "--stimulus"]
21
+
22
+ assert_file "app/channels/user_channel.rb" do |content|
23
+ assert_match(/class\ UserChannel\ </, content)
24
+ assert_match(/stream_for\ User\.find\(params\[:id\]\)/, content)
25
+ end
26
+
27
+ assert_file "app/javascript/channels/user_channel.js", /"UserChannel"/
28
+ assert_file "app/javascript/controllers/user_controller.js", /'UserChannel'/
29
+ end
30
+
31
+ test "should generate channel with different resource name" do
32
+ run_generator ["my_name", "--stream-for=under_scored_resource_name", "--no-stimulus"]
33
+
34
+ assert_file "app/channels/my_name_channel.rb" do |content|
35
+ assert_match(/class\ MyNameChannel\ </, content)
36
+ assert_match(/stream_for\ UnderScoredResourceName\.find\(params\[:id\]\)/, content)
37
+ end
38
+
39
+ assert_file "app/javascript/channels/my_name_channel.js", /"MyNameChannel"/
40
+ assert_no_file "app/javascript/controllers/my_name_controller.js"
41
+ end
42
+
43
+ test "should not generate stimulus controller if not requested" do
44
+ run_generator ["comment", "--stream-for=comment", "--no-stimulus"]
45
+
46
+ assert_file "app/channels/comment_channel.rb"
47
+ assert_file "app/javascript/channels/comment_channel.js"
48
+ assert_no_file "app/javascript/controllers/comment_controller.js"
49
+ end
50
+
51
+ test "should run the generator when streaming from identifier" do
52
+ run_generator ["page", "--stream-from=page"]
53
+
54
+ assert_file "app/channels/page_channel.rb" do |content|
55
+ assert_match(/PageChannel/, content)
56
+ assert_match(/stream_from\ "page"/, content)
57
+ end
58
+
59
+ assert_file "app/javascript/channels/page_channel.js" do |content|
60
+ assert_match(/"PageChannel"/, content)
61
+ assert_match(/import\ CableReady/, content)
62
+ assert_match(/if\ \(data\.cableReady\)\ CableReady\.perform\(data\.operations\)/, content)
63
+ end
64
+ end
65
+
66
+ test "should run the generator when streaming without resource and different identifier" do
67
+ run_generator ["my_page", "--stream-from=ThisIsMyPage"]
68
+
69
+ assert_file "app/channels/my_page_channel.rb" do |content|
70
+ assert_match(/MyPageChannel/, content)
71
+ assert_match(/stream_from\ "this_is_my_page"/, content)
72
+ end
73
+
74
+ assert_file "app/javascript/channels/my_page_channel.js" do |content|
75
+ assert_match(/"MyPageChannel"/, content)
76
+ assert_match(/import\ CableReady/, content)
77
+ assert_match(/if\ \(data\.cableReady\)\ CableReady\.perform\(data\.operations\)/, content)
78
+ end
79
+ end
80
+
81
+ test "should run the generator and use the NAME for --stream-from if nothing passed" do
82
+ run_generator ["house", "--stream-from"]
83
+
84
+ assert_file "app/channels/house_channel.rb" do |content|
85
+ assert_match(/HouseChannel/, content)
86
+ assert_match(/stream_from\ "house"/, content)
87
+ end
88
+
89
+ assert_file "app/javascript/channels/house_channel.js" do |content|
90
+ assert_match(/"HouseChannel"/, content)
91
+ assert_match(/import\ CableReady/, content)
92
+ assert_match(/if\ \(data\.cableReady\)\ CableReady\.perform\(data\.operations\)/, content)
93
+ end
94
+ end
95
+
96
+ test "should run the generator and use the NAME for --stream-for if nothing passed" do
97
+ run_generator ["option", "--stream-for", "--stimulus"]
98
+
99
+ assert_file "app/channels/option_channel.rb" do |content|
100
+ assert_match(/class\ OptionChannel\ </, content)
101
+ assert_match(/stream_for\ Option\.find\(params\[:id\]\)/, content)
102
+ end
103
+
104
+ assert_file "app/javascript/channels/option_channel.js", /"OptionChannel"/
105
+ assert_file "app/javascript/controllers/option_controller.js", /'OptionChannel'/
106
+ end
107
+
108
+ test "should run not generate anything if passed stream_from and stream_for" do
109
+ assert_raises "Can't specify --stream-from and --stream-for at the same time" do
110
+ run_generator ["error", "--stream-from=1", "--stream-for=2"]
111
+ end
112
+ end
113
+
114
+ # some tests without generator options to simulate the inputs passed via cli
115
+
116
+ test "should generate channel with the same resource name and stimulus controller (without options)" do
117
+ CableReady::ChannelGenerator.any_instance.stubs(:using_broadcast_to?).returns(true)
118
+ CableReady::ChannelGenerator.any_instance.stubs(:resource).returns("Post")
119
+ CableReady::ChannelGenerator.any_instance.stubs(:using_stimulus?).returns(true)
120
+
121
+ run_generator ["post"]
122
+
123
+ assert_file "app/channels/post_channel.rb" do |content|
124
+ assert_match(/class\ PostChannel\ </, content)
125
+ assert_match(/stream_for\ Post\.find\(params\[:id\]\)/, content)
126
+ end
127
+
128
+ assert_file "app/javascript/channels/post_channel.js", /PostChannel/
129
+ assert_file "app/javascript/controllers/post_controller.js", /'PostChannel'/
130
+ end
131
+
132
+ test "should not generate stimulus controller if not requested (without options)" do
133
+ CableReady::ChannelGenerator.any_instance.stubs(:using_broadcast_to?).returns(true)
134
+ CableReady::ChannelGenerator.any_instance.stubs(:resource).returns("Admin")
135
+ CableReady::ChannelGenerator.any_instance.stubs(:using_stimulus?).returns(false)
136
+
137
+ run_generator ["admin"]
138
+
139
+ assert_file "app/channels/admin_channel.rb"
140
+ assert_file "app/javascript/channels/admin_channel.js"
141
+ assert_no_file "app/javascript/controllers/admin_controller.js"
142
+ end
143
+
144
+ test "should run the generator when streaming from identifier (without options)" do
145
+ CableReady::ChannelGenerator.any_instance.stubs(:using_broadcast_to?).returns(false)
146
+ CableReady::ChannelGenerator.any_instance.stubs(:identifier).returns("index_identifier")
147
+
148
+ run_generator ["index"]
149
+
150
+ assert_file "app/channels/index_channel.rb" do |content|
151
+ assert_match(/IndexChannel/, content)
152
+ assert_match(/stream_from\ "index_identifier"/, content)
153
+ end
154
+
155
+ assert_file "app/javascript/channels/index_channel.js", /"IndexChannel"/
156
+ end
157
+ end