capybara-lockstep 2.2.0 → 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +15 -15
- data/README.md +12 -12
- data/lib/capybara-lockstep/capybara_ext.rb +29 -22
- data/lib/capybara-lockstep/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8bad1a61632d37c5e705b886be4cb840a62923f73887c1443060fb00c6e69aa2
|
4
|
+
data.tar.gz: 9243b559659a33a00e6f803304284aa9cd47e5c2f110a11b47eb2e4e62441537
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b285d685609f913c92b4b8d5556d34d7d77e2fb6d80e5fac4cda189c81a2b81445fc65a5680726c2d21b16d0bcdcb1fcb35e3a6169b2febca3244eaa555b985
|
7
|
+
data.tar.gz: d598437ffb3eaf066d6cbcb747ac6c5445bed0a2c2cbc5113f42e0d947d4b71fc7bb4752ede4193cca989acafd5d126757c67d3454fbfc226014d7b42056b55f
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file.
|
|
2
2
|
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
4
4
|
|
5
|
+
# 2.2.1
|
6
|
+
|
7
|
+
- Fixed a bug that disabled most functionality for drivers with `browser: :remote`.
|
8
|
+
|
5
9
|
|
6
10
|
# 2.2.0
|
7
11
|
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
capybara-lockstep (2.2.
|
4
|
+
capybara-lockstep (2.2.1)
|
5
5
|
activesupport (>= 4.2)
|
6
6
|
capybara (>= 3.0)
|
7
7
|
ruby2_keywords
|
@@ -31,7 +31,7 @@ GEM
|
|
31
31
|
childprocess (4.1.0)
|
32
32
|
concurrent-ruby (1.1.10)
|
33
33
|
daemons (1.4.1)
|
34
|
-
diff-lcs (1.
|
34
|
+
diff-lcs (1.5.1)
|
35
35
|
eventmachine (1.2.7)
|
36
36
|
gemika (0.8.1)
|
37
37
|
i18n (1.12.0)
|
@@ -58,21 +58,21 @@ GEM
|
|
58
58
|
rake (13.1.0)
|
59
59
|
regexp_parser (2.8.2)
|
60
60
|
rexml (3.2.5)
|
61
|
-
rspec (3.
|
62
|
-
rspec-core (~> 3.
|
63
|
-
rspec-expectations (~> 3.
|
64
|
-
rspec-mocks (~> 3.
|
65
|
-
rspec-core (3.
|
66
|
-
rspec-support (~> 3.
|
67
|
-
rspec-expectations (3.
|
61
|
+
rspec (3.13.0)
|
62
|
+
rspec-core (~> 3.13.0)
|
63
|
+
rspec-expectations (~> 3.13.0)
|
64
|
+
rspec-mocks (~> 3.13.0)
|
65
|
+
rspec-core (3.13.0)
|
66
|
+
rspec-support (~> 3.13.0)
|
67
|
+
rspec-expectations (3.13.1)
|
68
68
|
diff-lcs (>= 1.2.0, < 2.0)
|
69
|
-
rspec-support (~> 3.
|
70
|
-
rspec-mocks (3.
|
69
|
+
rspec-support (~> 3.13.0)
|
70
|
+
rspec-mocks (3.13.1)
|
71
71
|
diff-lcs (>= 1.2.0, < 2.0)
|
72
|
-
rspec-support (~> 3.
|
73
|
-
rspec-support (3.
|
74
|
-
rspec-wait (0.0.
|
75
|
-
rspec (>= 3
|
72
|
+
rspec-support (~> 3.13.0)
|
73
|
+
rspec-support (3.13.1)
|
74
|
+
rspec-wait (0.0.10)
|
75
|
+
rspec (>= 3.0)
|
76
76
|
ruby2_keywords (0.0.5)
|
77
77
|
rubyzip (2.3.2)
|
78
78
|
selenium-webdriver (4.1.0)
|
data/README.md
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
This Ruby gem synchronizes [Capybara](https://github.com/teamcapybara/capybara) commands with client-side JavaScript and AJAX requests. This greatly improves the stability of an end-to-end ("E2E") test suite, even if that suite has timing issues.
|
4
4
|
|
5
|
-
The next section
|
5
|
+
The next section explains why your test suite is flaky and how capybara-lockstep can help.\
|
6
6
|
If you don't care you may **skip to [installation instructions](#installation)**.
|
7
7
|
|
8
8
|
|
9
9
|
Why are tests flaky?
|
10
10
|
--------------------
|
11
11
|
|
12
|
-
A naively written E2E test will have [race conditions](https://makandracards.com/makandra/47336-fixing-flaky-integration-tests) between the test script and the controlled browser. How often these timing issues will
|
12
|
+
A naively written E2E test will have [race conditions](https://makandracards.com/makandra/47336-fixing-flaky-integration-tests) between the test script and the controlled browser. How often these timing issues will cause your tests to fail depends on luck and your machine's performance. You may not see these issues for years until a colleague runs your suite on their new laptop.
|
13
13
|
|
14
14
|
Here is a typical example for a test that will fail with unlucky timing:
|
15
15
|
|
@@ -26,10 +26,10 @@ end
|
|
26
26
|
|
27
27
|
This test has four timing issues that may cause it to fail:
|
28
28
|
|
29
|
-
1. We click on the *New tweet* button, but the
|
30
|
-
2. We start filling in the form, but it
|
29
|
+
1. We click on the *New tweet* button, but the JS event handler to open the tweet form hasn't been registered yet.
|
30
|
+
2. We start filling in the form, but it hasn't been loaded yet.
|
31
31
|
3. After sending the tweet we immediately navigate away, killing the form submission request that is still in flight. Hence the tweet will never appear in the next step.
|
32
|
-
4. We look for the new tweet, but the timeline
|
32
|
+
4. We look for the new tweet, but the timeline hasn't been loaded yet.
|
33
33
|
|
34
34
|
[Capybara will retry](https://github.com/teamcapybara/capybara#asynchronous-javascript-ajax-and-friends) individual commands or expectations when they fail.\
|
35
35
|
However, only issues **2** and **4** can be healed by retrying.
|
@@ -71,10 +71,10 @@ When capybara-lockstep synchronizes it will:
|
|
71
71
|
- wait for client-side JavaScript to render or hydrate DOM elements.
|
72
72
|
- wait for any pending AJAX requests to finish and their callbacks to be called.
|
73
73
|
- wait for dynamically inserted `<script>`s to load (e.g. from [dynamic imports](https://webpack.js.org/guides/code-splitting/#dynamic-imports) or Analytics snippets).
|
74
|
-
-
|
75
|
-
-
|
74
|
+
- wait for dynamically inserted `<img>` or `<iframe>` elements to load (ignoring [lazy-loaded](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#lazy) elements).
|
75
|
+
- wait for dynamically inserted `<audio>` and `<video>` elements to load their [metadata](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/loadedmetadata_event)
|
76
76
|
|
77
|
-
In summary Capybara can no longer observe or interact with the page while HTTP requests are in flight.
|
77
|
+
In summary, Capybara can no longer observe or interact with the page while HTTP requests are in flight.
|
78
78
|
This covers most async work that causes flaky tests.
|
79
79
|
|
80
80
|
|
@@ -84,7 +84,6 @@ Async work not synchronized by capybara-lockstep includes:
|
|
84
84
|
|
85
85
|
- Animations
|
86
86
|
- Websocket connections
|
87
|
-
- Media elements (`<video>`, `<audio>`)
|
88
87
|
- Service workers
|
89
88
|
- Work scheduled via `setTimeout()` or `setInterval()`.
|
90
89
|
|
@@ -100,13 +99,14 @@ Check if your application satisfies all requirements for capybara-lockstep:
|
|
100
99
|
|
101
100
|
- Capybara 2.0 or higher.
|
102
101
|
- Your Capybara driver must use [selenium-webdriver](https://rubygems.org/gems/selenium-webdriver/) 3.0 or higher. capybara-lockstep deactivates itself for any other driver.
|
102
|
+
There is a [fork](https://github.com/Skalar/capybara-lockstep/tree/playwright-driver) with support for [capybara-playwright-driver](https://github.com/YusukeIwaki/capybara-playwright-driver).
|
103
103
|
- 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.
|
104
104
|
- This gem was only tested with Rails, but there's no Rails dependency.
|
105
105
|
|
106
106
|
|
107
107
|
### Installing the Ruby gem
|
108
108
|
|
109
|
-
Assuming that you're using Rails
|
109
|
+
Assuming that you're using Rails, add this to your application's `Gemfile`:
|
110
110
|
|
111
111
|
```ruby
|
112
112
|
group :test do
|
@@ -142,9 +142,9 @@ Ideally the snippet should be included in the `<head>` before any other `<script
|
|
142
142
|
|
143
143
|
### Including the middleware (optional)
|
144
144
|
|
145
|
-
This gem provides
|
145
|
+
This gem provides Rack middleware to block Capybara while your Rails (or Rack) backend is busy.
|
146
146
|
|
147
|
-
Using the middleware is optional, as the [JavaScript snippet](#including-the-javascript-snippet-required) already for
|
147
|
+
Using the middleware is optional, as the [JavaScript snippet](#including-the-javascript-snippet-required) already waits for asynchronous work on the client. However, using the middleware covers some additional edge cases. For example, the middleware detects requests that were aborted on the frontend, but are still being processed by the backend.
|
148
148
|
|
149
149
|
To include the middleware in a Rails application, add the following line to `config/environments/test.rb`:
|
150
150
|
|
@@ -3,36 +3,46 @@ require 'ruby2_keywords'
|
|
3
3
|
module Capybara
|
4
4
|
module Lockstep
|
5
5
|
module SynchronizeMacros
|
6
|
+
def self.extended(by)
|
7
|
+
by.instance_eval do
|
8
|
+
prepend(@synchronize_before_module = Module.new)
|
9
|
+
prepend(@synchronize_after_module = Module.new)
|
10
|
+
prepend(@unsynchronize_after_module = Module.new)
|
11
|
+
end
|
12
|
+
end
|
6
13
|
|
7
14
|
def synchronize_before(meth, lazy:)
|
8
|
-
|
15
|
+
@synchronize_before_module.module_eval do
|
9
16
|
define_method meth do |*args, &block|
|
10
|
-
|
17
|
+
@synchronize_before_count ||= 0
|
18
|
+
@synchronize_before_count += 1
|
19
|
+
Lockstep.auto_synchronize(lazy: lazy, log: "Synchronizing before ##{meth}") if @synchronize_before_count == 1
|
11
20
|
super(*args, &block)
|
21
|
+
ensure
|
22
|
+
@synchronize_before_count -= 1
|
12
23
|
end
|
13
24
|
|
14
25
|
ruby2_keywords meth
|
15
26
|
end
|
16
|
-
|
17
|
-
prepend(mod)
|
18
27
|
end
|
19
28
|
|
20
29
|
def synchronize_after(meth)
|
21
|
-
|
30
|
+
@synchronize_after_module.module_eval do
|
22
31
|
define_method meth do |*args, &block|
|
32
|
+
@synchronize_after_count ||= 0
|
33
|
+
@synchronize_after_count += 1
|
23
34
|
super(*args, &block)
|
24
35
|
ensure
|
25
|
-
Lockstep.auto_synchronize
|
36
|
+
Lockstep.auto_synchronize(log: "Synchronizing after ##{meth}") if @synchronize_after_count == 1
|
37
|
+
@synchronize_after_count -= 1
|
26
38
|
end
|
27
39
|
|
28
40
|
ruby2_keywords meth
|
29
41
|
end
|
30
|
-
|
31
|
-
prepend(mod)
|
32
42
|
end
|
33
43
|
|
34
44
|
def unsynchronize_after(meth)
|
35
|
-
|
45
|
+
@unsynchronize_after_module.module_eval do
|
36
46
|
define_method meth do |*args, &block|
|
37
47
|
super(*args, &block)
|
38
48
|
ensure
|
@@ -41,10 +51,7 @@ module Capybara
|
|
41
51
|
|
42
52
|
ruby2_keywords meth
|
43
53
|
end
|
44
|
-
|
45
|
-
prepend(mod)
|
46
54
|
end
|
47
|
-
|
48
55
|
end
|
49
56
|
end
|
50
57
|
end
|
@@ -158,23 +165,23 @@ Capybara::Session.class_eval do
|
|
158
165
|
synchronize_around_script_method :evaluate_async_script
|
159
166
|
end
|
160
167
|
|
161
|
-
# Capybara 3
|
162
|
-
#
|
163
|
-
|
168
|
+
# In Capybara 3 there are the specialized classes for nodes for most browers.
|
169
|
+
# We need to patch relevant methods on all of these.
|
170
|
+
driver_specific_node_classes = [
|
164
171
|
(Capybara::Selenium::ChromeNode if defined?(Capybara::Selenium::ChromeNode)),
|
165
172
|
(Capybara::Selenium::FirefoxNode if defined?(Capybara::Selenium::FirefoxNode)),
|
166
173
|
(Capybara::Selenium::SafariNode if defined?(Capybara::Selenium::SafariNode)),
|
167
174
|
(Capybara::Selenium::EdgeNode if defined?(Capybara::Selenium::EdgeNode)),
|
168
175
|
(Capybara::Selenium::IENode if defined?(Capybara::Selenium::IENode)),
|
169
|
-
].compact
|
176
|
+
].compact.freeze
|
170
177
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
178
|
+
# For other browsers (like the :remote browser) we instead get a generic node class.
|
179
|
+
# This is also the case for Capybara 2.
|
180
|
+
generic_node_classes = [
|
181
|
+
Capybara::Selenium::Node,
|
182
|
+
].freeze
|
176
183
|
|
177
|
-
|
184
|
+
[*driver_specific_node_classes, *generic_node_classes].each do |node_class|
|
178
185
|
node_class.class_eval do
|
179
186
|
extend Capybara::Lockstep::SynchronizeMacros
|
180
187
|
|
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: 2.2.
|
4
|
+
version: 2.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henning Koch
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
126
|
requirements: []
|
127
|
-
rubygems_version: 3.4.
|
127
|
+
rubygems_version: 3.4.1
|
128
128
|
signing_key:
|
129
129
|
specification_version: 4
|
130
130
|
summary: Synchronize Capybara commands with client-side JavaScript and AJAX requests
|