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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +36 -0
- data/.gitignore +1 -0
- data/CHANGELOG.md +33 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +34 -7
- data/README.md +109 -56
- data/Rakefile +8 -0
- data/capybara-lockstep.gemspec +1 -0
- data/lib/capybara-lockstep/capybara_ext.rb +62 -7
- data/lib/capybara-lockstep/configuration.rb +44 -4
- data/lib/capybara-lockstep/helper.js +180 -72
- data/lib/capybara-lockstep/helper.rb +16 -1
- data/lib/capybara-lockstep/lockstep.rb +46 -16
- data/lib/capybara-lockstep/logging.rb +8 -2
- data/lib/capybara-lockstep/version.rb +1 -1
- metadata +19 -3
@@ -17,7 +17,22 @@ module Capybara
|
|
17
17
|
tag_options[:nonce] = options.fetch(:nonce, true)
|
18
18
|
end
|
19
19
|
|
20
|
-
|
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 :
|
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?) ||
|
27
|
+
if (lazy && synchronized?) || synchronizing? || disabled?
|
26
28
|
return
|
27
29
|
end
|
28
30
|
|
29
|
-
|
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
|
-
|
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
|
-
|
74
|
-
@synchronized = false
|
75
|
-
raise e
|
98
|
+
unhandled_synchronize_error(e)
|
76
99
|
ensure
|
77
|
-
|
100
|
+
self.synchronizing = false
|
78
101
|
end
|
79
102
|
end
|
80
103
|
|
81
|
-
|
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 = "[
|
7
|
-
if
|
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
|
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.
|
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-
|
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.
|
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
|