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.
- checksums.yaml +4 -4
- data/Gemfile +4 -1
- data/Gemfile.lock +119 -100
- data/README.md +2 -5
- data/app/assets/javascripts/cable_ready.js +457 -151
- data/app/assets/javascripts/cable_ready.min.js +1 -1
- data/app/assets/javascripts/cable_ready.min.js.map +1 -1
- data/app/assets/javascripts/cable_ready.umd.js +441 -165
- data/app/assets/javascripts/cable_ready.umd.min.js +1 -1
- data/app/assets/javascripts/cable_ready.umd.min.js.map +1 -1
- data/app/channels/cable_ready/stream.rb +7 -5
- data/app/helpers/cable_ready/view_helper.rb +58 -0
- data/app/jobs/cable_ready_broadcast_job.rb +9 -8
- data/app/models/concerns/cable_ready/updatable/collection_updatable_callbacks.rb +2 -0
- data/app/models/concerns/cable_ready/updatable/collections_registry.rb +2 -0
- data/app/models/concerns/cable_ready/updatable/model_updatable_callbacks.rb +5 -2
- data/app/models/concerns/cable_ready/updatable.rb +67 -19
- data/app/models/concerns/extend_has_many.rb +2 -0
- data/cable_ready.gemspec +4 -6
- data/lib/cable_ready/broadcaster.rb +2 -0
- data/lib/cable_ready/cable_car.rb +2 -0
- data/lib/cable_ready/channel.rb +12 -4
- data/lib/cable_ready/channels.rb +3 -1
- data/lib/cable_ready/config.rb +16 -2
- data/lib/cable_ready/engine.rb +19 -9
- data/lib/cable_ready/identifiable.rb +23 -5
- data/lib/cable_ready/importmap.rb +2 -0
- data/lib/cable_ready/installer.rb +224 -0
- data/lib/cable_ready/operation_builder.rb +1 -1
- data/lib/cable_ready/sanity_checker.rb +1 -31
- data/lib/cable_ready/version.rb +1 -1
- data/lib/cable_ready.rb +3 -8
- data/lib/cable_ready_helper.rb +13 -0
- data/lib/generators/cable_ready/channel_generator.rb +51 -12
- data/lib/generators/cable_ready/templates/config/initializers/cable_ready.rb +10 -6
- data/lib/install/action_cable.rb +144 -0
- data/lib/install/broadcaster.rb +109 -0
- data/lib/install/bundle.rb +54 -0
- data/lib/install/compression.rb +51 -0
- data/lib/install/config.rb +39 -0
- data/lib/install/development.rb +34 -0
- data/lib/install/esbuild.rb +101 -0
- data/lib/install/importmap.rb +96 -0
- data/lib/install/initializers.rb +15 -0
- data/lib/install/mrujs.rb +121 -0
- data/lib/install/npm_packages.rb +13 -0
- data/lib/install/shakapacker.rb +61 -0
- data/lib/install/spring.rb +54 -0
- data/lib/install/updatable.rb +34 -0
- data/lib/install/vite.rb +62 -0
- data/lib/install/webpacker.rb +81 -0
- data/lib/install/yarn.rb +56 -0
- data/lib/tasks/cable_ready/cable_ready.rake +249 -0
- data/package.json +28 -18
- data/{rollup.config.js → rollup.config.mjs} +9 -8
- data/web-test-runner.config.mjs +12 -0
- data/yarn.lock +2210 -404
- metadata +37 -161
- data/LATEST +0 -1
- data/app/helpers/cable_ready_helper.rb +0 -26
- data/lib/generators/cable_ready/helpers_generator.rb +0 -43
- data/lib/generators/cable_ready/initializer_generator.rb +0 -14
- data/test/dummy/app/channels/application_cable/channel.rb +0 -4
- data/test/dummy/app/channels/application_cable/connection.rb +0 -4
- data/test/dummy/app/controllers/application_controller.rb +0 -2
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/jobs/application_job.rb +0 -7
- data/test/dummy/app/mailers/application_mailer.rb +0 -4
- data/test/dummy/app/models/application_record.rb +0 -3
- data/test/dummy/app/models/dugong.rb +0 -4
- data/test/dummy/app/models/global_idable_entity.rb +0 -16
- data/test/dummy/app/models/post.rb +0 -4
- data/test/dummy/app/models/section.rb +0 -6
- data/test/dummy/app/models/team.rb +0 -6
- data/test/dummy/app/models/topic.rb +0 -4
- data/test/dummy/app/models/user.rb +0 -7
- data/test/dummy/config/application.rb +0 -22
- data/test/dummy/config/boot.rb +0 -5
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -76
- data/test/dummy/config/environments/production.rb +0 -120
- data/test/dummy/config/environments/test.rb +0 -59
- data/test/dummy/config/initializers/application_controller_renderer.rb +0 -8
- data/test/dummy/config/initializers/assets.rb +0 -12
- data/test/dummy/config/initializers/backtrace_silencers.rb +0 -8
- data/test/dummy/config/initializers/cable_ready.rb +0 -18
- data/test/dummy/config/initializers/content_security_policy.rb +0 -28
- data/test/dummy/config/initializers/cookies_serializer.rb +0 -5
- data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -6
- data/test/dummy/config/initializers/inflections.rb +0 -16
- data/test/dummy/config/initializers/mime_types.rb +0 -4
- data/test/dummy/config/initializers/permissions_policy.rb +0 -11
- data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/test/dummy/config/puma.rb +0 -43
- data/test/dummy/config/routes.rb +0 -3
- data/test/dummy/db/migrate/20210902154139_create_users.rb +0 -9
- data/test/dummy/db/migrate/20210902154153_create_posts.rb +0 -10
- data/test/dummy/db/migrate/20210904081930_create_topics.rb +0 -9
- data/test/dummy/db/migrate/20210904093607_create_sections.rb +0 -9
- data/test/dummy/db/migrate/20210913191735_create_teams.rb +0 -8
- data/test/dummy/db/migrate/20210913191759_add_team_reference_to_users.rb +0 -5
- data/test/dummy/db/migrate/20220329222959_create_dugongs.rb +0 -8
- data/test/dummy/db/migrate/20220329230221_create_active_storage_tables.active_storage.rb +0 -36
- data/test/dummy/db/schema.rb +0 -84
- data/test/dummy/test/models/dugong_test.rb +0 -7
- data/test/dummy/test/models/post_test.rb +0 -7
- data/test/dummy/test/models/section_test.rb +0 -7
- data/test/dummy/test/models/team_test.rb +0 -7
- data/test/dummy/test/models/topic_test.rb +0 -7
- data/test/dummy/test/models/user_test.rb +0 -7
- data/test/lib/cable_ready/cable_car_test.rb +0 -50
- data/test/lib/cable_ready/compoundable_test.rb +0 -26
- data/test/lib/cable_ready/helper_test.rb +0 -25
- data/test/lib/cable_ready/identifiable_test.rb +0 -69
- data/test/lib/cable_ready/operation_builder_test.rb +0 -189
- data/test/lib/cable_ready/updatable_test.rb +0 -135
- data/test/lib/generators/cable_ready/channel_generator_test.rb +0 -157
- data/test/support/generator_test_helpers.rb +0 -28
- 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
|