cable_ready 5.0.0.pre9 → 5.0.0.pre10

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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -1
  3. data/Gemfile.lock +119 -100
  4. data/README.md +2 -5
  5. data/app/assets/javascripts/cable_ready.js +457 -151
  6. data/app/assets/javascripts/cable_ready.min.js +1 -1
  7. data/app/assets/javascripts/cable_ready.min.js.map +1 -1
  8. data/app/assets/javascripts/cable_ready.umd.js +441 -165
  9. data/app/assets/javascripts/cable_ready.umd.min.js +1 -1
  10. data/app/assets/javascripts/cable_ready.umd.min.js.map +1 -1
  11. data/app/channels/cable_ready/stream.rb +7 -5
  12. data/app/helpers/cable_ready/view_helper.rb +58 -0
  13. data/app/jobs/cable_ready_broadcast_job.rb +9 -8
  14. data/app/models/concerns/cable_ready/updatable/collection_updatable_callbacks.rb +2 -0
  15. data/app/models/concerns/cable_ready/updatable/collections_registry.rb +2 -0
  16. data/app/models/concerns/cable_ready/updatable/model_updatable_callbacks.rb +5 -2
  17. data/app/models/concerns/cable_ready/updatable.rb +67 -19
  18. data/app/models/concerns/extend_has_many.rb +2 -0
  19. data/cable_ready.gemspec +4 -6
  20. data/lib/cable_ready/broadcaster.rb +2 -0
  21. data/lib/cable_ready/cable_car.rb +2 -0
  22. data/lib/cable_ready/channel.rb +12 -4
  23. data/lib/cable_ready/channels.rb +3 -1
  24. data/lib/cable_ready/config.rb +16 -2
  25. data/lib/cable_ready/engine.rb +19 -9
  26. data/lib/cable_ready/identifiable.rb +23 -5
  27. data/lib/cable_ready/importmap.rb +2 -0
  28. data/lib/cable_ready/installer.rb +224 -0
  29. data/lib/cable_ready/operation_builder.rb +1 -1
  30. data/lib/cable_ready/sanity_checker.rb +1 -31
  31. data/lib/cable_ready/version.rb +1 -1
  32. data/lib/cable_ready.rb +3 -8
  33. data/lib/cable_ready_helper.rb +13 -0
  34. data/lib/generators/cable_ready/channel_generator.rb +51 -12
  35. data/lib/generators/cable_ready/templates/config/initializers/cable_ready.rb +10 -6
  36. data/lib/install/action_cable.rb +144 -0
  37. data/lib/install/broadcaster.rb +109 -0
  38. data/lib/install/bundle.rb +54 -0
  39. data/lib/install/compression.rb +51 -0
  40. data/lib/install/config.rb +39 -0
  41. data/lib/install/development.rb +34 -0
  42. data/lib/install/esbuild.rb +101 -0
  43. data/lib/install/importmap.rb +96 -0
  44. data/lib/install/initializers.rb +15 -0
  45. data/lib/install/mrujs.rb +121 -0
  46. data/lib/install/npm_packages.rb +13 -0
  47. data/lib/install/shakapacker.rb +61 -0
  48. data/lib/install/spring.rb +54 -0
  49. data/lib/install/updatable.rb +34 -0
  50. data/lib/install/vite.rb +62 -0
  51. data/lib/install/webpacker.rb +81 -0
  52. data/lib/install/yarn.rb +56 -0
  53. data/lib/tasks/cable_ready/cable_ready.rake +249 -0
  54. data/package.json +28 -18
  55. data/{rollup.config.js → rollup.config.mjs} +9 -8
  56. data/web-test-runner.config.mjs +12 -0
  57. data/yarn.lock +2210 -404
  58. metadata +37 -161
  59. data/LATEST +0 -1
  60. data/app/helpers/cable_ready_helper.rb +0 -26
  61. data/lib/generators/cable_ready/helpers_generator.rb +0 -43
  62. data/lib/generators/cable_ready/initializer_generator.rb +0 -14
  63. data/test/dummy/app/channels/application_cable/channel.rb +0 -4
  64. data/test/dummy/app/channels/application_cable/connection.rb +0 -4
  65. data/test/dummy/app/controllers/application_controller.rb +0 -2
  66. data/test/dummy/app/helpers/application_helper.rb +0 -2
  67. data/test/dummy/app/jobs/application_job.rb +0 -7
  68. data/test/dummy/app/mailers/application_mailer.rb +0 -4
  69. data/test/dummy/app/models/application_record.rb +0 -3
  70. data/test/dummy/app/models/dugong.rb +0 -4
  71. data/test/dummy/app/models/global_idable_entity.rb +0 -16
  72. data/test/dummy/app/models/post.rb +0 -4
  73. data/test/dummy/app/models/section.rb +0 -6
  74. data/test/dummy/app/models/team.rb +0 -6
  75. data/test/dummy/app/models/topic.rb +0 -4
  76. data/test/dummy/app/models/user.rb +0 -7
  77. data/test/dummy/config/application.rb +0 -22
  78. data/test/dummy/config/boot.rb +0 -5
  79. data/test/dummy/config/environment.rb +0 -5
  80. data/test/dummy/config/environments/development.rb +0 -76
  81. data/test/dummy/config/environments/production.rb +0 -120
  82. data/test/dummy/config/environments/test.rb +0 -59
  83. data/test/dummy/config/initializers/application_controller_renderer.rb +0 -8
  84. data/test/dummy/config/initializers/assets.rb +0 -12
  85. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -8
  86. data/test/dummy/config/initializers/cable_ready.rb +0 -18
  87. data/test/dummy/config/initializers/content_security_policy.rb +0 -28
  88. data/test/dummy/config/initializers/cookies_serializer.rb +0 -5
  89. data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -6
  90. data/test/dummy/config/initializers/inflections.rb +0 -16
  91. data/test/dummy/config/initializers/mime_types.rb +0 -4
  92. data/test/dummy/config/initializers/permissions_policy.rb +0 -11
  93. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  94. data/test/dummy/config/puma.rb +0 -43
  95. data/test/dummy/config/routes.rb +0 -3
  96. data/test/dummy/db/migrate/20210902154139_create_users.rb +0 -9
  97. data/test/dummy/db/migrate/20210902154153_create_posts.rb +0 -10
  98. data/test/dummy/db/migrate/20210904081930_create_topics.rb +0 -9
  99. data/test/dummy/db/migrate/20210904093607_create_sections.rb +0 -9
  100. data/test/dummy/db/migrate/20210913191735_create_teams.rb +0 -8
  101. data/test/dummy/db/migrate/20210913191759_add_team_reference_to_users.rb +0 -5
  102. data/test/dummy/db/migrate/20220329222959_create_dugongs.rb +0 -8
  103. data/test/dummy/db/migrate/20220329230221_create_active_storage_tables.active_storage.rb +0 -36
  104. data/test/dummy/db/schema.rb +0 -84
  105. data/test/dummy/test/models/dugong_test.rb +0 -7
  106. data/test/dummy/test/models/post_test.rb +0 -7
  107. data/test/dummy/test/models/section_test.rb +0 -7
  108. data/test/dummy/test/models/team_test.rb +0 -7
  109. data/test/dummy/test/models/topic_test.rb +0 -7
  110. data/test/dummy/test/models/user_test.rb +0 -7
  111. data/test/lib/cable_ready/cable_car_test.rb +0 -50
  112. data/test/lib/cable_ready/compoundable_test.rb +0 -26
  113. data/test/lib/cable_ready/helper_test.rb +0 -25
  114. data/test/lib/cable_ready/identifiable_test.rb +0 -69
  115. data/test/lib/cable_ready/operation_builder_test.rb +0 -189
  116. data/test/lib/cable_ready/updatable_test.rb +0 -135
  117. data/test/lib/generators/cable_ready/channel_generator_test.rb +0 -157
  118. data/test/support/generator_test_helpers.rb +0 -28
  119. data/test/test_helper.rb +0 -18
