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/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # HyperSpec
2
2
 
3
+ [![Build Status](https://travis-ci.org/ruby-hyperloop/hyper-spec.svg?branch=master)](https://travis-ci.org/ruby-hyperloop/hyper-spec)
4
+
3
5
  With HyperSpec you can run *isomorphic* specs for all your Hyperloop code using RSpec. Everything runs as standard RSpec test specs.
4
6
 
5
7
  For example if you have a component like this:
@@ -47,7 +49,7 @@ end
47
49
 
48
50
  Hyperloop wants to make the server-client divide as transparent to the developer as practical. Given this, it makes sense that the testing should also be done with as little concern for client versus server.
49
51
 
50
- HyperSpec allows you to directly use tools like FactoryGirl (or Hyperloop Operations) to setup some test data, then run a spec to make sure that a component correctly displays, or modifies that data. You can use Timecop to manipulate time and keep in sync between the server and client. This makes testing easier and more realistic without writing a lot of redundant code.
52
+ HyperSpec allows you to directly use tools like FactoryBot (or Hyperloop Operations) to setup some test data, then run a spec to make sure that a component correctly displays, or modifies that data. You can use Timecop to manipulate time and keep in sync between the server and client. This makes testing easier and more realistic without writing a lot of redundant code.
51
53
 
52
54
 
53
55
  ## Installation
data/Rakefile CHANGED
@@ -2,4 +2,10 @@ require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
+
6
+ namespace :spec do
7
+ task :prepare do
8
+ end
9
+ end
10
+
5
11
  task :default => :spec
data/hyper-spec.gemspec CHANGED
@@ -6,67 +6,55 @@ 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 = ['catmando', 'adamcreekroad']
10
- spec.email = ['mitch@catprint.com']
11
-
12
- spec.summary =
13
- 'Drive your Hyperloop client and server specs from RSpec and Capybara'
14
- spec.description =
15
- 'A Hyperloop application consists of isomorphic React Components, '\
16
- 'Active Record Models, Stores, Operations and Policiespec. '\
17
- 'Test them all from Rspec, regardless if the code runs on the client or server.'
18
- spec.homepage = 'https://github.com/ruby-hyperloop/hyper-spec'
9
+ spec.authors = ['Mitch VanDuyn', 'Adam Creekroad', 'Jan Biedermann']
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, '\
13
+ 'Active Record Models, Stores, Operations and Policiespec. '\
14
+ 'Test them all from Rspec, regardless if the code runs on the client or server.'
15
+ spec.homepage = 'http://ruby-hyperloop.org'
19
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
+ # }
20
21
 
21
- # Prevent pushing this gem to RubyGemspec.org. To allow pushes either set the 'allowed_push_host'
22
- # to allow pushing to a single host or delete this section to allow pushing to any host.
23
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
24
-
25
- spec.files =
26
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(gemfiles|spec)/}) }
27
23
  spec.bindir = 'exe'
28
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
25
  spec.require_paths = ['lib']
30
26
 
