hyper-spec 1.0.alpha1.2 → 1.0.alpha1.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66a08824d73e2409d1ea2b98184617132adcbfd98ccd272dcc9a9fbc24feabf3
4
- data.tar.gz: e069b110c83c4752a1e3b0689b1d0a70145eec47225bed772d28b3c0bc218620
3
+ metadata.gz: 9d0e20bf955270ec0d934a3fa9c8d78d7ea27eb3ad039d8a05c35f1731eb2b9b
4
+ data.tar.gz: 5647583d90fee9e2334c84abba0d7d72248f8226b1bdbd1acc42569bfac64683
5
5
  SHA512:
6
- metadata.gz: 95105fd6d6969a1e03a4e8fd16cc03f3882a800ecee550c5e6cd0bfa195f088ee86ccb640c92b65f39f7c6a7c1970eb62fed48e247926fda04d2a6490104a334
7
- data.tar.gz: dd9022dd09c03bab88a24e767e49aa77418bce33895640b8b41839be9b203b23401a9f0fc9b13c87b54c4d7f579b2ebf9fadfb0761e2ef1001759c3817baca01
6
+ metadata.gz: c53e9f034651011bde6e54a0567535ed7838db56d8e812f671c295ac6185996029e2108504287b7589de1e3cc10488200f828b1c323f391894828da748231ad6
7
+ data.tar.gz: bb81db032b7bf29be3c8aeaf36db51be4b26bd6a106e0ddfa7f802fd30adc2565b8d34308ca133daac1d70b2b2e1e3b9aef54c954533e6b83fc262ad362624a3
data/.gitignore CHANGED
@@ -52,3 +52,7 @@ bower.json
52
52
 
53
53
  # ignore Idea files
54
54
  .idea
55
+
56
+ # ignore Gemfile.locks https://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
57
+ /spec/test_app/Gemfile.lock
58
+ /Gemfile.lock
data/bin/console CHANGED
File without changes
data/bin/setup CHANGED
File without changes
data/hyper-spec.gemspec CHANGED
@@ -6,54 +6,51 @@ require 'hyper-spec/version'
6
6
  Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
7
7
  spec.name = 'hyper-spec'
8
8
  spec.version = HyperSpec::VERSION
9
- spec.authors = ['Mitch VanDuyn', 'Adam Creekroad', 'Jan Biedermann']
9
+ spec.authors = ['Mitch VanDuyn', 'AdamCreekroad', 'Jan Biedermann']
10
10
  spec.email = ['mitch@catprint.com', 'jan@kursator.com']
11
- spec.summary = 'Drive your Hyperloop client and server specs from RSpec and Capybara'
12
- spec.description = 'A Hyperloop application consists of isomorphic React Components, '\
11
+ spec.summary = 'Drive your Opal and Hyperstack client and server specs from RSpec and Capybara'
12
+ spec.description = 'A Hyperstack application consists of isomorphic React Components, '\
13
13
  'Active Record Models, Stores, Operations and Policiespec. '\
14
14
  'Test them all from Rspec, regardless if the code runs on the client or server.'
15
- spec.homepage = 'http://ruby-hyperloop.org'
15
+ spec.homepage = 'http://hyperstack.org'
16
16
  spec.license = 'MIT'
17
- # spec.metadata = {
18
- # "homepage_uri" => 'http://ruby-hyperloop.org',
19
- # "source_code_uri" => 'https://github.com/ruby-hyperloop/hyper-component'
20
- # }
21
-
22
17
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(gemfiles|spec)/}) }
23
18
  spec.bindir = 'exe'
24
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
20
  spec.require_paths = ['lib']
26
21
 
22
+ spec.add_dependency 'actionview'
27
23
  spec.add_dependency 'capybara'
28
24
  spec.add_dependency 'chromedriver-helper', '1.2.0'
29
- spec.add_dependency 'libv8', '~> 6.3.0' # see https://github.com/discourse/mini_racer/issues/92
25
+ spec.add_dependency 'filecache'
30
26
  spec.add_dependency 'method_source'
