capybara-lockstep 0.2.2 → 0.2.3
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/Gemfile.lock +16 -13
- data/README.md +1 -1
- data/lib/capybara-lockstep/capybara_ext.rb +33 -7
- data/lib/capybara-lockstep/lockstep.rb +62 -39
- data/lib/capybara-lockstep/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa8ccde381bb125f66222689d93c93008ec2137cfabc664a6ce83ff0701cd7a8
|
4
|
+
data.tar.gz: 7485b88104f0c4b43387f252e600ad7dc23a917eac28914249b8f279d5ab9df3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19f52ab1ca0e9f30fe8be0e791b66bcefe9992d958a104a30c602987e310363587f075f7af19bebf8248e76836a008601c700092bc3b1d53fff3fda5b764dcdc
|
7
|
+
data.tar.gz: e6380494b6940092842f87e54c898e6a2da9311aa2fd1951a602fb193fb44c7ee6f96907704d80382bd1cc2ccc31a7e0b433e27da8906f889aa6f7178fcd2dff
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
capybara-lockstep (0.2.
|
4
|
+
capybara-lockstep (0.2.3)
|
5
5
|
activesupport (>= 3.2)
|
6
6
|
capybara (>= 2.0)
|
7
7
|
selenium-webdriver (>= 3)
|
@@ -9,11 +9,12 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
activesupport (
|
12
|
+
activesupport (6.1.3)
|
13
13
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
|
-
i18n (>=
|
15
|
-
minitest (
|
16
|
-
tzinfo (~>
|
14
|
+
i18n (>= 1.6, < 2)
|
15
|
+
minitest (>= 5.1)
|
16
|
+
tzinfo (~> 2.0)
|
17
|
+
zeitwerk (~> 2.3)
|
17
18
|
addressable (2.7.0)
|
18
19
|
public_suffix (>= 2.0.2, < 5.0)
|
19
20
|
capybara (3.35.3)
|
@@ -25,13 +26,15 @@ GEM
|
|
25
26
|
regexp_parser (>= 1.5, < 3.0)
|
26
27
|
xpath (~> 3.2)
|
27
28
|
childprocess (3.0.0)
|
28
|
-
concurrent-ruby (1.1.
|
29
|
+
concurrent-ruby (1.1.8)
|
29
30
|
diff-lcs (1.3)
|
30
|
-
i18n (1.8.
|
31
|
+
i18n (1.8.9)
|
31
32
|
concurrent-ruby (~> 1.0)
|
32
33
|
mini_mime (1.0.2)
|
33
|
-
|
34
|
-
|
34
|
+
mini_portile2 (2.5.0)
|
35
|
+
minitest (5.14.4)
|
36
|
+
nokogiri (1.11.1)
|
37
|
+
mini_portile2 (~> 2.5.0)
|
35
38
|
racc (~> 1.4)
|
36
39
|
public_suffix (4.0.6)
|
37
40
|
racc (1.5.2)
|
@@ -53,15 +56,15 @@ GEM
|
|
53
56
|
diff-lcs (>= 1.2.0, < 2.0)
|
54
57
|
rspec-support (~> 3.7.0)
|
55
58
|
rspec-support (3.7.0)
|
56
|
-
rubyzip (
|
59
|
+
rubyzip (2.3.0)
|
57
60
|
selenium-webdriver (3.142.7)
|
58
61
|
childprocess (>= 0.5, < 4.0)
|
59
62
|
rubyzip (>= 1.2.2)
|
60
|
-
|
61
|
-
|
62
|
-
thread_safe (~> 0.1)
|
63
|
+
tzinfo (2.0.4)
|
64
|
+
concurrent-ruby (~> 1.0)
|
63
65
|
xpath (3.2.0)
|
64
66
|
nokogiri (~> 1.8)
|
67
|
+
zeitwerk (2.4.2)
|
65
68
|
|
66
69
|
PLATFORMS
|
67
70
|
ruby
|
data/README.md
CHANGED
@@ -59,7 +59,7 @@ Installation
|
|
59
59
|
Check if your application satisfies all requirements for capybara-lockstep:
|
60
60
|
|
61
61
|
- Capybara 2 or higher.
|
62
|
-
- Your Capybara driver must use [selenium-webdriver](https://rubygems.org/gems/selenium-webdriver/). capybara-
|
62
|
+
- Your Capybara driver must use [selenium-webdriver](https://rubygems.org/gems/selenium-webdriver/). capybara-lockstep deactivates itself for any other driver.
|
63
63
|
- This gem was only tested with a Selenium-controlled Chrome browser. [Chrome in headless mode](https://makandracards.com/makandra/492109-running-capybara-tests-in-headless-chrome) is recommended, but not required.
|
64
64
|
- This gem was only tested with Rails, but there's no Rails dependency.
|
65
65
|
|
@@ -1,24 +1,38 @@
|
|
1
1
|
module Capybara
|
2
2
|
module Lockstep
|
3
3
|
module VisitWithWaiting
|
4
|
-
def visit(*args,
|
5
|
-
|
4
|
+
def visit(*args, &block)
|
5
|
+
visiting_remote_url = !args[0].start_with?('data:')
|
6
|
+
|
7
|
+
Capybara::Lockstep.catch_up
|
8
|
+
|
9
|
+
super(*args, &block).tap do
|
6
10
|
# There is a step that changes drivers mid-scenario.
|
7
11
|
# It works by creating a new Capybara session and re-visits the
|
8
12
|
# URL from the previous session. If this happens before a URL is ever
|
9
13
|
# loaded, it re-visits the URL "data:", which will never "finish"
|
10
14
|
# initializing.
|
11
|
-
|
15
|
+
if visiting_remote_url
|
12
16
|
Capybara::Lockstep.await_initialized
|
13
17
|
end
|
14
18
|
end
|
15
19
|
end
|
16
20
|
end
|
21
|
+
end
|
22
|
+
end
|
17
23
|
|
24
|
+
|
25
|
+
Capybara::Session.class_eval do
|
26
|
+
prepend Capybara::Lockstep::VisitWithWaiting
|
27
|
+
end
|
28
|
+
|
29
|
+
module Capybara
|
30
|
+
module Lockstep
|
18
31
|
module AwaitIdle
|
19
32
|
def await_idle(meth)
|
20
33
|
mod = Module.new do
|
21
34
|
define_method meth do |*args, &block|
|
35
|
+
Capybara::Lockstep.catch_up
|
22
36
|
super(*args, &block).tap do
|
23
37
|
Capybara::Lockstep.await_idle
|
24
38
|
end
|
@@ -30,10 +44,6 @@ module Capybara
|
|
30
44
|
end
|
31
45
|
end
|
32
46
|
|
33
|
-
Capybara::Session.class_eval do
|
34
|
-
prepend Capybara::Lockstep::VisitWithWaiting
|
35
|
-
end
|
36
|
-
|
37
47
|
# Capybara 3 has driver-specific Node classes which sometimes
|
38
48
|
# super to Capybara::Selenium::Node, but not always.
|
39
49
|
node_classes = [
|
@@ -69,3 +79,19 @@ node_classes.each do |node_class|
|
|
69
79
|
await_idle :trigger
|
70
80
|
end
|
71
81
|
end
|
82
|
+
|
83
|
+
module Capybara
|
84
|
+
module Lockstep
|
85
|
+
module SynchronizeWithCatchUp
|
86
|
+
def synchronize(*args, &block)
|
87
|
+
Capybara::Lockstep.catch_up
|
88
|
+
|
89
|
+
super(*args, &block)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
Capybara::Node::Base.class_eval do
|
96
|
+
prepend Capybara::Lockstep::SynchronizeWithCatchUp
|
97
|
+
end
|
@@ -5,25 +5,28 @@ module Capybara
|
|
5
5
|
include Configuration
|
6
6
|
|
7
7
|
def await_idle
|
8
|
+
@delay_await_idle = false
|
8
9
|
return unless enabled?
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
JS
|
21
|
-
log(message_from_js)
|
22
|
-
end
|
11
|
+
with_max_wait_time(timeout) do
|
12
|
+
message_from_js = evaluate_async_script(<<~JS)
|
13
|
+
let done = arguments[0]
|
14
|
+
if (window.CapybaraLockstep) {
|
15
|
+
CapybaraLockstep.awaitIdle(done)
|
16
|
+
} else {
|
17
|
+
done('Cannot synchronize: Capybara::Lockstep was not included in page')
|
18
|
+
}
|
19
|
+
JS
|
20
|
+
log(message_from_js)
|
23
21
|
end
|
22
|
+
rescue ::Selenium::WebDriver::Error::UnexpectedAlertOpenError
|
23
|
+
log 'Cannot synchronize: Alert is open'
|
24
|
+
@delay_await_idle = true
|
24
25
|
end
|
25
26
|
|
26
27
|
def await_initialized
|
28
|
+
@delay_await_initialized = false
|
29
|
+
@delay_await_idle = false # since we're also waiting for idle
|
27
30
|
return unless enabled?
|
28
31
|
|
29
32
|
# We're retrying the initialize check every few ms.
|
@@ -41,6 +44,29 @@ module Capybara
|
|
41
44
|
raise Busy, reason
|
42
45
|
end
|
43
46
|
end
|
47
|
+
rescue ::Selenium::WebDriver::Error::UnexpectedAlertOpenError
|
48
|
+
log 'Cannot synchronize: Alert is open'
|
49
|
+
@delay_await_initialized = true
|
50
|
+
end
|
51
|
+
|
52
|
+
def catch_up
|
53
|
+
return if @catching_up
|
54
|
+
|
55
|
+
begin
|
56
|
+
@catching_up = true
|
57
|
+
if @delay_await_initialized
|
58
|
+
log 'Retrying synchronization'
|
59
|
+
await_initialized
|
60
|
+
# elsif browser_made_full_page_load?
|
61
|
+
# log 'Browser loaded new page'
|
62
|
+
# await_initialized
|
63
|
+
elsif @delay_await_idle
|
64
|
+
log 'Retrying synchronization'
|
65
|
+
await_idle
|
66
|
+
end
|
67
|
+
ensure
|
68
|
+
@catching_up = false
|
69
|
+
end
|
44
70
|
end
|
45
71
|
|
46
72
|
def idle?
|
@@ -72,31 +98,34 @@ module Capybara
|
|
72
98
|
|
73
99
|
private
|
74
100
|
|
101
|
+
def browser_made_full_page_load?
|
102
|
+
# Page change without visit()
|
103
|
+
page.has_css?('body[data-hydrating]')
|
104
|
+
end
|
105
|
+
|
75
106
|
def initialize_reason
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
}
|
107
|
+
execute_script(<<~JS)
|
108
|
+
if (location.href.indexOf('data:') == 0) {
|
109
|
+
return 'Requesting initial page'
|
110
|
+
}
|
81
111
|
|
82
|
-
|
83
|
-
|
84
|
-
|
112
|
+
if (document.readyState !== "complete") {
|
113
|
+
return 'Document is loading'
|
114
|
+
}
|
85
115
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
116
|
+
// The application layouts render a <body data-initializing>.
|
117
|
+
// The [data-initializing] attribute is removed by an Angular directive or Unpoly compiler (frontend).
|
118
|
+
// to signal that all elements have been activated.
|
119
|
+
if (document.querySelector('body[data-initializing]')) {
|
120
|
+
return 'DOM is being hydrated'
|
121
|
+
}
|
92
122
|
|
93
|
-
|
94
|
-
|
95
|
-
|
123
|
+
if (window.CapybaraLockstep && CapybaraLockstep.isBusy()) {
|
124
|
+
return 'JavaScript or AJAX requests are running'
|
125
|
+
}
|
96
126
|
|
97
|
-
|
98
|
-
|
99
|
-
end
|
127
|
+
return false
|
128
|
+
JS
|
100
129
|
end
|
101
130
|
|
102
131
|
def page
|
@@ -105,12 +134,6 @@ module Capybara
|
|
105
134
|
|
106
135
|
delegate :evaluate_script, :evaluate_async_script, :execute_script, :driver, to: :page
|
107
136
|
|
108
|
-
def ignoring_alerts(&block)
|
109
|
-
block.call
|
110
|
-
rescue ::Selenium::WebDriver::Error::UnexpectedAlertOpenError
|
111
|
-
# noop
|
112
|
-
end
|
113
|
-
|
114
137
|
def with_max_wait_time(seconds, &block)
|
115
138
|
old_max_wait_time = Capybara.default_max_wait_time
|
116
139
|
Capybara.default_max_wait_time = seconds
|