31
- # Test app dependencies
32
- spec.add_development_dependency 'bundler', '~> 1.12'
33
- spec.add_development_dependency 'hyper-react', '>= 0.10.0'
34
- spec.add_development_dependency 'rails', '~>5.0.0'
35
- spec.add_development_dependency 'rake', '~> 10.0'
36
- spec.add_development_dependency 'react-rails', '< 1.10.0'
37
-
38
- # Keep linter-rubocop happy
39
- spec.add_development_dependency 'rubocop'
40
-
41
- if RUBY_PLATFORM == 'java'
42
- spec.add_development_dependency 'therubyrhino'
43
- else
44
- spec.add_development_dependency 'therubyracer', '0.12.2'
45
-
46
- # Actual dependencies
47
- spec.add_dependency 'capybara'
48
- spec.add_dependency 'opal'
49
- spec.add_dependency 'parser'
50
- spec.add_dependency 'poltergeist'
51
- spec.add_dependency 'pry'
52
- spec.add_dependency 'rspec-rails'
53
- spec.add_dependency 'selenium-webdriver', '2.53.4'
54
- spec.add_dependency 'timecop'
55
- spec.add_dependency 'unparser', '0.2.5'
56
-
57
- # Test app dependencies
58
- spec.add_development_dependency 'chromedriver-helper'
59
- spec.add_development_dependency 'method_source'
60
- spec.add_development_dependency 'opal-browser'
61
- spec.add_development_dependency 'opal-rails'
62
- spec.add_development_dependency 'puma'
63
- spec.add_development_dependency 'rspec-collection_matchers'
64
- spec.add_development_dependency 'rspec-expectations'
65
- spec.add_development_dependency 'rspec-its'
66
- spec.add_development_dependency 'rspec-mocks'
67
- spec.add_development_dependency 'rspec-steps'
68
- spec.add_development_dependency 'shoulda'
69
- spec.add_development_dependency 'shoulda-matchers'
70
- spec.add_development_dependency 'spring-commands-rspec'
71
- end
27
+ spec.add_dependency 'capybara'
28
+ 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
30
+ 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'
36
+ spec.add_dependency 'selenium-webdriver'
37
+ spec.add_dependency 'timecop', '~> 0.8.1'
38
+ spec.add_dependency 'uglifier'
39
+ spec.add_dependency 'unparser'
40
+ spec.add_dependency 'webdrivers'
41
+
42
+ spec.add_development_dependency 'bundler'
43
+ spec.add_development_dependency 'hyper-component', HyperSpec::VERSION
44
+ spec.add_development_dependency 'opal-browser', '~> 0.2.0'
45
+ spec.add_development_dependency 'opal-rails', '~> 0.9.4'
46
+ spec.add_development_dependency 'pry-rescue'
47
+ spec.add_development_dependency 'puma'
48
+ spec.add_development_dependency 'rails', '>= 4.0.0'
49
+ spec.add_development_dependency 'rake'
50
+ spec.add_development_dependency 'react-rails', '>= 2.3.0', '< 2.5.0'
51
+ spec.add_development_dependency 'rspec-collection_matchers'
52
+ spec.add_development_dependency 'rspec-expectations'
53
+ spec.add_development_dependency 'rspec-its'
54
+ spec.add_development_dependency 'rspec-mocks'
55
+ spec.add_development_dependency 'rspec-steps', '~> 2.1.1'
56
+ spec.add_development_dependency 'rubocop', '~> 0.51.0'
57
+ spec.add_development_dependency 'shoulda'
58
+ spec.add_development_dependency 'shoulda-matchers'
59
+ spec.add_development_dependency 'spring-commands-rspec'
72
60
  end
Binary file
data/lib/hyper-spec.rb CHANGED
@@ -1,13 +1,10 @@
1
1
  require 'capybara/rspec'
2
- require 'capybara/poltergeist'
3
2
  require 'opal'
4
3
  require 'selenium-webdriver'
5
4
 
6
5
  require 'hyper-spec/component_test_helpers'
7
- require 'hyper-spec/rails/engine'
8
6
  require 'hyper-spec/version'
9
7
  require 'hyper-spec/wait_for_ajax'
10
- require 'react/isomorphic_helpers'
11
8
  require 'selenium/web_driver/firefox/profile'
12
9
 
13
10
  RSpec.configure do |config|
@@ -17,14 +14,20 @@ RSpec.configure do |config|
17
14
 
18
15
  config.mock_with :rspec
19
16
 
20
- if defined?(HyperMesh)
21
- config.before(:each) do
22
- HyperMesh.class_eval do
23
- def self.on_server?
24
- true
25
- end
17
+ config.add_setting :debugger_width, default: nil
18
+
19
+ config.before(:each) do
20
+ Hyperloop.class_eval do
21
+ def self.on_server?
22
+ true
26
23
  end
27
- end
24
+ end if defined?(Hyperloop)
25
+ # for compatibility with HyperMesh
26
+ HyperMesh.class_eval do
27
+ def self.on_server?
28
+ true
29
+ end
30
+ end if defined?(HyperMesh)
28
31
  end
29
32
 
30
33
  config.before(:each, js: true) do
@@ -40,49 +43,65 @@ RSpec.configure do |config|
40
43
  PusherFake::Channel.reset if defined? PusherFake
