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

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.
@@ -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