capybara-lockstep 2.1.0 → 2.2.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 +3 -3
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/README.md +18 -1
- data/capybara-lockstep.gemspec +1 -1
- data/lib/capybara-lockstep/helper.js +39 -30
- 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: fa4a510d3f4745ef60812fdf3ab03f6c3e8ede0c6ea4046cb87364d6664e2a7d
|
4
|
+
data.tar.gz: 78be38bdb5aa4fcb9147394ac3adb11f3112c18539ba53a096c214931be753cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 356df47acf01a2642769be49f54c48736ea030c803a92b3c059c587e5e82bb927fa0b4e5dcf7953060162a46491cf0122c6a2d0debd1f607cbd1b09cc8608ff2
|
7
|
+
data.tar.gz: c5d1189ee309d32197f19765dad9014cc59f13a8d9f6a17287537045cbf02664b480ce9d087e933b3fad1a2c63b4460b5dc5e61e20d3e0b98d76cde9d90eaff3
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file.
|
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
4
4
|
|
5
5
|
|
6
|
+
# 2.2.0
|
7
|
+
|
8
|
+
- We now wait for `<video>` and `<audio>` elements to load their metadata. This addresses a race condition where a media element is inserted into the DOM, but another user action deletes or renames the source before the browser could load the initial metadata frames.
|
9
|
+
- We now wait for `<script type="module">`.
|
10
|
+
- We no longer wait for `<img loading="lazy">` or `<iframe loading="lazy">`. This prevents a deadlock where we would wait forever for an element that defers loading until it is scrolled into the viewport.
|
11
|
+
|
12
|
+
|
6
13
|
# 2.1.0
|
7
14
|
|
8
15
|
- We now synchronize for an additional [JavaScript task](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) after `history.pushState()`, `history.replaceState()`, `history.forward()`, `history.back()` and `history.go()`.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -71,7 +71,8 @@ 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
|
-
- waits for dynamically inserted `<img>` or `<iframe>` elements to load.
|
74
|
+
- waits 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
|
+
- waits for dynamically inserted `<audio>` and `<video>` elements to load their [metadata](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/loadedmetadata_event)
|
75
76
|
|
76
77
|
In summary Capybara can no longer observe or interact with the page while HTTP requests are in flight.
|
77
78
|
This covers most async work that causes flaky tests.
|
@@ -158,7 +159,23 @@ use Capybara::Lockstep::Middleware
|
|
158
159
|
# Other middleware here
|
159
160
|
```
|
160
161
|
|
162
|
+
### Configuring Selenium WebDriver (recommended)
|
161
163
|
|
164
|
+
By default, webdrivers will automatically dismiss any user prompts (like alerts) when trying to perform an action.
|
165
|
+
While capybara-lockstep carefully detects alerts before synchronizing, and will skip interaction with the browser to avoid accidentally dismissing alerts, it can not synchronize around some rare race conditions.
|
166
|
+
|
167
|
+
[We recommend](https://makandracards.com/makandra/617366-how-to-configure-selenium-webdriver-to-not-automatically-close-alerts-or-other-browser-dialogs) you configure your webdriver to not automatically dismiss user prompts by setting the "unhandled prompt behavior" capability to [`ignore`](https://w3c.github.io/webdriver/#dfn-known-prompt-handling-approaches-table). Using "ignore", errors are raised like with the default behavior, but user prompts are kept open.
|
168
|
+
|
169
|
+
For example, the Chrome driver can be configured like this:
|
170
|
+
```ruby
|
171
|
+
Capybara.register_driver(:selenium) do |app|
|
172
|
+
options = Selenium::WebDriver::Chrome::Options.new(
|
173
|
+
unhandled_prompt_behavior: 'ignore',
|
174
|
+
# ...
|
175
|
+
)
|
176
|
+
Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
|
177
|
+
end
|
178
|
+
```
|
162
179
|
|
163
180
|
### Verify successful integration
|
164
181
|
|
data/capybara-lockstep.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
|
|
15
15
|
spec.metadata["source_code_uri"] = spec.homepage
|
16
16
|
|
17
17
|
spec.metadata["bug_tracker_uri"] = "https://github.com/makandra/capybara-lockstep/issues"
|
18
|
-
spec.metadata["changelog_uri"] = "https://github.com/makandra/capybara-lockstep/blob/
|
18
|
+
spec.metadata["changelog_uri"] = "https://github.com/makandra/capybara-lockstep/blob/main/CHANGELOG.md"
|
19
19
|
spec.metadata["rubygems_mfa_required"] = 'true'
|
20
20
|
|
21
21
|
# Specify which files should be added to the gem when it is released.
|
@@ -177,39 +177,47 @@ window.CapybaraLockstep = (function() {
|
|
177
177
|
}
|
178
178
|
|
179
179
|
function isRemoteScript(element) {
|
180
|
-
|
181
|
-
|
182
|
-
let type = element.getAttribute('type')
|
180
|
+
return element.matches('script[src]') && !hasDataSource(element)
|
181
|
+
}
|
183
182
|
|
184
|
-
|
185
|
-
|
183
|
+
function isTrackableImage(element) {
|
184
|
+
return element.matches('img') &&
|
185
|
+
!element.complete &&
|
186
|
+
!hasDataSource(element) &&
|
187
|
+
element.getAttribute('loading') !== 'lazy'
|
186
188
|
}
|
187
189
|
|
188
|
-
function
|
189
|
-
|
190
|
-
|
191
|
-
|
190
|
+
function isTrackableIFrame(element) {
|
191
|
+
return element.matches('iframe') &&
|
192
|
+
!hasDataSource(element) &&
|
193
|
+
element.getAttribute('loading') !== 'lazy'
|
194
|
+
}
|
195
|
+
|
196
|
+
function hasDataSource(element) {
|
197
|
+
// <img> can have <img src> and <img srcset>
|
198
|
+
// <video> can have <video src> or <video><source src>
|
199
|
+
// <audio> can have <audio src> or <audio><source src>
|
200
|
+
return element.matches('[src*="data:"], [srcset*="data:"]') ||
|
201
|
+
!!element.querySelector('source [src*="data:"], source [srcset*="data:"]')
|
202
|
+
}
|
192
203
|
|
193
|
-
|
194
|
-
|
204
|
+
function isTrackableMediaElement(element) {
|
205
|
+
return element.matches('audio, video') &&
|
206
|
+
element.readyState === 0 && // no metadata known
|
207
|
+
!hasDataSource(element) &&
|
208
|
+
element.getAttribute('preload') !== 'none'
|
209
|
+
}
|
195
210
|
|
196
|
-
|
197
|
-
|
211
|
+
function trackRemoteElement(element, condition, workTag) {
|
212
|
+
trackLoadingElement(element, condition, workTag, 'load', 'error')
|
198
213
|
|
199
|
-
return (src && !hasLocalSrc) || (srcSet && !hasLocalSrcSet)
|
200
|
-
}
|
201
214
|
}
|
202
215
|
|
203
|
-
function
|
204
|
-
|
205
|
-
let src = element.getAttribute('src')
|
206
|
-
let localSrcPattern = /^data:/
|
207
|
-
let hasLocalSrc = src && localSrcPattern.test(src)
|
208
|
-
return (src && !hasLocalSrc)
|
209
|
-
}
|
216
|
+
function trackMediaElement(element, condition, workTag) {
|
217
|
+
trackLoadingElement(element, condition, workTag, 'loadedmetadata', 'error')
|
210
218
|
}
|
211
219
|
|
212
|
-
function
|
220
|
+
function trackLoadingElement(element, condition, workTag, loadEvent, errorEvent) {
|
213
221
|
if (!condition(element)) {
|
214
222
|
return
|
215
223
|
}
|
@@ -220,8 +228,8 @@ window.CapybaraLockstep = (function() {
|
|
220
228
|
|
221
229
|
let doStop = function() {
|
222
230
|
stopped = true
|
223
|
-
element.removeEventListener(
|
224
|
-
element.removeEventListener(
|
231
|
+
element.removeEventListener(loadEvent, doStop)
|
232
|
+
element.removeEventListener(errorEvent, doStop)
|
225
233
|
stopWork(workTag)
|
226
234
|
}
|
227
235
|
|
@@ -240,11 +248,11 @@ window.CapybaraLockstep = (function() {
|
|
240
248
|
}
|
241
249
|
|
242
250
|
let scheduleCheckCondition = function() {
|
243
|
-
setTimeout(checkCondition,
|
251
|
+
setTimeout(checkCondition, 150)
|
244
252
|
}
|
245
253
|
|
246
|
-
element.addEventListener(
|
247
|
-
element.addEventListener(
|
254
|
+
element.addEventListener(loadEvent, doStop)
|
255
|
+
element.addEventListener(errorEvent, doStop)
|
248
256
|
|
249
257
|
// We periodically check whether we still think the element will
|
250
258
|
// produce a `load` or `error` event.
|
@@ -256,8 +264,9 @@ window.CapybaraLockstep = (function() {
|
|
256
264
|
change.addedNodes.forEach(function(addedNode) {
|
257
265
|
if (addedNode.nodeType === Node.ELEMENT_NODE) {
|
258
266
|
trackRemoteElement(addedNode, isRemoteScript, 'Script')
|
259
|
-
trackRemoteElement(addedNode,
|
260
|
-
trackRemoteElement(addedNode,
|
267
|
+
trackRemoteElement(addedNode, isTrackableImage, 'Image')
|
268
|
+
trackRemoteElement(addedNode, isTrackableIFrame, 'Inline frame')
|
269
|
+
trackMediaElement(addedNode, isTrackableMediaElement, 'Media element')
|
261
270
|
}
|
262
271
|
})
|
263
272
|
})
|
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.
|
4
|
+
version: 2.2.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: 2024-
|
11
|
+
date: 2024-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
@@ -107,7 +107,7 @@ metadata:
|
|
107
107
|
homepage_uri: https://github.com/makandra/capybara-lockstep
|
108
108
|
source_code_uri: https://github.com/makandra/capybara-lockstep
|
109
109
|
bug_tracker_uri: https://github.com/makandra/capybara-lockstep/issues
|
110
|
-
changelog_uri: https://github.com/makandra/capybara-lockstep/blob/
|
110
|
+
changelog_uri: https://github.com/makandra/capybara-lockstep/blob/main/CHANGELOG.md
|
111
111
|
rubygems_mfa_required: 'true'
|
112
112
|
post_install_message:
|
113
113
|
rdoc_options: []
|