31
- spec.add_dependency 'mini_racer', '~> 0.1.15'
32
- spec.add_dependency 'opal', '>= 0.11.0', '< 0.12.0'
33
- spec.add_dependency 'parser', '>= 2.3.3.1'
34
- spec.add_dependency 'pry'
35
- spec.add_dependency 'rspec-rails'
27
+ spec.add_dependency 'opal', ENV['OPAL_VERSION'] || '>= 0.11.0', '< 2.0'
28
+ spec.add_dependency 'parser'
29
+ spec.add_dependency 'rspec'
36
30
  spec.add_dependency 'selenium-webdriver'
37
31
  spec.add_dependency 'timecop', '~> 0.8.1'
38
32
  spec.add_dependency 'uglifier'
39
- spec.add_dependency 'unparser'
33
+ spec.add_dependency 'unparser', '>= 0.4.2'
40
34
  spec.add_dependency 'webdrivers'
41
35
 
42
36
  spec.add_development_dependency 'bundler'
43
37
  spec.add_development_dependency 'hyper-component', HyperSpec::VERSION
38
+ spec.add_development_dependency 'mini_racer'
44
39
  spec.add_development_dependency 'opal-browser', '~> 0.2.0'
45
- spec.add_development_dependency 'opal-rails', '~> 0.9.4'
40
+ spec.add_development_dependency 'opal-rails', '>= 0.9.4'
46
41
  spec.add_development_dependency 'pry-rescue'
42
+ spec.add_development_dependency 'pry-stack_explorer'
47
43
  spec.add_development_dependency 'puma'
48
- spec.add_development_dependency 'rails', '>= 4.0.0'
44
+ spec.add_development_dependency 'rails', ENV['RAILS_VERSION'] || '>= 5.0.0', '< 7.0'
49
45
  spec.add_development_dependency 'rake'
50
46
  spec.add_development_dependency 'react-rails', '>= 2.3.0', '< 2.5.0'
47
+ spec.add_development_dependency 'rspec-rails'
51
48
  spec.add_development_dependency 'rspec-collection_matchers'
52
49
  spec.add_development_dependency 'rspec-expectations'
53
50
  spec.add_development_dependency 'rspec-its'
54
51
  spec.add_development_dependency 'rspec-mocks'
55
52
  spec.add_development_dependency 'rspec-steps', '~> 2.1.1'
56
- spec.add_development_dependency 'rubocop', '~> 0.51.0'
53
+ spec.add_development_dependency 'rubocop' #, '~> 0.51.0'
57
54
  spec.add_development_dependency 'shoulda'
58
55
  spec.add_development_dependency 'shoulda-matchers'
59
56
  spec.add_development_dependency 'spring-commands-rspec'
data/lib/hyper-spec.rb CHANGED
@@ -1,14 +1,144 @@
1
- require 'capybara/rspec'
1
+ # hyper-spec
2
+ require 'action_view'
2
3
  require 'opal'
4
+ require 'unparser'
5
+ require 'method_source'
6
+ require 'filecache'
7
+
8
+ require 'capybara/rspec'
9
+ require 'hyper-spec/internal/client_execution'
10
+ require 'hyper-spec/internal/component_mount'
11
+ require 'hyper-spec/internal/controller'
12
+ require 'hyper-spec/internal/copy_locals'
13
+ require 'hyper-spec/internal/patches'
14
+ require 'hyper-spec/internal/rails_controller_helpers'
15
+ require 'hyper-spec/internal/time_cop.rb'
16
+ require 'hyper-spec/internal/window_sizing'
17
+
18
+ require 'hyper-spec/controller_helpers'
19
+
20
+ require 'hyper-spec/wait_for_ajax'
21
+
22
+ require 'hyper-spec/helpers'
23
+ require 'hyper-spec/expectations'
24
+
25
+ require 'parser/current'
26
+ if defined?(Selenium::WebDriver::Firefox)
27
+ require 'selenium/web_driver/firefox/profile'
28
+ end
3
29
  require 'selenium-webdriver'
