hyper-spec 0.1.2 → 0.99.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rubocop.yml DELETED
@@ -1,107 +0,0 @@
1
- Style/BlockDelimiters:
2
- EnforcedStyle: line_count_based
3
- SupportedStyles:
4
- # The `line_count_based` style enforces braces around single line blocks and
5
- # do..end around multi-line blocks.
6
- - line_count_based
7
- # The `semantic` style enforces braces around functional blocks, where the
8
- # primary purpose of the block is to return a value and do..end for
9
- # procedural blocks, where the primary purpose of the block is its
10
- # side-effects.
11
- #
12
- # This looks at the usage of a block's method to determine its type (e.g. is
13
- # the result of a `map` assigned to a variable or passed to another
14
- # method) but exceptions are permitted in the `ProceduralMethods`,
15
- # `FunctionalMethods` and `IgnoredMethods` sections below.
16
- - semantic
17
- # The `braces_for_chaining` style enforces braces around single line blocks
18
- # and do..end around multi-line blocks, except for multi-line blocks whose
19
- # return value is being chained with another method (in which case braces
20
- # are enforced).
21
- - braces_for_chaining
22
- ProceduralMethods:
23
- # Methods that are known to be procedural in nature but look functional from
24
- # their usage, e.g.
25
- #
26
- # time = Benchmark.realtime do
27
- # foo.bar
28
- # end
29
- #
30
- # Here, the return value of the block is discarded but the return value of
31
- # `Benchmark.realtime` is used.
32
- - benchmark
33
- - bm
34
- - bmbm
35
- - create
36
- - each_with_object
37
- - measure
38
- - new
39
- - realtime
40
- - tap
41
- - with_object
42
- FunctionalMethods:
43
- # Methods that are known to be functional in nature but look procedural from
44
- # their usage, e.g.
45
- #
46
- # let(:foo) { Foo.new }
47
- #
48
- # Here, the return value of `Foo.new` is used to define a `foo` helper but
49
- # doesn't appear to be used from the return value of `let`.
50
- - let
51
- - let!
52
- - subject
53
- - watch
54
- IgnoredMethods:
55
- # Methods that can be either procedural or functional and cannot be
56
- # categorised from their usage alone, e.g.
57
- #
58
- # foo = lambda do |x|
59
- # puts "Hello, #{x}"
60
- # end
61
- #
62
- # foo = lambda do |x|
63
- # x * 100
64
- # end
65
- #
66
- # Here, it is impossible to tell from the return value of `lambda` whether
67
- # the inner block's return value is significant.
68
- - lambda
69
- - proc
70
- - it
71
-
72
- Style/Documentation:
73
- Description: 'Document classes and non-namespace modules.'
74
- Enabled: false
75
- Exclude:
76
- - 'spec/**/*'
77
- - 'test/**/*'
78
-
79
- # Multi-line method chaining should be done with trailing dots.
80
- Style/DotPosition:
81
- EnforcedStyle: leading
82
- SupportedStyles:
83
- - leading
84
- - trailing
85
-
86
- Style/FrozenStringLiteralComment:
87
- Description: >-
88
- Add the frozen_string_literal comment to the top of files
89
- to help transition from Ruby 2.3.0 to Ruby 3.0.
90
- Enabled: false
91
-
92
- Style/MultilineBlockChain:
93
- Description: 'Avoid multi-line chains of blocks.'
94
- StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#single-line-blocks'
95
- Enabled: false
96
-
97
- Style/MutableConstant:
98
- Description: 'Do not assign mutable objects to constants.'
99
- Enabled: false
100
-
101
- Metrics/AbcSize:
102
- # The ABC size is a calculated magnitude, so this number can be a Fixnum or
103
- # a Float.
104
- Max: 20
105
-
106
- Metrics/LineLength:
107
- Max: 100
data/CODE_OF_CONDUCT.md DELETED
@@ -1,49 +0,0 @@
1
- # Contributor Code of Conduct
2
-
3
- As contributors and maintainers of this project, and in the interest of
4
- fostering an open and welcoming community, we pledge to respect all people who
5
- contribute through reporting issues, posting feature requests, updating
6
- documentation, submitting pull requests or patches, and other activities.
7
-
8
- We are committed to making participation in this project a harassment-free
9
- experience for everyone, regardless of level of experience, gender, gender
10
- identity and expression, sexual orientation, disability, personal appearance,
11
- body size, race, ethnicity, age, religion, or nationality.
12
-
13
- Examples of unacceptable behavior by participants include:
14
-
15
- * The use of sexualized language or imagery
16
- * Personal attacks
17
- * Trolling or insulting/derogatory comments
18
- * Public or private harassment
19
- * Publishing other's private information, such as physical or electronic
20
- addresses, without explicit permission
21
- * Other unethical or unprofessional conduct
22
-
23
- Project maintainers have the right and responsibility to remove, edit, or
24
- reject comments, commits, code, wiki edits, issues, and other contributions
25
- that are not aligned to this Code of Conduct, or to ban temporarily or
26
- permanently any contributor for other behaviors that they deem inappropriate,
27
- threatening, offensive, or harmful.
28
-
29
- By adopting this Code of Conduct, project maintainers commit themselves to
30
- fairly and consistently applying these principles to every aspect of managing
31
- this project. Project maintainers who do not follow or enforce the Code of
32
- Conduct may be permanently removed from the project team.
33
-
34
- This code of conduct applies both within project spaces and in public spaces
35
- when an individual is representing the project or its community.
36
-
37
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
- reported by contacting a project maintainer at mitch@catprint.com. All
39
- complaints will be reviewed and investigated and will result in a response that
40
- is deemed necessary and appropriate to the circumstances. Maintainers are
41
- obligated to maintain confidentiality with regard to the reporter of an
42
- incident.
43
-
44
- This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
- version 1.3.0, available at
46
- [http://contributor-covenant.org/version/1/3/0/][version]
47
-
48
- [homepage]: http://contributor-covenant.org
49
- [version]: http://contributor-covenant.org/version/1/3/0/
data/LICENSE.txt DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2017 catmando
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
@@ -1,368 +0,0 @@
1
- # see component_test_helpers_spec.rb for examples
2
-
3
- require 'parser/current'
4
- require 'unparser'
5
- require 'method_source'
6
- require_relative '../../vendor/assets/javascripts/time_cop' #'hyper-spec/time_cop'
7
-
8
-
9
- module ComponentTestHelpers
10
-
11
- def self.compile_to_opal(&block)
12
- Opal.compile(block.source.split("\n")[1..-2].join("\n"))
13
- end
14
-
15
-
16
- TOP_LEVEL_COMPONENT_PATCH = lambda { |&block| Opal.compile(block.source.split("\n")[1..-2].join("\n"))}.call do #ComponentTestHelpers.compile_to_opal do
17
- module React
18
- class TopLevelRailsComponent
19
-
20
- class << self
21
- attr_accessor :event_history
22
-
23
- def callback_history_for(proc_name)
24
- event_history[proc_name]
25
- end
26
-
27
- def last_callback_for(proc_name)
28
- event_history[proc_name].last
29
- end
30
-
31
- def clear_callback_history_for(proc_name)
32
- event_history[proc_name] = []
33
- end
34
-
35
- def event_history_for(event_name)
36
- event_history["_on#{event_name.event_camelize}"]
37
- end
38
-
39
- def last_event_for(event_name)
40
- event_history["_on#{event_name.event_camelize}"].last
41
- end
42
-
43
- def clear_event_history_for(event_name)
44
- event_history["_on#{event_name.event_camelize}"] = []
45
- end
46
-
47
- end
48
-
49
- def component
50
- return @component if @component
51
- paths_searched = []
52
- if params.component_name.start_with? "::"
53
- paths_searched << params.component_name.gsub(/^\:\:/,"")
54
- @component = params.component_name.gsub(/^\:\:/,"").split("::").inject(Module) { |scope, next_const| scope.const_get(next_const, false) } rescue nil
55
- return @component if @component && @component.method_defined?(:render)
56
- else
57
- self.class.search_path.each do |path|
58
- # try each path + params.controller + params.component_name
59
- paths_searched << "#{path.name + '::' unless path == Module}#{params.controller}::#{params.component_name}"
60
- @component = "#{params.controller}::#{params.component_name}".split("::").inject(path) { |scope, next_const| scope.const_get(next_const, false) } rescue nil
61
- return @component if @component && @component.method_defined?(:render)
62
- end
63
- self.class.search_path.each do |path|
64
- # then try each path + params.component_name
65
- paths_searched << "#{path.name + '::' unless path == Module}#{params.component_name}"
66
- @component = "#{params.component_name}".split("::").inject(path) { |scope, next_const| scope.const_get(next_const, false) } rescue nil
67
- return @component if @component && @component.method_defined?(:render)
68
- end
69
- end
70
- @component = nil
71
- raise "Could not find component class '#{params.component_name}' for params.controller '#{params.controller}' in any component directory. Tried [#{paths_searched.join(", ")}]"
72
- end
73
-
74
- before_mount do
75
- TopLevelRailsComponent.event_history = Hash.new {|h,k| h[k] = [] }
76
- @render_params = params.render_params
77
- component.validator.rules.each do |name, rules|
78
- if rules[:type] == Proc
79
- TopLevelRailsComponent.event_history[name] = []
80
- @render_params[name] = lambda { |*args| TopLevelRailsComponent.event_history[name] << args } #args.collect { |arg| Native(arg).to_n } }
81
- end
82
- end
83
- end
84
-
85
- def render
86
- present component, @render_params
87
- end
88
- end
89
- end
90
- end
91
-
92
- def build_test_url_for(controller)
93
-
94
- unless controller
95
- Object.const_set("ReactTestController", Class.new(ApplicationController)) unless defined?(::ReactTestController)
96
- controller = ::ReactTestController
97
- end
98
-
99
- route_root = controller.name.gsub(/Controller$/,"").underscore
100
-
101
- unless controller.method_defined? :test
102
- controller.class_eval do
103
- define_method(:test) do
104
- route_root = self.class.name.gsub(/Controller$/,"").underscore
105
- test_params = Rails.cache.read("/#{route_root}/#{params[:id]}")
106
- @component_name = test_params[0]
107
- @component_params = test_params[1]
108
- render_params = test_params[2]
109
- render_on = render_params.delete(:render_on) || :client_only
110
- mock_time = render_params.delete(:mock_time)
111
- style_sheet = render_params.delete(:style_sheet)
112
- javascript = render_params.delete(:javascript)
113
- code = render_params.delete(:code)
114
- page = "<%= react_component @component_name, @component_params, { prerender: #{render_on != :client_only} } %>"
115
- page = "<script type='text/javascript'>\n#{TOP_LEVEL_COMPONENT_PATCH}\n</script>\n#{page}"
116
-
117
- if code
118
- page = "<script type='text/javascript'>\n#{code}\n</script>\n"+page
119
- end
120
-
121
- #TODO figure out how to auto insert this line???? something like:
122
- #page = "<%= javascript_include_tag 'reactrb-router' %>\n#{page}"
123
-
124
-
125
- if true || Lolex.initialized?
126
- page = "<%= javascript_include_tag 'time_cop' %>\n"+page
127
- end
128
- if (render_on != :server_only && !render_params[:layout]) || javascript
129
- #page = "<script src='/assets/application.js?ts=#{Time.now.to_f}'></script>\n"+page
130
- page = "<%= javascript_include_tag '#{javascript || 'application'}' %>\n"+page
131
- end
132
- if !render_params[:layout] || style_sheet
133
- page = "<%= stylesheet_link_tag '#{style_sheet || 'application'}' %>\n"+page
134
- end
135
- if render_on == :server_only # so that test helper wait_for_ajax works
136
- page = "<script type='text/javascript'>window.jQuery = {'active': 0}</script>\n#{page}"
137
- else
138
- page = "<%= javascript_include_tag 'jquery' %>\n<%= javascript_include_tag 'jquery_ujs' %>\n#{page}"
139
- end
140
- page = "<script type='text/javascript'>go = function() {window.hyper_spec_waiting_for_go = false}</script>\n#{page}"
141
- title = view_context.escape_javascript(ComponentTestHelpers.current_example.description)
142
- title = "#{title}...continued." if ComponentTestHelpers.description_displayed
143
- page = "<script type='text/javascript'>console.log(console.log('%c#{title}','color:green; font-weight:bold; font-size: 200%'))</script>\n#{page}"
144
- ComponentTestHelpers.description_displayed = true
145
- render_params[:inline] = page
146
- render render_params
147
- end
148
- end
149
-
150
- # test_routes = Proc.new do
151
- # get "/#{route_root}/:id", to: "#{route_root}#test"
152
- # end
153
- # Rails.application.routes.eval_block(test_routes)
154
-
155
- begin
156
- routes = Rails.application.routes
157
- routes.disable_clear_and_finalize = true
158
- routes.clear!
159
- routes.draw do
160
- get "/#{route_root}/:id", to: "#{route_root}#test"
161
- end
162
- Rails.application.routes_reloader.paths.each{ |path| load(path) }
163
- routes.finalize!
164
- ActiveSupport.on_load(:action_controller) { routes.finalize! }
165
- ensure
166
- routes.disable_clear_and_finalize = false
167
- end
168
- end
169
-
170
- "/#{route_root}/#{@test_id = (@test_id || 0) + 1}"
171
-
172
- end
173
-
174
- def isomorphic(&block)
175
- yield
176
- on_client(&block)
177
- end
178
-
179
- def evaluate_ruby(str="", opts={}, &block)
180
- insure_mount
181
- str = "#{str}\n#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.last}" if block
182
- js = Opal.compile(str).gsub("\n","").gsub("(Opal);","(Opal)")
183
- JSON.parse(evaluate_script("[#{js}].$to_json()"), opts).first
184
- end
185
-
186
- def expect_evaluate_ruby(str = '', opts = {}, &block)
187
- insure_mount
188
- expect(evaluate_ruby(add_opal_block(str, block), opts))
189
- end
190
-
191
- def add_opal_block(str, block)
192
- # big assumption here is that we are going to follow this with a .to
193
- # hence .children.first followed by .children.last
194
- # probably should do some kind of "search" to make this work nicely
195
- return str unless block
196
- "#{str}\n"\
197
- "#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.first.children.last}"
198
- end
199
-
200
- def expect_promise(str = '', opts = {}, &block)
201
- insure_mount
202
- str = add_opal_block(str, block)
203
- str = "#{str}.then { |args| args = [args]; `window.hyper_spec_promise_result = args` }"
204
- js = Opal.compile(str).gsub("\n","").gsub("(Opal);","(Opal)")
205
- page.evaluate_script("window.hyper_spec_promise_result = false")
206
- page.execute_script(js)
207
- Timeout.timeout(Capybara.default_max_wait_time) do
208
- loop do
209
- sleep 0.25
210
- break if page.evaluate_script("!!window.hyper_spec_promise_result")
211
- end
212
- end
213
- expect(JSON.parse(page.evaluate_script("window.hyper_spec_promise_result.$to_json()"), opts).first)
214
- end
215
-
216
- def ppr(str)
217
- js = Opal.compile(str).gsub("\n","").gsub("(Opal);","(Opal)")
218
- execute_script("console.log(#{js})")
219
- end
220
-
221
-
222
- def on_client(&block)
223
- @client_code = "#{@client_code}#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.last}\n"
224
- end
225
-
226
- def debugger
227
- `debugger`
228
- nil
229
- end
230
-
231
- class << self
232
- attr_accessor :current_example
233
- attr_accessor :description_displayed
234
- def display_example_description
235
- "<script type='text/javascript'>console.log(console.log('%c#{current_example.description}','color:green; font-weight:bold; font-size: 200%'))</script>"
236
- end
237
- end
238
-
239
- def insure_mount
240
- # rescue in case page is not defined...
241
- mount unless page.instance_variable_get("@hyper_spec_mounted") #rescue nil
242
- end
243
-
244
- def client_option(opts = {})
245
- @client_options ||= {}
246
- @client_options.merge! opts
247
- end
248
-
249
- alias client_options client_option
250
-
251
- def mount(component_name = nil, params = nil, opts = {}, &block)
252
- unless params
253
- params = opts
254
- opts = {}
255
- end
256
- opts = client_options opts
257
- test_url = build_test_url_for(opts.delete(:controller))
258
- if block || @client_code || component_name.nil?
259
- block_with_helpers = <<-code
260
- module ComponentHelpers
261
- def self.js_eval(s)
262
- `eval(s)`
263
- end
264
- def self.dasherize(s)
265
- `s.replace(/[-_\\s]+/g, '-')
266
- .replace(/([A-Z\\d]+)([A-Z][a-z])/g, '$1-$2')
267
- .replace(/([a-z\\d])([A-Z])/g, '$1-$2')
268
- .toLowerCase()`
269
- end
270
- def self.add_class(class_name, styles={})
271
- style = styles.collect { |attr, value| "\#{dasherize(attr)}:\#{value}"}.join("; ")
272
- s = "<style type='text/css'> .\#{class_name}{ \#{style} } </style>"
273
- `$(\#{s}).appendTo("head");`
274
- end
275
- end
276
- class React::Component::HyperTestDummy < React::Component::Base
277
- def render; end
278
- end
279
- #{@client_code}
280
- #{Unparser.unparse(Parser::CurrentRuby.parse(block.source).children.last) if block}
281
- code
282
- opts[:code] = Opal.compile(block_with_helpers)
283
- end
284
- component_name ||= 'React::Component::HyperTestDummy'
285
- Rails.cache.write(test_url, [component_name, params, opts])
286
- visit test_url
287
- wait_for_ajax unless opts[:no_wait]
288
- page.instance_variable_set("@hyper_spec_mounted", true)
289
- Lolex.init(self, client_options[:time_zone], client_options[:clock_resolution])
290
- end
291
-
292
- [:callback_history_for, :last_callback_for, :clear_callback_history_for, :event_history_for, :last_event_for, :clear_event_history_for].each do |method|
293
- define_method(method) { |event_name| evaluate_ruby("React::TopLevelRailsComponent.#{method}('#{event_name}')") }
294
- end
295
-
296
- def run_on_client(&block)
297
- script = Opal.compile(Unparser.unparse Parser::CurrentRuby.parse(block.source).children.last)
298
- execute_script(script)
299
- end
300
-
301
- def add_class(class_name, style)
302
- @client_code = "#{@client_code}ComponentHelpers.add_class '#{class_name}', #{style}\n"
303
- end
304
-
305
- def open_in_chrome
306
- if false && ['linux', 'freebsd'].include?(`uname`.downcase)
307
- `google-chrome http://#{page.server.host}:#{page.server.port}#{page.current_path}`
308
- else
309
- `open http://#{page.server.host}:#{page.server.port}#{page.current_path}`
310
- end
311
- while true
312
- sleep 1.hour
313
- end
314
- end
315
-
316
- def pause(message = nil)
317
- if message
318
- puts message
319
- page.evaluate_ruby "puts #{message.inspect}.to_s + ' (type go() to continue)'"
320
- end
321
- page.evaluate_script("window.hyper_spec_waiting_for_go = true")
322
- loop do
323
- sleep 0.25
324
- break unless page.evaluate_script("window.hyper_spec_waiting_for_go")
325
- end
326
- end
327
-
328
- def size_window(width=nil, height=nil)
329
- width, height = [height, width] if width == :portrait
330
- width, height = width if width.is_a? Array
331
- portrait = true if height == :portrait
332
- case width
333
- when :small
334
- width, height = [480, 320]
335
- when :mobile
336
- width, height = [640, 480]
337
- when :tablet
338
- width, height = [960, 640]
339
- when :large
340
- width, height = [1920, 6000]
341
- when :default, nil
342
- width, height = [1024, 768]
343
- end
344
- if portrait
345
- width, height = [height, width]
346
- end
347
- if page.driver.browser.respond_to?(:manage)
348
- page.driver.browser.manage.window.resize_to(width, height)
349
- elsif page.driver.respond_to?(:resize)
350
- page.driver.resize(width, height)
351
- end
352
- end
353
-
354
- end
355
-
356
- RSpec.configure do |config|
357
- config.before(:each) do |example|
358
- ComponentTestHelpers.current_example = example
359
- ComponentTestHelpers.description_displayed = false
360
- end
361
- config.before(:all) do
362
- ActiveRecord::Base.class_eval do
363
- def attributes_on_client(page)
364
- page.evaluate_ruby("#{self.class.name}.find(#{id}).attributes", symbolize_names: true)
365
- end
366
- end
367
- end if defined? ActiveRecord
368
- end