41
44
  end
42
45
  end
46
+
43
47
  end
44
48
 
45
49
  # Capybara config
46
50
  RSpec.configure do |_config|
47
51
  Capybara.default_max_wait_time = 10
48
52
 
49
- # # In case Google ever fixes chromedriver to work with Opal...
50
- # Capybara.register_driver :chrome do |app|
51
- # caps = Selenium::WebDriver::Remote::Capabilities.chrome(
52
- # 'chromeOptions' => { 'args' => ['--window-size=200,200'] }
53
- # )
54
- #
55
- # Capybara::Selenium::Driver.new(app, browser: :chrome, desired_capabilities: caps)
56
- # end
57
-
58
- Capybara.register_driver :poltergeist do |app|
59
- options = {
60
- js_errors: false, timeout: 180, inspector: true,
61
- phantomjs_options: ['--load-images=no', '--ignore-ssl-errors=yes']
62
- }.tap do |hash|
63
- unless ENV['SHOW_LOGS']
64
- hash[:phantomjs_logger] = StringIO.new
65
- hash[:logger] = StringIO.new
66
- end
67
- end
53
+ Capybara.register_driver :chrome do |app|
54
+ options = {}
55
+ 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.
60
+ options['mobileEmulation'] = { 'deviceName' => ENV['DEVICE'].tr('-', ' ') } if ENV['DEVICE']
61
+ capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(chromeOptions: options)
62
+ Capybara::Selenium::Driver.new(app, browser: :chrome, desired_capabilities: capabilities)
63
+ end
68
64
 
69
- Capybara::Poltergeist::Driver.new(app, options)
65
+ Capybara.register_driver :chrome_headless_docker_travis do |app|
66
+ options = ::Selenium::WebDriver::Chrome::Options.new
67
+ options.add_argument('--headless')
68
+ options.add_argument('--no-sandbox')
69
+ 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)
75
+ end
76
+
77
+ Capybara.register_driver :firefox_headless do |app|
78
+ options = Selenium::WebDriver::Firefox::Options.new
79
+ options.headless!
80
+ Capybara::Selenium::Driver.new(app, browser: :firefox, options: options)
70
81
  end
71
82
 
72
83
  Capybara.register_driver :selenium_with_firebug do |app|
73
84
  profile = Selenium::WebDriver::Firefox::Profile.new
74
- profile.frame_position = ENV['DRIVER'] && ENV['DRIVER'][2]
85
+ ENV['FRAME_POSITION'] && profile.frame_position = ENV['FRAME_POSITION']
75
86
  profile.enable_firebug
87
+ options = Selenium::WebDriver::Firefox::Options.new(profile: profile)
88
+ Capybara::Selenium::Driver.new(app, browser: :firefox, options: options)
89
+ end
76
90
 
77
- Capybara::Selenium::Driver.new(app, browser: :firefox, profile: profile)
91
+ Capybara.register_driver :safari do |app|
92
+ Capybara::Selenium::Driver.new(app, browser: :safari)
78
93
  end
79
94
 
80
95
  Capybara.javascript_driver =
81
- if ENV['DRIVER'] =~ /^ff/
82
- :selenium_with_firebug
83
- # elsif ENV['DRIVER'] == 'chrome'
84
- # Capybara.javascript_driver = :chrome
85
- else
86
- :poltergeist
96
+ case ENV['DRIVER']
97
+ when 'beheaded' then :firefox_headless
98
+ when 'chrome' then :chrome
99
+ when 'ff' then :selenium_with_firebug
100
+ when 'firefox' then :firefox
101
+ when 'headless' then :selenium_chrome_headless
102
+ when 'safari' then :safari
103
+ when 'travis' then :chrome_headless_docker_travis
104
+ else :selenium_chrome_headless
87
105
  end
106
+
88
107
  end
@@ -1,29 +1,31 @@
1
1
  # see component_test_helpers_spec.rb for examples
2
-
3
2
  require 'parser/current'
4
3
  require 'unparser'
5
4
  require 'method_source'