4
30
 
5
- require 'hyper-spec/component_test_helpers'
6
31
  require 'hyper-spec/version'
7
- require 'hyper-spec/wait_for_ajax'
8
- require 'selenium/web_driver/firefox/profile'
32
+
33
+
34
+ begin
35
+ require 'pry'
36
+ rescue LoadError
37
+ nil
38
+ end
39
+
40
+ # opt-in to most recent AST format:
41
+ Parser::Builders::Default.emit_lambda = true
42
+ Parser::Builders::Default.emit_procarg0 = true
43
+ (Parser::Builders::Default.emit_encoding = true) rescue nil
44
+ (Parser::Builders::Default.emit_index = true) rescue nil
45
+ (Parser::Builders::Default.emit_arg_inside_procarg0 = true) rescue nil
46
+ (Parser::Builders::Default.emit_forward_arg = true) rescue nil
47
+ (Parser::Builders::Default.emit_kwargs = true) rescue nil
48
+ (Parser::Builders::Default.emit_match_pattern = true) rescue nil
49
+
50
+ # not available in parser 2.3
51
+ if Parser::Builders::Default.respond_to? :emit_arg_inside_procarg0
52
+ Parser::Builders::Default.emit_arg_inside_procarg0 = true
53
+ end
54
+
55
+ module HyperSpec
56
+ if defined? Pry
57
+ # add a before eval hook to pry so we can capture the source
58
+ class << self
59
+ attr_accessor :current_pry_code_block
60
+ Pry.hooks.add_hook(:before_eval, 'hyper_spec_code_capture') do |code|
61
+ HyperSpec.current_pry_code_block = code
62
+ end
63
+ end
64
+ end
65
+
66
+ def self.reset_between_examples
67
+ @reset_between_examples ||= []
68
+ end
69
+
70
+ def self.reset_between_examples?
71
+ RSpec.configuration.reset_between_examples
72
+ end
73
+
74
+ def self.reset_sessions!
75
+ Capybara.old_reset_sessions!
76
+ end
77
+ end
78
+
79
+ # TODO: figure out why we need this patch - its because we are on an old version
80
+ # of Selenium Webdriver, but why?
81
+ require 'selenium-webdriver'
82
+
83
+ module Selenium
84
+ module WebDriver
85
+ module Chrome
86
+ module Bridge
87
+ COMMANDS = remove_const(:COMMANDS).dup
88
+ COMMANDS[:get_log] = [:post, 'session/:session_id/log']
89
+ COMMANDS.freeze
90
+
91
+ def log(type)
92
+ data = execute :get_log, {}, type: type.to_s
93
+
94
+ Array(data).map do |l|
95
+ begin
96
+ LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
97
+ rescue KeyError
98
+ next
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ module Capybara
108
+ class << self
109
+ alias old_reset_sessions! reset_sessions!
110
+ def reset_sessions!
111
+ old_reset_sessions! if HyperSpec.reset_between_examples?
112
+ end
113
+ end
114
+ end
115
+
116
+ RSpec.configure do |config|
117
+ config.add_setting :reset_between_examples, default: true
118
+ config.before(:all, no_reset: true) do
119
+ HyperSpec.reset_between_examples << RSpec.configuration.reset_between_examples
120
+ RSpec.configuration.reset_between_examples = false
121
+ end
122
+ config.before(:all, no_reset: false) do
123
+ HyperSpec.reset_between_examples << RSpec.configuration.reset_between_examples
124
+ RSpec.configuration.reset_between_examples = true
125
+ end
126
+ config.after(:all) do
127
+ HyperSpec.reset_sessions! unless HyperSpec.reset_between_examples?
128
+ # If rspecs step is used first in a file, it will NOT call config.before(:all) causing the
129
+ # reset_between_examples stack to be mismatched, so we check, if its already empty we
130
+ # just leave.
131
+ next if HyperSpec.reset_between_examples.empty?
132
+
133
+ RSpec.configuration.reset_between_examples = HyperSpec.reset_between_examples.pop
134
+ end
135
+ config.before(:each) do |example|
136
+ insure_page_loaded(true) if example.metadata[:js] && !HyperSpec.reset_between_examples?
137
+ end
138
+ end
9
139
 
