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.
Files changed (173) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +6 -0
  3. data/.gitignore +33 -0
  4. data/.travis.yml +9 -0
  5. data/Gemfile +2 -0
  6. data/LICENSE +19 -0
  7. data/README.md +117 -0
  8. data/Rakefile +28 -0
  9. data/config.ru +16 -0
  10. data/example/examples/Gemfile +7 -0
  11. data/example/examples/app/basics.js.rb +42 -0
  12. data/example/examples/app/items.rb +11 -0
  13. data/example/examples/app/jquery.js +5 -0
  14. data/example/examples/app/nodes.rb +61 -0
  15. data/example/examples/app/react-router.js +6 -0
  16. data/example/examples/app/react_api_demo.rb +29 -0
  17. data/example/examples/app/rerendering.rb +72 -0
  18. data/example/examples/app/reuse.rb +59 -0
  19. data/example/examples/app/show.rb +52 -0
  20. data/example/examples/config.ru +38 -0
  21. data/example/rails-tutorial/.gitignore +17 -0
  22. data/example/rails-tutorial/Gemfile +51 -0
  23. data/example/rails-tutorial/README.rdoc +28 -0
  24. data/example/rails-tutorial/Rakefile +6 -0
  25. data/example/rails-tutorial/app/assets/images/.keep +0 -0
  26. data/example/rails-tutorial/app/assets/javascripts/application.rb +15 -0
  27. data/example/rails-tutorial/app/assets/stylesheets/application.css +15 -0
  28. data/example/rails-tutorial/app/controllers/application_controller.rb +6 -0
  29. data/example/rails-tutorial/app/controllers/concerns/.keep +0 -0
  30. data/example/rails-tutorial/app/controllers/home_controller.rb +6 -0
  31. data/example/rails-tutorial/app/helpers/application_helper.rb +2 -0
  32. data/example/rails-tutorial/app/mailers/.keep +0 -0
  33. data/example/rails-tutorial/app/models/.keep +0 -0
  34. data/example/rails-tutorial/app/models/concerns/.keep +0 -0
  35. data/example/rails-tutorial/app/views/components.rb +3 -0
  36. data/example/rails-tutorial/app/views/components/home/show.rb +47 -0
  37. data/example/rails-tutorial/app/views/layouts/application.html.erb +14 -0
  38. data/example/rails-tutorial/bin/bundle +3 -0
  39. data/example/rails-tutorial/bin/rails +8 -0
  40. data/example/rails-tutorial/bin/rake +8 -0
  41. data/example/rails-tutorial/bin/setup +29 -0
  42. data/example/rails-tutorial/bin/spring +15 -0
  43. data/example/rails-tutorial/config.ru +4 -0
  44. data/example/rails-tutorial/config/application.rb +26 -0
  45. data/example/rails-tutorial/config/boot.rb +3 -0
  46. data/example/rails-tutorial/config/database.yml +25 -0
  47. data/example/rails-tutorial/config/environment.rb +5 -0
  48. data/example/rails-tutorial/config/environments/development.rb +41 -0
  49. data/example/rails-tutorial/config/environments/production.rb +79 -0
  50. data/example/rails-tutorial/config/environments/test.rb +42 -0
  51. data/example/rails-tutorial/config/initializers/assets.rb +11 -0
  52. data/example/rails-tutorial/config/initializers/backtrace_silencers.rb +7 -0
  53. data/example/rails-tutorial/config/initializers/cookies_serializer.rb +3 -0
  54. data/example/rails-tutorial/config/initializers/filter_parameter_logging.rb +4 -0
  55. data/example/rails-tutorial/config/initializers/inflections.rb +16 -0
  56. data/example/rails-tutorial/config/initializers/mime_types.rb +4 -0
  57. data/example/rails-tutorial/config/initializers/session_store.rb +3 -0
  58. data/example/rails-tutorial/config/initializers/wrap_parameters.rb +14 -0
  59. data/example/rails-tutorial/config/locales/en.yml +23 -0
  60. data/example/rails-tutorial/config/routes.rb +59 -0
  61. data/example/rails-tutorial/config/secrets.yml +22 -0
  62. data/example/rails-tutorial/db/seeds.rb +7 -0
  63. data/example/rails-tutorial/lib/assets/.keep +0 -0
  64. data/example/rails-tutorial/lib/tasks/.keep +0 -0
  65. data/example/rails-tutorial/log/.keep +0 -0
  66. data/example/rails-tutorial/public/404.html +67 -0
  67. data/example/rails-tutorial/public/422.html +67 -0
  68. data/example/rails-tutorial/public/500.html +66 -0
  69. data/example/rails-tutorial/public/favicon.ico +0 -0
  70. data/example/rails-tutorial/public/robots.txt +5 -0
  71. data/example/rails-tutorial/test/controllers/.keep +0 -0
  72. data/example/rails-tutorial/test/fixtures/.keep +0 -0
  73. data/example/rails-tutorial/test/helpers/.keep +0 -0
  74. data/example/rails-tutorial/test/integration/.keep +0 -0
  75. data/example/rails-tutorial/test/mailers/.keep +0 -0
  76. data/example/rails-tutorial/test/models/.keep +0 -0
  77. data/example/rails-tutorial/test/test_helper.rb +10 -0
  78. data/example/rails-tutorial/vendor/assets/javascripts/.keep +0 -0
  79. data/example/rails-tutorial/vendor/assets/stylesheets/.keep +0 -0
  80. data/example/sinatra-tutorial/.DS_Store +0 -0
  81. data/example/sinatra-tutorial/Gemfile +5 -0
  82. data/example/sinatra-tutorial/README.md +8 -0
  83. data/example/sinatra-tutorial/_comments.json +42 -0
  84. data/example/sinatra-tutorial/app/example.rb +290 -0
  85. data/example/sinatra-tutorial/app/jquery.js +5 -0
  86. data/example/sinatra-tutorial/config.ru +58 -0
  87. data/example/sinatra-tutorial/public/base.css +62 -0
  88. data/example/todos/Gemfile +11 -0
  89. data/example/todos/README.md +37 -0
  90. data/example/todos/Rakefile +8 -0
  91. data/example/todos/app/application.rb +22 -0
  92. data/example/todos/app/components/app.react.rb +61 -0
  93. data/example/todos/app/components/footer.react.rb +31 -0
  94. data/example/todos/app/components/todo_item.react.rb +46 -0
  95. data/example/todos/app/components/todo_list.react.rb +25 -0
  96. data/example/todos/app/models/todo.rb +19 -0
  97. data/example/todos/config.ru +14 -0
  98. data/example/todos/index.html.haml +16 -0
  99. data/example/todos/spec/todo_spec.rb +28 -0
  100. data/example/todos/vendor/base.css +410 -0
  101. data/example/todos/vendor/bg.png +0 -0
  102. data/example/todos/vendor/jquery.js +4 -0
  103. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +4 -0
  104. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +2 -0
  105. data/lib/generators/reactive_ruby/test_app/templates/boot.rb.erb +6 -0
  106. data/lib/generators/reactive_ruby/test_app/templates/script/rails +5 -0
  107. data/lib/generators/reactive_ruby/test_app/templates/test_application.rb.erb +13 -0
  108. data/lib/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +11 -0
  109. data/lib/generators/reactive_ruby/test_app/templates/views/components/todo.rb +14 -0
  110. data/lib/generators/reactive_ruby/test_app/test_app_generator.rb +105 -0
  111. data/lib/rails-helpers/top_level_rails_component.rb +54 -0
  112. data/lib/react/api.rb +127 -0
  113. data/lib/react/callbacks.rb +42 -0
  114. data/lib/react/component.rb +269 -0
  115. data/lib/react/component/api.rb +50 -0
  116. data/lib/react/component/base.rb +9 -0
  117. data/lib/react/component/class_methods.rb +190 -0
  118. data/lib/react/component/props_wrapper.rb +82 -0
  119. data/lib/react/element.rb +77 -0
  120. data/lib/react/event.rb +76 -0
  121. data/lib/react/ext/hash.rb +9 -0
  122. data/lib/react/ext/string.rb +8 -0
  123. data/lib/react/native_library.rb +53 -0
  124. data/lib/react/observable.rb +29 -0
  125. data/lib/react/rendering_context.rb +109 -0
  126. data/lib/react/state.rb +140 -0
  127. data/lib/react/top_level.rb +97 -0
  128. data/lib/react/validator.rb +136 -0
  129. data/lib/reactive-ruby/component_loader.rb +45 -0
  130. data/lib/reactive-ruby/isomorphic_helpers.rb +196 -0
  131. data/lib/reactive-ruby/rails.rb +7 -0
  132. data/lib/reactive-ruby/rails/component_mount.rb +44 -0
  133. data/lib/reactive-ruby/rails/controller_helper.rb +13 -0
  134. data/lib/reactive-ruby/rails/railtie.rb +14 -0
  135. data/lib/reactive-ruby/serializers.rb +15 -0
  136. data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +42 -0
  137. data/lib/reactive-ruby/version.rb +3 -0
  138. data/lib/reactrb.rb +50 -0
  139. data/lib/sources/react-latest.js +21167 -0
  140. data/lib/sources/react-v13.js +21642 -0
  141. data/lib/sources/react-v14.js +20818 -0
  142. data/lib/sources/react-v15.js +21167 -0
  143. data/logo1.png +0 -0
  144. data/logo2.png +0 -0
  145. data/logo3.png +0 -0
  146. data/path_release_steps.md +9 -0
  147. data/reactrb.gemspec +43 -0
  148. data/spec/controller_helper_spec.rb +22 -0
  149. data/spec/index.html.erb +12 -0
  150. data/spec/react/callbacks_spec.rb +106 -0
  151. data/spec/react/component/base_spec.rb +36 -0
  152. data/spec/react/component_spec.rb +721 -0
  153. data/spec/react/dsl_spec.rb +161 -0
  154. data/spec/react/element_spec.rb +47 -0
  155. data/spec/react/event_spec.rb +24 -0
  156. data/spec/react/native_library_spec.rb +10 -0
  157. data/spec/react/observable_spec.rb +7 -0
  158. data/spec/react/param_declaration_spec.rb +286 -0
  159. data/spec/react/react_spec.rb +211 -0
  160. data/spec/react/state_spec.rb +26 -0
  161. data/spec/react/top_level_component_spec.rb +68 -0
  162. data/spec/react/tutorial/tutorial_spec.rb +35 -0
  163. data/spec/react/validator_spec.rb +128 -0
  164. data/spec/reactive-ruby/component_loader_spec.rb +68 -0
  165. data/spec/reactive-ruby/isomorphic_helpers_spec.rb +155 -0
  166. data/spec/reactive-ruby/rails/asset_pipeline_spec.rb +9 -0
  167. data/spec/reactive-ruby/rails/component_mount_spec.rb +66 -0
  168. data/spec/reactive-ruby/server_rendering/contextual_renderer_spec.rb +35 -0
  169. data/spec/spec_helper.rb +109 -0
  170. data/spec/support/react/spec_helpers.rb +57 -0
  171. data/spec/vendor/es5-shim.min.js +6 -0
  172. data/spec/vendor/jquery-2.2.4.min.js +4 -0
  173. metadata +441 -0