6
- require_relative '../../vendor/assets/javascripts/time_cop' # 'hyper-spec/time_cop'
5
+ require_relative '../../lib/hyper-spec/time_cop.rb'
7
6
 
8
7
  module HyperSpec
9
8
  module ComponentTestHelpers
10
9
  TOP_LEVEL_COMPONENT_PATCH =
11
10
  Opal.compile(File.read(File.expand_path('../../react/top_level_rails_component.rb', __FILE__)))
11
+ TIME_COP_CLIENT_PATCH =
12
+ Opal.compile(File.read(File.expand_path('../../hyper-spec/time_cop.rb', __FILE__))) +
13
+ "\n#{File.read(File.expand_path('../../sources/lolex.js', __FILE__))}"
12
14
 
13
15
  class << self
14
16
  attr_accessor :current_example
15
17
  attr_accessor :description_displayed
16
18
 
17
19
  def display_example_description
18
- "<script type='text/javascript'>console.log(console.log('%c#{current_example.description}'"\
19
- ",'color:green; font-weight:bold; font-size: 200%'))</script>"
20
+ "<script type='text/javascript'>console.log('%c#{current_example.description}'"\
21
+ ",'color:green; font-weight:bold; font-size: 200%')</script>"
20
22
  end
21
23
  end
22
24
 
23
25
  def build_test_url_for(controller)
24
26
  unless controller
25
27
  unless defined?(::ReactTestController)
26
- Object.const_set('ReactTestController', Class.new(ActionController::Base))
28
+ Object.const_set('ReactTestController', Class.new(::ActionController::Base))
27
29
  end
28
30
 
29
31
  controller = ::ReactTestController
@@ -47,11 +49,14 @@ module HyperSpec
47
49
 
48
50
  page = '<%= react_component @component_name, @component_params, '\
49
51
  "{ prerender: #{render_on != :client_only} } %>"
50
- page = "<script type='text/javascript'>\n#{TOP_LEVEL_COMPONENT_PATCH}\n</script>\n#{page}"
51
-
52
- page = "<script type='text/javascript'>\n#{code}\n</script>\n#{page}" if code
52
+ unless render_on == :server_only
53
+ page = "<script type='text/javascript'>\n#{TOP_LEVEL_COMPONENT_PATCH}\n</script>\n#{page}"
54
+ page = "<script type='text/javascript'>\n#{code}\n</script>\n#{page}" if code
55
+ end
53
56
 
54
- page = "<%= javascript_include_tag 'time_cop' %>\n#{page}" if true || Lolex.initialized?
57
+ if render_on != :server_only || Lolex.initialized?
58
+ page = "<script type='text/javascript'>\n#{TIME_COP_CLIENT_PATCH}\n</script>\n#{page}"
59
+ end
55
60
 
56
61
  if (render_on != :server_only && !render_params[:layout]) || javascript
57
62
  page = "<%= javascript_include_tag '#{javascript || 'application'}' %>\n#{page}"
@@ -60,22 +65,14 @@ module HyperSpec
60
65
  if !render_params[:layout] || style_sheet
61
66
  page = "<%= stylesheet_link_tag '#{style_sheet || 'application'}' %>\n#{page}"
62
67
  end
63
-
64
- if render_on == :server_only # so that test helper wait_for_ajax works
65
- page = "<script type='text/javascript'>window.jQuery = {'active': 0}</script>\n#{page}"
66
- else
67
- page = "<%= javascript_include_tag 'jquery' %>\n"\
68
- "<%= javascript_include_tag 'jquery_ujs' %>\n#{page}"
69
- end
70
-
71
68
  page = "<script type='text/javascript'>go = function() "\
72
69
  "{window.hyper_spec_waiting_for_go = false}</script>\n#{page}"
73
70
 
74
71
  title = view_context.escape_javascript(ComponentTestHelpers.current_example.description)
75
72
  title = "#{title}...continued." if ComponentTestHelpers.description_displayed
76
73
 
77
- page = "<script type='text/javascript'>console.log(console.log('%c#{title}',"\
78
- "'color:green; font-weight:bold; font-size: 200%'))</script>\n#{page}"
74
+ page = "<script type='text/javascript'>console.log('%c#{title}',"\
75
+ "'color:green; font-weight:bold; font-size: 200%')</script>\n#{page}"
79
76
 