10
140
  RSpec.configure do |config|
11
- config.include HyperSpec::ComponentTestHelpers
141
+ config.include HyperSpec::Helpers
12
142
  config.include HyperSpec::WaitForAjax
13
143
  config.include Capybara::DSL
14
144
 
@@ -17,17 +147,21 @@ RSpec.configure do |config|
17
147
  config.add_setting :debugger_width, default: nil
18
148
 
19
149
  config.before(:each) do
20
- Hyperstack.class_eval do
21
- def self.on_server?
22
- true
150
+ if defined?(Hyperstack)
151
+ Hyperstack.class_eval do
152
+ def self.on_server?
153
+ true
154
+ end
23
155
  end
24
- end if defined?(Hyperstack)
156
+ end
25
157
  # for compatibility with HyperMesh
26
- HyperMesh.class_eval do
27
- def self.on_server?
28
- true
158
+ if defined?(HyperMesh)
159
+ HyperMesh.class_eval do
160
+ def self.on_server?
161
+ true
162
+ end
29
163
  end
30
- end if defined?(HyperMesh)
164
+ end
31
165
  end
32
166
 
33
167
  config.before(:each, js: true) do
@@ -43,42 +177,51 @@ RSpec.configure do |config|
43
177
  PusherFake::Channel.reset if defined? PusherFake
44
178
  end
45
179
  end
46
-
47
180
  end
48
181
 
49
182
  # Capybara config
50
- RSpec.configure do |_config|
183
+ RSpec.configure do |config|
184
+ config.before(:each) do |example|
185
+ HyperSpec::Internal::Controller.current_example = example
186
+ HyperSpec::Internal::Controller.description_displayed = false
187
+ end
188
+
189
+ config.add_setting :wait_for_initialization_time
190
+ config.wait_for_initialization_time = 3
191
+
51
192
  Capybara.default_max_wait_time = 10
52
193
 
53
194
  Capybara.register_driver :chrome do |app|
54
195
  options = {}
55
196
  options.merge!(
56
- args: %w[auto-open-devtools-for-tabs],
57
- prefs: { 'devtools.open_docked' => false, "devtools.currentDockState" => "undocked", devtools: {currentDockState: :undocked} }
58
- ) unless ENV['NO_DEBUGGER']
59
- # this does not seem to work properly. Don't document this feature yet.
197
+ w3c: false,
198
+ args: %w[auto-open-devtools-for-tabs]
199
+ )
60
200
  options['mobileEmulation'] = { 'deviceName' => ENV['DEVICE'].tr('-', ' ') } if ENV['DEVICE']
61
- capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(chromeOptions: options)
201
+ capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
202
+ chromeOptions: options, 'goog:loggingPrefs' => { browser: 'ALL' }
203
+ )
62
204
  Capybara::Selenium::Driver.new(app, browser: :chrome, desired_capabilities: capabilities)
63
205
  end
64
206
 
207
+ Capybara.register_driver :firefox do |app|
208
+ Capybara::Selenium::Driver.new(app, browser: :firefox)
209
+ end
210
+
65
211
  Capybara.register_driver :chrome_headless_docker_travis do |app|
66
212
  options = ::Selenium::WebDriver::Chrome::Options.new
67
213
  options.add_argument('--headless')
68
214
  options.add_argument('--no-sandbox')
69
215
  options.add_argument('--disable-dev-shm-usage')
