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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 495d3ed978e831569eb691423ab97e79b4a354e415ce7247c7fba01916bce60a
4
- data.tar.gz: bb51f4acfbd6cbe7b19f3e326d7e8d771004babe1ed415ca9f283c1301822ac9
3
+ metadata.gz: 514789431b5b017176575acd43c1a5b6558040f31cf7cb4ac119cf10e756dbee
4
+ data.tar.gz: 2945ac3b32b7f83a7bc2bd14848f67950c12e5063033d8dbe2063788dfe8c024
5
5
  SHA512:
6
- metadata.gz: aeb726459feb3f529e02bc8cc5d8c8cd5afe2377d7906ff5e78485137770ad851cfa7e9a175a3f9ff59bbf2deb4a8fc0d14a06af584928e552a8d25bba3ddc43
7
- data.tar.gz: 8f6955613d8a1073dcfeb26d003a22c0694462bdbab917ae66f31b11bbca2af36d5164394e4eafd18157b57d5684d7c9ae2afce4c0693230f91aca7c532d8528
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capybara-lockstep (2.0.2)
4
+ capybara-lockstep (2.1.0)
5
5
  activesupport (>= 4.2)
6
6
  capybara (>= 3.0)
7
7
  ruby2_keywords
data/README.md CHANGED
@@ -349,7 +349,23 @@ ensure
349
349
  end
350
350
  ```
351
351
 
352
- In the `:manual` mode you may still force synchronization by calling `Capybara::Lockstep.synchronize` manually.
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 // default is 1
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.
@@ -58,7 +58,7 @@ module Capybara
58
58
  self.mode = temporary_mode
59
59
  block.call
60
60
  ensure
61
- self.mode = temporary_mode
61
+ self.mode = old_mode
62
62
  end
63
63
 
64
64
  def enabled=(enabled)
@@ -4,14 +4,14 @@ window.CapybaraLockstep = (function() {
4
4
  let jobCount
5
5
  let idleCallbacks
6
6
  let finishedWorkTags
7
- let waitTasks
7
+ let defaultWaitTasks
8
8
  reset()
9
9
 
10
10
  function reset() {
11
11
  jobCount = 0
12
12
  idleCallbacks = []
13
13
  finishedWorkTags = []
14
- waitTasks = 1
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
- afterWaitTasks(stopWorkNow.bind(this, tag))
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 || waitTasks > 0) {
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, tasksLeft = waitTasks) {
259
- if (tasksLeft > 0) {
260
- afterWaitTasks(fn, tasksLeft - 1)
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 trackInteraction(eventType) {
283
- document.addEventListener(eventType, function() {
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
- if (waitTasks > 0) {
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
- trackInteraction('touchstart')
301
- trackInteraction('mousedown')
302
- trackInteraction('click')
303
- trackInteraction('keydown')
304
- trackInteraction('focusin')
305
- trackInteraction('focusout')
306
- trackInteraction('input')
307
- trackInteraction('change')
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) { 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
- JS = IO.read(JS_PATH)
6
+ HELPER_JS = IO.read(JS_PATH)
7
7
 
8
- def capybara_lockstep_js
9
- JS
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
- js = capybara_lockstep_js + capybara_lockstep_config_js(options)
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
 
@@ -1,5 +1,5 @@
1
1
  module Capybara
2
2
  module Lockstep
3
- VERSION = "2.0.2"
3
+ VERSION = "2.1.0"
4
4
  end
5
5
  end
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.2
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: 2023-12-22 00:00:00.000000000 Z
11
+ date: 2024-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara