hyper-react 0.99.6 → 1.0.0.lap21
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 +5 -5
- data/.codeclimate.yml +27 -0
- data/.gitignore +30 -37
- data/.rubocop.yml +1159 -0
- data/.travis.yml +32 -0
- data/Appraisals +31 -0
- data/CHANGELOG.md +143 -0
- data/DOCS.md +1515 -0
- data/Gemfile +2 -5
- data/LICENSE +19 -0
- data/README.md +5 -33
- data/Rakefile +25 -6
- data/UPGRADING.md +24 -0
- data/component-name-lookup.md +145 -0
- data/dciy.toml +3 -0
- data/dciy_prepare.sh +8 -0
- data/dciy_run.sh +10 -0
- data/hyper-react.gemspec +24 -18
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +3 -0
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/server_rendering.js +5 -0
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +2 -0
- data/lib/generators/reactive_ruby/test_app/templates/boot.rb.erb +6 -0
- data/lib/generators/reactive_ruby/test_app/templates/script/rails +5 -0
- data/lib/generators/reactive_ruby/test_app/templates/test_application.rb.erb +13 -0
- data/lib/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +11 -0
- data/lib/generators/reactive_ruby/test_app/templates/views/components/todo.rb +14 -0
- data/lib/generators/reactive_ruby/test_app/templates/views/layouts/test_layout.html.erb +0 -0
- data/lib/generators/reactive_ruby/test_app/test_app_generator.rb +117 -0
- data/lib/hyper-react.rb +66 -4
- data/lib/rails-helpers/top_level_rails_component.rb +75 -0
- data/lib/react/api.rb +203 -0
- data/lib/react/callbacks.rb +41 -0
- data/lib/react/children.rb +30 -0
- data/lib/react/component.rb +177 -0
- data/lib/react/component/api.rb +69 -0
- data/lib/react/component/base.rb +13 -0
- data/lib/react/component/class_methods.rb +181 -0
- data/lib/react/component/dsl_instance_methods.rb +23 -0
- data/lib/react/component/params.rb +6 -0
- data/lib/react/component/props_wrapper.rb +78 -0
- data/lib/react/component/should_component_update.rb +99 -0
- data/lib/react/component/tags.rb +108 -0
- data/lib/react/config.rb +5 -0
- data/lib/react/config/client.rb.erb +19 -0
- data/lib/react/config/server.rb +23 -0
- data/lib/react/element.rb +150 -0
- data/lib/react/event.rb +76 -0
- data/lib/react/ext/hash.rb +9 -0
- data/lib/react/ext/opal-jquery/element.rb +26 -0
- data/lib/react/ext/string.rb +8 -0
- data/lib/react/hash.rb +13 -0
- data/lib/react/native_library.rb +87 -0
- data/lib/react/object.rb +15 -0
- data/lib/react/react-source-browser.rb +3 -0
- data/lib/react/react-source-server.rb +3 -0
- data/lib/react/react-source.rb +16 -0
- data/lib/react/ref_callback.rb +31 -0
- data/lib/react/rendering_context.rb +146 -0
- data/lib/react/server.rb +19 -0
- data/lib/react/state_wrapper.rb +23 -0
- data/lib/react/test.rb +16 -0
- data/lib/react/test/dsl.rb +17 -0
- data/lib/react/test/matchers/render_html_matcher.rb +56 -0
- data/lib/react/test/rspec.rb +15 -0
- data/lib/react/test/session.rb +37 -0
- data/lib/react/test/utils.rb +71 -0
- data/lib/react/top_level.rb +110 -0
- data/lib/react/top_level_render.rb +28 -0
- data/lib/react/validator.rb +136 -0
- data/lib/reactive-ruby/component_loader.rb +43 -0
- data/lib/reactive-ruby/isomorphic_helpers.rb +235 -0
- data/lib/reactive-ruby/rails.rb +8 -0
- data/lib/reactive-ruby/rails/component_mount.rb +48 -0
- data/lib/reactive-ruby/rails/controller_helper.rb +14 -0
- data/lib/reactive-ruby/rails/railtie.rb +20 -0
- data/lib/reactive-ruby/serializers.rb +15 -0
- data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +41 -0
- data/lib/reactive-ruby/server_rendering/hyper_asset_container.rb +46 -0
- data/lib/reactive-ruby/version.rb +3 -0
- data/lib/reactrb/auto-import.rb +27 -0
- data/logo1.png +0 -0
- data/logo2.png +0 -0
- data/logo3.png +0 -0
- data/path_release_steps.md +9 -0
- data/spec/controller_helper_spec.rb +35 -0
- data/spec/index.html.erb +11 -0
- data/spec/react/callbacks_spec.rb +142 -0
- data/spec/react/children_spec.rb +132 -0
- data/spec/react/component/base_spec.rb +36 -0
- data/spec/react/component_spec.rb +1073 -0
- data/spec/react/dsl_spec.rb +323 -0
- data/spec/react/element_spec.rb +132 -0
- data/spec/react/event_spec.rb +39 -0
- data/spec/react/native_library_spec.rb +387 -0
- data/spec/react/observable_spec.rb +31 -0
- data/spec/react/opal_jquery_extensions_spec.rb +68 -0
- data/spec/react/param_declaration_spec.rb +253 -0
- data/spec/react/react_spec.rb +278 -0
- data/spec/react/refs_callback_spec.rb +65 -0
- data/spec/react/server_spec.rb +25 -0
- data/spec/react/state_spec.rb +52 -0
- data/spec/react/test/dsl_spec.rb +43 -0
- data/spec/react/test/matchers/render_html_matcher_spec.rb +83 -0
- data/spec/react/test/rspec_spec.rb +62 -0
- data/spec/react/test/session_spec.rb +88 -0
- data/spec/react/test/utils_spec.rb +28 -0
- data/spec/react/top_level_component_spec.rb +103 -0
- data/spec/react/tutorial/tutorial_spec.rb +42 -0
- data/spec/react/validator_spec.rb +134 -0
- data/spec/reactive-ruby/component_loader_spec.rb +74 -0
- data/spec/reactive-ruby/isomorphic_helpers_spec.rb +157 -0
- data/spec/reactive-ruby/rails/asset_pipeline_spec.rb +17 -0
- data/spec/reactive-ruby/rails/component_mount_spec.rb +64 -0
- data/spec/reactive-ruby/server_rendering/contextual_renderer_spec.rb +39 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/test_app/README.md +24 -0
- data/spec/test_app/Rakefile +6 -0
- data/spec/test_app/app/assets/config/manifest.js +3 -0
- data/spec/test_app/app/assets/images/.keep +0 -0
- data/spec/test_app/app/assets/javascripts/application.rb +7 -0
- data/spec/test_app/app/assets/javascripts/cable.js +13 -0
- data/spec/test_app/app/assets/javascripts/channels/.keep +0 -0
- data/spec/test_app/app/assets/javascripts/server_rendering.js +5 -0
- data/spec/test_app/app/assets/stylesheets/application.css +15 -0
- data/spec/test_app/app/channels/application_cable/channel.rb +4 -0
- data/spec/test_app/app/channels/application_cable/connection.rb +4 -0
- data/spec/test_app/app/controllers/application_controller.rb +3 -0
- data/spec/test_app/app/controllers/concerns/.keep +0 -0
- data/spec/test_app/app/helpers/application_helper.rb +2 -0
- data/spec/test_app/app/jobs/application_job.rb +2 -0
- data/spec/test_app/app/mailers/application_mailer.rb +4 -0
- data/spec/test_app/app/models/application_record.rb +3 -0
- data/spec/test_app/app/models/concerns/.keep +0 -0
- data/spec/test_app/app/views/components.rb +11 -0
- data/spec/test_app/app/views/components/hello_world.rb +11 -0
- data/spec/test_app/app/views/components/todo.rb +14 -0
- data/spec/test_app/app/views/layouts/application.html.erb +14 -0
- data/spec/test_app/app/views/layouts/explicit_layout.html.erb +0 -0
- data/spec/test_app/app/views/layouts/mailer.html.erb +13 -0
- data/spec/test_app/app/views/layouts/mailer.text.erb +1 -0
- data/spec/test_app/app/views/layouts/test_layout.html.erb +0 -0
- data/spec/test_app/bin/bundle +3 -0
- data/spec/test_app/bin/rails +4 -0
- data/spec/test_app/bin/rake +4 -0
- data/spec/test_app/bin/setup +38 -0
- data/spec/test_app/bin/update +29 -0
- data/spec/test_app/bin/yarn +11 -0
- data/spec/test_app/config.ru +5 -0
- data/spec/test_app/config/application.rb +45 -0
- data/spec/test_app/config/boot.rb +6 -0
- data/spec/test_app/config/cable.yml +10 -0
- data/spec/test_app/config/database.yml +25 -0
- data/spec/test_app/config/environment.rb +5 -0
- data/spec/test_app/config/environments/development.rb +54 -0
- data/spec/test_app/config/environments/production.rb +91 -0
- data/spec/test_app/config/environments/test.rb +42 -0
- data/spec/test_app/config/initializers/application_controller_renderer.rb +8 -0
- data/spec/test_app/config/initializers/assets.rb +14 -0
- data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/test_app/config/initializers/cookies_serializer.rb +5 -0
- data/spec/test_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/test_app/config/initializers/inflections.rb +16 -0
- data/spec/test_app/config/initializers/mime_types.rb +4 -0
- data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/test_app/config/locales/en.yml +33 -0
- data/spec/test_app/config/puma.rb +56 -0
- data/spec/test_app/config/routes.rb +3 -0
- data/spec/test_app/config/secrets.yml +32 -0
- data/spec/test_app/config/spring.rb +6 -0
- data/spec/test_app/db/development.sqlite3 +0 -0
- data/spec/test_app/db/schema.rb +15 -0
- data/spec/test_app/db/seeds.rb +7 -0
- data/spec/test_app/db/test.sqlite3 +0 -0
- data/spec/test_app/lib/assets/.keep +0 -0
- data/spec/test_app/log/.keep +0 -0
- data/spec/test_app/package.json +5 -0
- data/spec/test_app/public/404.html +67 -0
- data/spec/test_app/public/422.html +67 -0
- data/spec/test_app/public/500.html +66 -0
- data/spec/test_app/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/test_app/public/apple-touch-icon.png +0 -0
- data/spec/test_app/public/favicon.ico +0 -0
- data/spec/vendor/es5-shim.min.js +7 -0
- data/spec/vendor/jquery-2.2.4.min.js +4 -0
- metadata +401 -61
- data/CODE_OF_CONDUCT.md +0 -49
- data/lib/react/version.rb +0 -3
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'opal-jquery extensions', js: true do
|
|
4
|
+
describe 'Element' do
|
|
5
|
+
xit 'will reuse the wrapper componet class for the same Element' do
|
|
6
|
+
# TODO how come a def component_will_unmount will not be received
|
|
7
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
|
8
|
+
Foo.class_eval do
|
|
9
|
+
param :name
|
|
10
|
+
def render
|
|
11
|
+
"hello #{params.name}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def component_will_unmount
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
expect_any_instance_of(Foo).to_not receive(:component_will_unmount)
|
|
20
|
+
|
|
21
|
+
test_div = Element.new(:div)
|
|
22
|
+
test_div.render { Foo(name: 'fred') }
|
|
23
|
+
test_div.render { Foo(name: 'freddy') }
|
|
24
|
+
expect(Element[test_div].find('span').html).to eq('hello freddy')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'renders a top level component using render with a block' do
|
|
28
|
+
expect_evaluate_ruby do
|
|
29
|
+
class Foo < React::Component::Base
|
|
30
|
+
param :name
|
|
31
|
+
def render
|
|
32
|
+
"hello #{params.name}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
test_div = Element.new(:div)
|
|
36
|
+
test_div.render { Foo(name: 'fred') }
|
|
37
|
+
Element[test_div].find('span').html
|
|
38
|
+
end.to eq('hello fred')
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'renders a top level component using render with a container and params ' do
|
|
42
|
+
expect_evaluate_ruby do
|
|
43
|
+
test_div = Element.new(:div)
|
|
44
|
+
test_div.render(:span, id: :render_test_span) { 'hello' }
|
|
45
|
+
Element[test_div].find('#render_test_span').html
|
|
46
|
+
end.to eq('hello')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'will find the DOM node given a react element' do
|
|
50
|
+
expect_evaluate_ruby do
|
|
51
|
+
class Foo < React::Component::Base
|
|
52
|
+
def render
|
|
53
|
+
div { 'hello' }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
Element[React::Test::Utils.render_component_into_document(Foo)].html
|
|
57
|
+
end.to eq('hello')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "accepts plain js object as selector" do
|
|
61
|
+
evaluate_ruby do
|
|
62
|
+
Element[JS.call(:eval, "(function () { return window; })();")]
|
|
63
|
+
end
|
|
64
|
+
expect(page.driver.browser.manage.logs.get(:browser).map { |m| m.message.gsub(/\\n/, "\n") }.to_a.join("\n"))
|
|
65
|
+
.not_to match(/Exception|Error/)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'the param macro', js: true do
|
|
4
|
+
it 'defines collect_other_params_as method on params proxy' do
|
|
5
|
+
mount 'Foo', bar: 'biz' do
|
|
6
|
+
class Foo < React::Component::Base
|
|
7
|
+
collect_other_params_as :foo
|
|
8
|
+
|
|
9
|
+
def render
|
|
10
|
+
div { params.foo[:bar] }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
expect(page.body[-35..-19]).to include("<div>biz</div>")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "can create and access a required param" do
|
|
18
|
+
mount 'Foo', foo: :bar do
|
|
19
|
+
class Foo < React::Component::Base
|
|
20
|
+
param :foo
|
|
21
|
+
|
|
22
|
+
def render
|
|
23
|
+
div { params.foo }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
expect(page.body[-35..-19]).to include("<div>bar</div>")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "can create and access an optional params" do
|
|
31
|
+
mount 'Foo', foo1: :bar1, foo3: :bar3 do
|
|
32
|
+
class Foo < React::Component::Base
|
|
33
|
+
|
|
34
|
+
param foo1: :no_bar1
|
|
35
|
+
param foo2: :no_bar2
|
|
36
|
+
param :foo3, default: :no_bar3
|
|
37
|
+
param :foo4, default: :no_bar4
|
|
38
|
+
|
|
39
|
+
def render
|
|
40
|
+
div { "#{params.foo1}-#{params.foo2}-#{params.foo3}-#{params.foo4}" }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
expect(page.body[-60..-19]).to include('<div>bar1-no_bar2-bar3-no_bar4</div>')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'can specify validation rules with the type option' do
|
|
48
|
+
expect_evaluate_ruby do
|
|
49
|
+
class Foo < React::Component::Base
|
|
50
|
+
param :foo, type: String
|
|
51
|
+
end
|
|
52
|
+
Foo.prop_types
|
|
53
|
+
end.to have_key('_componentValidator')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "can type check params" do
|
|
57
|
+
mount 'Foo', foo1: 12, foo2: "string" do
|
|
58
|
+
class Foo < React::Component::Base
|
|
59
|
+
|
|
60
|
+
param :foo1, type: String
|
|
61
|
+
param :foo2, type: String
|
|
62
|
+
|
|
63
|
+
def render
|
|
64
|
+
div { "#{params.foo1}-#{params.foo2}" }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
expect(page.body[-60..-19]).to include('<div>12-string</div>')
|
|
69
|
+
expect(page.driver.browser.manage.logs.get(:browser).map { |m| m.message.gsub(/\\n/, "\n") }.to_a.join("\n"))
|
|
70
|
+
.to match(/Warning: Failed prop( type|Type): In component `Foo`\nProvided prop `foo1` could not be converted to String/)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'logs error in warning if validation failed' do
|
|
74
|
+
evaluate_ruby do
|
|
75
|
+
class Lorem; end
|
|
76
|
+
class Foo2 < React::Component::Base
|
|
77
|
+
param :foo
|
|
78
|
+
param :lorem, type: Lorem
|
|
79
|
+
param :bar, default: nil, type: String
|
|
80
|
+
def render; div; end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
React::Test::Utils.render_component_into_document(Foo2, bar: 10, lorem: Lorem.new)
|
|
84
|
+
end
|
|
85
|
+
expect(page.driver.browser.manage.logs.get(:browser).map { |m| m.message.gsub(/\\n/, "\n") }.to_a.join("\n"))
|
|
86
|
+
.to match(/Warning: Failed prop( type|Type): In component `Foo2`\nRequired prop `foo` was not specified\nProvided prop `bar` could not be converted to String/)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'should not log anything if validation passes' do
|
|
90
|
+
evaluate_ruby do
|
|
91
|
+
class Lorem; end
|
|
92
|
+
class Foo < React::Component::Base
|
|
93
|
+
param :foo
|
|
94
|
+
param :lorem, type: Lorem
|
|
95
|
+
param :bar, default: nil, type: String
|
|
96
|
+
|
|
97
|
+
def render; div; end
|
|
98
|
+
end
|
|
99
|
+
React::Test::Utils.render_component_into_document(Foo, foo: 10, bar: '10', lorem: Lorem.new)
|
|
100
|
+
end
|
|
101
|
+
expect(page.driver.browser.manage.logs.get(:browser).reject { |m| m.message =~ /(D|d)eprecated/ }.map { |m| m.message.gsub(/\\n/, "\n") }.to_a.join("\n"))
|
|
102
|
+
.not_to match(/Warning|Error/)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe 'advanced type handling' do
|
|
106
|
+
before(:each) do
|
|
107
|
+
on_client do
|
|
108
|
+
class Foo < React::Component::Base
|
|
109
|
+
def render; ""; end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "can use the [] notation for arrays" do
|
|
115
|
+
mount 'Foo', foo: 10, bar: [10] do
|
|
116
|
+
Foo.class_eval do
|
|
117
|
+
param :foo, type: []
|
|
118
|
+
param :bar, type: []
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
expect(page.driver.browser.manage.logs.get(:browser).map { |m| m.message.gsub(/\\n/, "\n") }.to_a.join("\n"))
|
|
122
|
+
.to match(/Warning: Failed prop( type|Type): In component `Foo`\nProvided prop `foo` could not be converted to Array/)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "can use the [xxx] notation for arrays of a specific type" do
|
|
126
|
+
mount 'Foo', foo: [10], bar: ["10"] do
|
|
127
|
+
Foo.class_eval do
|
|
128
|
+
param :foo, type: [String]
|
|
129
|
+
param :bar, type: [String]
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
expect(page.driver.browser.manage.logs.get(:browser).map { |m| m.message.gsub(/\\n/, "\n") }.to_a.join("\n"))
|
|
133
|
+
.to match(/Warning: Failed prop( type|Type): In component `Foo`\nProvided prop `foo`\[0\] could not be converted to String/)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "can convert a json hash to a type" do
|
|
137
|
+
mount 'Foo', foo: "", bar: { bazwoggle: 1 }, baz: [{ bazwoggle: 2 }] do
|
|
138
|
+
class BazWoggle
|
|
139
|
+
def initialize(kind)
|
|
140
|
+
@kind = kind
|
|
141
|
+
end
|
|
142
|
+
attr_accessor :kind
|
|
143
|
+
def self._react_param_conversion(json, validate_only)
|
|
144
|
+
new(json[:bazwoggle]) if json[:bazwoggle]
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
Foo.class_eval do
|
|
148
|
+
param :foo, type: BazWoggle
|
|
149
|
+
param :bar, type: BazWoggle
|
|
150
|
+
param :baz, type: [BazWoggle]
|
|
151
|
+
def render
|
|
152
|
+
"#{params.bar.kind}, #{params.baz[0].kind}"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
expect(page.body[-60..-19]).to include('<span>1, 2</span>')
|
|
157
|
+
expect(page.driver.browser.manage.logs.get(:browser).map { |m| m.message.gsub(/\\n/, "\n") }.to_a.join("\n"))
|
|
158
|
+
.to match(/Warning: Failed prop( type|Type): In component `Foo`\nProvided prop `foo` could not be converted to BazWoggle/)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
describe "converts params only once" do
|
|
162
|
+
it "not on every access" do
|
|
163
|
+
mount 'Foo', foo: {bazwoggle: 1} do
|
|
164
|
+
class BazWoggle
|
|
165
|
+
def initialize(kind)
|
|
166
|
+
@kind = kind
|
|
167
|
+
end
|
|
168
|
+
attr_accessor :kind
|
|
169
|
+
def self._react_param_conversion(json, validate_only)
|
|
170
|
+
new(json[:bazwoggle]) if json[:bazwoggle]
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
Foo.class_eval do
|
|
174
|
+
param :foo, type: BazWoggle
|
|
175
|
+
def render
|
|
176
|
+
params.foo.kind = params.foo.kind+1
|
|
177
|
+
"#{params.foo.kind}"
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
expect(page.body[-60..-19]).to include('<span>2</span>')
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "even if contains an embedded native object"
|
|
185
|
+
# its not clear what this test was trying to accomplish...
|
|
186
|
+
# do
|
|
187
|
+
# pending 'Fix after merging'
|
|
188
|
+
# stub_const "Bar", Class.new(React::Component::Base)
|
|
189
|
+
# stub_const "BazWoggle", Class.new
|
|
190
|
+
# BazWoggle.class_eval do
|
|
191
|
+
# def initialize(kind)
|
|
192
|
+
# @kind = kind
|
|
193
|
+
# end
|
|
194
|
+
# attr_accessor :kind
|
|
195
|
+
# def self._react_param_conversion(json, validate_only)
|
|
196
|
+
# new(JSON.from_object(json[0])[:bazwoggle]) if JSON.from_object(json[0])[:bazwoggle]
|
|
197
|
+
# end
|
|
198
|
+
# end
|
|
199
|
+
# Bar.class_eval do
|
|
200
|
+
# param :foo, type: BazWoggle
|
|
201
|
+
# def render
|
|
202
|
+
# params.foo.kind.to_s
|
|
203
|
+
# end
|
|
204
|
+
# end
|
|
205
|
+
# Foo.class_eval do
|
|
206
|
+
# export_state :change_me
|
|
207
|
+
# before_mount do
|
|
208
|
+
# Foo.change_me! "initial"
|
|
209
|
+
# end
|
|
210
|
+
# def render
|
|
211
|
+
# Bar(foo: Native([`{bazwoggle: #{Foo.change_me}}`]))
|
|
212
|
+
# end
|
|
213
|
+
# end
|
|
214
|
+
# div = `document.createElement("div")`
|
|
215
|
+
# React.render(React.create_element(Foo, {}), div)
|
|
216
|
+
# Foo.change_me! "updated"
|
|
217
|
+
# expect(`div.children[0].innerHTML`).to eq("updated")
|
|
218
|
+
# end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it "will alias a Proc type param" do
|
|
222
|
+
evaluate_ruby do
|
|
223
|
+
Foo.class_eval do
|
|
224
|
+
param :foo, type: Proc
|
|
225
|
+
def render
|
|
226
|
+
params.foo
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
React::Test::Utils.render_component_into_document(Foo, foo: lambda { 'works!' })
|
|
230
|
+
end
|
|
231
|
+
expect(page.body[-60..-19]).to include('<span>works!</span>')
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
it "will create a 'bang' (i.e. update) method if the type is React::Observable" do
|
|
235
|
+
expect_evaluate_ruby do
|
|
236
|
+
Foo.class_eval do
|
|
237
|
+
param :foo, type: React::Observable
|
|
238
|
+
before_mount do
|
|
239
|
+
params.foo! "ha!"
|
|
240
|
+
end
|
|
241
|
+
def render
|
|
242
|
+
params.foo
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
current_state = ""
|
|
246
|
+
observer = React::Observable.new(current_state) { |new_state| current_state = new_state }
|
|
247
|
+
React::Test::Utils.render_component_into_document(Foo, foo: observer)
|
|
248
|
+
current_state
|
|
249
|
+
end.to eq("ha!")
|
|
250
|
+
expect(page.body[-60..-19]).to include('<span>ha!</span>')
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe 'React', js: true do
|
|
4
|
+
describe "is_valid_element?" do
|
|
5
|
+
it "should return true if passed a valid element" do
|
|
6
|
+
|
|
7
|
+
expect_evaluate_ruby do
|
|
8
|
+
element = React::Element.new(JS.call(:eval, "React.createElement('div')"))
|
|
9
|
+
React.is_valid_element?(element)
|
|
10
|
+
end.to eq(true)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should return false is passed a non React element" do
|
|
14
|
+
|
|
15
|
+
expect_evaluate_ruby do
|
|
16
|
+
element = React::Element.new(JS.call(:eval, "{}"))
|
|
17
|
+
React.is_valid_element?(element)
|
|
18
|
+
end.to eq(false)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "create_element" do
|
|
23
|
+
it "should create a valid element with only tag" do
|
|
24
|
+
|
|
25
|
+
expect_evaluate_ruby do
|
|
26
|
+
element = React.create_element('div')
|
|
27
|
+
React.is_valid_element?(element)
|
|
28
|
+
end.to eq(true)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context "with block" do
|
|
32
|
+
it "should create a valid element with text as only child when block yield String" do
|
|
33
|
+
|
|
34
|
+
evaluate_ruby do
|
|
35
|
+
ELEMENT = React.create_element('div') { "lorem ipsum" }
|
|
36
|
+
end
|
|
37
|
+
expect_evaluate_ruby("React.is_valid_element?(ELEMENT)").to eq(true)
|
|
38
|
+
expect_evaluate_ruby("ELEMENT.props.children").to eq("lorem ipsum")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should create a valid element with children as array when block yield Array of element" do
|
|
42
|
+
|
|
43
|
+
evaluate_ruby do
|
|
44
|
+
ELEMENT = React.create_element('div') do
|
|
45
|
+
[React.create_element('span'), React.create_element('span'), React.create_element('span')]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
expect_evaluate_ruby("React.is_valid_element?(ELEMENT)").to eq(true)
|
|
49
|
+
expect_evaluate_ruby("ELEMENT.props.children.length").to eq(3)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should render element with children as array when block yield Array of element" do
|
|
53
|
+
|
|
54
|
+
expect_evaluate_ruby do
|
|
55
|
+
element = React.create_element('div') do
|
|
56
|
+
[React.create_element('span'), React.create_element('span'), React.create_element('span')]
|
|
57
|
+
end
|
|
58
|
+
dom_node = React::Test::Utils.render_into_document(element)
|
|
59
|
+
dom_node.JS[:children].JS[:length]
|
|
60
|
+
end.to eq(3)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "custom element" do
|
|
65
|
+
before :each do
|
|
66
|
+
on_client do
|
|
67
|
+
class Foo < React::Component::Base
|
|
68
|
+
def initialize(native)
|
|
69
|
+
@native = native
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def render
|
|
73
|
+
React.create_element("div") { "lorem" }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def props
|
|
77
|
+
Hash.new(@native.JS[:props])
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "should render element with only one children correctly" do
|
|
84
|
+
|
|
85
|
+
evaluate_ruby do
|
|
86
|
+
element = React.create_element(Foo) { React.create_element('span') }
|
|
87
|
+
INSTANCE = React::Test::Utils.render_into_document(element)
|
|
88
|
+
true
|
|
89
|
+
end
|
|
90
|
+
expect_evaluate_ruby("INSTANCE.props[:children].is_a?(Array)").to be_falsy
|
|
91
|
+
expect_evaluate_ruby("INSTANCE.props[:children][:type]").to eq("span")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "should render element with more than one children correctly" do
|
|
95
|
+
|
|
96
|
+
evaluate_ruby do
|
|
97
|
+
element = React.create_element(Foo) { [React.create_element('span'), React.create_element('span')] }
|
|
98
|
+
INSTANCE = React::Test::Utils.render_into_document(element)
|
|
99
|
+
true
|
|
100
|
+
end
|
|
101
|
+
expect_evaluate_ruby("INSTANCE.props[:children].is_a?(Array)").to be_truthy
|
|
102
|
+
expect_evaluate_ruby("INSTANCE.props[:children].length").to eq(2)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "should create a valid element provided class defined `render`" do
|
|
106
|
+
|
|
107
|
+
expect_evaluate_ruby do
|
|
108
|
+
element = React.create_element(Foo)
|
|
109
|
+
React.is_valid_element?(element)
|
|
110
|
+
end.to eq(true)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "should allow creating with properties" do
|
|
114
|
+
expect_evaluate_ruby do
|
|
115
|
+
Foo.class_eval do
|
|
116
|
+
param :foo
|
|
117
|
+
end
|
|
118
|
+
element = React.create_element(Foo, foo: "bar")
|
|
119
|
+
element.props.foo
|
|
120
|
+
end.to eq("bar")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "should raise error if provided class doesn't defined `render`" do
|
|
124
|
+
|
|
125
|
+
expect_evaluate_ruby do
|
|
126
|
+
begin
|
|
127
|
+
React.create_element(Array)
|
|
128
|
+
rescue
|
|
129
|
+
'failed'
|
|
130
|
+
end
|
|
131
|
+
end.to eq('failed')
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "should use the same instance for the same ReactComponent" do
|
|
135
|
+
|
|
136
|
+
mount 'Foo' do
|
|
137
|
+
Foo.class_eval do
|
|
138
|
+
attr_accessor :a
|
|
139
|
+
|
|
140
|
+
def initialize(n)
|
|
141
|
+
self.a = 10
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def component_will_mount
|
|
145
|
+
self.a = 20
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def render
|
|
149
|
+
React.create_element("div") { self.a.to_s }
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
expect(page.body[-60..-19]).to include("<div>20</div>")
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it "should match the instance cycle to ReactComponent life cycle" do
|
|
157
|
+
expect_evaluate_ruby do
|
|
158
|
+
Foo.class_eval do
|
|
159
|
+
def initialize(native)
|
|
160
|
+
@@count ||= 0
|
|
161
|
+
@@count += 1
|
|
162
|
+
end
|
|
163
|
+
def render
|
|
164
|
+
React.create_element("div")
|
|
165
|
+
end
|
|
166
|
+
def self.count
|
|
167
|
+
@@count
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
React::Test::Utils.render_component_into_document(Foo)
|
|
172
|
+
React::Test::Utils.render_component_into_document(Foo)
|
|
173
|
+
Foo.count
|
|
174
|
+
end.to eq(2)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
describe "create element with properties" do
|
|
179
|
+
it "should enforce snake-cased property name" do
|
|
180
|
+
|
|
181
|
+
expect_evaluate_ruby do
|
|
182
|
+
element = React.create_element("div", class_name: "foo")
|
|
183
|
+
element.props.className
|
|
184
|
+
end.to eq("foo")
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it "should allow custom property" do
|
|
188
|
+
|
|
189
|
+
expect_evaluate_ruby do
|
|
190
|
+
element = React.create_element("div", foo: "bar")
|
|
191
|
+
element.props.foo
|
|
192
|
+
end.to eq("bar")
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it "should not camel-case custom property" do
|
|
196
|
+
|
|
197
|
+
expect_evaluate_ruby do
|
|
198
|
+
element = React.create_element("div", foo_bar: "foo")
|
|
199
|
+
element.props.foo_bar
|
|
200
|
+
end.to eq("foo")
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
describe "class_name helpers (React.addons.classSet)" do
|
|
205
|
+
it "should not alter behavior when passing a string" do
|
|
206
|
+
|
|
207
|
+
expect_evaluate_ruby do
|
|
208
|
+
element = React.create_element("div", class_name: "foo bar")
|
|
209
|
+
element.props.className
|
|
210
|
+
end.to eq("foo bar")
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
describe "render" do
|
|
216
|
+
it "should render element to DOM" do # was async, don know how to handle
|
|
217
|
+
|
|
218
|
+
evaluate_ruby do
|
|
219
|
+
DIV = JS.call(:eval, 'document.createElement("div")')
|
|
220
|
+
React.render(React.create_element('span') { "lorem" }, DIV)
|
|
221
|
+
'' # make to_json happy
|
|
222
|
+
end
|
|
223
|
+
expect_evaluate_ruby("DIV.JS[:children].JS[0].JS[:tagName]").to eq("SPAN")
|
|
224
|
+
expect_evaluate_ruby("DIV.JS[:textContent]").to eq("lorem")
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
it "should work without providing a block" do
|
|
228
|
+
expect_evaluate_ruby do
|
|
229
|
+
begin
|
|
230
|
+
React::Test::Utils.render_into_document(React.create_element('span') { "lorem" })
|
|
231
|
+
true
|
|
232
|
+
rescue
|
|
233
|
+
false
|
|
234
|
+
end
|
|
235
|
+
end.to be_truthy
|
|
236
|
+
expect(page.body[-80..-10]).to include('<div><span>lorem</span></div>')
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it "returns the actual ruby instance" do
|
|
240
|
+
|
|
241
|
+
expect_evaluate_ruby do
|
|
242
|
+
class Foo
|
|
243
|
+
def render
|
|
244
|
+
React.create_element("div") { "lorem" }
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
div = JS.call(:eval, 'document.createElement("div")')
|
|
249
|
+
instance = React.render(React.create_element(Foo), div)
|
|
250
|
+
instance.is_a?(Foo)
|
|
251
|
+
end.to be_truthy
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
it "returns the actual DOM node" do
|
|
255
|
+
|
|
256
|
+
expect_evaluate_ruby do
|
|
257
|
+
div = JS.call(:eval, 'document.createElement("div")')
|
|
258
|
+
node = React.render(React.create_element('span') { "lorem" }, div)
|
|
259
|
+
node.JS['nodeType']
|
|
260
|
+
end.to eq(1)
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
describe "unmount_component_at_node" do
|
|
265
|
+
it "should unmount component at node" do
|
|
266
|
+
|
|
267
|
+
# was run_async
|
|
268
|
+
# unmount was passed in a block run_async which passed in a block to React.render
|
|
269
|
+
# trying to emulate that failed, becasue during render, _getOpalInstance was not yet defined.
|
|
270
|
+
# it is defined only after render, when the component was mounted. So we call unmount after render
|
|
271
|
+
expect_evaluate_ruby do
|
|
272
|
+
div = JS.call(:eval, 'document.createElement("div")')
|
|
273
|
+
React.render(React.create_element('span') { "lorem" }, div )
|
|
274
|
+
React.unmount_component_at_node(div)
|
|
275
|
+
end.to eq(true)
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|