70
- Capybara::Selenium::Driver.new(app, browser: :chrome, :driver_path => "/usr/lib/chromium-browser/chromedriver", options: options)
71
- end
72
-
73
- Capybara.register_driver :firefox do |app|
74
- Capybara::Selenium::Driver.new(app, browser: :firefox)
216
+ Selenium::WebDriver::Chrome::Service.driver_path = '/usr/lib/chromium-browser/chromedriver'
217
+ Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
75
218
  end
76
219
 
77
220
  Capybara.register_driver :firefox_headless do |app|
78
221
  options = Selenium::WebDriver::Firefox::Options.new
79
222
  options.headless!
80
223
  Capybara::Selenium::Driver.new(app, browser: :firefox, options: options)
81
- end
224
+ end if defined?(Selenium::WebDriver::Firefox)
82
225
 
83
226
  Capybara.register_driver :selenium_with_firebug do |app|
84
227
  profile = Selenium::WebDriver::Firefox::Profile.new
@@ -86,7 +229,7 @@ RSpec.configure do |_config|
86
229
  profile.enable_firebug
87
230
  options = Selenium::WebDriver::Firefox::Options.new(profile: profile)
88
231
  Capybara::Selenium::Driver.new(app, browser: :firefox, options: options)
89
- end
232
+ end if defined?(Selenium::WebDriver::Firefox)
90
233
 
91
234
  Capybara.register_driver :safari do |app|
92
235
  Capybara::Selenium::Driver.new(app, browser: :safari)
@@ -103,5 +246,4 @@ RSpec.configure do |_config|
103
246
  when 'travis' then :chrome_headless_docker_travis
104
247
  else :selenium_chrome_headless
105
248
  end
106
-
107
249
  end
