cable_ready 4.5.0 → 5.0.0.pre0
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/CHANGELOG.md +194 -161
- data/Gemfile.lock +122 -85
- data/LATEST +1 -0
- data/README.md +9 -9
- data/Rakefile +8 -2
- data/bin/standardize +1 -1
- data/cable_ready.gemspec +2 -1
- data/lib/cable_ready.rb +37 -5
- data/lib/cable_ready/broadcaster.rb +3 -4
- data/lib/cable_ready/cable_car.rb +17 -0
- data/lib/cable_ready/channel.rb +12 -32
- data/lib/cable_ready/channels.rb +4 -7
- data/lib/cable_ready/compoundable.rb +11 -0
- data/lib/cable_ready/config.rb +15 -5
- data/lib/cable_ready/identifiable.rb +19 -0
- data/lib/cable_ready/operation_builder.rb +69 -0
- data/lib/cable_ready/sanity_checker.rb +151 -0
- data/lib/cable_ready/stream_identifier.rb +13 -0
- data/lib/cable_ready/version.rb +1 -1
- data/lib/generators/cable_ready/channel_generator.rb +71 -0
- data/lib/generators/cable_ready/initializer_generator.rb +14 -0
- data/lib/generators/cable_ready/stream_from_generator.rb +43 -0
- data/lib/generators/cable_ready/templates/config/initializers/cable_ready.rb +18 -0
- data/package.json +8 -5
- data/tags +21 -3
- data/test/lib/cable_ready/cable_car_test.rb +28 -0
- data/test/lib/cable_ready/identifiable_test.rb +75 -0
- data/test/lib/cable_ready/operation_builder_test.rb +128 -0
- data/test/lib/generators/cable_ready/channel_generator_test.rb +157 -0
- data/test/support/generator_test_helpers.rb +28 -0
- data/test/test_helper.rb +15 -0
- data/yarn.lock +134 -124
- metadata +44 -7
data/lib/cable_ready/version.rb
CHANGED
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CableReady::ChannelGenerator < Rails::Generators::NamedBase
|
4
|
+
source_root File.expand_path("templates", __dir__)
|
5
|
+
|
6
|
+
class_option :stream_from, type: :string
|
7
|
+
class_option :stream_for, type: :string
|
8
|
+
class_option :stimulus, type: :boolean
|
9
|
+
|
10
|
+
def check_options
|
11
|
+
raise "Can't specify --stream-from and --stream-for at the same time" if options.key?(:stream_from) && options.key?(:stream_for)
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_channel
|
15
|
+
generate "channel", file_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def enhance_channels
|
19
|
+
if using_broadcast_to?
|
20
|
+
gsub_file "app/channels/#{file_name}_channel.rb", /# stream_from.*\n/, "stream_for #{resource}.find(params[:id])\n"
|
21
|
+
template "app/javascript/controllers/%file_name%_controller.js" if using_stimulus?
|
22
|
+
else
|
23
|
+
prepend_to_file "app/javascript/channels/#{file_name}_channel.js", "import CableReady from 'cable_ready'\n"
|
24
|
+
inject_into_file "app/javascript/channels/#{file_name}_channel.js", after: "// Called when there's incoming data on the websocket for this channel\n" do
|
25
|
+
<<-JS
|
26
|
+
if (data.cableReady) CableReady.perform(data.operations)
|
27
|
+
JS
|
28
|
+
end
|
29
|
+
|
30
|
+
gsub_file "app/channels/#{file_name}_channel.rb", /# stream_from.*\n/, "stream_from \"#{identifier}\"\n"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def option_given?
|
37
|
+
options.key?(:stream_from) || options.key?(:stream_for)
|
38
|
+
end
|
39
|
+
|
40
|
+
def using_broadcast_to?
|
41
|
+
@using_broadcast_to ||= option_given? ? options.key?(:stream_for) : yes?("Are you streaming to a resource using broadcast_to? (y/N)")
|
42
|
+
end
|
43
|
+
|
44
|
+
def using_stimulus?
|
45
|
+
@using_stimulus ||= options.fetch(:stimulus) {
|
46
|
+
yes?("Are you going to use a Stimulus controller to subscribe to this channel? (y/N)")
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def resource
|
51
|
+
return @resource if @resource
|
52
|
+
|
53
|
+
stream_for = options.fetch(:stream_for) {
|
54
|
+
ask("Which resource are you streaming for?", default: class_name)
|
55
|
+
}
|
56
|
+
|
57
|
+
stream_for = file_name if stream_for == "stream_for"
|
58
|
+
@resource = stream_for.camelize
|
59
|
+
end
|
60
|
+
|
61
|
+
def identifier
|
62
|
+
return @identifier if @identifier
|
63
|
+
|
64
|
+
stream_from = options.fetch(:stream_from) {
|
65
|
+
ask("What is the stream identifier that goes into stream_from?", default: file_name)
|
66
|
+
}
|
67
|
+
|
68
|
+
stream_from = file_name if stream_from == "stream_from"
|
69
|
+
@identifier = stream_from.underscore
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
|
5
|
+
module CableReady
|
6
|
+
class InitializerGenerator < Rails::Generators::Base
|
7
|
+
desc "Creates a CableReady initializer template in config/initializers"
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
def copy_initializer_file
|
11
|
+
copy_file "config/initializers/cable_ready.rb"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
module CableReady
|
7
|
+
class StreamFromGenerator < Rails::Generators::Base
|
8
|
+
desc "Initializes CableReady with a reference to the shared ActionCable consumer"
|
9
|
+
source_root File.expand_path("templates", __dir__)
|
10
|
+
|
11
|
+
def copy_controller_file
|
12
|
+
main_folder = defined?(Webpacker) ? Webpacker.config.source_path.to_s.gsub("#{Rails.root}/", "") : "app/javascript"
|
13
|
+
|
14
|
+
filepath = [
|
15
|
+
"#{main_folder}/controllers/index.js",
|
16
|
+
"#{main_folder}/controllers/index.ts",
|
17
|
+
"#{main_folder}/packs/application.js",
|
18
|
+
"#{main_folder}/packs/application.ts"
|
19
|
+
]
|
20
|
+
.select { |path| File.exist?(path) }
|
21
|
+
.map { |path| Rails.root.join(path) }
|
22
|
+
.first
|
23
|
+
|
24
|
+
lines = File.open(filepath, "r") { |f| f.readlines }
|
25
|
+
|
26
|
+
unless lines.find { |line| line.start_with?("import CableReady") }
|
27
|
+
matches = lines.select { |line| line =~ /\A(require|import)/ }
|
28
|
+
lines.insert lines.index(matches.last).to_i + 1, "import CableReady from 'cable_ready'\n"
|
29
|
+
File.open(filepath, "w") { |f| f.write lines.join }
|
30
|
+
end
|
31
|
+
|
32
|
+
unless lines.find { |line| line.start_with?("import consumer") }
|
33
|
+
matches = lines.select { |line| line =~ /\A(require|import)/ }
|
34
|
+
lines.insert lines.index(matches.last).to_i + 1, "import consumer from '../channels/consumer'\n"
|
35
|
+
File.open(filepath, "w") { |f| f.write lines.join }
|
36
|
+
end
|
37
|
+
|
38
|
+
unless lines.find { |line| line.include?("CableReady.initialize({ consumer })") }
|
39
|
+
append_to_file filepath, "CableReady.initialize({ consumer })"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
CableReady.configure do |config|
|
4
|
+
# Enable/disable exiting / warning when the sanity checks fail options:
|
5
|
+
# `:exit` or `:warn` or `:ignore`
|
6
|
+
|
7
|
+
# config.on_failed_sanity_checks = :exit
|
8
|
+
|
9
|
+
# Enable/disable exiting / warning when there's a new CableReady release
|
10
|
+
# `:exit` or `:warn` or `:ignore`
|
11
|
+
|
12
|
+
# config.on_new_version_available = :ignore
|
13
|
+
|
14
|
+
# Define your own custom operations
|
15
|
+
# https://cableready.stimulusreflex.com/customization#custom-operations
|
16
|
+
|
17
|
+
# config.add_operation_name :jazz_hands
|
18
|
+
end
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "cable_ready",
|
3
|
-
"version": "4.
|
3
|
+
"version": "4.5.0",
|
4
4
|
"description": "CableReady helps you create great real-time user experiences by making it simple to trigger client-side DOM changes from server-side Ruby.",
|
5
5
|
"keywords": [
|
6
6
|
"ruby",
|
@@ -15,17 +15,20 @@
|
|
15
15
|
],
|
16
16
|
"homepage": "https://cableready.stimulusreflex.com/",
|
17
17
|
"bugs": {
|
18
|
-
"url": "https://github.com/
|
18
|
+
"url": "https://github.com/stimulusreflex/cable_ready/issues"
|
19
19
|
},
|
20
20
|
"repository": {
|
21
21
|
"type": "git",
|
22
|
-
"url": "git+https://github.com:
|
22
|
+
"url": "git+https://github.com:stimulusreflex/cable_ready.git"
|
23
23
|
},
|
24
24
|
"license": "MIT",
|
25
25
|
"author": "Nathan Hopkins <natehop@gmail.com>",
|
26
|
-
"main": "./javascript/
|
26
|
+
"main": "./javascript/index.js",
|
27
27
|
"scripts": {
|
28
|
-
"
|
28
|
+
"lint": "yarn run prettier-standard:check",
|
29
|
+
"format": "yarn run prettier-standard:format",
|
30
|
+
"prettier-standard:check": "yarn run prettier-standard --check ./javascript/**/*.js",
|
31
|
+
"prettier-standard:format": "yarn run prettier-standard ./javascript/**/*.js"
|
29
32
|
},
|
30
33
|
"dependencies": {
|
31
34
|
"morphdom": "^2.6.1"
|
data/tags
CHANGED
@@ -11,28 +11,35 @@ CableReady lib/cable_ready/channel.rb /^module CableReady$/;" m
|
|
11
11
|
CableReady lib/cable_ready/channels.rb /^module CableReady$/;" m
|
12
12
|
CableReady lib/cable_ready/config.rb /^module CableReady$/;" m
|
13
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
|
14
16
|
Channel lib/cable_ready/channel.rb /^ class Channel$/;" c class:CableReady
|
15
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
|
16
19
|
Config lib/cable_ready/config.rb /^ class Config$/;" c class:CableReady
|
17
20
|
Engine lib/cable_ready.rb /^ class Engine < Rails::Engine$/;" c class:CableReady
|
21
|
+
GeneratorTestHelpers test/support/generator_test_helpers.rb /^module GeneratorTestHelpers$/;" m
|
18
22
|
[] lib/cable_ready/channels.rb /^ def [](identifier)$/;" f class:CableReady.Channels
|
19
|
-
add_operation_definition lib/cable_ready/config.rb /^ def add_operation_definition(name)$/;" f class:CableReady.Config
|
20
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
|
21
25
|
broadcast lib/cable_ready/channel.rb /^ def broadcast(clear: true)$/;" f class:CableReady.Channel
|
22
26
|
broadcast lib/cable_ready/channels.rb /^ def broadcast(*identifiers, clear: true)$/;" f class:CableReady.Channels
|
23
27
|
broadcast_to lib/cable_ready/channel.rb /^ def broadcast_to(model, clear: true)$/;" f class:CableReady.Channel
|
24
28
|
broadcast_to lib/cable_ready/channels.rb /^ def broadcast_to(model, *identifiers, clear: true)$/;" f class:CableReady.Channels
|
25
29
|
broadcastable_operations lib/cable_ready/channel.rb /^ def broadcastable_operations$/;" f class:CableReady.Channel
|
26
30
|
cable_ready lib/cable_ready/broadcaster.rb /^ def cable_ready$/;" f class:CableReady.Broadcaster
|
31
|
+
check_options lib/generators/cable_ready/channel_generator.rb /^ def check_options$/;" f class:CableReady
|
27
32
|
config lib/cable_ready.rb /^ def self.config$/;" F class:CableReady
|
28
33
|
configure lib/cable_ready.rb /^ def self.configure$/;" F class:CableReady
|
29
34
|
const.bubbles javascript/utils.js /^ const init = { bubbles: true, cancelable: true, detail: detail }$/;" p
|
30
35
|
const.cancelable javascript/utils.js /^ const init = { bubbles: true, cancelable: true, detail: detail }$/;" p
|
31
36
|
const.detail javascript/utils.js /^ const init = { bubbles: true, cancelable: true, detail: detail }$/;" p
|
32
|
-
const.
|
33
|
-
|
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
|
34
40
|
default_operation_names lib/cable_ready/config.rb /^ def default_operation_names$/;" f class:CableReady.Config
|
35
41
|
dom_id lib/cable_ready/broadcaster.rb /^ def dom_id(record, prefix = nil)$/;" f class:CableReady.Broadcaster
|
42
|
+
enhance_channels lib/generators/cable_ready/channel_generator.rb /^ def enhance_channels$/;" f class:CableReady
|
36
43
|
export.INPUT javascript/enums.js /^ INPUT: true,$/;" p
|
37
44
|
export.OPTION javascript/enums.js /^ OPTION: true$/;" p
|
38
45
|
export.SELECT javascript/enums.js /^ SELECT: true$/;" p
|
@@ -55,8 +62,19 @@ export.textarea javascript/enums.js /^ textarea: true,$/;" p
|
|
55
62
|
export.time javascript/enums.js /^ time: true,$/;" p
|
56
63
|
export.url javascript/enums.js /^ url: true,$/;" p
|
57
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
|
58
68
|
initialize lib/cable_ready/channel.rb /^ def initialize(identifier)$/;" f class:CableReady.Channel
|
59
69
|
initialize lib/cable_ready/channels.rb /^ def initialize$/;" f class:CableReady.Channels
|
60
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
|
61
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
|
62
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,28 @@
|
|
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
|
+
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,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
require_relative "../../../lib/cable_ready"
|
5
|
+
|
6
|
+
class CableReady::OperationBuilderTest < ActiveSupport::TestCase
|
7
|
+
setup do
|
8
|
+
@operation_builder = CableReady::OperationBuilder.new("test")
|
9
|
+
end
|
10
|
+
|
11
|
+
test "should create enqueued operations" do
|
12
|
+
assert_not_nil @operation_builder.instance_variable_get(:@enqueued_operations)
|
13
|
+
end
|
14
|
+
|
15
|
+
test "should add observer to cable ready" do
|
16
|
+
assert_not_nil CableReady.config.instance_variable_get(:@observer_peers)[@operation_builder]
|
17
|
+
end
|
18
|
+
|
19
|
+
test "should remove observer when destroyed" do
|
20
|
+
@operation_builder = nil
|
21
|
+
assert_nil CableReady.config.instance_variable_get(:@observer_peers)[@operation_builder]
|
22
|
+
end
|
23
|
+
|
24
|
+
test "should add operation method" do
|
25
|
+
@operation_builder.add_operation_method("foobar")
|
26
|
+
assert @operation_builder.respond_to?(:foobar)
|
27
|
+
end
|
28
|
+
|
29
|
+
test "added operation method should add keys" do
|
30
|
+
@operation_builder.add_operation_method("foobar")
|
31
|
+
@operation_builder.foobar({name: "passed_option"})
|
32
|
+
|
33
|
+
operations = @operation_builder.instance_variable_get(:@enqueued_operations)
|
34
|
+
|
35
|
+
assert_equal 1, operations["foobar"].size
|
36
|
+
assert_equal({"name" => "passed_option"}, operations["foobar"].first)
|
37
|
+
end
|
38
|
+
|
39
|
+
test "should json-ify operations" do
|
40
|
+
@operation_builder.add_operation_method("foobar")
|
41
|
+
@operation_builder.foobar({name: "passed_option"})
|
42
|
+
assert_equal("{\"foobar\":[{\"name\":\"passed_option\"}]}", @operation_builder.to_json)
|
43
|
+
end
|
44
|
+
|
45
|
+
test "should apply! many operations" do
|
46
|
+
@operation_builder.apply!(foobar: [{name: "passed_option"}])
|
47
|
+
|
48
|
+
operations = @operation_builder.instance_variable_get(:@enqueued_operations)
|
49
|
+
assert_equal 1, operations["foobar"].size
|
50
|
+
assert_equal({"name" => "passed_option"}, operations["foobar"].first)
|
51
|
+
end
|
52
|
+
|
53
|
+
test "should apply! many operations from a string" do
|
54
|
+
@operation_builder.apply!(JSON.generate({foobar: [{name: "passed_option"}]}))
|
55
|
+
|
56
|
+
operations = @operation_builder.instance_variable_get(:@enqueued_operations)
|
57
|
+
assert_equal 1, operations["foobar"].size
|
58
|
+
assert_equal({"name" => "passed_option"}, operations["foobar"].first)
|
59
|
+
end
|
60
|
+
|
61
|
+
test "operations payload should omit empty operations" do
|
62
|
+
@operation_builder.add_operation_method("foobar")
|
63
|
+
payload = @operation_builder.operations_payload
|
64
|
+
assert_equal({}, payload)
|
65
|
+
end
|
66
|
+
|
67
|
+
test "operations payload should camelize keys" do
|
68
|
+
@operation_builder.add_operation_method("foo_bar")
|
69
|
+
@operation_builder.foo_bar({beep_boop: "passed_option"})
|
70
|
+
assert_equal({"fooBar" => [{"beepBoop" => "passed_option"}]}, @operation_builder.operations_payload)
|
71
|
+
end
|
72
|
+
|
73
|
+
test "should take first argument as selector" do
|
74
|
+
@operation_builder.add_operation_method("inner_html")
|
75
|
+
|
76
|
+
@operation_builder.inner_html("#smelly", html: "<span>I rock</span>")
|
77
|
+
|
78
|
+
operations = {
|
79
|
+
"innerHtml" => [{"html" => "<span>I rock</span>", "selector" => "#smelly"}]
|
80
|
+
}
|
81
|
+
|
82
|
+
assert_equal(operations, @operation_builder.operations_payload)
|
83
|
+
end
|
84
|
+
|
85
|
+
test "should use previously passed selector in next operation" do
|
86
|
+
@operation_builder.add_operation_method("inner_html")
|
87
|
+
@operation_builder.add_operation_method("set_focus")
|
88
|
+
|
89
|
+
@operation_builder.set_focus("#smelly").inner_html(html: "<span>I rock</span>")
|
90
|
+
|
91
|
+
operations = {
|
92
|
+
"setFocus" => [{"selector" => "#smelly"}],
|
93
|
+
"innerHtml" => [{"html" => "<span>I rock</span>", "selector" => "#smelly"}]
|
94
|
+
}
|
95
|
+
|
96
|
+
assert_equal(operations, @operation_builder.operations_payload)
|
97
|
+
end
|
98
|
+
|
99
|
+
test "should clear previous_selector after calling reset!" do
|
100
|
+
@operation_builder.add_operation_method("inner_html")
|
101
|
+
@operation_builder.inner_html(selector: "#smelly", html: "<span>I rock</span>")
|
102
|
+
|
103
|
+
@operation_builder.reset!
|
104
|
+
|
105
|
+
@operation_builder.inner_html(html: "<span>winning</span>")
|
106
|
+
|
107
|
+
assert_equal({"innerHtml" => [{"html" => "<span>winning</span>"}]}, @operation_builder.operations_payload)
|
108
|
+
end
|
109
|
+
|
110
|
+
test "should use previous_selector if present and should use `selector` if explicitly provided" do
|
111
|
+
@operation_builder.add_operation_method("inner_html")
|
112
|
+
@operation_builder.add_operation_method("set_focus")
|
113
|
+
|
114
|
+
@operation_builder.set_focus("#smelly").inner_html(html: "<span>I rock</span>").inner_html(html: "<span>I rock too</span>", selector: "#smelly2")
|
115
|
+
|
116
|
+
operations = {
|
117
|
+
"setFocus" => [
|
118
|
+
{"selector" => "#smelly"}
|
119
|
+
],
|
120
|
+
"innerHtml" => [
|
121
|
+
{"html" => "<span>I rock</span>", "selector" => "#smelly"},
|
122
|
+
{"html" => "<span>I rock too</span>", "selector" => "#smelly2"}
|
123
|
+
]
|
124
|
+
}
|
125
|
+
|
126
|
+
assert_equal(operations, @operation_builder.operations_payload)
|
127
|
+
end
|
128
|
+
end
|