80
77
  ComponentTestHelpers.description_displayed = true
81
78
  render_params[:inline] = page
@@ -112,6 +109,8 @@ module HyperSpec
112
109
  str = "#{str}\n#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.last}"
113
110
  end
114
111
  js = Opal.compile(str).delete("\n").gsub('(Opal);', '(Opal)')
112
+ # workaround for firefox 58 and geckodriver 0.19.1, because firefox is unable to find .$to_json:
113
+ # JSON.parse(evaluate_script("(function(){var a=Opal.Array.$new(); a[0]=#{js}; return a.$to_json();})();"), opts).first
115
114
  JSON.parse(evaluate_script("[#{js}].$to_json()"), opts).first
116
115
  end
117
116
 
@@ -129,25 +128,25 @@ module HyperSpec
129
128
  "#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.first.children.last}"
130
129
  end
131
130
 
132
- def expect_promise(str = '', opts = {}, &block)
131
+ def evaluate_promise(str = '', opts = {}, &block)
133
132
  insure_mount
134
-
135
- str = add_opal_block(str, block)
133
+ str = "#{str}\n#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.last}" if block
136
134
  str = "#{str}.then { |args| args = [args]; `window.hyper_spec_promise_result = args` }"
137
- js = Opal.compile(str).delete("\n").gsub('(Opal);', '(Opal)')
138
- page.evaluate_script('window.hyper_spec_promise_result = false')
135
+ js = Opal.compile(str).gsub("\n","").gsub("(Opal);","(Opal)")
136
+ page.evaluate_script("window.hyper_spec_promise_result = false")
139
137
  page.execute_script(js)
140
-
141
138
  Timeout.timeout(Capybara.default_max_wait_time) do
142
139
  loop do
143
140
  sleep 0.25
144
- break if page.evaluate_script('!!window.hyper_spec_promise_result')
141
+ break if page.evaluate_script("!!window.hyper_spec_promise_result")
145
142
  end
146
143
  end
144
+ JSON.parse(page.evaluate_script("window.hyper_spec_promise_result.$to_json()"), opts).first
145
+ end
147
146
 
148
- result =
149
- JSON.parse(page.evaluate_script('window.hyper_spec_promise_result.$to_json()'), opts).first
150
- expect(result)
147
+ def expect_promise(str = '', opts = {}, &block)
148
+ insure_mount
149
+ expect(evaluate_promise(add_opal_block(str, block), opts))
151
150
  end
152
151
 
153
152
  def ppr(str)
@@ -193,19 +192,32 @@ module HyperSpec
193
192
  `eval(s)`
194
193
  end
195
194
  def self.dasherize(s)
196
- `s.replace(/[-_\\s]+/g, '-')
195
+ res = %x{
196
+ s.replace(/[-_\\s]+/g, '-')
197
197
  .replace(/([A-Z\\d]+)([A-Z][a-z])/g, '$1-$2')
198
198
  .replace(/([a-z\\d])([A-Z])/g, '$1-$2')
199
- .toLowerCase()`
199
+ .toLowerCase()
200
+ }
201
+ res
200
202
  end
201
203
  def self.add_class(class_name, styles={})
202
- style = styles.collect { |attr, value| "\#{dasherize(attr)}:\#{value}"}.join("; ")
203
- s = "<style type='text/css'> .\#{class_name}{ \#{style} } </style>"
204
- `$(\#{s}).appendTo("head");`
204
+ style = styles.collect { |attr, value| "\#{dasherize(attr)}:\#{value}" }.join("; ")
205
+ cs = class_name.to_s
206
+ %x{
207
+ var style_el = document.createElement("style");
208
+ var css = "." + cs + " { " + style + " }";
209
+ style_el.type = "text/css";
210
+ if (style_el.styleSheet){
211
+ style_el.styleSheet.cssText = css;
212
+ } else {
213
+ style_el.appendChild(document.createTextNode(css));
214
+ }
215
+ document.head.appendChild(style_el);
216
+ }
205
217
  end
