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,103 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
describe 'React::TopLevelRailsComponent', js: true do
|
|
5
|
+
before :each do
|
|
6
|
+
on_client do
|
|
7
|
+
module Components
|
|
8
|
+
module Controller
|
|
9
|
+
class Component1
|
|
10
|
+
include React::Component
|
|
11
|
+
def render
|
|
12
|
+
self.class.name.to_s
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class Component1
|
|
18
|
+
include React::Component
|
|
19
|
+
def render
|
|
20
|
+
self.class.name.to_s
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class Component2
|
|
25
|
+
include React::Component
|
|
26
|
+
def render
|
|
27
|
+
self.class.name.to_s
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module Controller
|
|
33
|
+
class SomeOtherClass # see issue #80
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class Component1
|
|
38
|
+
include React::Component
|
|
39
|
+
def render
|
|
40
|
+
self.class.name.to_s
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def render_top_level(controller, component_name)
|
|
45
|
+
params = {
|
|
46
|
+
controller: controller,
|
|
47
|
+
component_name: component_name,
|
|
48
|
+
render_params: {}
|
|
49
|
+
}
|
|
50
|
+
component = React::Test::Utils.render_component_into_document(React::TopLevelRailsComponent, params)
|
|
51
|
+
component.dom_node.JS[:outerHTML]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'uses the controller name to lookup a component' do
|
|
57
|
+
expect_evaluate_ruby('render_top_level("Controller", "Component1")').to eq('<span>Components::Controller::Component1</span>')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'can find the name without matching the controller' do
|
|
61
|
+
expect_evaluate_ruby('render_top_level("Controller", "Component2")').to eq('<span>Components::Component2</span>')
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'will find the outer most matching component' do
|
|
65
|
+
expect_evaluate_ruby('render_top_level("OtherController", "Component1")').to eq('<span>Component1</span>')
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'can find the correct component when the name is fully qualified' do
|
|
69
|
+
expect_evaluate_ruby('render_top_level("Controller", "::Components::Component1")').to eq('<span>Components::Component1</span>')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe '.html_tag?' do
|
|
73
|
+
it 'is truthy for valid html tags' do
|
|
74
|
+
expect_evaluate_ruby('React.html_tag?("a")').to be_truthy
|
|
75
|
+
expect_evaluate_ruby('React.html_tag?("div")').to be_truthy
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'is truthy for valid svg tags' do
|
|
79
|
+
expect_evaluate_ruby('React.html_tag?("svg")').to be_truthy
|
|
80
|
+
expect_evaluate_ruby('React.html_tag?("circle")').to be_truthy
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'is falsey for invalid tags' do
|
|
84
|
+
expect_evaluate_ruby('React.html_tag?("tagizzle")').to be_falsey
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe '.html_attr?' do
|
|
89
|
+
it 'is truthy for valid html attributes' do
|
|
90
|
+
expect_evaluate_ruby('React.html_attr?("id")').to be_truthy
|
|
91
|
+
expect_evaluate_ruby('React.html_attr?("data")').to be_truthy
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'is truthy for valid svg attributes' do
|
|
95
|
+
expect_evaluate_ruby('React.html_attr?("cx")').to be_truthy
|
|
96
|
+
expect_evaluate_ruby('React.html_attr?("strokeWidth")').to be_truthy
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'is falsey for invalid attributes' do
|
|
100
|
+
expect_evaluate_ruby('React.html_tag?("attrizzle")').to be_falsey
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'An Example from the react.rb doc', js: true do
|
|
4
|
+
it 'produces the correct result' do
|
|
5
|
+
mount 'HelloMessage' do
|
|
6
|
+
class HelloMessage
|
|
7
|
+
include React::Component
|
|
8
|
+
def render
|
|
9
|
+
div { "Hello World!" }
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
expect(page).to have_xpath('//div', text: 'Hello World!')
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe 'Adding state to a component (second tutorial example)', js: true do
|
|
18
|
+
before :each do
|
|
19
|
+
on_client do
|
|
20
|
+
class HelloMessage2
|
|
21
|
+
include React::Component
|
|
22
|
+
define_state(:user_name) { '@catmando' }
|
|
23
|
+
def render
|
|
24
|
+
div { "Hello #{state.user_name}" }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "produces the correct result" do
|
|
31
|
+
mount 'HelloMessage2'
|
|
32
|
+
expect(page).to have_xpath('//div', text: 'Hello @catmando')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'renders to the document' do
|
|
36
|
+
evaluate_ruby do
|
|
37
|
+
ele = JS.call(:eval, "document.body.appendChild(document.createElement('div'))")
|
|
38
|
+
React.render(React.create_element(HelloMessage2), ele)
|
|
39
|
+
end
|
|
40
|
+
expect(page).to have_xpath('//div', text: 'Hello @catmando')
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe 'React::Validator', js: true do
|
|
4
|
+
describe '#validate' do
|
|
5
|
+
describe "Presence validation" do
|
|
6
|
+
it "should check if required props provided" do
|
|
7
|
+
evaluate_ruby do
|
|
8
|
+
VALIDATOR = React::Validator.new.build do
|
|
9
|
+
requires :foo
|
|
10
|
+
requires :bar
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
expect_evaluate_ruby('VALIDATOR.validate({})').to eq(["Required prop `foo` was not specified", "Required prop `bar` was not specified"])
|
|
14
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: 1, bar: 3})').to eq([])
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should check if passed non specified prop" do
|
|
18
|
+
evaluate_ruby do
|
|
19
|
+
VALIDATOR = React::Validator.new.build do
|
|
20
|
+
optional :foo
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
expect_evaluate_ruby('VALIDATOR.validate({bar: 10})').to eq(["Provided prop `bar` not specified in spec"])
|
|
24
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: 10})').to eq([])
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "Type validation" do
|
|
29
|
+
it "should check if passed value with wrong type" do
|
|
30
|
+
evaluate_ruby do
|
|
31
|
+
VALIDATOR = React::Validator.new.build do
|
|
32
|
+
requires :foo, type: String
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: 10})').to eq(["Provided prop `foo` could not be converted to String"])
|
|
36
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: "10"})').to eq([])
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should check if passed value with wrong custom type" do
|
|
40
|
+
evaluate_ruby do
|
|
41
|
+
class Bar; end
|
|
42
|
+
VALIDATOR = React::Validator.new.build do
|
|
43
|
+
requires :foo, type: Bar
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: 10})').to eq(["Provided prop `foo` could not be converted to Bar"])
|
|
47
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: Bar.new})').to eq([])
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'coerces native JS prop types to opal objects' do
|
|
51
|
+
evaluate_ruby do
|
|
52
|
+
VALIDATOR = React::Validator.new.build do
|
|
53
|
+
requires :foo, type: JS.call(:eval, "(function () { return { x: 1 }; })();")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: `{ x: 1 }`})').to eq(["Provided prop `foo` could not be converted to [object Object]"])
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'coerces native JS values to opal objects' do
|
|
60
|
+
evaluate_ruby do
|
|
61
|
+
VALIDATOR = React::Validator.new.build do
|
|
62
|
+
requires :foo, type: Array[Integer]
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: `[ { x: 1 } ]`})').to eq(["Provided prop `foo`[0] could not be converted to #{Integer.name}"])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "should support Array[Class] validation" do
|
|
69
|
+
evaluate_ruby do
|
|
70
|
+
VALIDATOR = React::Validator.new.build do
|
|
71
|
+
requires :foo, type: Array[Hash]
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: [1,"2",3]})').to eq(
|
|
75
|
+
[
|
|
76
|
+
"Provided prop `foo`[0] could not be converted to Hash",
|
|
77
|
+
"Provided prop `foo`[1] could not be converted to Hash",
|
|
78
|
+
"Provided prop `foo`[2] could not be converted to Hash"
|
|
79
|
+
]
|
|
80
|
+
)
|
|
81
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: [{},{},{}]})').to eq([])
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe "Limited values" do
|
|
86
|
+
it "should check if passed value is not one of the specified values" do
|
|
87
|
+
evaluate_ruby do
|
|
88
|
+
VALIDATOR = React::Validator.new.build do
|
|
89
|
+
requires :foo, values: [4,5,6]
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: 3})').to eq(["Value `3` for prop `foo` is not an allowed value"])
|
|
93
|
+
expect_evaluate_ruby('VALIDATOR.validate({foo: 4})').to eq([])
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe '#undefined_props' do
|
|
99
|
+
before :each do
|
|
100
|
+
on_client do
|
|
101
|
+
PROPS = { foo: 'foo', bar: 'bar', biz: 'biz', baz: 'baz' }
|
|
102
|
+
VALIDATOR = React::Validator.new.build do
|
|
103
|
+
requires :foo
|
|
104
|
+
optional :bar
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
it 'slurps up any extra params into a hash' do
|
|
111
|
+
expect_evaluate_ruby('VALIDATOR.undefined_props(PROPS)').to eq({ "biz" => 'biz', "baz" => 'baz' })
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it 'prevents validate non-specified params' do
|
|
115
|
+
evaluate_ruby do
|
|
116
|
+
VALIDATOR.undefined_props(PROPS)
|
|
117
|
+
end
|
|
118
|
+
expect_evaluate_ruby('VALIDATOR.validate(PROPS)').to eq([])
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
describe "default_props" do
|
|
123
|
+
it "should return specified default values" do
|
|
124
|
+
evaluate_ruby do
|
|
125
|
+
VALIDATOR = React::Validator.new.build do
|
|
126
|
+
requires :foo, default: 10
|
|
127
|
+
requires :bar
|
|
128
|
+
optional :lorem, default: 20
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
expect_evaluate_ruby('VALIDATOR.default_props').to eq({"foo" => 10, "lorem" => 20})
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ReactiveRuby::ComponentLoader do
|
|
4
|
+
GLOBAL_WRAPPER = <<-JS
|
|
5
|
+
#{React::ServerRendering::ExecJSRenderer::GLOBAL_WRAPPER}
|
|
6
|
+
var console = {
|
|
7
|
+
warn: function(s) { }
|
|
8
|
+
};
|
|
9
|
+
JS
|
|
10
|
+
|
|
11
|
+
let(:js) do
|
|
12
|
+
if ::Rails.application.assets['react-server.js']
|
|
13
|
+
react_source = ::Rails.application.assets['react-server.js']
|
|
14
|
+
else
|
|
15
|
+
react_source = ::Rails.application.assets['react.js']
|
|
16
|
+
end
|
|
17
|
+
::Rails.application.assets['components'].to_s + react_source.to_s
|
|
18
|
+
end
|
|
19
|
+
let(:context) { ExecJS.compile(GLOBAL_WRAPPER + js) }
|
|
20
|
+
let(:v8_context) { ReactiveRuby::ServerRendering.context_instance_for(context) }
|
|
21
|
+
|
|
22
|
+
describe '.new' do
|
|
23
|
+
it 'raises a meaningful exception when initialized without a context' do
|
|
24
|
+
expect {
|
|
25
|
+
described_class.new(nil)
|
|
26
|
+
}.to raise_error(/Could not obtain ExecJS runtime context/)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#load' do
|
|
31
|
+
xit 'loads given asset file into context' do
|
|
32
|
+
loader = described_class.new(v8_context)
|
|
33
|
+
|
|
34
|
+
expect {
|
|
35
|
+
loader.load('components')
|
|
36
|
+
}.to change { !!v8_context.eval('Opal.React !== undefined') }.from(false).to(true)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
xit 'is truthy upon successful load' do
|
|
40
|
+
loader = described_class.new(v8_context)
|
|
41
|
+
expect(loader.load('components')).to be_truthy
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
xit 'fails silently returning false' do
|
|
45
|
+
loader = described_class.new(v8_context)
|
|
46
|
+
expect(loader.load('foo')).to be_falsey
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe '#load!' do
|
|
51
|
+
xit 'is truthy upon successful load' do
|
|
52
|
+
loader = described_class.new(v8_context)
|
|
53
|
+
expect(loader.load!('components')).to be_truthy
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
xit 'raises an expection if loading fails' do
|
|
57
|
+
loader = described_class.new(v8_context)
|
|
58
|
+
expect { loader.load!('foo') }.to raise_error(/No HyperReact components/)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
describe '#loaded?' do
|
|
63
|
+
xit 'is truthy if components file is already loaded' do
|
|
64
|
+
loader = described_class.new(v8_context)
|
|
65
|
+
loader.load('components')
|
|
66
|
+
expect(loader).to be_loaded
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
xit 'is false if components file is not loaded' do
|
|
70
|
+
loader = described_class.new(v8_context)
|
|
71
|
+
expect(loader).to_not be_loaded
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe React::IsomorphicHelpers do
|
|
4
|
+
describe 'code execution context' do
|
|
5
|
+
let(:klass) { Class.send(:include, described_class) }
|
|
6
|
+
|
|
7
|
+
describe 'module class methods', :opal do
|
|
8
|
+
it { expect(described_class).to_not be_on_opal_server }
|
|
9
|
+
it { expect(described_class).to be_on_opal_client }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe 'included class methods', :opal do
|
|
13
|
+
it { expect(klass).to_not be_on_opal_server }
|
|
14
|
+
it { expect(klass).to be_on_opal_client }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe 'included instance methods', :opal do
|
|
18
|
+
it { expect(klass.new).to_not be_on_opal_server }
|
|
19
|
+
it { expect(klass.new).to be_on_opal_client }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe 'module class methods', :ruby do
|
|
23
|
+
it { is_expected.to_not be_on_opal_server }
|
|
24
|
+
it { is_expected.to_not be_on_opal_client }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe 'included class methods', :ruby do
|
|
28
|
+
subject { klass }
|
|
29
|
+
it { is_expected.to_not be_on_opal_server }
|
|
30
|
+
it { is_expected.to_not be_on_opal_client }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe 'included instance methods', :ruby do
|
|
34
|
+
subject { klass.new }
|
|
35
|
+
it { is_expected.to_not be_on_opal_server }
|
|
36
|
+
it { is_expected.to_not be_on_opal_client }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe 'load_context', :ruby do
|
|
41
|
+
let(:v8_context) { TestV8Context.new }
|
|
42
|
+
let(:controller) { double('controller') }
|
|
43
|
+
let(:name) { double('name') }
|
|
44
|
+
|
|
45
|
+
it 'creates a context and sets a controller' do
|
|
46
|
+
context = described_class.load_context(v8_context, controller, name)
|
|
47
|
+
expect(context.controller).to eq(controller)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'creates a context and sets a unique_id', js: true do
|
|
51
|
+
# this tests loads the prerender context and somehow trys evaluate_ruby, works only with above js: true
|
|
52
|
+
# TODO this is triggered by TimeCop for some reason
|
|
53
|
+
Timecop.freeze do
|
|
54
|
+
stamp = Time.now.to_i
|
|
55
|
+
context = described_class.load_context(v8_context, controller, name)
|
|
56
|
+
expect(context.unique_id).to eq("#{ controller.object_id }-#{ stamp }")
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe React::IsomorphicHelpers::Context do
|
|
62
|
+
class TestV8Context < Hash
|
|
63
|
+
def eval(args)
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
def attach(*args)
|
|
67
|
+
true
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Need to decouple/dry up this...
|
|
72
|
+
def test_context(files = nil)
|
|
73
|
+
js = ReactiveRuby::ServerRendering::ContextualRenderer::CONSOLE_POLYFILL.dup
|
|
74
|
+
js << Opal::Builder.build('opal').to_s
|
|
75
|
+
Array(files).each do |filename|
|
|
76
|
+
js << ::Rails.application.assets[filename].to_s
|
|
77
|
+
end
|
|
78
|
+
js = "#{React::ServerRendering::ExecJSRenderer::GLOBAL_WRAPPER}#{js}"
|
|
79
|
+
ctx = ExecJS.compile(js)
|
|
80
|
+
ctx = ReactiveRuby::ServerRendering.context_instance_for(ctx)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def react_context
|
|
84
|
+
if ::Rails.application.assets['react-server.js']
|
|
85
|
+
test_context(['server_rendering.js', 'react-server.js'])
|
|
86
|
+
else
|
|
87
|
+
test_context(['components', 'react.js'])
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
let(:v8_context) { TestV8Context.new }
|
|
92
|
+
let(:controller) { double('controller') }
|
|
93
|
+
let(:name) { double('name') }
|
|
94
|
+
before do
|
|
95
|
+
described_class.instance_variable_set :@before_first_mount_blocks, nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe '#initialize' do
|
|
99
|
+
it 'calls before mount callbacks' do
|
|
100
|
+
string = instance_double(String)
|
|
101
|
+
described_class.register_before_first_mount_block do
|
|
102
|
+
string.inspect
|
|
103
|
+
end
|
|
104
|
+
expect(string).to receive(:inspect).once
|
|
105
|
+
context = described_class.new('unique-id', v8_context, controller, name)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
describe '#eval' do
|
|
110
|
+
it 'delegates to given context' do
|
|
111
|
+
context = described_class.new('unique-id', v8_context, controller, name)
|
|
112
|
+
js = 'true;'
|
|
113
|
+
expect(v8_context).to receive(:eval).with(js).once
|
|
114
|
+
context.eval(js)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
describe '#send_to_opal' do
|
|
119
|
+
let(:opal_code) { Opal::Builder.new.build_str(ruby_code, __FILE__).to_s }
|
|
120
|
+
let(:ruby_code) { %Q[
|
|
121
|
+
module React::IsomorphicHelpers
|
|
122
|
+
def self.greet(name)
|
|
123
|
+
"Hello, " + name + "!"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def self.valediction
|
|
127
|
+
'Goodbye'
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
]}
|
|
131
|
+
|
|
132
|
+
it 'raises an error when react cannot be loaded' do
|
|
133
|
+
context = described_class.new('unique-id', v8_context, controller, name)
|
|
134
|
+
context.instance_variable_set(:@ctx, test_context)
|
|
135
|
+
expect {
|
|
136
|
+
context.send_to_opal(:foo)
|
|
137
|
+
}.to raise_error(/No HyperReact components found/)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it 'executes method with args inside opal rubyracer context' do
|
|
141
|
+
ctx = react_context
|
|
142
|
+
context = described_class.new('unique-id', ctx, controller, name)
|
|
143
|
+
context.eval(opal_code)
|
|
144
|
+
result = context.send_to_opal(:greet, 'world')
|
|
145
|
+
expect(result).to eq('Hello, world!')
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it 'executes the method inside opal rubyracer context' do
|
|
149
|
+
ctx = react_context
|
|
150
|
+
context = described_class.new('unique-id', ctx, controller, name)
|
|
151
|
+
context.eval(opal_code)
|
|
152
|
+
result = context.send_to_opal(:valediction)
|
|
153
|
+
expect(result).to eq('Goodbye')
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|