@@ -0,0 +1,211 @@
1
+ require "spec_helper"
2
+
3
+ if opal?
4
+ describe React do
5
+ after(:each) do
6
+ React::API.clear_component_class_cache
7
+ end
8
+
9
+ describe "is_valid_element" do
10
+ it "should return true if passed a valid element" do
11
+ element = React::Element.new(`React.createElement('div')`)
12
+ expect(React.is_valid_element(element)).to eq(true)
13
+ end
14
+
15
+ it "should return false is passed a non React element" do
16
+ element = React::Element.new(`{}`)
17
+ expect(React.is_valid_element(element)).to eq(false)
18
+ end
19
+ end
20
+
21
+ describe "create_element" do
22
+ it "should create a valid element with only tag" do
23
+ element = React.create_element('div')
24
+ expect(React.is_valid_element(element)).to eq(true)
25
+ end
26
+
27
+ context "with block" do
28
+ it "should create a valid element with text as only child when block yield String" do
29
+ element = React.create_element('div') { "lorem ipsum" }
30
+ expect(React.is_valid_element(element)).to eq(true)
31
+ expect(element.props.children).to eq("lorem ipsum")
32
+ end
33
+
34
+ it "should create a valid element with children as array when block yield Array of element" do
35
+ element = React.create_element('div') do
36
+ [React.create_element('span'), React.create_element('span'), React.create_element('span')]
37
+ end
38
+ expect(React.is_valid_element(element)).to eq(true)
39
+ expect(element.props.children.length).to eq(3)
40
+ end
41
+
42
+ it "should render element with children as array when block yield Array of element" do
43
+ element = React.create_element('div') do
44
+ [React.create_element('span'), React.create_element('span'), React.create_element('span')]
45
+ end
46
+ instance = renderElementToDocument(element)
47
+ expect(Element[instance].children.length).to eq(3)
48
+ end
49
+ end
50
+
51
+ describe "custom element" do
52
+ before do
53
+ stub_const 'Foo', Class.new
54
+ Foo.class_eval do
55
+ def render
56
+ React.create_element("div") { "lorem" }
57
+ end
58
+ end
59
+ end
60
+
61
+ it "should render element with only one children correctly" do
62
+ element = React.create_element(Foo) { React.create_element('span') }
63
+ instance = renderElementToDocument(element)
64
+ expect(instance.props.children).not_to be_a(Array)
65
+ expect(instance.props.children.type).to eq("span")
66
+ end
67
+
68
+ it "should render element with more than one children correctly" do
69
+ element = React.create_element(Foo) { [React.create_element('span'), React.create_element('span')] }
70
+ instance = renderElementToDocument(element)
71
+ expect(instance.props.children).to be_a(Array)
72
+ expect(instance.props.children.length).to eq(2)
73
+ end
74
+
75
+ it "should create a valid element provided class defined `render`" do
76
+ element = React.create_element(Foo)
77
+ expect(React.is_valid_element(element)).to eq(true)
78
+ end
79
+
80
+ it "should allow creating with properties" do
81
+ element = React.create_element(Foo, foo: "bar")
82
+ expect(element.props.foo).to eq("bar")
83
+ end
84
+
85
+ it "should raise error if provided class doesn't defined `render`" do
86
+ expect { React.create_element(Array) }.to raise_error
87
+ end
88
+
89
+ it "should use the same instance for the same ReactComponent" do
90
+ Foo.class_eval do
91
+ attr_accessor :a
92
+ def initialize(n)
93
+ self.a = 10
94
+ end
95
+
96
+ def component_will_mount
97
+ self.a = 20
98
+ end
99
+
100
+ def render
101
+ React.create_element("div") { self.a.to_s }
102
+ end
103
+ end
104
+
105
+ expect(React.render_to_static_markup(React.create_element(Foo))).to eq("<div>20</div>")
106
+ end
107
+
108
+ it "should match the instance cycle to ReactComponent life cycle" do
109
+ `var count = 0;`
110
+
111
+ Foo.class_eval do
112
+ def initialize
113
+ `count = count + 1;`
114
+ end
115
+ def render
116
+ React.create_element("div")
117
+ end
118
+ end
119
+
120
+ renderToDocument(Foo)
121
+ renderToDocument(Foo)
122
+
123
+ expect(`count`).to eq(2)
124
+ end
125
+ end
126
+
127
+ describe "create element with properties" do
128
+ it "should enforce snake-cased property name" do
129
+ element = React.create_element("div", class_name: "foo")
130
+ expect(element.props.className).to eq("foo")
131
+ end
132
+
133
+ it "should allow custom property" do
134
+ element = React.create_element("div", foo: "bar")
135
+ expect(element.props.foo).to eq("bar")
136
+ end
137
+
138
+ it "should not camel-case custom property" do
139
+ element = React.create_element("div", foo_bar: "foo")
140
+ expect(element.props.foo_bar).to eq("foo")
141
+ end
142
+ end
143
+
144
+ describe "class_name helpers (React.addons.classSet)" do
145
+
146
+ # deprecated as of React 14
147
+ # it "should transform Hash provided to `class_name` props as string" do
148
+ # classes = {foo: true, bar: false, lorem: true}
149
+ # element = React.create_element("div", class_name: classes)
150
+ # expect(element.props.className).to eq("foo lorem")
151
+ # end
152
+
153
+ it "should not alter behavior when passing a string" do
154
+ element = React.create_element("div", class_name: "foo bar")
155
+
156
+ expect(element.props.className).to eq("foo bar")
157
+ end
158
+ end
159
+ end
160
+
161
+ describe "render" do
162
+ async "should render element to DOM" do
163
+ div = `document.createElement("div")`
164
+ React.render(React.create_element('span') { "lorem" }, div) do
165
+ run_async {
166
+ expect(`div.children[0].tagName`).to eq("SPAN")
167
+ expect(`div.textContent`).to eq("lorem")
168
+ }
169
+ end
170
+ end
171
+
172
+ it "should work without providing a block" do
173
+ div = `document.createElement("div")`
174
+ React.render(React.create_element('span') { "lorem" }, div)
175
+ end
176
+
177
+ it "should return a React::Component::API compatible object" do
178
+ div = `document.createElement("div")`
179
+ component = React.render(React.create_element('span') { "lorem" }, div)
180
+ React::Component::API.public_instance_methods(true).each do |method_name|
181
+ expect(component).to respond_to(method_name)
182
+ end
183
+ end
184
+
185
+ pending "should return nil to prevent abstraction leakage" do
186
+ div = `document.createElement("div")`
187
+ expect {
188
+ React.render(React.create_element('span') { "lorem" }, div)
189
+ }.to be_nil
190
+ end
191
+ end
192
+
193
+ describe "render_to_string" do
194
+ it "should render a React.Element to string" do
195
+ ele = React.create_element('span') { "lorem" }
196
+ expect(React.render_to_string(ele)).to be_kind_of(String)
197
+ end
198
+ end
199
+
200
+ describe "unmount_component_at_node" do
201
+ async "should unmount component at node" do
202
+ div = `document.createElement("div")`
203
+ React.render(React.create_element('span') { "lorem" }, div ) do
204
+ run_async {
205
+ expect(React.unmount_component_at_node(div)).to eq(true)
206
+ }
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ describe 'React::State' do
5
+ it "can created static exported states" do
6
+ stub_const 'Foo', Class.new
7
+ Foo.class_eval do
8
+ include React::Component
9
+ export_state(:foo) { 'bar' }
10
+ end
11
+
12
+ expect(Foo.foo).to eq('bar')
13
+ end
14
+
15
+ # these will all require async operations and testing to see if things get
16
+ # re-rendered see spec_helper the "render" test method
17
+
18
+ # if Foo.foo is used during rendering then when Foo.foo changes we will
19
+ # rerender
20
+ it "sets up observers when exported states are read"
21
+
22
+ # React::State.set_state(object, attribute, value) +
23
+ # React::State.get_state(object, attribute)
24
+ it "can be accessed outside of react using get/set_state"
25
+ end
26
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+
5
+ module Components
6
+
7
+ module Controller
8
+ class Component1
9
+ include React::Component
10
+ def render
11
+ self.class.name.to_s
12
+ end
13
+ end
14
+ end
15
+
16
+ class Component1
17
+ include React::Component
18
+ def render
19
+ self.class.name.to_s
20
+ end
21
+ end
22
+
23
+ class Component2
24
+ include React::Component
25
+ def render
26
+ self.class.name.to_s
27
+ end
28
+ end
29
+ end
30
+
31
+ module Controller
32
+ class SomeOtherClass # see issue #80
33
+ end
34
+ end
35
+
36
+ class Component1
37
+ include React::Component
38
+ def render
39
+ self.class.name.to_s
40
+ end
41
+ end
42
+
43
+
44
+ def render_top_level(controller, component_name)
45
+ React.render_to_static_markup(React.create_element(
46
+ React::TopLevelRailsComponent, {controller: controller, component_name: component_name, render_params: {}}))
47
+ end
48
+
49
+ describe React::TopLevelRailsComponent do
50
+
51
+ it 'uses the controller name to lookup a component' do
52
+ expect(render_top_level("Controller", "Component1")).to eq('<span>Components::Controller::Component1</span>')
53
+ end
54
+
55
+ it 'can find the name without matching the controller' do
56
+ expect(render_top_level("Controller", "Component2")).to eq('<span>Components::Component2</span>')
57
+ end
58
+
59
+ it 'will find the outer most matching component' do
60
+ expect(render_top_level("OtherController", "Component1")).to eq('<span>Component1</span>')
61
+ end
62
+
63
+ it 'can find the correct component when the name is fully qualified' do
64
+ expect(render_top_level("Controller", "::Components::Component1")).to eq('<span>Components::Component1</span>')
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ class HelloMessage
5
+ include React::Component
6
+ def render
7
+ div { "Hello World!" }
8
+ end
9
+ end
10
+
11
+ describe 'An Example from the react.rb doc' do
12
+ it 'produces the correct result' do
13
+ expect(React.render_to_static_markup(React.create_element(HelloMessage))).to eq('<div>Hello World!</div>')
14
+ end
15
+ end
16
+
17
+ class HelloMessage2
18
+ include React::Component
19
+ define_state(:user_name) { '@catmando' }
20
+ def render
21
+ div { "Hello #{user_name}" }
22
+ end
23
+ end
24
+
25
+ describe 'Adding state to a component (second tutorial example)' do
26
+ it "produces the correct result" do
27
+ expect(React.render_to_static_markup(React.create_element(HelloMessage2))).to eq('<div>Hello @catmando</div>')
28
+ end
29
+
30
+ it 'renders to the document' do
31
+ React.render(React.create_element(HelloMessage2), `document.getElementById('render_here')`)
32
+ expect(`document.getElementById('render_here').innerHTML`) =~ 'Hello @catmando'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,128 @@
1
+ require "spec_helper"
2
+
3
+ if opal?
4
+ describe React::Validator do
5
+ before do
6
+ stub_const 'Foo', Class.new(React::Component::Base)
7
+ end
8
+ describe '#validate' do
9
+ describe "Presence validation" do
10
+ it "should check if required props provided" do
11
+ validator = React::Validator.new(Foo).build do
12
+ requires :foo
13
+ requires :bar
14
+ end
15
+
16
+ expect(validator.validate({})).to eq(["Required prop `foo` was not specified", "Required prop `bar` was not specified"])
17
+ expect(validator.validate({foo: 1, bar: 3})).to eq([])
18
+ end
19
+
20
+ it "should check if passed non specified prop" do
21
+ validator = React::Validator.new(Foo).build do
22
+ optional :foo
23
+ end
24
+
25
+ expect(validator.validate({bar: 10})).to eq(["Provided prop `bar` not specified in spec"])
26
+ expect(validator.validate({foo: 10})).to eq([])
27
+ end
28
+ end
29
+
30
+ describe "Type validation" do
31
+ it "should check if passed value with wrong type" do
32
+ validator = React::Validator.new(Foo).build do
33
+ requires :foo, type: String
34
+ end
35
+
36
+ expect(validator.validate({foo: 10})).to eq(["Provided prop `foo` could not be converted to String"])
37
+ expect(validator.validate({foo: "10"})).to eq([])
38
+ end
39
+
40
+ it "should check if passed value with wrong custom type" do
41
+ stub_const 'Bar', Class.new
42
+ validator = React::Validator.new(Foo).build do
43
+ requires :foo, type: Bar
44
+ end
45
+
46
+ expect(validator.validate({foo: 10})).to eq(["Provided prop `foo` could not be converted to Bar"])
47
+ expect(validator.validate({foo: Bar.new})).to eq([])
48
+ end
49
+
50
+ it 'coerces native JS prop types to opal objects' do
51
+ validator = React::Validator.new(Foo).build do
52
+ requires :foo, type: `{ x: 1 }`
53
+ end
54
+
55
+ message = "Provided prop `foo` could not be converted to [object Object]"
56
+ expect(validator.validate({foo: `{ x: 1 }`})).to eq([message])
57
+ end
58
+
59
+ it 'coerces native JS values to opal objects' do
60
+ validator = React::Validator.new(Foo).build do
61
+ requires :foo, type: Array[Fixnum]
62
+ end
63
+
64
+ message = "Provided prop `foo`[0] could not be converted to Numeric"
65
+ expect(validator.validate({foo: `[ { x: 1 } ]`})).to eq([message])
66
+ end
67
+
68
+ it "should support Array[Class] validation" do
69
+ validator = React::Validator.new(Foo).build do
70
+ requires :foo, type: Array[Hash]
71
+ end
72
+
73
+ expect(validator.validate({foo: [1,'2',3]})).to eq(
74
+ [
75
+ "Provided prop `foo`[0] could not be converted to Hash",
76
+ "Provided prop `foo`[1] could not be converted to Hash",
77
+ "Provided prop `foo`[2] could not be converted to Hash"
78
+ ]
79
+ )
80
+ expect(validator.validate({foo: [{},{},{}]})).to eq([])
81
+ end
82
+ end
83
+
84
+ describe "Limited values" do
85
+ it "should check if passed value is not one of the specified values" do
86
+ validator = React::Validator.new(Foo).build do
87
+ requires :foo, values: [4,5,6]
88
+ end
89
+
90
+ expect(validator.validate({foo: 3})).to eq(["Value `3` for prop `foo` is not an allowed value"])
91
+ expect(validator.validate({foo: 4})).to eq([])
92
+ end
93
+ end
94
+ end
95
+
96
+ describe '#undefined_props' do
97
+ let(:props) { { foo: 'foo', bar: 'bar', biz: 'biz', baz: 'baz' } }
98
+ let(:validator) do
99
+ React::Validator.new(Foo).build do
100
+ requires :foo
101
+ optional :bar
102
+ end
103
+ end
104
+
105
+ it 'slurps up any extra params into a hash' do
106
+ others = validator.undefined_props(props)
107
+ expect(others).to eq({ biz: 'biz', baz: 'baz' })
108
+ end
109
+
110
+ it 'prevents validate non-specified params' do
111
+ validator.undefined_props(props)
112
+ expect(validator.validate(props)).to eq([])
113
+ end
114
+ end
115
+
116
+ describe "default_props" do
117
+ it "should return specified default values" do
118
+ validator = React::Validator.new(Foo).build do
119
+ requires :foo, default: 10
120
+ requires :bar
121
+ optional :lorem, default: 20
122
+ end
123
+
124
+ expect(validator.default_props).to eq({foo: 10, lorem: 20})
125
+ end
126
+ end
127
+ end
128
+ end