206
218
  end
207
219
  class React::Component::HyperTestDummy < React::Component::Base
208
- def render; end
220
+ def render; end
209
221
  end
210
222
  #{@client_code}
211
223
  #{Unparser.unparse(Parser::CurrentRuby.parse(block.source).children.last) if block}
@@ -215,6 +227,19 @@ module HyperSpec
215
227
 
216
228
  component_name ||= 'React::Component::HyperTestDummy'
217
229
  ::Rails.cache.write(test_url, [component_name, params, opts])
230
+ test_code_key = "hyper_spec_prerender_test_code.js"
231
+ @@original_server_render_files ||= ::Rails.configuration.react.server_renderer_options[:files]
232
+ if opts[:render_on] == :both || opts[:render_on] == :server_only
233
+ unless opts[:code].blank?
234
+ ::Rails.cache.write(test_code_key, opts[:code])
235
+ ::Rails.configuration.react.server_renderer_options[:files] = @@original_server_render_files + [test_code_key]
236
+ ::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
237
+ else
238
+ ::Rails.cache.delete(test_code_key)
239
+ ::Rails.configuration.react.server_renderer_options[:files] = @@original_server_render_files
240
+ ::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
241
+ end
242
+ end
218
243
  visit test_url
219
244
  wait_for_ajax unless opts[:no_wait]
220
245
  page.instance_variable_set('@hyper_spec_mounted', true)
@@ -234,7 +259,7 @@ module HyperSpec
234
259
  end
235
260
 
236
261
  def add_class(class_name, style)
237
- @client_code = "#{@client_code}ComponentHelpers.add_class '#{class_name}', #{style}\n"
262
+ @client_code = "#{@client_code}ComponentHelpers.add_class('#{class_name}', #{style})\n"
238
263
  end
239
264
 
240
265
  def open_in_chrome
@@ -263,7 +288,28 @@ module HyperSpec
263
288
  end
264
289
  end
265
290
 
291
+ def wait_for_size(width, height)
292
+ start_time = Capybara::Helpers.monotonic_time
293
+ stable_count_w = 0
294
+ stable_count_h = 0
295
+ prev_size = [0, 0]
296
+ begin
297
+ sleep 0.05
298
+ curr_size = Capybara.current_session.current_window.size
299
+ return if [width, height] == curr_size
300
+ # some maximum or minimum is reached and size doesnt change anymore
301
+ stable_count_w += 1 if prev_size[0] == curr_size[0]
302
+ stable_count_h += 1 if prev_size[1] == curr_size[1]
303
+ return if stable_count_w > 2 || stable_count_h > 2
304
+ prev_size = curr_size
305
+ end while (Capybara::Helpers.monotonic_time - start_time) < Capybara.current_session.config.default_max_wait_time
306
+ raise Capybara::WindowError, "Window size not stable within #{Capybara.current_session.config.default_max_wait_time} seconds."
307
+ end
308
+
266
309
  def size_window(width = nil, height = nil)
310
+ # return if @window_cannot_be_resized
311
+ # original_width = evaluate_script('window.innerWidth')
312
+ # original_height = evaluate_script('window.innerHeight')
267
313
  width, height = [height, width] if width == :portrait
268
314
  width, height = width if width.is_a? Array
269
315
  portrait = true if height == :portrait
@@ -283,7 +329,15 @@ module HyperSpec
283
329
 
284
330
  width, height = [height, width] if portrait
285
331
 
286
- Capybara.current_session.current_window.resize_to(width, height)
332
+ unless RSpec.configuration.debugger_width
333
+ Capybara.current_session.current_window.resize_to(1000, 500)
334
+ wait_for_size(1000, 500)
335
+ inner_width = evaluate_script('window.innerWidth')
336
+ RSpec.configuration.debugger_width = 1000 - inner_width
337
+ end
338
+ Capybara.current_session.current_window
339
+ .resize_to(width + RSpec.configuration.debugger_width, height)
340
+ wait_for_size(width + RSpec.configuration.debugger_width, height)
287
341
  end
288
342
  end
289
343