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
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
if ruby?
|
|
4
|
+
RSpec.describe ReactiveRuby::ComponentLoader do
|
|
5
|
+
GLOBAL_WRAPPER = <<-JS
|
|
6
|
+
var global = global || this;
|
|
7
|
+
var self = self || this;
|
|
8
|
+
var window = window || this;
|
|
9
|
+
JS
|
|
10
|
+
|
|
11
|
+
let(:js) { ::Rails.application.assets['components'].to_s }
|
|
12
|
+
let(:context) { ExecJS.compile(GLOBAL_WRAPPER + js) }
|
|
13
|
+
let(:v8_context) { ReactiveRuby::ServerRendering.context_instance_for(context) }
|
|
14
|
+
|
|
15
|
+
describe '.new' do
|
|
16
|
+
it 'raises a meaningful exception when initialized without a context' do
|
|
17
|
+
expect {
|
|
18
|
+
described_class.new(nil)
|
|
19
|
+
}.to raise_error(/Could not obtain ExecJS runtime context/)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#load' do
|
|
24
|
+
it 'loads given asset file into context' do
|
|
25
|
+
loader = described_class.new(v8_context)
|
|
26
|
+
|
|
27
|
+
expect {
|
|
28
|
+
loader.load
|
|
29
|
+
}.to change { !!v8_context.eval('Opal.React') }.from(false).to(true)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'is truthy upon successful load' do
|
|
33
|
+
loader = described_class.new(v8_context)
|
|
34
|
+
expect(loader.load).to be_truthy
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'fails silently returning false' do
|
|
38
|
+
loader = described_class.new(v8_context)
|
|
39
|
+
expect(loader.load('foo')).to be_falsey
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe '#load!' do
|
|
44
|
+
it 'is truthy upon successful load' do
|
|
45
|
+
loader = described_class.new(v8_context)
|
|
46
|
+
expect(loader.load!).to be_truthy
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'raises an expection if loading fails' do
|
|
50
|
+
loader = described_class.new(v8_context)
|
|
51
|
+
expect { loader.load!('foo') }.to raise_error(/No react\.rb components/)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe '#loaded?' do
|
|
56
|
+
it 'is truthy if components file is already loaded' do
|
|
57
|
+
loader = described_class.new(v8_context)
|
|
58
|
+
loader.load
|
|
59
|
+
expect(loader).to be_loaded
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'is false if components file is not loaded' do
|
|
63
|
+
loader = described_class.new(v8_context)
|
|
64
|
+
expect(loader).to_not be_loaded
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.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
|
+
if ruby?
|
|
41
|
+
describe 'load_context', :ruby do
|
|
42
|
+
let(:v8_context) { TestV8Context.new }
|
|
43
|
+
let(:controller) { double('controller') }
|
|
44
|
+
let(:name) { double('name') }
|
|
45
|
+
|
|
46
|
+
it 'creates a context and sets a controller' do
|
|
47
|
+
context = described_class.load_context(v8_context, controller, name)
|
|
48
|
+
expect(context.controller).to eq(controller)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'creates a context and sets a unique_id' do
|
|
52
|
+
Timecop.freeze do
|
|
53
|
+
stamp = Time.now.to_i
|
|
54
|
+
context = described_class.load_context(v8_context, controller, name)
|
|
55
|
+
expect(context.unique_id).to eq("#{ controller.object_id }-#{ stamp }")
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe React::IsomorphicHelpers::Context do
|
|
61
|
+
class TestV8Context < Hash
|
|
62
|
+
def eval(args)
|
|
63
|
+
true
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Need to decouple/dry up this...
|
|
68
|
+
def test_context(files = nil)
|
|
69
|
+
js = ReactiveRuby::ServerRendering::ContextualRenderer::CONSOLE_POLYFILL.dup
|
|
70
|
+
js << Opal::Builder.build('opal').to_s
|
|
71
|
+
Array(files).each do |filename|
|
|
72
|
+
js << ::Rails.application.assets[filename].to_s
|
|
73
|
+
end
|
|
74
|
+
js = "#{React::ServerRendering::ExecJSRenderer::GLOBAL_WRAPPER}#{js}"
|
|
75
|
+
ctx = ExecJS.compile(js)
|
|
76
|
+
ctx = ReactiveRuby::ServerRendering.context_instance_for(ctx)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def react_context
|
|
80
|
+
test_context('components')
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
let(:v8_context) { TestV8Context.new }
|
|
84
|
+
let(:controller) { double('controller') }
|
|
85
|
+
let(:name) { double('name') }
|
|
86
|
+
before do
|
|
87
|
+
described_class.instance_variable_set :@before_first_mount_blocks, nil
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
describe '#initialize' do
|
|
91
|
+
it "sets the given V8 context's ServerSideIsomorphicMethods to itself" do
|
|
92
|
+
context = described_class.new('unique-id', v8_context, controller, name)
|
|
93
|
+
expect(v8_context['ServerSideIsomorphicMethods']).to eq(context)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'calls before mount callbacks' do
|
|
97
|
+
string = instance_double(String)
|
|
98
|
+
described_class.register_before_first_mount_block do
|
|
99
|
+
string.inspect
|
|
100
|
+
end
|
|
101
|
+
expect(string).to receive(:inspect).once
|
|
102
|
+
context = described_class.new('unique-id', v8_context, controller, name)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe '#eval' do
|
|
107
|
+
it 'delegates to given context' do
|
|
108
|
+
context = described_class.new('unique-id', v8_context, controller, name)
|
|
109
|
+
js = 'true;'
|
|
110
|
+
expect(v8_context).to receive(:eval).with(js).once
|
|
111
|
+
context.eval(js)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
describe '#send_to_opal' do
|
|
116
|
+
let(:opal_code) { Opal::Builder.new.build_str(ruby_code, __FILE__) }
|
|
117
|
+
let(:ruby_code) { %Q[
|
|
118
|
+
module React::IsomorphicHelpers
|
|
119
|
+
def self.greet(name)
|
|
120
|
+
"Hello, #\{name}!"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def self.valediction
|
|
124
|
+
'Goodbye'
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
]}
|
|
128
|
+
|
|
129
|
+
it 'raises an error when react cannot be loaded' do
|
|
130
|
+
context = described_class.new('unique-id', v8_context, controller, name)
|
|
131
|
+
context.instance_variable_set(:@ctx, test_context)
|
|
132
|
+
expect {
|
|
133
|
+
context.send_to_opal(:foo)
|
|
134
|
+
}.to raise_error(/No react.rb components found/)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it 'executes method with args inside opal rubyracer context' do
|
|
138
|
+
ctx = react_context
|
|
139
|
+
context = described_class.new('unique-id', ctx, controller, name)
|
|
140
|
+
ctx.eval(opal_code)
|
|
141
|
+
result = context.send_to_opal(:greet, 'world')
|
|
142
|
+
expect(result).to eq('Hello, world!')
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it 'executes the method inside opal rubyracer context' do
|
|
146
|
+
ctx = react_context
|
|
147
|
+
context = described_class.new('unique-id', ctx, controller, name)
|
|
148
|
+
ctx.eval(opal_code)
|
|
149
|
+
result = context.send_to_opal(:valediction)
|
|
150
|
+
expect(result).to eq('Goodbye')
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
if ruby?
|
|
4
|
+
RSpec.describe ReactiveRuby::Rails::ComponentMount do
|
|
5
|
+
let(:helper) { described_class.new }
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
helper.setup(ActionView::TestCase::TestController.new)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#react_component' do
|
|
12
|
+
it 'renders a div' do
|
|
13
|
+
html = helper.react_component('Components::HelloWorld')
|
|
14
|
+
expect(html).to match(/<div.*><\/div>/)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'accepts a pre-render option' do
|
|
18
|
+
html = helper.react_component('Components::HelloWorld', {}, prerender: true)
|
|
19
|
+
expect(html).to match(/<div.*><span.*>Hello, World!<\/span><\/div>/)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'sets data-react-class to React.TopLevelRailsComponent' do
|
|
23
|
+
html = helper.react_component('Components::HelloWorld')
|
|
24
|
+
top_level_class = 'React.TopLevelRailsComponent'
|
|
25
|
+
expect(attr_value(html, 'data-react-class')).to eq(top_level_class)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'sets component_name in data-react-props hash' do
|
|
29
|
+
html = helper.react_component('Components::HelloWorld')
|
|
30
|
+
props = react_props_for(html)
|
|
31
|
+
|
|
32
|
+
expect(props['component_name']).to eq('Components::HelloWorld')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'sets render_params in data-react-props hash' do
|
|
36
|
+
html = helper.react_component('Components::HelloWorld', {'foo' => 'bar'})
|
|
37
|
+
props = react_props_for(html)
|
|
38
|
+
|
|
39
|
+
expect(props['render_params']).to include({ 'foo' => 'bar' })
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'sets controller in data-react-props hash' do
|
|
43
|
+
html = helper.react_component('Components::HelloWorld')
|
|
44
|
+
props = react_props_for(html)
|
|
45
|
+
|
|
46
|
+
expect(props['controller']).to eq('ActionView::TestCase::Test')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'passes additional options through as html attributes' do
|
|
50
|
+
html = helper.react_component('Components::HelloWorld', {},
|
|
51
|
+
{ 'foo-bar' => 'biz-baz' })
|
|
52
|
+
|
|
53
|
+
expect(attr_value(html, 'foo-bar')).to eq('biz-baz')
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def attr_value(html, attr)
|
|
58
|
+
matches = html.match(/#{attr}=["']((?:.(?!["']\s+(?:\S+)=|[>"']))+.)["']?/)
|
|
59
|
+
matches.captures.first
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def react_props_for(html)
|
|
63
|
+
JSON.parse(CGI.unescapeHTML("#{attr_value(html, 'data-react-props')}"))
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
if ruby?
|
|
4
|
+
RSpec.describe ReactiveRuby::ServerRendering::ContextualRenderer do
|
|
5
|
+
let(:renderer) { described_class.new({}) }
|
|
6
|
+
let(:init) { Proc.new {} }
|
|
7
|
+
let(:options) { { context_initializer: init } }
|
|
8
|
+
|
|
9
|
+
describe '#render' do
|
|
10
|
+
it 'pre-renders HTML' do
|
|
11
|
+
result = renderer.render('Components.Todo',
|
|
12
|
+
{ todo: 'finish reactive-ruby' },
|
|
13
|
+
options)
|
|
14
|
+
expect(result).to match(/<li.*>finish reactive-ruby<\/li>/)
|
|
15
|
+
expect(result).to match(/data-react-checksum/)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'accepts props as a string' do
|
|
19
|
+
result = renderer.render('Components.Todo',
|
|
20
|
+
{ todo: 'finish reactive-ruby' }.to_json,
|
|
21
|
+
options)
|
|
22
|
+
expect(result).to match(/<li.*>finish reactive-ruby<\/li>/)
|
|
23
|
+
expect(result).to match(/data-react-checksum/)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'pre-renders static content' do
|
|
27
|
+
result = renderer.render('Components.Todo',
|
|
28
|
+
{ todo: 'finish reactive-ruby' },
|
|
29
|
+
:static)
|
|
30
|
+
expect(result).to match(/<li.*>finish reactive-ruby<\/li>/)
|
|
31
|
+
expect(result).to_not match(/data-react-checksum/)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
ENV["RAILS_ENV"] ||= 'test'
|
|
2
|
+
|
|
3
|
+
require 'opal'
|
|
4
|
+
require 'opal-rspec'
|
|
5
|
+
require 'opal-jquery'
|
|
6
|
+
|
|
7
|
+
def opal?
|
|
8
|
+
RUBY_ENGINE == 'opal'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def ruby?
|
|
12
|
+
!opal?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if RUBY_ENGINE == 'opal'
|
|
17
|
+
require File.expand_path('../vendor/jquery-2.2.4.min', __FILE__)
|
|
18
|
+
require 'react-latest'
|
|
19
|
+
require 'reactive-ruby'
|
|
20
|
+
|
|
21
|
+
require File.expand_path('../support/react/spec_helpers', __FILE__)
|
|
22
|
+
|
|
23
|
+
module Opal
|
|
24
|
+
module RSpec
|
|
25
|
+
module AsyncHelpers
|
|
26
|
+
module ClassMethods
|
|
27
|
+
def rendering(title, &block)
|
|
28
|
+
klass = Class.new do
|
|
29
|
+
include React::Component
|
|
30
|
+
|
|
31
|
+
def self.block
|
|
32
|
+
@block
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.name
|
|
36
|
+
"dummy class"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def render
|
|
40
|
+
instance_eval &self.class.block
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.should_generate(opts={}, &block)
|
|
44
|
+
sself = self
|
|
45
|
+
@self.async(@title, opts) do
|
|
46
|
+
expect_component_to_eventually(sself, &block)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.should_immediately_generate(opts={}, &block)
|
|
51
|
+
sself = self
|
|
52
|
+
@self.it(@title, opts) do
|
|
53
|
+
element = build_element sself, {}
|
|
54
|
+
context = block.arity > 0 ? self : element
|
|
55
|
+
expect((element and context.instance_exec(element, &block))).to be(true)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
klass.instance_variable_set("@block", block)
|
|
61
|
+
klass.instance_variable_set("@self", self)
|
|
62
|
+
klass.instance_variable_set("@title", "it can render #{title}")
|
|
63
|
+
klass
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
RSpec.configure do |config|
|
|
72
|
+
config.include React::SpecHelpers
|
|
73
|
+
config.filter_run_excluding :ruby
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
if RUBY_ENGINE != 'opal'
|
|
78
|
+
begin
|
|
79
|
+
require File.expand_path('../test_app/config/environment', __FILE__)
|
|
80
|
+
rescue LoadError
|
|
81
|
+
puts 'Could not load test application. Please ensure you have run `bundle exec rake test_app`'
|
|
82
|
+
end
|
|
83
|
+
require 'rspec/rails'
|
|
84
|
+
require 'timecop'
|
|
85
|
+
|
|
86
|
+
Dir["./spec/support/**/*.rb"].sort.each { |f| require f }
|
|
87
|
+
|
|
88
|
+
RSpec.configure do |config|
|
|
89
|
+
config.color = true
|
|
90
|
+
config.fail_fast = ENV['FAIL_FAST'] || false
|
|
91
|
+
config.fixture_path = File.join(File.expand_path(File.dirname(__FILE__)), "fixtures")
|
|
92
|
+
config.infer_spec_type_from_file_location!
|
|
93
|
+
config.mock_with :rspec
|
|
94
|
+
config.raise_errors_for_deprecations!
|
|
95
|
+
|
|
96
|
+
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
|
97
|
+
# examples within a transaction, comment the following line or assign false
|
|
98
|
+
# instead of true.
|
|
99
|
+
config.use_transactional_fixtures = true
|
|
100
|
+
|
|
101
|
+
config.before :each do
|
|
102
|
+
Rails.cache.clear
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
config.filter_run_including focus: true
|
|
106
|
+
config.filter_run_excluding opal: true
|
|
107
|
+
config.run_all_when_everything_filtered = true
|
|
108
|
+
end
|
|
109
|
+
end
|