@@ -1,50 +0,0 @@
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([{"operation" => "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([{"operation" => "innerHtml", "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([{"operation" => "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([{"operation" => "innerHtml", "selector" => "#users", "html" => "<span>winning</span>"}], dispatch)
49
- end
50
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "test_helper"
4
- require_relative "../../../lib/cable_ready"
5
-
6
- class CableReady::CompoundableTest < ActiveSupport::TestCase
7
- include CableReady::Compoundable
8
-
9
- test "compounds an ActiveRecord::Base" do
10
- user = User.create(name: "Alan Turing")
11
-
12
- assert_equal "gid://dummy/User/1", compound([user])
13
- end
14
-
15
- test "compounds any GlobalId-able entity" do
16
- entity = GlobalIdableEntity.new
17
-
18
- assert_equal "gid://dummy/GlobalIdableEntity/fake-id", compound([entity])
19
- end
20
-
21
- test "compounds any combination of globalid-able and strings" do
22
- user = User.create(name: "Alan Turing")
23
-
24
- assert_equal "gid://dummy/User/1:enigma", compound([user, :enigma])
25
- end
26
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "test_helper"
4
-
5
- class CableReady::HelperTest < ActionView::TestCase
6
- include CableReadyHelper
7
-
8
- # stream_from
9
-
10
- test "stream_from renders html options" do
11
- element = Nokogiri::HTML.fragment(stream_from("key", html_options: {class: "block", data: {controller: "modal"}}) {})
12
-
13
- assert_equal "block", element.children.first["class"]
14
- assert_equal "modal", element.children.first["data-controller"]
15
- end
16
-
17
- # updates_for
18
-
19
- test "updates_for renders html options" do
20
- element = Nokogiri::HTML.fragment(updates_for("key", html_options: {class: "block", data: {controller: "modal"}}) {})
21
-
22
- assert_equal "block", element.children.first["class"]
23
- assert_equal "modal", element.children.first["data-controller"]
24
- end
25
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "test_helper"
4
- require_relative "../../../lib/cable_ready"
5
-
6
- class CableReady::IdentifiableTest < ActiveSupport::TestCase
7
- include CableReady::Identifiable
8
-
9
- test "should handle nil" do
10
- assert_equal "#", dom_id(nil)
11
- end
12
-
13
- test "should work with strings" do
14
- assert_equal "#users", dom_id("users")
15
- assert_equal "#users", dom_id("users ")
16
- assert_equal "#users", dom_id(" users ")
17
- end
18
-
19
- test "should work with symbols" do
20
- assert_equal "#users", dom_id(:users)
21
- assert_equal "#active_users", dom_id(:active_users)
22
- end
23
-
24
- test "should just return one hash" do
25
- assert_equal "#users", dom_id("users")
26
- assert_equal "#users", dom_id("#users")
27
- assert_equal "#users", dom_id("##users")
28
- end
29
-
30
- test "should strip prefixes" do
31
- assert_equal "#active_users", dom_id(" users ", " active ")
32
- assert_equal "#all_active_users", dom_id(" users ", " all_active ")
33
- end
34
-
35
- test "should not include provided prefix if prefix is nil" do
36
- assert_equal "#users", dom_id("users", nil)
37
- end
38
-
39
- test "should work with ActiveRecord::Relation" do
40
- relation = mock("ActiveRecord::Relation")
41
-
42
- relation.stubs(:is_a?).with(ActiveRecord::Relation).returns(true).at_least_once
43
- relation.stubs(:is_a?).with(ActiveRecord::Base).never
44
- relation.stubs(:model_name).returns(OpenStruct.new(plural: "users"))
45
-
46
- assert_equal "#users", dom_id(relation)
47
- assert_equal "#users", dom_id(relation, nil)
48
- assert_equal "#active_users", dom_id(relation, "active")
49
- end
50
-
51
- test "should work with ActiveRecord::Base" do
52
- User.any_instance.stubs(:is_a?).with(ActiveRecord::Relation).returns(false)
53
- User.any_instance.stubs(:is_a?).with(ActiveRecord::Base).returns(true)
54
-
55
- assert_equal "#new_user", dom_id(User.new(id: nil))
56
-
57
- user = User.new(id: 42)
58
-
59
- assert_equal "#user_42", dom_id(user)
60
- assert_equal "#user_42", dom_id(user, nil)
61
- assert_equal "#all_active_user_42", dom_id(user, "all_active")
62
-
63
- user = User.new(id: 99)
64
-
65
- assert_equal "#user_99", dom_id(user)
66
- assert_equal "#user_99", dom_id(user, nil)
67
- assert_equal "#all_active_user_99", dom_id(user, "all_active")
68
- end
69
- end
@@ -1,189 +0,0 @@
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.size
59
- assert_equal({"name" => "passed_option", "operation" => "foobar"}, operations.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("[{\"name\":\"passed_option\",\"operation\":\"foobar\"}]", @operation_builder.to_json)
66
- end
67
-
68
- test "should apply! many operations" do
69
- @operation_builder.apply!({name: "passed_option"})
70
-
71
- operations = @operation_builder.instance_variable_get(:@enqueued_operations)
72
- assert_equal 1, operations.size
73
- assert_equal({"name" => "passed_option"}, operations.first)
74
- end
75
-
76
- test "should apply! many operations from a string" do
77
- @operation_builder.apply!(JSON.generate({name: "passed_option"}))
78
-
79
- operations = @operation_builder.instance_variable_get(:@enqueued_operations)
80
- assert_equal 1, operations.size
81
- assert_equal({"name" => "passed_option"}, operations.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([{"operation" => "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 = [{"operation" => "innerHtml", "html" => "<span>I rock</span>", "selector" => "#smelly"}]
102
-
103
- assert_equal(operations, @operation_builder.operations_payload)
104
- end
105
-
106
- test "should use previously passed selector in next operation" do
107
- @operation_builder.add_operation_method("inner_html")
108
- @operation_builder.add_operation_method("set_focus")
109
-
110
- @operation_builder.set_focus("#smelly").inner_html(html: "<span>I rock</span>")
111
-
112
- operations = [
113
- {"operation" => "setFocus", "selector" => "#smelly"},
114
- {"operation" => "innerHtml", "html" => "<span>I rock</span>", "selector" => "#smelly"}
115
- ]
116
-
117
- assert_equal(operations, @operation_builder.operations_payload)
118
- end
119
-
120
- test "should clear previous_selector after calling reset!" do
121
- @operation_builder.add_operation_method("inner_html")
122
- @operation_builder.inner_html(selector: "#smelly", html: "<span>I rock</span>")
123
-
124
- @operation_builder.reset!
125
-
126
- @operation_builder.inner_html(html: "<span>winning</span>")
127
-
128
- assert_equal([{"operation" => "innerHtml", "html" => "<span>winning</span>"}], @operation_builder.operations_payload)
129
- end
130
-
131
- test "should use previous_selector if present and should use `selector` if explicitly provided" do
132
- @operation_builder.add_operation_method("inner_html")
133
- @operation_builder.add_operation_method("set_focus")
134
-
135
- @operation_builder.set_focus("#smelly").inner_html(html: "<span>I rock</span>").inner_html(html: "<span>I rock too</span>", selector: "#smelly2")
136
-
137
- operations = [
138
- {"operation" => "setFocus", "selector" => "#smelly"},
139
- {"operation" => "innerHtml", "html" => "<span>I rock</span>", "selector" => "#smelly"},
140
- {"operation" => "innerHtml", "html" => "<span>I rock too</span>", "selector" => "#smelly2"}
141
- ]
142
-
143
- assert_equal(operations, @operation_builder.operations_payload)
144
- end
145
-
146
- test "should pull html option from Death object" do
147
- @operation_builder.add_operation_method("inner_html")
148
- death = Death.new
149
-
150
- @operation_builder.inner_html(html: death)
151
-
152
- operations = [{"operation" => "innerHtml", "html" => "I rock"}]
153
-
154
- assert_equal(operations, @operation_builder.operations_payload)
155
- end
156
-
157
- test "should pull html option with selector from Death object" do
158
- @operation_builder.add_operation_method("inner_html")
159
- death = Death.new
160
-
161
- @operation_builder.inner_html(death, html: death)
162
-
163
- operations = [{"operation" => "innerHtml", "html" => "I rock", "selector" => "#death"}]
164
-
165
- assert_equal(operations, @operation_builder.operations_payload)
166
- end
167
-
168
- test "should pull html and dom_id options from Death object" do
169
- @operation_builder.add_operation_method("inner_html")
170
- death = Death.new
171
-
172
- @operation_builder.inner_html(death)
173
-
174
- operations = [{"operation" => "innerHtml", "html" => "I rock", "domId" => "death"}]
175
-
176
- assert_equal(operations, @operation_builder.operations_payload)
177
- end
178
-
179
- test "should pull html and dom_id options from Life object" do
180
- @operation_builder.add_operation_method("inner_html")
181
- life = Life.new
182
-
183
- @operation_builder.inner_html(life)
184
-
185
- operations = [{"operation" => "innerHtml", "html" => "You go, girl", "domId" => "life"}]
186
-
187
- assert_equal(operations, @operation_builder.operations_payload)
188
- end
189
- end
@@ -1,135 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "test_helper"
4
-
5
- class CableReady::UpdatableTest < ActiveSupport::TestCase
6
- test "includes the module automatically in associated models" do
7
- user = User.create(name: "John Doe")
8
-
9
- post = user.posts.build
10
- assert post.class < CableReady::Updatable
11
- end
12
-
13
- test "updates the collection when an item is added" do
14
- mock_server = mock("server")
15
- mock_server.expects(:broadcast).with(User, {}).once
16
- mock_server.expects(:broadcast).with("gid://dummy/User/1:posts", {changed: ["id", "title", "user_id", "created_at", "updated_at"]}).once
17
-
18
- ActionCable.stubs(:server).returns(mock_server)
19
- user = User.create(name: "John Doe")
20
-
21
- user.posts.create(title: "Lorem")
22
- end
23
-
24
- test "updates the collection when an item is destroyed" do
25
- user = User.create(name: "John Doe")
26
- post = user.posts.create(title: "Lorem")
27
-
28
- mock_server = mock("server")
29
- mock_server.expects(:broadcast).with("gid://dummy/User/1:posts", {changed: ["id", "title", "user_id", "created_at", "updated_at"]}).once
30
-
31
- ActionCable.stubs(:server).returns(mock_server)
32
-
33
- post.destroy
34
- end
35
-
36
- test "updates the collection when an item is updated" do
37
- user = User.create(name: "John Doe")
38
- post = user.posts.create(title: "Lorem")
39
-
40
- mock_server = mock("server")
41
- mock_server.expects(:broadcast).with("gid://dummy/User/1:posts", {changed: ["title", "updated_at"]}).once
42
-
43
- ActionCable.stubs(:server).returns(mock_server)
44
-
45
- post.update(title: "Ipsum")
46
- end
47
-
48
- test "updates the model when it is updated" do
49
- user = User.create(name: "John Doe")
50
-
51
- mock_server = mock("server")
52
- mock_server.expects(:broadcast).with(User, {}).once
53
- mock_server.expects(:broadcast).with(user.to_global_id, {changed: ["name", "updated_at"]}).once
54
-
55
- ActionCable.stubs(:server).returns(mock_server)
56
-
57
- user.update(name: "Jane Doe")
58
- end
59
-
60
- test "updates the parent when it is touched" do
61
- team = Team.create
62
- user = team.users.create(name: "Ada Lovelace")
63
-
64
- mock_server = mock("server")
65
- mock_server.expects(:broadcast).with(User, {}).once
66
- mock_server.expects(:broadcast).with(user.to_global_id, {changed: ["name", "updated_at"]}).once
67
- mock_server.expects(:broadcast).with("gid://dummy/Team/1:users", {changed: ["name", "updated_at"]}).once
68
- mock_server.expects(:broadcast).with(Team, {}).once
69
- mock_server.expects(:broadcast).with(team.to_global_id, {changed: ["id", "created_at", "updated_at"]}).once
70
-
71
- ActionCable.stubs(:server).returns(mock_server)
72
-
73
- user.update(name: "Jane Doe")
74
- end
75
-
76
- test "respects :on to specify persistence methods" do
77
- mock_server = mock("server")
78
-
79
- ActionCable.stubs(:server).returns(mock_server)
80
-
81
- mock_server.expects(:broadcast).with(Topic, {}).once
82
- topic = Topic.create(title: "Reactive Rails with Hotwire")
83
-
84
- mock_server.expects(:broadcast).with(topic.to_global_id, {}).never
85
- topic.update(title: "Reactive Rails with CableReady")
86
- end
87
-
88
- test "respects :if on enable_updates" do
89
- mock_server = mock("server")
90
-
91
- ActionCable.stubs(:server).returns(mock_server)
92
-
93
- section = Section.create
94
- section.updates_enabled = true
95
-
96
- mock_server.expects(:broadcast).with(Section, {}).once
97
- mock_server.expects(:broadcast).with(section.to_global_id, {changed: ["title", "updated_at", "updates_enabled"]}).once
98
- section.update(title: "First Section")
99
- end
100
-
101
- test "updates any GlobalID-able entity" do
102
- entity = GlobalIdableEntity.new
103
-
104
- mock_server = mock("server")
105
- mock_server.expects(:broadcast).with(GlobalIdableEntity, {}).once
106
- mock_server.expects(:broadcast).with(entity.to_global_id, {}).once
107
-
108
- ActionCable.stubs(:server).returns(mock_server)
109
-
110
- entity.fake_update
111
- end
112
-
113
- test "updates the collection when a file is attached" do
114
- mock_server = mock("server")
115
- image = File.open(Rails.root.join("test", "fixtures", "files", "dugong.jpg"))
116
- dugong = Dugong.create
117
-
118
- mock_server.expects(:broadcast).with("gid://dummy/Dugong/1:images", {changed: ["id", "name", "record_type", "record_id", "blob_id", "created_at"]}).once
119
- ActionCable.stubs(:server).returns(mock_server)
120
-
121
- dugong.images.attach(io: image, filename: "dugong.jpg")
122
- end
123
-
124
- test "updates the collection when a file is destroyed" do
125
- mock_server = mock("server")
126
- image = File.open(Rails.root.join("test", "fixtures", "files", "dugong.jpg"))
127
- dugong = Dugong.create
128
- dugong.images.attach(io: image, filename: "dugong.jpg")
129
-
130
- mock_server.expects(:broadcast).with("gid://dummy/Dugong/1:images", {changed: ["id", "name", "record_type", "record_id", "blob_id", "created_at"]}).once
131
- ActionCable.stubs(:server).returns(mock_server)
132
-
133
- dugong.images.first.destroy
134
- end
135
- end
@@ -1,157 +0,0 @@
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
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GeneratorTestHelpers
4
- def self.included(base)
5
- base.extend ClassMethods
6
- end
7
-
8
- module ClassMethods
9
- def sample_app_path
10
- File.expand_path("../../tmp/dummy", __dir__)
11
- end
12
-
13
- def prepare_destination
14
- FileUtils.rm_rf(sample_app_path) if Dir.exist?(sample_app_path)
15
- FileUtils.mkdir_p(sample_app_path)
16
- end
17
-
18
- def create_sample_app
19
- FileUtils.cd(sample_app_path) do
20
- system "rails new . --minimal --skip-active-record --skip-test-unit --skip-spring --skip-bundle --quiet --force"
21
- end
22
- end
23
-
24
- def remove_sample_app
25
- FileUtils.rm_rf(destination_root)
26
- end
27
- end
28
- end