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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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