capybara-lockstep 0.3.2 → 0.7.0

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.
@@ -17,7 +17,22 @@ module Capybara
17
17
  tag_options[:nonce] = options.fetch(:nonce, true)
18
18
  end
19
19
 
20
- javascript_tag(capybara_lockstep_js, tag_options)
20
+ js = capybara_lockstep_js + capybara_lockstep_config_js(options)
21
+ javascript_tag(js, tag_options)
22
+ end
23
+
24
+ def capybara_lockstep_config_js(options = {})
25
+ js = ''
26
+
27
+ if (debug = options.fetch(:debug, Lockstep.debug?))
28
+ js += "\nCapybaraLockstep.debug = #{debug.to_json}"
29
+ end
30
+
31
+ if (wait_tasks = options.fetch(:wait_tasks, Lockstep.wait_tasks))
32
+ js += "\nCapybaraLockstep.waitTasks = #{wait_tasks.to_json}"
33
+ end
34
+
35
+ js
21
36
  end
22
37
 
23
38
  end
@@ -1,10 +1,16 @@
1
1
  module Capybara
2
2
  module Lockstep
3
+ ERROR_SNIPPET_MISSING = 'Cannot synchronize: capybara-lockstep JavaScript snippet is missing'
4
+ ERROR_PAGE_MISSING = 'Cannot synchronize before initial Capybara visit'
5
+ ERROR_ALERT_OPEN = 'Cannot synchronize while an alert is open'
6
+ ERROR_NAVIGATED_AWAY = "Browser navigated away while synchronizing"
7
+
3
8
  class << self
4
9
  include Configuration
5
10
  include Logging
6
11
 
7
- attr_accessor :synchronized
12
+ attr_accessor :synchronizing
13
+ alias synchronizing? synchronizing
8
14
 
9
15
  def synchronized?
10
16
  value = page.instance_variable_get(:@lockstep_synchronized)
@@ -17,19 +23,24 @@ module Capybara
17
23
  page.instance_variable_set(:@lockstep_synchronized, value)
18
24
  end
19
25
 
20
- ERROR_SNIPPET_MISSING = 'Cannot synchronize: Capybara::Lockstep JavaScript snippet is missing on page'
21
- ERROR_PAGE_MISSING = 'Cannot synchronize before initial Capybara visit'
22
- ERROR_ALERT_OPEN = 'Cannot synchronize while an alert is open'
23
-
24
26
  def synchronize(lazy: false)
25
- if (lazy && synchronized?) || @synchronizing || disabled?
27
+ if (lazy && synchronized?) || synchronizing? || disabled?
26
28
  return
27
29
  end
28
30
 
29
- @synchronizing = true
31
+ synchronize_now
32
+ end
33
+
34
+ private
35
+
36
+ def synchronize_now
37
+ self.synchronizing = true
38
+ self.synchronized = false
30
39
 
31
40
  log 'Synchronizing'
32
41
 
42
+ start_time = current_seconds
43
+
33
44
  begin
34
45
  with_max_wait_time(timeout) do
35
46
  message_from_js = evaluate_async_script(<<~JS)
@@ -54,31 +65,46 @@ module Capybara
54
65
  case message_from_js
55
66
  when ERROR_PAGE_MISSING
56
67
  log(message_from_js)
57
- self.synchronized = false
58
68
  when ERROR_SNIPPET_MISSING
59
69
  log(message_from_js)
60
- self.synchronized = false
61
70
  else
62
71
  log message_from_js
63
- log "Synchronized successfully"
72
+ end_time = current_seconds
73
+ ms_elapsed = ((end_time.to_f - start_time) * 1000).round
74
+ log "Synchronized successfully [#{ms_elapsed} ms]"
64
75
  self.synchronized = true
65
76
  end
66
77
  end
78
+ rescue ::Selenium::WebDriver::Error::ScriptTimeoutError
79
+ log "Could not synchronize within #{timeout} seconds"
80
+ # Don't raise an error, this may happen if the server is slow to respond.
81
+ # We will retry on the next Capybara synchronize call.
67
82
  rescue ::Selenium::WebDriver::Error::UnexpectedAlertOpenError
68
83
  log ERROR_ALERT_OPEN
69
- @synchronized = false
70
84
  # Don't raise an error, this will happen in an innocent test.
71
85
  # We will retry on the next Capybara synchronize call.
86
+ rescue ::Selenium::WebDriver::Error::JavascriptError => e
87
+ # When the URL changes while a script is running, my current selenium-webdriver
88
+ # raises a Selenium::WebDriver::Error::JavascriptError with the message:
89
+ # "javascript error: document unloaded while waiting for result".
90
+ # We will retry on the next Capybara synchronize call, by then we should see
91
+ # the new page.
92
+ if e.message.include?('unload')
93
+ log ERROR_NAVIGATED_AWAY
94
+ else
95
+ unhandled_synchronize_error(e)
96
+ end
72
97
  rescue StandardError => e
73
- log "#{e.class.name} while synchronizing: #{e.message}"
74
- @synchronized = false
75
- raise e
98
+ unhandled_synchronize_error(e)
76
99
  ensure
77
- @synchronizing = false
100
+ self.synchronizing = false
78
101
  end
79
102
  end
80
103
 
81
- private
104
+ def unhandled_synchronize_error(e)
105
+ log "#{e.class.name} while synchronizing: #{e.message}"
106
+ raise e
107
+ end
82
108
 
83
109
  def page
84
110
  Capybara.current_session
@@ -102,6 +128,10 @@ module Capybara
102
128
  # no-op
103
129
  end
104
130
 
131
+ def current_seconds
132
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
133
+ end
134
+
105
135
  end
106
136
 
107
137
  end
@@ -3,8 +3,8 @@ module Capybara
3
3
  module Logging
4
4
  def log(message)
5
5
  if debug? && message.present?
6
- message = "[Capybara::Lockstep] #{message}"
7
- if @debug.respond_to?(:debug)
6
+ message = "[capybara-lockstep] #{message}"
7
+ if is_logger?(@debug)
8
8
  # If someone set Capybara::Lockstep to a logger, use that
9
9
  @debug.debug(message)
10
10
  else
@@ -13,6 +13,12 @@ module Capybara
13
13
  end
14
14
  end
15
15
  end
16
+
17
+ private
18
+
19
+ def is_logger?(object)
20
+ @debug.respond_to?(:debug)
21
+ end
16
22
  end
17
23
  end
18
24
  end
@@ -1,5 +1,5 @@
1
1
  module Capybara
2
2
  module Lockstep
3
- VERSION = "0.3.2"
3
+ VERSION = "0.7.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-lockstep
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henning Koch
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-04 00:00:00.000000000 Z
11
+ date: 2021-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ruby2_keywords
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description:
56
70
  email:
57
71
  - henning.koch@makandra.de
@@ -59,9 +73,11 @@ executables: []
59
73
  extensions: []
60
74
  extra_rdoc_files: []
61
75
  files:
76
+ - ".github/workflows/test.yml"
62
77
  - ".gitignore"
63
78
  - ".rspec"
64
79
  - ".ruby-version"
80
+ - CHANGELOG.md
65
81
  - Gemfile
66
82
  - Gemfile.lock
67
83
  - LICENSE.txt
@@ -100,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
116
  - !ruby/object:Gem::Version
101
117
  version: '0'
102
118
  requirements: []
103
- rubygems_version: 3.2.5
119
+ rubygems_version: 3.0.3
104
120
  signing_key:
105
121
  specification_version: 4
106
122
  summary: Synchronize Capybara commands with client-side JavaScript and AJAX requests