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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc0373be228e0d19b35174656617d256a469fb1f652728eaa031b91a9370aa38
4
- data.tar.gz: 45a3b441340e1cf477564f47af7961799ac0cf37e533a42393c89a08744f1657
3
+ metadata.gz: 92432e49d223c6a01c09cbe199fec3d3ad0fdc80c5eb5def77883e25f5bace80
4
+ data.tar.gz: 43fcb6f560accb02c5a6081506a6d1b65c571ab149b0d470efeddf49adb853b9
5
5
  SHA512:
6
- metadata.gz: b3c3f17a3a6b1e32b43ee86106294b9351bc312234070f4308e93dce8dfeae4198831f04c50e20ca37fc533ecbf1f77b51fe11e24c1336f2866018380052e07a
7
- data.tar.gz: 64b39c510daba699db4c0204caa5004e8d367c3e6208a9b2d0a7912925e4dd7c5223e3caf516633310c7f41dbf524af0520715c5051c1d0ead3f8494a0bb0a75
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capybara-lockstep (2.0.3)
4
+ capybara-lockstep (2.1.1)
5
5
  activesupport (>= 4.2)
6
6
  capybara (>= 3.0)
7
7
  ruby2_keywords
@@ -113,4 +113,4 @@ DEPENDENCIES
113
113
  thin
114
114
 
115
115
  BUNDLED WITH
116
- 2.2.32
116
+ 4.0.15
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
- In the `:manual` mode you may still force synchronization by calling `Capybara::Lockstep.synchronize` manually.
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.
@@ -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,11 +277,11 @@ window.CapybaraLockstep = (function() {
255
277
  }
256
278
  }
257
279
 
258
- function afterWaitTasks(fn, tasksLeft = waitTasks) {
259
- if (tasksLeft > 0) {
280
+ function afterWaitTasks(fn, waitTasks = defaultWaitTasks) {
281
+ if (waitTasks > 0) {
260
282
  // Wait 1 task and recurse
261
283
  setTimeout(function() {
262
- afterWaitTasks(fn, tasksLeft - 1)
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 trackInteraction(eventType) {
286
- document.addEventListener(eventType, function() {
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
- if (waitTasks > 0) {
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
- trackInteraction('touchstart')
304
- trackInteraction('mousedown')
305
- trackInteraction('click')
306
- trackInteraction('keydown')
307
- trackInteraction('focusin')
308
- trackInteraction('focusout')
309
- trackInteraction('input')
310
- 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)
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) { waitTasks = value }
356
+ set waitTasks(value) { defaultWaitTasks = value }
331
357
  }
332
358
  })()
333
359
 
@@ -1,5 +1,5 @@
1
1
  module Capybara
2
2
  module Lockstep
3
- VERSION = "2.0.3"
3
+ VERSION = "2.1.1"
4
4
  end
5
5
  end
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.0.3
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: 2024-01-08 00:00:00.000000000 Z
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: 3.4.3
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: []