capybara-lockstep 0.3.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|