reactrb 0.7.42
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 +7 -0
- data/.codeclimate.yml +6 -0
- data/.gitignore +33 -0
- data/.travis.yml +9 -0
- data/Gemfile +2 -0
- data/LICENSE +19 -0
- data/README.md +117 -0
- data/Rakefile +28 -0
- data/config.ru +16 -0
- data/example/examples/Gemfile +7 -0
- data/example/examples/app/basics.js.rb +42 -0
- data/example/examples/app/items.rb +11 -0
- data/example/examples/app/jquery.js +5 -0
- data/example/examples/app/nodes.rb +61 -0
- data/example/examples/app/react-router.js +6 -0
- data/example/examples/app/react_api_demo.rb +29 -0
- data/example/examples/app/rerendering.rb +72 -0
- data/example/examples/app/reuse.rb +59 -0
- data/example/examples/app/show.rb +52 -0
- data/example/examples/config.ru +38 -0
- data/example/rails-tutorial/.gitignore +17 -0
- data/example/rails-tutorial/Gemfile +51 -0
- data/example/rails-tutorial/README.rdoc +28 -0
- data/example/rails-tutorial/Rakefile +6 -0
- data/example/rails-tutorial/app/assets/images/.keep +0 -0
- data/example/rails-tutorial/app/assets/javascripts/application.rb +15 -0
- data/example/rails-tutorial/app/assets/stylesheets/application.css +15 -0
- data/example/rails-tutorial/app/controllers/application_controller.rb +6 -0
- data/example/rails-tutorial/app/controllers/concerns/.keep +0 -0
- data/example/rails-tutorial/app/controllers/home_controller.rb +6 -0
- data/example/rails-tutorial/app/helpers/application_helper.rb +2 -0
- data/example/rails-tutorial/app/mailers/.keep +0 -0
- data/example/rails-tutorial/app/models/.keep +0 -0
- data/example/rails-tutorial/app/models/concerns/.keep +0 -0
- data/example/rails-tutorial/app/views/components.rb +3 -0
- data/example/rails-tutorial/app/views/components/home/show.rb +47 -0
- data/example/rails-tutorial/app/views/layouts/application.html.erb +14 -0
- data/example/rails-tutorial/bin/bundle +3 -0
- data/example/rails-tutorial/bin/rails +8 -0
- data/example/rails-tutorial/bin/rake +8 -0
- data/example/rails-tutorial/bin/setup +29 -0
- data/example/rails-tutorial/bin/spring +15 -0
- data/example/rails-tutorial/config.ru +4 -0
- data/example/rails-tutorial/config/application.rb +26 -0
- data/example/rails-tutorial/config/boot.rb +3 -0
- data/example/rails-tutorial/config/database.yml +25 -0
- data/example/rails-tutorial/config/environment.rb +5 -0
- data/example/rails-tutorial/config/environments/development.rb +41 -0
- data/example/rails-tutorial/config/environments/production.rb +79 -0
- data/example/rails-tutorial/config/environments/test.rb +42 -0
- data/example/rails-tutorial/config/initializers/assets.rb +11 -0
- data/example/rails-tutorial/config/initializers/backtrace_silencers.rb +7 -0
- data/example/rails-tutorial/config/initializers/cookies_serializer.rb +3 -0
- data/example/rails-tutorial/config/initializers/filter_parameter_logging.rb +4 -0
- data/example/rails-tutorial/config/initializers/inflections.rb +16 -0
- data/example/rails-tutorial/config/initializers/mime_types.rb +4 -0
- data/example/rails-tutorial/config/initializers/session_store.rb +3 -0
- data/example/rails-tutorial/config/initializers/wrap_parameters.rb +14 -0
- data/example/rails-tutorial/config/locales/en.yml +23 -0
- data/example/rails-tutorial/config/routes.rb +59 -0
- data/example/rails-tutorial/config/secrets.yml +22 -0
- data/example/rails-tutorial/db/seeds.rb +7 -0
- data/example/rails-tutorial/lib/assets/.keep +0 -0
- data/example/rails-tutorial/lib/tasks/.keep +0 -0
- data/example/rails-tutorial/log/.keep +0 -0
- data/example/rails-tutorial/public/404.html +67 -0
- data/example/rails-tutorial/public/422.html +67 -0
- data/example/rails-tutorial/public/500.html +66 -0
- data/example/rails-tutorial/public/favicon.ico +0 -0
- data/example/rails-tutorial/public/robots.txt +5 -0
- data/example/rails-tutorial/test/controllers/.keep +0 -0
- data/example/rails-tutorial/test/fixtures/.keep +0 -0
- data/example/rails-tutorial/test/helpers/.keep +0 -0
- data/example/rails-tutorial/test/integration/.keep +0 -0
- data/example/rails-tutorial/test/mailers/.keep +0 -0
- data/example/rails-tutorial/test/models/.keep +0 -0
- data/example/rails-tutorial/test/test_helper.rb +10 -0
- data/example/rails-tutorial/vendor/assets/javascripts/.keep +0 -0
- data/example/rails-tutorial/vendor/assets/stylesheets/.keep +0 -0
- data/example/sinatra-tutorial/.DS_Store +0 -0
- data/example/sinatra-tutorial/Gemfile +5 -0
- data/example/sinatra-tutorial/README.md +8 -0
- data/example/sinatra-tutorial/_comments.json +42 -0
- data/example/sinatra-tutorial/app/example.rb +290 -0
- data/example/sinatra-tutorial/app/jquery.js +5 -0
- data/example/sinatra-tutorial/config.ru +58 -0
- data/example/sinatra-tutorial/public/base.css +62 -0
- data/example/todos/Gemfile +11 -0
- data/example/todos/README.md +37 -0
- data/example/todos/Rakefile +8 -0
- data/example/todos/app/application.rb +22 -0
- data/example/todos/app/components/app.react.rb +61 -0
- data/example/todos/app/components/footer.react.rb +31 -0
- data/example/todos/app/components/todo_item.react.rb +46 -0
- data/example/todos/app/components/todo_list.react.rb +25 -0
- data/example/todos/app/models/todo.rb +19 -0
- data/example/todos/config.ru +14 -0
- data/example/todos/index.html.haml +16 -0
- data/example/todos/spec/todo_spec.rb +28 -0
- data/example/todos/vendor/base.css +410 -0
- data/example/todos/vendor/bg.png +0 -0
- data/example/todos/vendor/jquery.js +4 -0
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +4 -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/test_app_generator.rb +105 -0
- data/lib/rails-helpers/top_level_rails_component.rb +54 -0
- data/lib/react/api.rb +127 -0
- data/lib/react/callbacks.rb +42 -0
- data/lib/react/component.rb +269 -0
- data/lib/react/component/api.rb +50 -0
- data/lib/react/component/base.rb +9 -0
- data/lib/react/component/class_methods.rb +190 -0
- data/lib/react/component/props_wrapper.rb +82 -0
- data/lib/react/element.rb +77 -0
- data/lib/react/event.rb +76 -0
- data/lib/react/ext/hash.rb +9 -0
- data/lib/react/ext/string.rb +8 -0
- data/lib/react/native_library.rb +53 -0
- data/lib/react/observable.rb +29 -0
- data/lib/react/rendering_context.rb +109 -0
- data/lib/react/state.rb +140 -0
- data/lib/react/top_level.rb +97 -0
- data/lib/react/validator.rb +136 -0
- data/lib/reactive-ruby/component_loader.rb +45 -0
- data/lib/reactive-ruby/isomorphic_helpers.rb +196 -0
- data/lib/reactive-ruby/rails.rb +7 -0
- data/lib/reactive-ruby/rails/component_mount.rb +44 -0
- data/lib/reactive-ruby/rails/controller_helper.rb +13 -0
- data/lib/reactive-ruby/rails/railtie.rb +14 -0
- data/lib/reactive-ruby/serializers.rb +15 -0
- data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +42 -0
- data/lib/reactive-ruby/version.rb +3 -0
- data/lib/reactrb.rb +50 -0
- data/lib/sources/react-latest.js +21167 -0
- data/lib/sources/react-v13.js +21642 -0
- data/lib/sources/react-v14.js +20818 -0
- data/lib/sources/react-v15.js +21167 -0
- data/logo1.png +0 -0
- data/logo2.png +0 -0
- data/logo3.png +0 -0
- data/path_release_steps.md +9 -0
- data/reactrb.gemspec +43 -0
- data/spec/controller_helper_spec.rb +22 -0
- data/spec/index.html.erb +12 -0
- data/spec/react/callbacks_spec.rb +106 -0
- data/spec/react/component/base_spec.rb +36 -0
- data/spec/react/component_spec.rb +721 -0
- data/spec/react/dsl_spec.rb +161 -0
- data/spec/react/element_spec.rb +47 -0
- data/spec/react/event_spec.rb +24 -0
- data/spec/react/native_library_spec.rb +10 -0
- data/spec/react/observable_spec.rb +7 -0
- data/spec/react/param_declaration_spec.rb +286 -0
- data/spec/react/react_spec.rb +211 -0
- data/spec/react/state_spec.rb +26 -0
- data/spec/react/top_level_component_spec.rb +68 -0
- data/spec/react/tutorial/tutorial_spec.rb +35 -0
- data/spec/react/validator_spec.rb +128 -0
- data/spec/reactive-ruby/component_loader_spec.rb +68 -0
- data/spec/reactive-ruby/isomorphic_helpers_spec.rb +155 -0
- data/spec/reactive-ruby/rails/asset_pipeline_spec.rb +9 -0
- data/spec/reactive-ruby/rails/component_mount_spec.rb +66 -0
- data/spec/reactive-ruby/server_rendering/contextual_renderer_spec.rb +35 -0
- data/spec/spec_helper.rb +109 -0
- data/spec/support/react/spec_helpers.rb +57 -0
- data/spec/vendor/es5-shim.min.js +6 -0
- data/spec/vendor/jquery-2.2.4.min.js +4 -0
- metadata +441 -0
data/logo1.png
ADDED
|
Binary file
|
data/logo2.png
ADDED
|
Binary file
|
data/logo3.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
For example assuming you are releasing fix to 0.8.18
|
|
3
|
+
|
|
4
|
+
1. Checkout 0-8-stable
|
|
5
|
+
2. Update tests, fix the bug and commit the changes.
|
|
6
|
+
3. Build & Release to RubyGems (Remember the version in version.rb should already be 0.8.19)
|
|
7
|
+
4. Create a tag 'v0.8.19' pointing to that commit. (`tag v0.8.19`)
|
|
8
|
+
5. Bump the version in 0-8-stable to 0.8.20 so it will be ready for the next patch level release.
|
|
9
|
+
6. Commit the version bump, and do a `git push --tags` so the new tag goes up
|
data/reactrb.gemspec
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path('../lib/', __FILE__)
|
|
3
|
+
|
|
4
|
+
require 'reactive-ruby/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |s|
|
|
7
|
+
s.name = 'reactrb'
|
|
8
|
+
s.version = React::VERSION
|
|
9
|
+
|
|
10
|
+
s.authors = ['David Chang', 'Adam Jahn', 'Mitch VanDuyn']
|
|
11
|
+
s.email = 'reactrb@catprint.com'
|
|
12
|
+
s.homepage = 'https://reactrb.org'
|
|
13
|
+
s.summary = 'Opal Ruby wrapper of React.js library.'
|
|
14
|
+
s.license = 'MIT'
|
|
15
|
+
s.description = "Write React UI components in pure Ruby."
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
19
|
+
s.require_paths = ['lib']
|
|
20
|
+
|
|
21
|
+
s.add_dependency 'opal', '>= 0.8.0'
|
|
22
|
+
s.add_dependency 'opal-activesupport', '>= 0.2.0'
|
|
23
|
+
s.add_dependency 'opal-browser', '0.2.0'
|
|
24
|
+
s.add_development_dependency 'rake'
|
|
25
|
+
s.add_development_dependency 'rspec-rails', '3.3.3'
|
|
26
|
+
s.add_development_dependency 'timecop'
|
|
27
|
+
s.add_development_dependency 'opal-rspec', '0.4.3'
|
|
28
|
+
s.add_development_dependency 'sinatra'
|
|
29
|
+
s.add_development_dependency 'opal-jquery'
|
|
30
|
+
|
|
31
|
+
# For Test Rails App
|
|
32
|
+
s.add_development_dependency 'rails', '4.2.4'
|
|
33
|
+
s.add_development_dependency 'react-rails'
|
|
34
|
+
s.add_development_dependency 'opal-rails', '0.8.1'
|
|
35
|
+
if RUBY_PLATFORM == 'java'
|
|
36
|
+
s.add_development_dependency 'jdbc-sqlite3'
|
|
37
|
+
s.add_development_dependency 'activerecord-jdbcsqlite3-adapter'
|
|
38
|
+
s.add_development_dependency 'therubyrhino'
|
|
39
|
+
else
|
|
40
|
+
s.add_development_dependency 'sqlite3', '1.3.10'
|
|
41
|
+
s.add_development_dependency 'therubyracer', '0.12.2'
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
if ruby?
|
|
4
|
+
class TestController < ActionController::Base; end
|
|
5
|
+
|
|
6
|
+
RSpec.describe TestController, type: :controller do
|
|
7
|
+
render_views
|
|
8
|
+
|
|
9
|
+
describe '#render_component' do
|
|
10
|
+
controller do
|
|
11
|
+
def index
|
|
12
|
+
render_component
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'renders the application layout' do
|
|
17
|
+
get :index, no_prerender: true
|
|
18
|
+
expect(response).to render_template(layout: :application)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/spec/index.html.erb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
</head>
|
|
5
|
+
<body>
|
|
6
|
+
<%= javascript_include_tag 'vendor/es5-shim.min' %>
|
|
7
|
+
<%= javascript_include_tag 'vendor/jquery-2.2.4.min' %>
|
|
8
|
+
<%= javascript_include_tag @server.main %>
|
|
9
|
+
<div id="placeholder" style="display: none"></div>
|
|
10
|
+
<div id="render_here"></div>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
if opal?
|
|
4
|
+
describe React::Callbacks do
|
|
5
|
+
it 'defines callback' do
|
|
6
|
+
stub_const 'Foo', Class.new
|
|
7
|
+
Foo.class_eval do
|
|
8
|
+
include React::Callbacks
|
|
9
|
+
define_callback :before_dinner
|
|
10
|
+
before_dinner :wash_hand
|
|
11
|
+
|
|
12
|
+
def wash_hand
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
expect_any_instance_of(Foo).to receive(:wash_hand)
|
|
17
|
+
Foo.new.run_callback(:before_dinner)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'defines multiple callbacks' do
|
|
21
|
+
stub_const 'Foo', Class.new
|
|
22
|
+
Foo.class_eval do
|
|
23
|
+
include React::Callbacks
|
|
24
|
+
define_callback :before_dinner
|
|
25
|
+
|
|
26
|
+
before_dinner :wash_hand, :turn_of_laptop
|
|
27
|
+
|
|
28
|
+
def wash_hand;end
|
|
29
|
+
|
|
30
|
+
def turn_of_laptop;end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
expect_any_instance_of(Foo).to receive(:wash_hand)
|
|
34
|
+
expect_any_instance_of(Foo).to receive(:turn_of_laptop)
|
|
35
|
+
Foo.new.run_callback(:before_dinner)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'defines block callback' do
|
|
39
|
+
stub_const 'Foo', Class.new
|
|
40
|
+
Foo.class_eval do
|
|
41
|
+
include React::Callbacks
|
|
42
|
+
attr_accessor :a
|
|
43
|
+
attr_accessor :b
|
|
44
|
+
|
|
45
|
+
define_callback :before_dinner
|
|
46
|
+
|
|
47
|
+
before_dinner do
|
|
48
|
+
self.a = 10
|
|
49
|
+
end
|
|
50
|
+
before_dinner do
|
|
51
|
+
self.b = 20
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
foo = Foo.new
|
|
56
|
+
foo.run_callback(:before_dinner)
|
|
57
|
+
expect(foo.a).to eq(10)
|
|
58
|
+
expect(foo.b).to eq(20)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'defines multiple callback group' do
|
|
62
|
+
stub_const 'Foo', Class.new
|
|
63
|
+
Foo.class_eval do
|
|
64
|
+
include React::Callbacks
|
|
65
|
+
define_callback :before_dinner
|
|
66
|
+
define_callback :after_dinner
|
|
67
|
+
attr_accessor :a
|
|
68
|
+
|
|
69
|
+
before_dinner do
|
|
70
|
+
self.a = 10
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
foo = Foo.new
|
|
75
|
+
foo.run_callback(:before_dinner)
|
|
76
|
+
foo.run_callback(:after_dinner)
|
|
77
|
+
|
|
78
|
+
expect(foo.a).to eq(10)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'receives args as callback' do
|
|
82
|
+
stub_const 'Foo', Class.new
|
|
83
|
+
Foo.class_eval do
|
|
84
|
+
include React::Callbacks
|
|
85
|
+
define_callback :before_dinner
|
|
86
|
+
define_callback :after_dinner
|
|
87
|
+
|
|
88
|
+
attr_accessor :lorem
|
|
89
|
+
|
|
90
|
+
before_dinner do |a, b|
|
|
91
|
+
self.lorem = "#{a}-#{b}"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
after_dinner :eat_ice_cream
|
|
95
|
+
def eat_ice_cream(a,b,c); end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
expect_any_instance_of(Foo).to receive(:eat_ice_cream).with(4,5,6)
|
|
99
|
+
|
|
100
|
+
foo = Foo.new
|
|
101
|
+
foo.run_callback(:before_dinner, 1, 2)
|
|
102
|
+
foo.run_callback(:after_dinner, 4, 5, 6)
|
|
103
|
+
expect(foo.lorem).to eq('1-2')
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
if opal?
|
|
4
|
+
describe React::Component::Base do
|
|
5
|
+
after(:each) do
|
|
6
|
+
React::API.clear_component_class_cache
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'can be inherited to create a component class' do
|
|
10
|
+
stub_const 'Foo', Class.new(React::Component::Base)
|
|
11
|
+
Foo.class_eval do
|
|
12
|
+
before_mount do
|
|
13
|
+
@instance_data = ["working"]
|
|
14
|
+
end
|
|
15
|
+
def render
|
|
16
|
+
@instance_data.first
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
stub_const 'Bar', Class.new(Foo)
|
|
20
|
+
Bar.class_eval do
|
|
21
|
+
before_mount do
|
|
22
|
+
@instance_data << "well"
|
|
23
|
+
end
|
|
24
|
+
def render
|
|
25
|
+
@instance_data.join(" ")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
expect(rendered_component(Foo)).to eq("<span>working</span>")
|
|
29
|
+
expect(rendered_component(Bar)).to eq("<span>working well</span>")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def rendered_component(component)
|
|
33
|
+
React.render_to_static_markup(React.create_element(component))
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,721 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
if opal?
|
|
4
|
+
describe React::Component do
|
|
5
|
+
after(:each) do
|
|
6
|
+
React::API.clear_component_class_cache
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'defines component spec methods' do
|
|
10
|
+
stub_const 'Foo', Class.new
|
|
11
|
+
Foo.class_eval do
|
|
12
|
+
include React::Component
|
|
13
|
+
def render
|
|
14
|
+
React.create_element('div')
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Class Methods
|
|
19
|
+
expect(Foo).to respond_to('initial_state')
|
|
20
|
+
expect(Foo).to respond_to('default_props')
|
|
21
|
+
expect(Foo).to respond_to('prop_types')
|
|
22
|
+
|
|
23
|
+
# Instance method
|
|
24
|
+
expect(Foo.new).to respond_to('component_will_mount')
|
|
25
|
+
expect(Foo.new).to respond_to('component_did_mount')
|
|
26
|
+
expect(Foo.new).to respond_to('component_will_receive_props')
|
|
27
|
+
expect(Foo.new).to respond_to('should_component_update?')
|
|
28
|
+
expect(Foo.new).to respond_to('component_will_update')
|
|
29
|
+
expect(Foo.new).to respond_to('component_did_update')
|
|
30
|
+
expect(Foo.new).to respond_to('component_will_unmount')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe 'Life Cycle' do
|
|
34
|
+
before(:each) do
|
|
35
|
+
stub_const 'Foo', Class.new
|
|
36
|
+
Foo.class_eval do
|
|
37
|
+
include React::Component
|
|
38
|
+
def render
|
|
39
|
+
React.create_element('div') { 'lorem' }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'invokes `before_mount` registered methods when `componentWillMount()`' do
|
|
45
|
+
Foo.class_eval do
|
|
46
|
+
before_mount :bar, :bar2
|
|
47
|
+
def bar; end
|
|
48
|
+
def bar2; end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
expect_any_instance_of(Foo).to receive(:bar)
|
|
52
|
+
expect_any_instance_of(Foo).to receive(:bar2)
|
|
53
|
+
|
|
54
|
+
renderToDocument(Foo)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'invokes `after_mount` registered methods when `componentDidMount()`' do
|
|
58
|
+
Foo.class_eval do
|
|
59
|
+
after_mount :bar3, :bar4
|
|
60
|
+
def bar3; end
|
|
61
|
+
def bar4; end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
expect_any_instance_of(Foo).to receive(:bar3)
|
|
65
|
+
expect_any_instance_of(Foo).to receive(:bar4)
|
|
66
|
+
|
|
67
|
+
renderToDocument(Foo)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'allows multiple class declared life cycle hooker' do
|
|
71
|
+
stub_const 'FooBar', Class.new
|
|
72
|
+
Foo.class_eval do
|
|
73
|
+
before_mount :bar
|
|
74
|
+
def bar; end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
FooBar.class_eval do
|
|
78
|
+
include React::Component
|
|
79
|
+
after_mount :bar2
|
|
80
|
+
def bar2; end
|
|
81
|
+
def render
|
|
82
|
+
React.create_element('div') { 'lorem' }
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
expect_any_instance_of(Foo).to receive(:bar)
|
|
87
|
+
|
|
88
|
+
renderToDocument(Foo)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'allows block for life cycle callback' do
|
|
92
|
+
Foo.class_eval do
|
|
93
|
+
export_state(:foo)
|
|
94
|
+
|
|
95
|
+
before_mount do
|
|
96
|
+
foo! 'bar'
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
element = renderToDocument(Foo)
|
|
101
|
+
expect(Foo.foo).to be('bar')
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe 'New style setter & getter' do
|
|
106
|
+
before(:each) do
|
|
107
|
+
stub_const 'Foo', Class.new
|
|
108
|
+
Foo.class_eval do
|
|
109
|
+
include React::Component
|
|
110
|
+
def render
|
|
111
|
+
div { state.foo }
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it 'implicitly will create a state variable when first written' do
|
|
117
|
+
Foo.class_eval do
|
|
118
|
+
before_mount do
|
|
119
|
+
state.foo! 'bar'
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>bar</div>')
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it 'allows kernal method names like "format" to be used as state variable names' do
|
|
127
|
+
Foo.class_eval do
|
|
128
|
+
before_mount do
|
|
129
|
+
state.format! 'yes'
|
|
130
|
+
state.foo! state.format
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>yes</div>')
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it 'returns an observer with the bang method and no arguments' do
|
|
138
|
+
Foo.class_eval do
|
|
139
|
+
before_mount do
|
|
140
|
+
state.foo!(state.baz!.class.name)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>React::Observable</div>')
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it 'returns the current value of a state when written' do
|
|
148
|
+
Foo.class_eval do
|
|
149
|
+
before_mount do
|
|
150
|
+
state.baz! 'bar'
|
|
151
|
+
state.foo!(state.baz!('pow'))
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>bar</div>')
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it 'can access an explicitly defined state`' do
|
|
159
|
+
Foo.class_eval do
|
|
160
|
+
define_state foo: :bar
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>bar</div>')
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe 'State setter & getter' do
|
|
169
|
+
before(:each) do
|
|
170
|
+
stub_const 'Foo', Class.new
|
|
171
|
+
Foo.class_eval do
|
|
172
|
+
include React::Component
|
|
173
|
+
def render
|
|
174
|
+
React.create_element('div') { 'lorem' }
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it 'defines setter using `define_state`' do
|
|
180
|
+
Foo.class_eval do
|
|
181
|
+
define_state :foo
|
|
182
|
+
before_mount :set_up
|
|
183
|
+
def set_up
|
|
184
|
+
self.foo = 'bar'
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
element = renderToDocument(Foo)
|
|
189
|
+
expect(element.state.foo).to be('bar')
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it 'defines init state by passing a block to `define_state`' do
|
|
193
|
+
Foo.class_eval do
|
|
194
|
+
define_state(:foo) { 10 }
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
element = renderToDocument(Foo)
|
|
198
|
+
expect(element.state.foo).to be(10)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it 'defines getter using `define_state`' do
|
|
202
|
+
Foo.class_eval do
|
|
203
|
+
define_state(:foo) { 10 }
|
|
204
|
+
before_mount :bump
|
|
205
|
+
def bump
|
|
206
|
+
self.foo = self.foo + 20
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
element = renderToDocument(Foo)
|
|
211
|
+
expect(element.state.foo).to be(30)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it 'defines multiple state accessors by passing array to `define_state`' do
|
|
215
|
+
Foo.class_eval do
|
|
216
|
+
define_state :foo, :foo2
|
|
217
|
+
before_mount :set_up
|
|
218
|
+
def set_up
|
|
219
|
+
self.foo = 10
|
|
220
|
+
self.foo2 = 20
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
element = renderToDocument(Foo)
|
|
225
|
+
expect(element.state.foo).to be(10)
|
|
226
|
+
expect(element.state.foo2).to be(20)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
it 'invokes `define_state` multiple times to define states' do
|
|
230
|
+
Foo.class_eval do
|
|
231
|
+
define_state(:foo) { 30 }
|
|
232
|
+
define_state(:foo2) { 40 }
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
element = renderToDocument(Foo)
|
|
236
|
+
expect(element.state.foo).to be(30)
|
|
237
|
+
expect(element.state.foo2).to be(40)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it 'can initialize multiple state variables with a block' do
|
|
241
|
+
Foo.class_eval do
|
|
242
|
+
define_state(:foo, :foo2) { 30 }
|
|
243
|
+
end
|
|
244
|
+
element = renderToDocument(Foo)
|
|
245
|
+
expect(element.state.foo).to be(30)
|
|
246
|
+
expect(element.state.foo2).to be(30)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
it 'can mix multiple state variables with initializers and a block' do
|
|
250
|
+
Foo.class_eval do
|
|
251
|
+
define_state(:x, :y, foo: 1, bar: 2) {3}
|
|
252
|
+
end
|
|
253
|
+
element = renderToDocument(Foo)
|
|
254
|
+
expect(element.state.x).to be(3)
|
|
255
|
+
expect(element.state.y).to be(3)
|
|
256
|
+
expect(element.state.foo).to be(1)
|
|
257
|
+
expect(element.state.bar).to be(2)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
it 'gets state in render method' do
|
|
261
|
+
Foo.class_eval do
|
|
262
|
+
define_state(:foo) { 10 }
|
|
263
|
+
def render
|
|
264
|
+
React.create_element('div') { self.foo }
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
element = renderToDocument(Foo)
|
|
269
|
+
expect(Element[element].text).to eq('10')
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
it 'supports original `setState` as `set_state` method' do
|
|
273
|
+
Foo.class_eval do
|
|
274
|
+
before_mount do
|
|
275
|
+
self.set_state(foo: 'bar')
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
element = renderToDocument(Foo)
|
|
280
|
+
expect(element.state.foo).to be('bar')
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
it 'supports original `replaceState` as `set_state!` method' do
|
|
284
|
+
Foo.class_eval do
|
|
285
|
+
before_mount do
|
|
286
|
+
self.set_state(foo: 'bar')
|
|
287
|
+
self.set_state!(bar: 'lorem')
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
element = renderToDocument(Foo)
|
|
292
|
+
expect(element.state.foo).to be_nil
|
|
293
|
+
expect(element.state.bar).to eq('lorem')
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
it 'supports original `state` method' do
|
|
297
|
+
Foo.class_eval do
|
|
298
|
+
before_mount do
|
|
299
|
+
self.set_state(foo: 'bar')
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def render
|
|
303
|
+
div { self.state[:foo] }
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>bar</div>')
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
it 'transforms state getter to Ruby object' do
|
|
311
|
+
Foo.class_eval do
|
|
312
|
+
define_state :foo
|
|
313
|
+
|
|
314
|
+
before_mount do
|
|
315
|
+
self.foo = [{a: "Hello"}]
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def render
|
|
319
|
+
div { self.foo[0][:a] }
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>Hello</div>')
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
describe 'Props' do
|
|
328
|
+
describe 'this.props could be accessed through `params` method' do
|
|
329
|
+
before do
|
|
330
|
+
stub_const 'Foo', Class.new
|
|
331
|
+
Foo.class_eval do
|
|
332
|
+
include React::Component
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
it 'reads from parent passed properties through `params`' do
|
|
337
|
+
Foo.class_eval do
|
|
338
|
+
def render
|
|
339
|
+
React.create_element('div') { params[:prop] }
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
element = renderToDocument(Foo, prop: 'foobar')
|
|
344
|
+
expect(Element[element].text).to eq('foobar')
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
it 'accesses nested params as orignal Ruby object' do
|
|
348
|
+
Foo.class_eval do
|
|
349
|
+
def render
|
|
350
|
+
React.create_element('div') { params[:prop][0][:foo] }
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
element = renderToDocument(Foo, prop: [{foo: 10}])
|
|
355
|
+
expect(Element[element].text).to eq('10')
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# deprecated as of React 14
|
|
360
|
+
# describe 'Props Updating' do
|
|
361
|
+
# before do
|
|
362
|
+
# stub_const 'Foo', Class.new
|
|
363
|
+
# Foo.class_eval do
|
|
364
|
+
# include React::Component
|
|
365
|
+
# end
|
|
366
|
+
# end
|
|
367
|
+
#
|
|
368
|
+
# it 'supports original `setProps` as method `set_props`' do
|
|
369
|
+
# Foo.class_eval do
|
|
370
|
+
# def render
|
|
371
|
+
# React.create_element('div') { params[:foo] }
|
|
372
|
+
# end
|
|
373
|
+
# end
|
|
374
|
+
#
|
|
375
|
+
# element = renderToDocument(Foo, {foo: 10})
|
|
376
|
+
# element.set_props(foo: 20)
|
|
377
|
+
# expect(`#{element.dom_node}.innerHTML`).to eq('20')
|
|
378
|
+
# end
|
|
379
|
+
#
|
|
380
|
+
# it 'supports original `replaceProps` as method `set_props!`' do
|
|
381
|
+
# Foo.class_eval do
|
|
382
|
+
# def render
|
|
383
|
+
# React.create_element('div') { params[:foo] ? 'exist' : 'null' }
|
|
384
|
+
# end
|
|
385
|
+
# end
|
|
386
|
+
#
|
|
387
|
+
# element = renderToDocument(Foo, {foo: 10})
|
|
388
|
+
# element.set_props!(bar: 20)
|
|
389
|
+
# expect(element.getDOMNode.innerHTML).to eq('null')
|
|
390
|
+
# end
|
|
391
|
+
# end
|
|
392
|
+
|
|
393
|
+
describe 'Prop validation' do
|
|
394
|
+
before do
|
|
395
|
+
stub_const 'Foo', Class.new
|
|
396
|
+
Foo.class_eval do
|
|
397
|
+
include React::Component
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
it 'specifies validation rules using `params` class method' do
|
|
402
|
+
Foo.class_eval do
|
|
403
|
+
params do
|
|
404
|
+
requires :foo, type: String
|
|
405
|
+
optional :bar
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
expect(Foo.prop_types).to have_key(:_componentValidator)
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
it 'logs error in warning if validation failed' do
|
|
413
|
+
stub_const 'Lorem', Class.new
|
|
414
|
+
Foo.class_eval do
|
|
415
|
+
params do
|
|
416
|
+
requires :foo
|
|
417
|
+
requires :lorem, type: Lorem
|
|
418
|
+
optional :bar, type: String
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def render; div; end
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
%x{
|
|
425
|
+
var log = [];
|
|
426
|
+
var org_warn_console = window.console.warn;
|
|
427
|
+
var org_error_console = window.console.error;
|
|
428
|
+
window.console.warn = window.console.error = function(str){log.push(str)}
|
|
429
|
+
}
|
|
430
|
+
renderToDocument(Foo, bar: 10, lorem: Lorem.new)
|
|
431
|
+
`window.console.warn = org_warn_console; window.console.error = org_error_console;`
|
|
432
|
+
expect(`log`).to eq(["Warning: Failed propType: In component `Foo`\nRequired prop `foo` was not specified\nProvided prop `bar` could not be converted to String"])
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
it 'should not log anything if validation pass' do
|
|
436
|
+
stub_const 'Lorem', Class.new
|
|
437
|
+
Foo.class_eval do
|
|
438
|
+
params do
|
|
439
|
+
requires :foo
|
|
440
|
+
requires :lorem, type: Lorem
|
|
441
|
+
optional :bar, type: String
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def render; div; end
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
%x{
|
|
448
|
+
var log = [];
|
|
449
|
+
var org_warn_console = window.console.warn;
|
|
450
|
+
var org_error_console = window.console.error
|
|
451
|
+
window.console.warn = window.console.error = function(str){log.push(str)}
|
|
452
|
+
}
|
|
453
|
+
renderToDocument(Foo, foo: 10, bar: '10', lorem: Lorem.new)
|
|
454
|
+
`window.console.warn = org_warn_console; window.console.error = org_error_console;`
|
|
455
|
+
expect(`log`).to eq([])
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
describe 'Default props' do
|
|
460
|
+
it 'sets default props using validation helper' do
|
|
461
|
+
stub_const 'Foo', Class.new
|
|
462
|
+
Foo.class_eval do
|
|
463
|
+
include React::Component
|
|
464
|
+
params do
|
|
465
|
+
optional :foo, default: 'foo'
|
|
466
|
+
optional :bar, default: 'bar'
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
def render
|
|
470
|
+
div { params[:foo] + '-' + params[:bar]}
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
expect(React.render_to_static_markup(React.create_element(Foo, foo: 'lorem'))).to eq('<div>lorem-bar</div>')
|
|
475
|
+
expect(React.render_to_static_markup(React.create_element(Foo))).to eq('<div>foo-bar</div>')
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
describe 'Event handling' do
|
|
481
|
+
before do
|
|
482
|
+
stub_const 'Foo', Class.new
|
|
483
|
+
Foo.class_eval do
|
|
484
|
+
include React::Component
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
it 'works in render method' do
|
|
489
|
+
Foo.class_eval do
|
|
490
|
+
define_state(:clicked) { false }
|
|
491
|
+
|
|
492
|
+
def render
|
|
493
|
+
React.create_element('div').on(:click) do
|
|
494
|
+
self.clicked = true
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
element = React.create_element(Foo)
|
|
500
|
+
instance = renderElementToDocument(element)
|
|
501
|
+
simulateEvent(:click, instance)
|
|
502
|
+
expect(instance.state.clicked).to eq(true)
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
it 'invokes handler on `this.props` using emit' do
|
|
506
|
+
Foo.class_eval do
|
|
507
|
+
after_mount :setup
|
|
508
|
+
|
|
509
|
+
def setup
|
|
510
|
+
self.emit(:foo_submit, 'bar')
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
def render
|
|
514
|
+
React.create_element('div')
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
expect { |b|
|
|
519
|
+
element = React.create_element(Foo).on(:foo_submit, &b)
|
|
520
|
+
renderElementToDocument(element)
|
|
521
|
+
}.to yield_with_args('bar')
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
it 'invokes handler with multiple params using emit' do
|
|
525
|
+
Foo.class_eval do
|
|
526
|
+
after_mount :setup
|
|
527
|
+
|
|
528
|
+
def setup
|
|
529
|
+
self.emit(:foo_invoked, [1,2,3], 'bar')
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
def render
|
|
533
|
+
React.create_element('div')
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
expect { |b|
|
|
538
|
+
element = React.create_element(Foo).on(:foo_invoked, &b)
|
|
539
|
+
renderElementToDocument(element)
|
|
540
|
+
}.to yield_with_args([1,2,3], 'bar')
|
|
541
|
+
end
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
describe '#refs' do
|
|
545
|
+
before do
|
|
546
|
+
stub_const 'Foo', Class.new
|
|
547
|
+
Foo.class_eval do
|
|
548
|
+
include React::Component
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
it 'correctly assigns refs' do
|
|
553
|
+
Foo.class_eval do
|
|
554
|
+
def render
|
|
555
|
+
React.create_element('input', type: :text, ref: :field)
|
|
556
|
+
end
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
element = renderToDocument(Foo)
|
|
560
|
+
expect(element.refs.field).not_to be_nil
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
it 'accesses refs through `refs` method' do
|
|
564
|
+
Foo.class_eval do
|
|
565
|
+
def render
|
|
566
|
+
React.create_element('input', type: :text, ref: :field).on(:click) do
|
|
567
|
+
refs[:field].value = 'some_stuff'
|
|
568
|
+
end
|
|
569
|
+
end
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
element = renderToDocument(Foo)
|
|
573
|
+
simulateEvent(:click, element)
|
|
574
|
+
|
|
575
|
+
expect(element.refs.field.value).to eq('some_stuff')
|
|
576
|
+
end
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
describe '#render' do
|
|
580
|
+
it 'supports element building helpers' do
|
|
581
|
+
stub_const 'Foo', Class.new
|
|
582
|
+
Foo.class_eval do
|
|
583
|
+
include React::Component
|
|
584
|
+
|
|
585
|
+
def render
|
|
586
|
+
div do
|
|
587
|
+
span { params[:foo] }
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
stub_const 'Bar', Class.new
|
|
593
|
+
Bar.class_eval do
|
|
594
|
+
include React::Component
|
|
595
|
+
def render
|
|
596
|
+
div do
|
|
597
|
+
present Foo, foo: 'astring'
|
|
598
|
+
end
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
expect(React.render_to_static_markup(React.create_element(Bar))).to eq('<div><div><span>astring</span></div></div>')
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
it 'builds single node in top-level render without providing a block' do
|
|
606
|
+
stub_const 'Foo', Class.new
|
|
607
|
+
Foo.class_eval do
|
|
608
|
+
include React::Component
|
|
609
|
+
|
|
610
|
+
def render
|
|
611
|
+
div
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
element = React.create_element(Foo)
|
|
616
|
+
expect(React.render_to_static_markup(element)).to eq('<div></div>')
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
it 'redefines `p` to make method missing work' do
|
|
620
|
+
stub_const 'Foo', Class.new
|
|
621
|
+
Foo.class_eval do
|
|
622
|
+
include React::Component
|
|
623
|
+
|
|
624
|
+
def render
|
|
625
|
+
p(class_name: 'foo') do
|
|
626
|
+
p
|
|
627
|
+
div { 'lorem ipsum' }
|
|
628
|
+
p(id: '10')
|
|
629
|
+
end
|
|
630
|
+
end
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
element = React.create_element(Foo)
|
|
634
|
+
markup = '<p class="foo"><p></p><div>lorem ipsum</div><p id="10"></p></p>'
|
|
635
|
+
expect(React.render_to_static_markup(element)).to eq(markup)
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
it 'only overrides `p` in render context' do
|
|
639
|
+
stub_const 'Foo', Class.new
|
|
640
|
+
Foo.class_eval do
|
|
641
|
+
include React::Component
|
|
642
|
+
|
|
643
|
+
before_mount do
|
|
644
|
+
p 'first'
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
after_mount do
|
|
648
|
+
p 'second'
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
def render
|
|
652
|
+
div
|
|
653
|
+
end
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
expect(Kernel).to receive(:p).with('first')
|
|
657
|
+
expect(Kernel).to receive(:p).with('second')
|
|
658
|
+
renderToDocument(Foo)
|
|
659
|
+
end
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
describe 'isMounted()' do
|
|
663
|
+
it 'returns true if after mounted' do
|
|
664
|
+
stub_const 'Foo', Class.new
|
|
665
|
+
Foo.class_eval do
|
|
666
|
+
include React::Component
|
|
667
|
+
|
|
668
|
+
def render
|
|
669
|
+
React.create_element('div')
|
|
670
|
+
end
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
component = renderToDocument(Foo)
|
|
674
|
+
expect(component.mounted?).to eq(true)
|
|
675
|
+
end
|
|
676
|
+
end
|
|
677
|
+
|
|
678
|
+
describe '#children' do
|
|
679
|
+
before(:each) do
|
|
680
|
+
stub_const 'Foo', Class.new
|
|
681
|
+
Foo.class_eval do
|
|
682
|
+
include React::Component
|
|
683
|
+
export_state :the_children
|
|
684
|
+
before_mount do
|
|
685
|
+
the_children! children
|
|
686
|
+
end
|
|
687
|
+
def render
|
|
688
|
+
React.create_element('div') { 'lorem' }
|
|
689
|
+
end
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
it 'returns an Enumerable' do
|
|
694
|
+
ele = React.create_element(Foo) {
|
|
695
|
+
[React.create_element('a'), React.create_element('li')]
|
|
696
|
+
}
|
|
697
|
+
renderElementToDocument(ele)
|
|
698
|
+
nodes = Foo.the_children.map { |ele| ele.element_type }
|
|
699
|
+
expect(nodes).to eq(['a', 'li'])
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
it 'returns an Enumerator when not providing a block' do
|
|
703
|
+
ele = React.create_element(Foo) {
|
|
704
|
+
[React.create_element('a'), React.create_element('li')]
|
|
705
|
+
}
|
|
706
|
+
renderElementToDocument(ele)
|
|
707
|
+
nodes = Foo.the_children.each
|
|
708
|
+
expect(nodes).to be_a(Enumerator)
|
|
709
|
+
expect(nodes.size).to eq(2)
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
it 'returns an empty Enumerator if there are no children' do
|
|
713
|
+
ele = React.create_element(Foo)
|
|
714
|
+
renderElementToDocument(ele)
|
|
715
|
+
nodes = Foo.the_children.each
|
|
716
|
+
expect(nodes.size).to eq(nil)
|
|
717
|
+
expect(nodes.count).to eq(0)
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
end
|
|
721
|
+
end
|