hyper-spec 1.0.alpha1.8 → 1.0.0.lap28

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,94 +0,0 @@
1
- module HyperSpec
2
- module Internal
3
- module ClientExecution
4
- def internal_evaluate_ruby(*args, &block)
5
- insure_page_loaded
6
- add_promise_execute_and_wait(*process_params(*args, &block))
7
- end
8
-
9
- private
10
-
11
- def add_opal_block(str, block)
12
- return str unless block
13
-
14
- source = block.source
15
- ast = Parser::CurrentRuby.parse(source)
16
- ast = find_block(ast)
17
- raise "could not find block within source: #{block.source}" unless ast
18
-
19
- "#{add_locals(str, block)}\n#{Unparser.unparse ast.children.last}"
20
- end
21
-
22
- def add_promise_execute_and_wait(str, opts)
23
- js = opal_compile(add_promise_wrapper(str))
24
- page.execute_script("window.hyper_spec_promise_result = false; #{js}")
25
- Timeout.timeout(Capybara.default_max_wait_time) do
26
- loop do
27
- break if page.evaluate_script('!!window.hyper_spec_promise_result')
28
- page.evaluate_script('!!window.hyper_spec_promise_failed && Opal.Opal.$raise(window.hyper_spec_promise_failed)')
29
-
30
- sleep 0.25
31
- end
32
- end
33
- JSON.parse(page.evaluate_script('window.hyper_spec_promise_result.$to_json()'), opts).first
34
- end
35
-
36
- def add_promise_wrapper(str)
37
- <<~RUBY
38
- (#{str}).tap do |r|
39
- if defined?(Promise) && r.is_a?(Promise)
40
- r.then { |args| `window.hyper_spec_promise_result = [args]` }
41
- .fail { |e| `window.hyper_spec_promise_failed = e` }
42
- else
43
- #after(0) do
44
- #puts "setting window.hyper_spec_promise_result = [\#{r}]"
45
- `window.hyper_spec_promise_result = [r]`
46
- #end
47
- end
48
- end
49
- RUBY
50
- end
51
-
52
- def find_block(node)
53
- # find a block with the ast tree.
54
-
55
- return false unless node.class == Parser::AST::Node
56
- return node if the_node_you_are_looking_for?(node)
57
-
58
- node.children.each do |child|
59
- found = find_block(child)
60
- return found if found
61
- end
62
- false
63
- end
64
-
65
- def process_params(*args, &block)
66
- args = ['', *args] if args[0].is_a? Hash
67
- args = [args[0], {}, args[1] || {}] if args.length < 3
68
- str, opts, vars = args
69
- vars.each do |name, value|
70
- str = "#{name} = #{value.inspect}\n#{str}"
71
- end
72
- [add_opal_block(str, block), opts]
73
- end
74
-
75
- def the_node_you_are_looking_for?(node)
76
- # we could also check that the block is going to the right method
77
- # respond_to?(node.children.first.children[1]) &&
78
- # method(node.children.first.children[1]) == method(:evaluate_ruby)
79
- # however that does not work for expect { ... }.on_client_to ...
80
- # because now the block is being sent to expect... so we could
81
- # check the above OR node.children.first.children[1] == :expect
82
- # but what if there are two blocks? on and on...
83
- node.type == :block &&
84
- node.children.first.class == Parser::AST::Node &&
85
- node.children.first.type == :send
86
- end
87
-
88
-
89
- def opal_compile(str)
90
- Opal.hyperspec_compile(str, arity_check: client_options[:arity_check])
91
- end
92
- end
93
- end
94
- end
@@ -1,140 +0,0 @@
1
- module HyperSpec
2
- module Internal
3
- module ComponentMount
4
- private
5
-
6
- TEST_CODE_KEY = 'hyper_spec_prerender_test_code.js'.freeze
7
-
8
- # rubocop:disable Metrics/MethodLength
9
- def add_block_with_helpers(component_name, opts, block)
10
- return unless block || @_hyperspec_private_client_code || component_name.nil?
11
-
12
- block_with_helpers = <<-RUBY
13
- module ComponentHelpers
14
- def self.js_eval(s)
15
- `eval(s)`
16
- end
17
- def self.dasherize(s)
18
- res = %x{
19
- s.replace(/[-_\\s]+/g, '-')
20
- .replace(/([A-Z\\d]+)([A-Z][a-z])/g, '$1-$2')
21
- .replace(/([a-z\\d])([A-Z])/g, '$1-$2')
22
- .toLowerCase()
23
- }
24
- res
25
- end
26
- def self.add_class(class_name, styles={})
27
- style = styles.collect { |attr, value| "\#{dasherize(attr)}:\#{value}" }.join("; ")
28
- cs = class_name.to_s
29
- %x{
30
- var style_el = document.createElement("style");
31
- var css = "." + cs + " { " + style + " }";
32
- style_el.type = "text/css";
33
- if (style_el.styleSheet){
34
- style_el.styleSheet.cssText = css;
35
- } else {
36
- style_el.appendChild(document.createTextNode(css));
37
- }
38
- document.head.appendChild(style_el);
39
- }
40
- end
41
- end
42
- #{test_dummy}
43
- #{@_hyperspec_private_client_code}
44
- #{"#{add_locals('', block)}\n#{Unparser.unparse(Parser::CurrentRuby.parse(block.source).children.last)}" if block}
45
- RUBY
46
- @_hyperspec_private_client_code = nil
47
- opts[:code] = opal_compile(block_with_helpers)
48
- end
49
- # rubocop:enable Metrics/MethodLength
50
-
51
- def build_test_url_for(controller = nil, ping = nil)
52
- id = ping ? 'ping' : Controller.test_id
53
- "/#{route_root_for(controller)}/#{id}"
54
- end
55
-
56
- def insure_page_loaded(only_if_code_or_html_exists = nil)
57
- return if only_if_code_or_html_exists && !@_hyperspec_private_client_code && !@_hyperspec_private_html_block
58
-
59
- # if we are not resetting between examples, or think its mounted
60
- # then look for Opal, but if we can't find it, then ping to clear and try again
61
- if !HyperSpec.reset_between_examples? || page.instance_variable_get('@hyper_spec_mounted')
62
- r = evaluate_script('Opal && true') rescue nil
63
- return if r
64
-
65
- page.visit build_test_url_for(nil, true) rescue nil
66
- end
67
- load_page
68
- end
69
-
70
- def internal_mount(component_name, params, opts, &block)
71
- # TODO: refactor this
72
- test_url = build_test_url_for(opts.delete(:controller))
73
- add_block_with_helpers(component_name, opts, block)
74
- send_params_to_controller_via_cache(test_url, component_name, params, opts)
75
- setup_prerendering(opts)
76
- page.instance_variable_set('@hyper_spec_mounted', false)
77
- visit test_url
78
- wait_for_ajax unless opts[:no_wait]
79
- page.instance_variable_set('@hyper_spec_mounted', true)
80
- Lolex.init(self, client_options[:time_zone], client_options[:clock_resolution])
81
- end
82
-
83
- def prerendering?(opts)
84
- %i[both server_only].include?(opts[:render_on])
85
- end
86
-
87
- def send_params_to_controller_via_cache(test_url, component_name, params, opts)
88
- component_name ||= 'Hyperstack::Internal::Component::TestDummy' if test_dummy
89
- Controller.cache_write(
90
- test_url,
91
- [component_name, params, @_hyperspec_private_html_block, opts]
92
- )
93
- @_hyperspec_private_html_block = nil
94
- end
95
-
96
- # test_code_key = "hyper_spec_prerender_test_code.js"
97
- # if defined? ::Hyperstack::Component
98
- # @@original_server_render_files ||= ::Rails.configuration.react.server_renderer_options[:files]
99
- # if opts[:render_on] == :both || opts[:render_on] == :server_only
100
- # unless opts[:code].blank?
101
- # ComponentTestHelpers.cache_write(test_code_key, opts[:code])
102
- # ::Rails.configuration.react.server_renderer_options[:files] = @@original_server_render_files + [test_code_key]
103
- # ::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
104
- # else
105
- # ComponentTestHelpers.cache_delete(test_code_key)
106
- # ::Rails.configuration.react.server_renderer_options[:files] = @@original_server_render_files
107
- # ::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
108
- # end
109
- # end
110
- # end
111
-
112
- def setup_prerendering(opts)
113
- return unless defined?(::Hyperstack::Component) && prerendering?(opts)
114
-
115
- @@original_server_render_files ||= ::Rails.configuration.react.server_renderer_options[:files]
116
- ::Rails.configuration.react.server_renderer_options[:files] = @@original_server_render_files
117
- if opts[:code].blank?
118
- Controller.cache_delete(TEST_CODE_KEY)
119
- else
120
- Controller.cache_write(TEST_CODE_KEY, opts[:code])
121
- ::Rails.configuration.react.server_renderer_options[:files] += [TEST_CODE_KEY]
122
- end
123
- ::React::ServerRendering.reset_pool
124
- # make sure contexts are reloaded so they dont use code from cache, as the rails filewatcher
125
- # doesnt look for cache changes
126
- end
127
-
128
- def test_dummy
129
- return unless defined? ::Hyperstack::Component
130
-
131
- <<-RUBY
132
- class Hyperstack::Internal::Component::TestDummy
133
- include Hyperstack::Component
134
- render {}
135
- end
136
- RUBY
137
- end
138
- end
139
- end
140
- end
@@ -1,70 +0,0 @@
1
- module HyperSpec
2
- module Internal
3
- module Controller
4
- class << self
5
- attr_accessor :current_example
6
- attr_accessor :description_displayed
7
-
8
- def test_id
9
- @_hyperspec_private_test_id ||= 0
10
- @_hyperspec_private_test_id += 1
11
- end
12
-
13
- include ActionView::Helpers::JavaScriptHelper
14
-
15
- def current_example_description!
16
- title = "#{title}...continued." if description_displayed
17
- self.description_displayed = true
18
- "#{escape_javascript(current_example.description)}#{title}"
19
- end
20
-
21
- def file_cache
22
- @file_cache ||= FileCache.new('cache', '/tmp/hyper-spec-caches', 30, 3)
23
- end
24
-
25
- def cache_read(key)
26
- file_cache.get(key)
27
- end
28
-
29
- def cache_write(key, value)
30
- file_cache.set(key, value)
31
- end
32
-
33
- def cache_delete(key)
34
- file_cache.delete(key)
35
- rescue StandardError
36
- nil
37
- end
38
- end
39
-
40
- # By default we assume we are operating in a Rails environment and will
41
- # hook in using a rails controller. To override this define the
42
- # HyperSpecController class in your spec helper. See the rack.rb file
43
- # for an example of how to do this.
44
-
45
- def hyper_spec_test_controller
46
- return ::HyperSpecTestController if defined?(::HyperSpecTestController)
47
-
48
- base = if defined? ApplicationController
49
- Class.new ApplicationController
50
- elsif defined? ::ActionController::Base
51
- Class.new ::ActionController::Base
52
- else
53
- raise "Unless using Rails you must define the HyperSpecTestController\n"\
54
- 'For rack apps try requiring hyper-spec/rack.'
55
- end
56
- Object.const_set('HyperSpecTestController', base)
57
- end
58
-
59
- # First insure we have a controller, then make sure it responds to the test method
60
- # if not, then add the rails specific controller methods. The RailsControllerHelpers
61
- # module will automatically add a top level route back to the controller.
62
-
63
- def route_root_for(controller)
64
- controller ||= hyper_spec_test_controller
65
- controller.include RailsControllerHelpers unless controller.method_defined?(:test)
66
- controller.route_root
67
- end
68
- end
69
- end
70
- end
@@ -1,103 +0,0 @@
1
- module HyperSpec
2
- module Internal
3
- module CopyLocals
4
- private
5
-
6
- def build_var_inclusion_lists
7
- build_included_list
8
- build_excluded_list
9
- end
10
-
11
- def build_included_list
12
- @_hyperspec_private_included_vars = nil
13
- return unless @_hyperspec_private_client_options.key? :include_vars
14
-
15
- included = @_hyperspec_private_client_options[:include_vars]
16
- if included.is_a? Symbol
17
- @_hyperspec_private_included_vars = [included]
18
- elsif included.is_a?(Array)
19
- @_hyperspec_private_included_vars = included
20
- elsif !included
21
- @_hyperspec_private_included_vars = []
22
- end
23
- end
24
-
25
- PRIVATE_VARIABLES = %i[
26
- @__inspect_output @__memoized @example @_hyperspec_private_client_code
27
- @_hyperspec_private_html_block @fixture_cache
28
- @fixture_connections @connection_subscriber @loaded_fixtures
29
- @_hyperspec_private_client_options
30
- @_hyperspec_private_included_vars
31
- @_hyperspec_private_excluded_vars
32
- b __ _ _ex_ pry_instance _out_ _in_ _dir_ _file_
33
- ]
34
-
35
- def build_excluded_list
36
- return unless @_hyperspec_private_client_options
37
-
38
- excluded = @_hyperspec_private_client_options[:exclude_vars]
39
- if excluded.is_a? Symbol
40
- @_hyperspec_private_excluded_vars = [excluded]
41
- elsif excluded.is_a?(Array)
42
- @_hyperspec_private_excluded_vars = excluded
43
- elsif excluded
44
- @_hyperspec_private_included_vars = []
45
- end
46
- end
47
-
48
- def var_excluded?(var, binding)
49
- return true if PRIVATE_VARIABLES.include? var
50
-
51
- excluded = binding.eval('instance_variable_get(:@_hyperspec_private_excluded_vars)')
52
- return true if excluded&.include?(var)
53
-
54
- included = binding.eval('instance_variable_get(:@_hyperspec_private_included_vars)')
55
- included && !included.include?(var)
56
- end
57
-
58
- def add_locals(in_str, block)
59
- b = block.binding
60
- add_instance_vars(b, add_local_vars(b, add_memoized_vars(b, in_str)))
61
- end
62
-
63
- def add_memoized_vars(binding, in_str)
64
- memoized = binding.eval('__memoized').instance_variable_get(:@memoized)
65
- return in_str unless memoized
66
-
67
- memoized.inject(in_str) do |str, pair|
68
- next str if var_excluded?(pair.first, binding)
69
-
70
- "#{str}\n#{set_local_var(pair.first, pair.last)}"
71
- end
72
- end
73
-
74
- def add_local_vars(binding, in_str)
75
- binding.local_variables.inject(in_str) do |str, var|
76
- next str if var_excluded?(var, binding)
77
-
78
- "#{str}\n#{set_local_var(var, binding.local_variable_get(var))}"
79
- end
80
- end
81
-
82
- def add_instance_vars(binding, in_str)
83
- binding.eval('instance_variables').inject(in_str) do |str, var|
84
- next str if var_excluded?(var, binding)
85
-
86
- "#{str}\n#{set_local_var(var, binding.eval("instance_variable_get('#{var}')"))}"
87
- end
88
- end
89
-
90
- def set_local_var(name, object)
91
- serialized = object.opal_serialize
92
- if serialized
93
- "#{name} = #{serialized}"
94
- else
95
- "self.class.define_method(:#{name}) "\
96
- "{ raise 'Attempt to access the variable #{name} "\
97
- 'that was defined in the spec, but its value could not be serialized '\
98
- "so it is undefined on the client.' }"
99
- end
100
- end
101
- end
102
- end
103
- end
@@ -1,86 +0,0 @@
1
- module Opal
2
- # strips off stuff that confuses things when transmitting to the client
3
- # and prints offending code if it can't be compiled
4
- def self.hyperspec_compile(str, opts = {})
5
- compile(str, opts).gsub("// Prepare super implicit arguments\n", '')
6
- .delete("\n").gsub('(Opal);', '(Opal)')
7
- # rubocop:disable Lint/RescueException
8
- # we are going to reraise it anyway, so its fine to catch EVERYTHING!
9
- rescue Exception => e
10
- puts "puts could not compile: \n\n#{str}\n\n"
11
- raise e
12
- end
13
- # rubocop:enable Lint/RescueException
14
- end
15
-
16
- module Unparser
17
- class Emitter
18
- # Emitter for send
19
- class Send < self
20
- def local_variable_clash?
21
- selector =~ /^[A-Z]/ ||
22
- local_variable_scope.local_variable_defined_for_node?(node, selector)
23
- end
24
- end
25
- end
26
- end
27
-
28
- module MethodSource
29
- class << self
30
- alias original_lines_for_before_hyper_spec lines_for
31
- alias original_source_helper_before_hyper_spec source_helper
32
-
33
- def source_helper(source_location, name = nil)
34
- source_location[1] = 1 if source_location[0] == '(pry)'
35
- original_source_helper_before_hyper_spec source_location, name
36
- end
37
-
38
- def lines_for(file_name, name = nil)
39
- if file_name == '(pry)'
40
- HyperSpec.current_pry_code_block
41
- else
42
- original_lines_for_before_hyper_spec file_name, name
43
- end
44
- end
45
- end
46
- end
47
-
48
- class Object
49
- def opal_serialize
50
- nil
51
- end
52
- end
53
-
54
- class Hash
55
- def opal_serialize
56
- "{#{collect { |k, v| "#{k.opal_serialize} => #{v.opal_serialize}" }.join(', ')}}"
57
- end
58
- end
59
-
60
- class Array
61
- def opal_serialize
62
- "[#{collect { |v| v.opal_serialize }.join(', ')}]"
63
- end
64
- end
65
-
66
- [FalseClass, Float, Integer, NilClass, String, Symbol, TrueClass].each do |klass|
67
- klass.send(:define_method, :opal_serialize) do
68
- inspect
69
- end
70
- end
71
-
72
- # rubocop:disable Lint/UnifiedInteger - patch for ruby prior to 2.4
73
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4.0')
74
- [Bignum, Fixnum].each do |klass|
75
- klass.send(:define_method, :opal_serialize) do
76
- inspect
77
- end
78
- end
79
- end
80
- # rubocop:enable Lint/UnifiedInteger
81
-
82
- class Time
83
- def to_opal_expression
84
- "Time.parse('#{inspect}')"
85
- end
86
- end