hyper-spec 1.0.alpha1.3 → 1.0.alpha1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,362 +0,0 @@
1
- # see component_test_helpers_spec.rb for examples
2
- require 'parser/current'
3
- require 'unparser'
4
- require 'hyper-spec/unparser_patch'
5
- require 'method_source'
6
- require_relative '../../lib/hyper-spec/time_cop.rb'
7
-
8
- module HyperSpec
9
- module ComponentTestHelpers
10
- TOP_LEVEL_COMPONENT_PATCH =
11
- Opal.compile(File.read(File.expand_path('../../sources/top_level_rails_component.rb', __FILE__)))
12
- TIME_COP_CLIENT_PATCH =
13
- Opal.compile(File.read(File.expand_path('../../hyper-spec/time_cop.rb', __FILE__))) +
14
- "\n#{File.read(File.expand_path('../../sources/lolex.js', __FILE__))}"
15
-
16
- class << self
17
- attr_accessor :current_example
18
- attr_accessor :description_displayed
19
-
20
- def display_example_description
21
- "<script type='text/javascript'>console.log('%c#{current_example.description}'"\
22
- ",'color:green; font-weight:bold; font-size: 200%')</script>"
23
- end
24
- end
25
-
26
- def build_test_url_for(controller)
27
- unless controller
28
- unless defined?(::HyperstackTestController)
29
- Object.const_set('HyperstackTestController', Class.new(::ActionController::Base))
30
- end
31
-
32
- controller = ::HyperstackTestController
33
- end
34
-
35
- route_root = controller.name.gsub(/Controller$/, '').underscore
36
-
37
- unless controller.method_defined?(:test)
38
- controller.class_eval do
39
- define_method(:test) do
40
- route_root = self.class.name.gsub(/Controller$/, '').underscore
41
- test_params = ::Rails.cache.read("/#{route_root}/#{params[:id]}")
42
- @component_name = test_params[0]
43
- @component_params = test_params[1]
44
- render_params = test_params[2]
45
- render_on = render_params.delete(:render_on) || :client_only
46
- _mock_time = render_params.delete(:mock_time)
47
- style_sheet = render_params.delete(:style_sheet)
48
- javascript = render_params.delete(:javascript)
49
- code = render_params.delete(:code)
50
-
51
- page = '<%= react_component @component_name, @component_params, '\
52
- "{ prerender: #{render_on != :client_only} } %>"
53
- unless render_on == :server_only
54
- page = "<script type='text/javascript'>\n#{TOP_LEVEL_COMPONENT_PATCH}\n</script>\n#{page}"
55
- page = "<script type='text/javascript'>\n#{code}\n</script>\n#{page}" if code
56
- end
57
-
58
- if render_on != :server_only || Lolex.initialized?
59
- page = "<script type='text/javascript'>\n#{TIME_COP_CLIENT_PATCH}\n</script>\n#{page}"
60
- end
61
-
62
- if (render_on != :server_only && !render_params[:layout]) || javascript
63
- page = "<%= javascript_include_tag '#{javascript || 'application'}' %>\n#{page}"
64
- end
65
-
66
- if !render_params[:layout] || style_sheet
67
- page = "<%= stylesheet_link_tag '#{style_sheet || 'application'}' %>\n#{page}"
68
- end
69
- page = "<script type='text/javascript'>go = function() "\
70
- "{window.hyper_spec_waiting_for_go = false}</script>\n#{page}"
71
-
72
- title = view_context.escape_javascript(ComponentTestHelpers.current_example.description)
73
- title = "#{title}...continued." if ComponentTestHelpers.description_displayed
74
-
75
- page = "<script type='text/javascript'>console.log('%c#{title}',"\
76
- "'color:green; font-weight:bold; font-size: 200%')</script>\n#{page}"
77
-
78
- ComponentTestHelpers.description_displayed = true
79
- render_params[:inline] = page
80
- render render_params
81
- end
82
- end
83
-
84
- begin
85
- routes = ::Rails.application.routes
86
- routes.disable_clear_and_finalize = true
87
- routes.clear!
88
- routes.draw do
89
- get "/#{route_root}/:id", to: "#{route_root}#test"
90
- end
91
- ::Rails.application.routes_reloader.paths.each { |path| load(path) }
92
- routes.finalize!
93
- ActiveSupport.on_load(:action_controller) { routes.finalize! }
94
- ensure
95
- routes.disable_clear_and_finalize = false
96
- end
97
- end
98
-
99
- "/#{route_root}/#{@test_id = (@test_id || 0) + 1}"
100
- end
101
-
102
- def isomorphic(&block)
103
- yield
104
- on_client(&block)
105
- end
106
-
107
- def evaluate_ruby(str = '', opts = {}, &block)
108
- insure_mount
109
- if block
110
- str = "#{str}\n#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.last}"
111
- end
112
- js = Opal.compile(str).delete("\n").gsub('(Opal);', '(Opal)')
113
- # workaround for firefox 58 and geckodriver 0.19.1, because firefox is unable to find .$to_json:
114
- # JSON.parse(evaluate_script("(function(){var a=Opal.Array.$new(); a[0]=#{js}; return a.$to_json();})();"), opts).first
115
- JSON.parse(evaluate_script("[#{js}].$to_json()"), opts).first
116
- end
117
-
118
- def expect_evaluate_ruby(str = '', opts = {}, &block)
119
- insure_mount
120
- expect(evaluate_ruby(add_opal_block(str, block), opts))
121
- end
122
-
123
- def add_opal_block(str, block)
124
- # big assumption here is that we are going to follow this with a .to
125
- # hence .children.first followed by .children.last
126
- # probably should do some kind of "search" to make this work nicely
127
- return str unless block
128
- "#{str}\n"\
129
- "#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.first.children.last}"
130
- end
131
-
132
- def evaluate_promise(str = '', opts = {}, &block)
133
- insure_mount
134
- str = "#{str}\n#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.last}" if block
135
- str = "#{str}.then { |args| args = [args]; `window.hyper_spec_promise_result = args` }"
136
- js = Opal.compile(str).gsub("\n","").gsub("(Opal);","(Opal)")
137
- page.evaluate_script("window.hyper_spec_promise_result = false")
138
- page.execute_script(js)
139
- Timeout.timeout(Capybara.default_max_wait_time) do
140
- loop do
141
- sleep 0.25
142
- break if page.evaluate_script("!!window.hyper_spec_promise_result")
143
- end
144
- end
145
- JSON.parse(page.evaluate_script("window.hyper_spec_promise_result.$to_json()"), opts).first
146
- end
147
-
148
- def expect_promise(str = '', opts = {}, &block)
149
- insure_mount
150
- expect(evaluate_promise(add_opal_block(str, block), opts))
151
- end
152
-
153
- def ppr(str)
154
- js = Opal.compile(str).delete("\n").gsub('(Opal);', '(Opal)')
155
- execute_script("console.log(#{js})")
156
- end
157
-
158
- def on_client(&block)
159
- @client_code =
160
- "#{@client_code}#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.last}\n"
161
- end
162
-
163
- def debugger
164
- `debugger`
165
- nil
166
- end
167
-
168
- def insure_mount
169
- # rescue in case page is not defined...
170
- mount unless page.instance_variable_get('@hyper_spec_mounted')
171
- end
172
-
173
- def client_option(opts = {})
174
- @client_options ||= {}
175
- @client_options.merge! opts
176
- end
177
-
178
- alias client_options client_option
179
-
180
- def mount(component_name = nil, params = nil, opts = {}, &block)
181
- unless params
182
- params = opts
183
- opts = {}
184
- end
185
-
186
- opts = client_options opts
187
- test_url = build_test_url_for(opts.delete(:controller))
188
-
189
- if block || @client_code || component_name.nil?
190
- block_with_helpers = <<-code
191
- module ComponentHelpers
192
- def self.js_eval(s)
193
- `eval(s)`
194
- end
195
- def self.dasherize(s)
196
- res = %x{
197
- s.replace(/[-_\\s]+/g, '-')
198
- .replace(/([A-Z\\d]+)([A-Z][a-z])/g, '$1-$2')
199
- .replace(/([a-z\\d])([A-Z])/g, '$1-$2')
200
- .toLowerCase()
201
- }
202
- res
203
- end
204
- def self.add_class(class_name, styles={})
205
- style = styles.collect { |attr, value| "\#{dasherize(attr)}:\#{value}" }.join("; ")
206
- cs = class_name.to_s
207
- %x{
208
- var style_el = document.createElement("style");
209
- var css = "." + cs + " { " + style + " }";
210
- style_el.type = "text/css";
211
- if (style_el.styleSheet){
212
- style_el.styleSheet.cssText = css;
213
- } else {
214
- style_el.appendChild(document.createTextNode(css));
215
- }
216
- document.head.appendChild(style_el);
217
- }
218
- end
219
- end
220
- class Hyperstack::Internal::Component::TestDummy
221
- include Hyperstack::Component
222
- render {}
223
- end
224
- #{@client_code}
225
- #{Unparser.unparse(Parser::CurrentRuby.parse(block.source).children.last) if block}
226
- code
227
- opts[:code] = Opal.compile(block_with_helpers)
228
- end
229
-
230
- component_name ||= 'Hyperstack::Internal::Component::TestDummy'
231
- ::Rails.cache.write(test_url, [component_name, params, opts])
232
- test_code_key = "hyper_spec_prerender_test_code.js"
233
- @@original_server_render_files ||= ::Rails.configuration.react.server_renderer_options[:files]
234
- if opts[:render_on] == :both || opts[:render_on] == :server_only
235
- unless opts[:code].blank?
236
- ::Rails.cache.write(test_code_key, opts[:code])
237
- ::Rails.configuration.react.server_renderer_options[:files] = @@original_server_render_files + [test_code_key]
238
- ::React::ServerRendering.reset_pool # make sure contexts are reloaded so they dont use code from cache, as the rails filewatcher doesnt look for cache changes
239
- else
240
- ::Rails.cache.delete(test_code_key)
241
- ::Rails.configuration.react.server_renderer_options[:files] = @@original_server_render_files
242
- ::React::ServerRendering.reset_pool # make sure contexts are reloaded so they dont use code from cache, as the rails filewatcher doesnt look for cache changes
243
- end
244
- end
245
- visit test_url
246
- wait_for_ajax unless opts[:no_wait]
247
- page.instance_variable_set('@hyper_spec_mounted', true)
248
- Lolex.init(self, client_options[:time_zone], client_options[:clock_resolution])
249
- end
250
-
251
- [:callback_history_for, :last_callback_for, :clear_callback_history_for,
252
- :event_history_for, :last_event_for, :clear_event_history_for].each do |method|
253
- define_method(method) do |event_name|
254
- evaluate_ruby("Hyperstack::Internal::Component::TopLevelRailsComponent.#{method}('#{event_name}')")
255
- end
256
- end
257
-
258
- def run_on_client(&block)
259
- script = Opal.compile(Unparser.unparse(Parser::CurrentRuby.parse(block.source).children.last))
260
- execute_script(script)
261
- end
262
-
263
- def add_class(class_name, style)
264
- @client_code = "#{@client_code}ComponentHelpers.add_class('#{class_name}', #{style})\n"
265
- end
266
-
267
- def open_in_chrome
268
- if false && ['linux', 'freebsd'].include?(`uname`.downcase)
269
- `google-chrome http://#{page.server.host}:#{page.server.port}#{page.current_path}`
270
- else
271
- `open http://#{page.server.host}:#{page.server.port}#{page.current_path}`
272
- end
273
-
274
- while true
275
- sleep 1.hour
276
- end
277
- end
278
-
279
- def pause(message = nil)
280
- if message
281
- puts message
282
- page.evaluate_ruby "puts #{message.inspect}.to_s + ' (type go() to continue)'"
283
- end
284
-
285
- page.evaluate_script('window.hyper_spec_waiting_for_go = true')
286
-
287
- loop do
288
- sleep 0.25
289
- break unless page.evaluate_script('window.hyper_spec_waiting_for_go')
290
- end
291
- end
292
-
293
- def wait_for_size(width, height)
294
- start_time = Capybara::Helpers.monotonic_time
295
- stable_count_w = 0
296
- stable_count_h = 0
297
- prev_size = [0, 0]
298
- begin
299
- sleep 0.05
300
- curr_size = Capybara.current_session.current_window.size
301
- return if [width, height] == curr_size
302
- # some maximum or minimum is reached and size doesnt change anymore
303
- stable_count_w += 1 if prev_size[0] == curr_size[0]
304
- stable_count_h += 1 if prev_size[1] == curr_size[1]
305
- return if stable_count_w > 2 || stable_count_h > 2
306
- prev_size = curr_size
307
- end while (Capybara::Helpers.monotonic_time - start_time) < Capybara.current_session.config.default_max_wait_time
308
- raise Capybara::WindowError, "Window size not stable within #{Capybara.current_session.config.default_max_wait_time} seconds."
309
- end
310
-
311
- def size_window(width = nil, height = nil)
312
- # return if @window_cannot_be_resized
313
- # original_width = evaluate_script('window.innerWidth')
314
- # original_height = evaluate_script('window.innerHeight')
315
- width, height = [height, width] if width == :portrait
316
- width, height = width if width.is_a? Array
317
- portrait = true if height == :portrait
318
-
319
- case width
320
- when :small
321
- width, height = [480, 320]
322
- when :mobile
323
- width, height = [640, 480]
324
- when :tablet
325
- width, height = [960, 640]
326
- when :large
327
- width, height = [1920, 6000]
328
- when :default, nil
329
- width, height = [1024, 768]
330
- end
331
-
332
- width, height = [height, width] if portrait
333
-
334
- unless RSpec.configuration.debugger_width
335
- Capybara.current_session.current_window.resize_to(1000, 500)
336
- wait_for_size(1000, 500)
337
- inner_width = evaluate_script('window.innerWidth')
338
- RSpec.configuration.debugger_width = 1000 - inner_width
339
- end
340
- Capybara.current_session.current_window
341
- .resize_to(width + RSpec.configuration.debugger_width, height)
342
- wait_for_size(width + RSpec.configuration.debugger_width, height)
343
- end
344
- end
345
-
346
- RSpec.configure do |config|
347
- config.before(:each) do |example|
348
- ComponentTestHelpers.current_example = example
349
- ComponentTestHelpers.description_displayed = false
350
- end
351
-
352
- if defined?(ActiveRecord)
353
- config.before(:all) do
354
- ActiveRecord::Base.class_eval do
355
- def attributes_on_client(page)
356
- page.evaluate_ruby("#{self.class.name}.find(#{id}).attributes", symbolize_names: true)
357
- end
358
- end
359
- end
360
- end
361
- end
362
- end
@@ -1,10 +0,0 @@
1
- module Unparser
2
- class Emitter
3
- # Emitter for send
4
- class Send < self
5
- def local_variable_clash?
6
- selector =~ /^[A-Z]/ || local_variable_scope.local_variable_defined_for_node?(node, selector)
7
- end
8
- end
9
- end
10
- end