capybara-lockstep 2.0.2 → 2.1.0
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 +15 -0
- data/Gemfile.lock +1 -1
- data/README.md +20 -2
- data/lib/capybara-lockstep/configuration.rb +1 -1
- data/lib/capybara-lockstep/helper.js +50 -21
- data/lib/capybara-lockstep/helper.rb +6 -5
- data/lib/capybara-lockstep/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 514789431b5b017176575acd43c1a5b6558040f31cf7cb4ac119cf10e756dbee
|
4
|
+
data.tar.gz: 2945ac3b32b7f83a7bc2bd14848f67950c12e5063033d8dbe2063788dfe8c024
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2dac0508c3caaa13fd28fe285c9c3b7d2b796dfba6c2bf788578ffee90135b6504a2e9b731d8bf4496806723d26c28bf5ccb536e5de21c2b5661b354a9e2de1
|
7
|
+
data.tar.gz: 4e80b685b588dfded10cb0783cbe62aceb00517199ef5527ce76fb76a234c96eb913ec0e7d08df2e22a7dd5a2b2d475bed0d4318add6ddee9fd27403afc2e0fe
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,21 @@ 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
|
+
|
14
|
+
# 2.0.3
|
15
|
+
|
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.
|
17
|
+
- Fix a bug where the `Capybara::Lockstep.wait_tasks` configuration would be ignored.
|
18
|
+
- Fix a bug where the `capybara_lockstep_js` helper (for use without Rails) would not include the current configuration.
|
19
|
+
|
20
|
+
|
6
21
|
# 2.0.2
|
7
22
|
|
8
23
|
- Fix a bug where setting a logger object with `Capybara::Lockstep.debug = logger` would crash (by @dorianmarie).
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -349,7 +349,23 @@ ensure
|
|
349
349
|
end
|
350
350
|
```
|
351
351
|
|
352
|
-
|
352
|
+
You can also disable automatic synchronization for the duration of a block:
|
353
|
+
|
354
|
+
```ruby
|
355
|
+
Capybara::Lockstep.with_mode(:manual) do
|
356
|
+
do_unsynchronized_work
|
357
|
+
end
|
358
|
+
```
|
359
|
+
|
360
|
+
In the `:manual` mode you may still force synchronization by calling `Capybara::Lockstep.synchronize` manually:
|
361
|
+
|
362
|
+
```ruby
|
363
|
+
Capybara::Lockstep.with_mode(:manual) do
|
364
|
+
do_some_work
|
365
|
+
Capybara::Lockstep.synchronize
|
366
|
+
do_other_work
|
367
|
+
end
|
368
|
+
```
|
353
369
|
|
354
370
|
To completely disable synchronization, even when `Capybara::Lockstep.synchronize` is called:
|
355
371
|
|
@@ -360,6 +376,8 @@ Capybara::Lockstep.synchronize # will not synchronize
|
|
360
376
|
|
361
377
|
|
362
378
|
|
379
|
+
|
380
|
+
|
363
381
|
## Handling legacy promises
|
364
382
|
|
365
383
|
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.
|
@@ -377,7 +395,7 @@ It is theoretically possible that your test will observe the browser in that win
|
|
377
395
|
Any issues caused by this will usually be mitigated by Capybara's retry logic. **If** you think that this is an issue for your test suite, you can configure capybara-headless to wait additional tasks before it considers the browser to be idle:
|
378
396
|
|
379
397
|
```ruby
|
380
|
-
Capybara::Lockstep.wait_tasks = 2
|
398
|
+
Capybara::Lockstep.wait_tasks = 2 # default is 1
|
381
399
|
```
|
382
400
|
|
383
401
|
If you see longer chains of `then()` or nested `setTimeout()` calls in your code, you may need to configure a higher number of tasks to wait.
|
@@ -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,9 +277,12 @@ window.CapybaraLockstep = (function() {
|
|
255
277
|
}
|
256
278
|
}
|
257
279
|
|
258
|
-
function afterWaitTasks(fn,
|
259
|
-
if (
|
260
|
-
|
280
|
+
function afterWaitTasks(fn, waitTasks = defaultWaitTasks) {
|
281
|
+
if (waitTasks > 0) {
|
282
|
+
// Wait 1 task and recurse
|
283
|
+
setTimeout(function() {
|
284
|
+
afterWaitTasks(fn, waitTasks - 1)
|
285
|
+
})
|
261
286
|
} else {
|
262
287
|
fn()
|
263
288
|
}
|
@@ -279,14 +304,16 @@ window.CapybaraLockstep = (function() {
|
|
279
304
|
})
|
280
305
|
}
|
281
306
|
|
282
|
-
function
|
283
|
-
|
307
|
+
function trackEvent(eventTarget, eventType, waitAdditionalTasks = 0) {
|
308
|
+
eventTarget.addEventListener(eventType, function() {
|
284
309
|
// Only litter the log with interaction events if we're actually going
|
285
310
|
// to be busy for at least 1 task.
|
286
|
-
|
311
|
+
let effectiveWaitTasks = defaultWaitTasks + waitAdditionalTasks
|
312
|
+
|
313
|
+
if (effectiveWaitTasks > 0) {
|
287
314
|
let tag = eventType
|
288
315
|
startWork(tag)
|
289
|
-
stopWork(tag)
|
316
|
+
stopWork(tag, waitAdditionalTasks)
|
290
317
|
}
|
291
318
|
})
|
292
319
|
}
|
@@ -294,17 +321,19 @@ window.CapybaraLockstep = (function() {
|
|
294
321
|
function track() {
|
295
322
|
trackOldUnpoly()
|
296
323
|
trackFetch()
|
324
|
+
trackHistory()
|
297
325
|
trackXHR()
|
298
326
|
trackRemoteElements()
|
299
327
|
trackJQuery()
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
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)
|
308
337
|
}
|
309
338
|
|
310
339
|
function synchronize(callback) {
|
@@ -324,7 +353,7 @@ window.CapybaraLockstep = (function() {
|
|
324
353
|
synchronize: synchronize,
|
325
354
|
reset: reset,
|
326
355
|
set debug(value) { debug = value },
|
327
|
-
set waitTasks(value) {
|
356
|
+
set waitTasks(value) { defaultWaitTasks = value }
|
328
357
|
}
|
329
358
|
})()
|
330
359
|
|
@@ -3,10 +3,10 @@ module Capybara
|
|
3
3
|
module Helper
|
4
4
|
|
5
5
|
JS_PATH = File.expand_path('../helper.js', __FILE__)
|
6
|
-
|
6
|
+
HELPER_JS = IO.read(JS_PATH)
|
7
7
|
|
8
|
-
def capybara_lockstep_js
|
9
|
-
|
8
|
+
def capybara_lockstep_js(options = {})
|
9
|
+
HELPER_JS + capybara_lockstep_config_js(options)
|
10
10
|
end
|
11
11
|
|
12
12
|
def capybara_lockstep(options = {})
|
@@ -17,10 +17,11 @@ module Capybara
|
|
17
17
|
tag_options[:nonce] = options.fetch(:nonce, true)
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
javascript_tag(js, tag_options)
|
20
|
+
javascript_tag(capybara_lockstep_js(options), tag_options)
|
22
21
|
end
|
23
22
|
|
23
|
+
private
|
24
|
+
|
24
25
|
def capybara_lockstep_config_js(options = {})
|
25
26
|
js = ''
|
26
27
|
|
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.0
|
4
|
+
version: 2.1.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:
|
11
|
+
date: 2024-01-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|