capybara-lockstep 2.0.3 → 2.1.1
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/CHANGELOG.md +9 -1
- data/Gemfile.lock +2 -2
- data/README.md +35 -1
- data/lib/capybara-lockstep/configuration.rb +1 -1
- data/lib/capybara-lockstep/helper.js +47 -21
- data/lib/capybara-lockstep/version.rb +1 -1
- metadata +3 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 92432e49d223c6a01c09cbe199fec3d3ad0fdc80c5eb5def77883e25f5bace80
|
|
4
|
+
data.tar.gz: 43fcb6f560accb02c5a6081506a6d1b65c571ab149b0d470efeddf49adb853b9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ef3cb7e6d8789b1108602ad7d18ba7e00bf52e93135d8ebec84d9307c556f800f05218d4b23a750d66888e99f9f2939c37f76d3fd3359cdf765b5799b2a3e182
|
|
7
|
+
data.tar.gz: d2017577968548a815e9e60c9d1fa5838ab3c16fcbb1122acdaf9185e2c44c36766cca61a53de6c016ed691b4d558ae4fab282ed34cd18aa5348a8db64f527ad
|
data/CHANGELOG.md
CHANGED
|
@@ -3,9 +3,17 @@ 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.1.0
|
|
7
|
+
|
|
8
|
+
- 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()`.
|
|
9
|
+
- We now synchronize for an additional JavaScript task after `popstate` and `hashchange` events.
|
|
10
|
+
- We now synchronize for an additional JavaScript task when the window is resized.
|
|
11
|
+
- You can now disable automatic synchronization for the duration of a block: `Capybara::Lockstep.with_mode(:manual) { ... }`.
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
# 2.0.3
|
|
7
15
|
|
|
8
|
-
- Fix a bug where we wouldn't wait for an additional JavaScript task after a tracked event or async job.
|
|
16
|
+
- Fix a bug where we wouldn't wait for an additional [JavaScript task](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) after a tracked event or async job.
|
|
9
17
|
- Fix a bug where the `Capybara::Lockstep.wait_tasks` configuration would be ignored.
|
|
10
18
|
- Fix a bug where the `capybara_lockstep_js` helper (for use without Rails) would not include the current configuration.
|
|
11
19
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -158,7 +158,23 @@ use Capybara::Lockstep::Middleware
|
|
|
158
158
|
# Other middleware here
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
+
### Configuring Selenium WebDriver (recommended)
|
|
161
162
|
|
|
163
|
+
By default, webdrivers will automatically dismiss any user prompts (like alerts) when trying to perform an action.
|
|
164
|
+
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.
|
|
165
|
+
|
|
166
|
+
[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.
|
|
167
|
+
|
|
168
|
+
For example, the Chrome driver can be configured like this:
|
|
169
|
+
```ruby
|
|
170
|
+
Capybara.register_driver(:selenium) do |app|
|
|
171
|
+
options = Selenium::WebDriver::Chrome::Options.new(
|
|
172
|
+
unhandled_prompt_behavior: 'ignore',
|
|
173
|
+
# ...
|
|
174
|
+
)
|
|
175
|
+
Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
|
|
176
|
+
end
|
|
177
|
+
```
|
|
162
178
|
|
|
163
179
|
### Verify successful integration
|
|
164
180
|
|
|
@@ -349,7 +365,23 @@ ensure
|
|
|
349
365
|
end
|
|
350
366
|
```
|
|
351
367
|
|
|
352
|
-
|
|
368
|
+
You can also disable automatic synchronization for the duration of a block:
|
|
369
|
+
|
|
370
|
+
```ruby
|
|
371
|
+
Capybara::Lockstep.with_mode(:manual) do
|
|
372
|
+
do_unsynchronized_work
|
|
373
|
+
end
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
In the `:manual` mode you may still force synchronization by calling `Capybara::Lockstep.synchronize` manually:
|
|
377
|
+
|
|
378
|
+
```ruby
|
|
379
|
+
Capybara::Lockstep.with_mode(:manual) do
|
|
380
|
+
do_some_work
|
|
381
|
+
Capybara::Lockstep.synchronize
|
|
382
|
+
do_other_work
|
|
383
|
+
end
|
|
384
|
+
```
|
|
353
385
|
|
|
354
386
|
To completely disable synchronization, even when `Capybara::Lockstep.synchronize` is called:
|
|
355
387
|
|
|
@@ -360,6 +392,8 @@ Capybara::Lockstep.synchronize # will not synchronize
|
|
|
360
392
|
|
|
361
393
|
|
|
362
394
|
|
|
395
|
+
|
|
396
|
+
|
|
363
397
|
## Handling legacy promises
|
|
364
398
|
|
|
365
399
|
Legacy promise implementations (like jQuery's `$.Deferred` and AngularJS' `$q`) work using [tasks instead of microtasks](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/). Their AJAX implementations (like `$.ajax()` and `$http`) use task-based promises to signal that a request is done.
|
|
@@ -4,14 +4,14 @@ window.CapybaraLockstep = (function() {
|
|
|
4
4
|
let jobCount
|
|
5
5
|
let idleCallbacks
|
|
6
6
|
let finishedWorkTags
|
|
7
|
-
let
|
|
7
|
+
let defaultWaitTasks
|
|
8
8
|
reset()
|
|
9
9
|
|
|
10
10
|
function reset() {
|
|
11
11
|
jobCount = 0
|
|
12
12
|
idleCallbacks = []
|
|
13
13
|
finishedWorkTags = []
|
|
14
|
-
|
|
14
|
+
defaultWaitTasks = 1
|
|
15
15
|
debug = false
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -57,8 +57,9 @@ window.CapybaraLockstep = (function() {
|
|
|
57
57
|
promise.then(taggedStopWork, taggedStopWork)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
function stopWork(tag) {
|
|
61
|
-
|
|
60
|
+
function stopWork(tag, waitAdditionalTasks = 0) {
|
|
61
|
+
let effectiveWaitTasks = defaultWaitTasks + waitAdditionalTasks
|
|
62
|
+
afterWaitTasks(stopWorkNow.bind(this, tag), effectiveWaitTasks)
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
function stopWorkNow(tag) {
|
|
@@ -92,6 +93,27 @@ window.CapybaraLockstep = (function() {
|
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
function trackHistory() {
|
|
97
|
+
// Wait an additional task because some browsers seem to require additional
|
|
98
|
+
// time before the URL changes.
|
|
99
|
+
trackEvent(document, 'popstate', 1)
|
|
100
|
+
trackEvent(document, 'hashchange', 1)
|
|
101
|
+
|
|
102
|
+
// API: https://developer.mozilla.org/en-US/docs/Web/API/History
|
|
103
|
+
for (let method of ['pushState', 'popState', 'forward', 'back', 'go']) {
|
|
104
|
+
let workTag = `history.${method}()`
|
|
105
|
+
let nativeImpl = history[method]
|
|
106
|
+
history[method] = function(...args) {
|
|
107
|
+
try {
|
|
108
|
+
startWork(workTag)
|
|
109
|
+
return nativeImpl.apply(history, args)
|
|
110
|
+
} finally {
|
|
111
|
+
stopWork(workTag, 1)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
95
117
|
function trackXHR() {
|
|
96
118
|
let oldOpen = XMLHttpRequest.prototype.open
|
|
97
119
|
let oldSend = XMLHttpRequest.prototype.send
|
|
@@ -135,7 +157,7 @@ window.CapybaraLockstep = (function() {
|
|
|
135
157
|
// CapybaraLockstep.track() is called as the first script in the head.
|
|
136
158
|
// jQuery will be loaded after us, so we wait until DOMContentReady.
|
|
137
159
|
whenReady(function() {
|
|
138
|
-
if (!window.jQuery ||
|
|
160
|
+
if (!window.jQuery || defaultWaitTasks > 0) {
|
|
139
161
|
return
|
|
140
162
|
}
|
|
141
163
|
|
|
@@ -255,11 +277,11 @@ window.CapybaraLockstep = (function() {
|
|
|
255
277
|
}
|
|
256
278
|
}
|
|
257
279
|
|
|
258
|
-
function afterWaitTasks(fn,
|
|
259
|
-
if (
|
|
280
|
+
function afterWaitTasks(fn, waitTasks = defaultWaitTasks) {
|
|
281
|
+
if (waitTasks > 0) {
|
|
260
282
|
// Wait 1 task and recurse
|
|
261
283
|
setTimeout(function() {
|
|
262
|
-
afterWaitTasks(fn,
|
|
284
|
+
afterWaitTasks(fn, waitTasks - 1)
|
|
263
285
|
})
|
|
264
286
|
} else {
|
|
265
287
|
fn()
|
|
@@ -282,14 +304,16 @@ window.CapybaraLockstep = (function() {
|
|
|
282
304
|
})
|
|
283
305
|
}
|
|
284
306
|
|
|
285
|
-
function
|
|
286
|
-
|
|
307
|
+
function trackEvent(eventTarget, eventType, waitAdditionalTasks = 0) {
|
|
308
|
+
eventTarget.addEventListener(eventType, function() {
|
|
287
309
|
// Only litter the log with interaction events if we're actually going
|
|
288
310
|
// to be busy for at least 1 task.
|
|
289
|
-
|
|
311
|
+
let effectiveWaitTasks = defaultWaitTasks + waitAdditionalTasks
|
|
312
|
+
|
|
313
|
+
if (effectiveWaitTasks > 0) {
|
|
290
314
|
let tag = eventType
|
|
291
315
|
startWork(tag)
|
|
292
|
-
stopWork(tag)
|
|
316
|
+
stopWork(tag, waitAdditionalTasks)
|
|
293
317
|
}
|
|
294
318
|
})
|
|
295
319
|
}
|
|
@@ -297,17 +321,19 @@ window.CapybaraLockstep = (function() {
|
|
|
297
321
|
function track() {
|
|
298
322
|
trackOldUnpoly()
|
|
299
323
|
trackFetch()
|
|
324
|
+
trackHistory()
|
|
300
325
|
trackXHR()
|
|
301
326
|
trackRemoteElements()
|
|
302
327
|
trackJQuery()
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
328
|
+
trackEvent(document, 'touchstart')
|
|
329
|
+
trackEvent(document, 'mousedown')
|
|
330
|
+
trackEvent(document, 'click')
|
|
331
|
+
trackEvent(document, 'keydown')
|
|
332
|
+
trackEvent(document, 'focusin')
|
|
333
|
+
trackEvent(document, 'focusout')
|
|
334
|
+
trackEvent(document, 'input')
|
|
335
|
+
trackEvent(document, 'change')
|
|
336
|
+
trackEvent(window, 'resize', 1)
|
|
311
337
|
}
|
|
312
338
|
|
|
313
339
|
function synchronize(callback) {
|
|
@@ -327,7 +353,7 @@ window.CapybaraLockstep = (function() {
|
|
|
327
353
|
synchronize: synchronize,
|
|
328
354
|
reset: reset,
|
|
329
355
|
set debug(value) { debug = value },
|
|
330
|
-
set waitTasks(value) {
|
|
356
|
+
set waitTasks(value) { defaultWaitTasks = value }
|
|
331
357
|
}
|
|
332
358
|
})()
|
|
333
359
|
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: capybara-lockstep
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Henning Koch
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: capybara
|
|
@@ -66,7 +65,6 @@ dependencies:
|
|
|
66
65
|
- - ">="
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
67
|
version: '0'
|
|
69
|
-
description:
|
|
70
68
|
email:
|
|
71
69
|
- henning.koch@makandra.de
|
|
72
70
|
executables: []
|
|
@@ -109,7 +107,6 @@ metadata:
|
|
|
109
107
|
bug_tracker_uri: https://github.com/makandra/capybara-lockstep/issues
|
|
110
108
|
changelog_uri: https://github.com/makandra/capybara-lockstep/blob/master/CHANGELOG.md
|
|
111
109
|
rubygems_mfa_required: 'true'
|
|
112
|
-
post_install_message:
|
|
113
110
|
rdoc_options: []
|
|
114
111
|
require_paths:
|
|
115
112
|
- lib
|
|
@@ -124,8 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
124
121
|
- !ruby/object:Gem::Version
|
|
125
122
|
version: '0'
|
|
126
123
|
requirements: []
|
|
127
|
-
rubygems_version:
|
|
128
|
-
signing_key:
|
|
124
|
+
rubygems_version: 4.0.15
|
|
129
125
|
specification_version: 4
|
|
130
126
|
summary: Synchronize Capybara commands with client-side JavaScript and AJAX requests
|
|
131
127
|
test_files: []
|