@@ -0,0 +1,164 @@
1
+ module HyperSpec
2
+ # Defines a series of methods that will build a test page
3
+ # This module is typically included into the HyperSpecTestController class.
4
+ module ControllerHelpers
5
+ # These methods are dependent on the stack being used. See the
6
+ # RailsControllerHelpers module and rack.rb for two implementations.
7
+ # Each method should append the appropriate code to the @page array
8
+
9
+ # return an empty 204 status either by setting headers or
10
+ # returning and appropriate response for rack.
11
+ def ping!
12
+ raise 'must implement'
13
+ end
14
+
15
+ def json!
16
+ # this can be a no-op but if json is not included by the application,
17
+ # hyper-spec will fail, with an error complaining about to_json
18
+ end
19
+
20
+ # return a script or style_sheet tag pointing to some asset.
21
+ # typically you be pointing to a path on the server or using
22
+ # sprockets to deliver the file.
23
+
24
+ def require!(_file_)
25
+ raise 'must implement'
26
+ end
27
+
28
+ def style_sheet!(_file_)
29
+ raise 'must implement'
30
+ end
31
+
32
+ # deliver the page. The @page variable will contain the html ready to go,
33
+ # any additional options that are passed through from the spec will be
34
+ # in the @render_params variable. For example layout: 'my_special_layout'
35
+
36
+ def deliver!
37
+ raise 'must implement'
38
+ end
39
+
40
+ # generate a react_render top level block. This will only be called if
41
+ # you use the mount directive in your specs, so it is optional.
42
+
43
+ def mount_component!
44
+ raise 'mount_component not implemented in HyperSpecTestController'
45
+ end
46
+
47
+ # by default the route back to the controller will be the controller name, less the
48
+ # word Controller, and underscored. If you want some other name redefine this
49
+ # method in the HyperSpecController class.
50
+
51
+ def self.included(base)
52
+ def base.route_root
53
+ # Implement underscore without using rails underscore, so we don't have a
54
+ # dependency on ActiveSupport
55
+ name.gsub(/Controller$/, '')
56
+ .gsub(/::/, '/')
57
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
58
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
59
+ .tr('-', '_')
60
+ .downcase
61
+ end
62
+ end
63
+
64
+ # The remainder of the methods should work for most implementations.
65
+
66
+ # helper method checking the render_on parameter
67
+
68
+ def on_client?
69
+ @render_on != :server_only
70
+ end
71
+
72
+ # The controllers behavior is kept as an array of values in the Controller cache
73
+ # under a unique id for each test run. Grab the parameters and move them to instance vars
74
+
75
+ # If this is just a ping! Then we can just exit with nil.
76
+
77
+ def initialize!
78
+ return if params[:id] == 'ping'
79
+
80
+ key = "/#{self.class.route_root}/#{params[:id]}"
81
+ test_params = Internal::Controller.cache_read(key)
82
+
83
+ @component_name = test_params[0]
84
+ @component_params = test_params[1]
85
+ @html_block = test_params[2]
86
+ @render_params = test_params[3]
87
+ @render_on = @render_params.delete(:render_on) || :client_only
88
+ @_mock_time = @render_params.delete(:mock_time)
89
+ @style_sheet = @render_params.delete(:style_sheet)
90
+ @javascript = @render_params.delete(:javascript)
91
+ @code = @render_params.delete(:code)
92
+
93
+ @page = ['<body>']
94
+ end
95
+
96
+ # add any html code generated by the insert_html directive
97
+
98
+ def html_block!
99
+ @page << @html_block
100
+ end
101
+
102
+ # patch behavior of the HyperComponent TopLevelRailsComponent class
103
+ # so that things like events are passed back to the test harness
104
+ TOP_LEVEL_COMPONENT_PATCH =
105
+ Opal.compile(File.read(File.expand_path('../sources/top_level_rails_component.rb', __dir__)))
106
+
107
+ # patch time cop and lolex so they stay in sync across the client and server
108
+ TIME_COP_CLIENT_PATCH =
109
+ Opal.compile(File.read(File.expand_path('../hyper-spec/internal/time_cop.rb', __dir__))) +
110
+ "\n#{File.read(File.expand_path('../sources/lolex.js', __dir__))}"
111
+
112
+ def client_code!
113
+ if @component_name
114
+ @page << "<script type='text/javascript'>\n#{TOP_LEVEL_COMPONENT_PATCH}\n</script>"
115
+ end
116
+ @page << "<script type='text/javascript'>\n#{@code}\n</script>" if @code
117
+ end
118
+
119
+ def time_cop_patch!
120
+ @page << "<script type='text/javascript'>\n#{TIME_COP_CLIENT_PATCH}\n</script>"
121
+ end
122
+
123
+ # Add the go_function to the client console. This is used to stop a hyper-spec pause directive.
124
+
125
+ def go_function!
126
+ @page << "<script type='text/javascript'>go = function() "\
127
+ '{window.hyper_spec_waiting_for_go = false}</script>'
128
+ end
129
+
130
+ # First lines displayed on the console will be the name of the spec
131
+
132
+ def example_title!
133
+ title = Internal::Controller.current_example_description!
134
+ @page << "<script type='text/javascript'>console.log('%c#{title}',"\
135
+ "'color:green; font-weight:bold; font-size: 200%')</script>"
136
+ end
137
+
138
+ # generate each piece of the page, and then deliver it
139
+
140
+ def style_sheet_file
141
+ @style_sheet || (!@render_params[:layout] && 'application')
142
+ end
143
+
144
+ def application_file
145
+ @javascript || (on_client? && !@render_params[:layout] && 'application')
146
+ end
147
+
148
+ def test
149
+ return ping! unless initialize!
150
+
151
+ html_block!
152
+ example_title! if Internal::Controller.current_example
153
+ go_function! if on_client?
154
+ style_sheet!(style_sheet_file) if style_sheet_file
155
+ application!(application_file) if application_file
156
+ json!
157
+ time_cop_patch! if on_client? || Lolex.initialized?
158
+ client_code! if on_client?
159
+ mount_component! if @component_name
160
+ @page = @page.join("\n") + "\n</body>\n"
161
+ deliver!
162
+ end
163
+ end
164
+ end