capybara-lockstep 0.3.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0d733ed210e1ba465d9d612fcf461618ee91c88a71b09f9c0020271e4ac28ef
4
- data.tar.gz: 5f30713c033ebd57b30d37f27e545c2a4547f6d40cd013c15f4ebba50a1f3893
3
+ metadata.gz: 8335399770451283be7443be41f3f1e5c2b0401f16a64a7722fb6b39ec2f3143
4
+ data.tar.gz: 601249c76c50789b44199e734a64fb039cd3b77c1db3e9f9068b1e7dea188216
5
5
  SHA512:
6
- metadata.gz: d8fcf72c9736d98a80661f282527f0f53affb22b5aa2b537f7e7fbc4ea246ca2886e4f798343654c984321ca3d7dfec25043fa8e70d4341558a9073ea69911fe
7
- data.tar.gz: c1f5144ed73a92f33e6ac36a0838401efae44d26ec199857f0e85a99b07afcd780d558ee6f3e859ac393db11649d186c8d56f72ddd6c2629fcddd68c2af907c0
6
+ metadata.gz: 638b0671d9f919c85b972cb2af4df763932a8c00ab21cd8387e3b483fda43448bb3c28b434aa821c0c6e75d4c67d82acb1dad0788128a5b1761bae0ae45400d6
7
+ data.tar.gz: eed68edd632b78dea169e208162e4a041cfc1ed2a78c6593eebf55d27d2fe54d9161e1c65f21771cb66de2ef4e2e2ce92573569118e30e8a3148368ffaaafe53
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: Tests
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
8
+ branches:
9
+ - master
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-20.04
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ include:
17
+ - ruby: 2.6.6
18
+ gemfile: Gemfile
19
+ - ruby: 2.7.2
20
+ gemfile: Gemfile
21
+ - ruby: 3.0.1
22
+ gemfile: Gemfile
23
+ env:
24
+ BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
25
+ steps:
26
+ - uses: actions/checkout@v2
27
+ - name: Install ruby
28
+ uses: ruby/setup-ruby@v1
29
+ with:
30
+ ruby-version: "${{ matrix.ruby }}"
31
+ - name: Bundle
32
+ run: |
33
+ gem install bundler:2.2.15
34
+ bundle install --no-deployment
35
+ - name: Run tests
36
+ run: bundle exec rake spec
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ .idea
9
10
 
10
11
  # rspec failure tracking
11
12
  .rspec_status
data/CHANGELOG.md ADDED
@@ -0,0 +1,33 @@
1
+ All notable changes to this project will be documented in this file.
2
+
3
+ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
4
+
5
+
6
+ ## Unreleased
7
+
8
+ ### Breaking changes
9
+
10
+ -
11
+
12
+ ### Compatible changes
13
+
14
+ -
15
+
16
+ ## 0.7.0 - 2021-05-04
17
+
18
+ ### Compatible changes
19
+
20
+ - add changelog
21
+ - add gemika for tests with github actions
22
+ - add Ruby 3 support
23
+
24
+ ## 0.6.0 - 2021-03-10
25
+ ## 0.5.0 - 2021-03-09
26
+ ## 0.4.0 - 2021-03-05
27
+ ## 0.3.3 - 2021-03-05
28
+ ## 0.3.2 - 2021-03-04
29
+ ## 0.3.1 - 2021-03-04
30
+ ## 0.3.0 - 2021-03-04
31
+ ## 0.2.3 - 2021-03-03
32
+ ## 0.2.2 - 2021-03-03
33
+ ## 0.2.1 - 2021-03-03
data/Gemfile CHANGED
@@ -8,3 +8,9 @@ gemspec
8
8
  gem "rake", "~> 13.0"
9
9
 
10
10
  gem "rspec", "~> 3.0"
11
+ gem 'jasmine'
12
+ gem 'thin' # ruby 3 does not include a webserver
13
+ gem 'chrome_remote'
14
+
15
+ gem 'byebug'
16
+ gem 'gemika'
data/Gemfile.lock CHANGED
@@ -1,15 +1,16 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capybara-lockstep (0.3.2)
4
+ capybara-lockstep (0.7.0)
5
5
  activesupport (>= 3.2)
6
6
  capybara (>= 2.0)
7
+ ruby2_keywords
7
8
  selenium-webdriver (>= 3)
8
9
 
9
10
  GEM
10
11
  remote: https://rubygems.org/
11
12
  specs:
12
- activesupport (6.1.3)
13
+ activesupport (6.1.3.1)
13
14
  concurrent-ruby (~> 1.0, >= 1.0.2)
14
15
  i18n (>= 1.6, < 2)
15
16
  minitest (>= 5.1)
@@ -17,6 +18,7 @@ GEM
17
18
  zeitwerk (~> 2.3)
18
19
  addressable (2.7.0)
19
20
  public_suffix (>= 2.0.2, < 5.0)
21
+ byebug (11.1.3)
20
22
  capybara (3.35.3)
21
23
  addressable
22
24
  mini_mime (>= 0.1.3)
@@ -26,16 +28,28 @@ GEM
26
28
  regexp_parser (>= 1.5, < 3.0)
27
29
  xpath (~> 3.2)
28
30
  childprocess (3.0.0)
31
+ chrome_remote (0.3.0)
32
+ websocket-driver (~> 0.6)
29
33
  concurrent-ruby (1.1.8)
34
+ daemons (1.3.1)
30
35
  diff-lcs (1.3)
31
- i18n (1.8.9)
36
+ eventmachine (1.2.7)
37
+ gemika (0.6.0)
38
+ i18n (1.8.10)
32
39
  concurrent-ruby (~> 1.0)
33
- mini_mime (1.0.2)
34
- mini_portile2 (2.5.0)
40
+ jasmine (3.6.0)
41
+ jasmine-core (~> 3.6.0)
42
+ phantomjs
43
+ rack (>= 1.2.1)
44
+ rake
45
+ jasmine-core (3.6.0)
46
+ mini_mime (1.1.0)
47
+ mini_portile2 (2.5.1)
35
48
  minitest (5.14.4)
36
- nokogiri (1.11.1)
49
+ nokogiri (1.11.3)
37
50
  mini_portile2 (~> 2.5.0)
38
51
  racc (~> 1.4)
52
+ phantomjs (2.1.1.0)
39
53
  public_suffix (4.0.6)
40
54
  racc (1.5.2)
41
55
  rack (2.2.3)
@@ -56,12 +70,20 @@ GEM
56
70
  diff-lcs (>= 1.2.0, < 2.0)
57
71
  rspec-support (~> 3.7.0)
58
72
  rspec-support (3.7.0)
73
+ ruby2_keywords (0.0.4)
59
74
  rubyzip (2.3.0)
60
75
  selenium-webdriver (3.142.7)
61
76
  childprocess (>= 0.5, < 4.0)
62
77
  rubyzip (>= 1.2.2)
78
+ thin (1.8.0)
79
+ daemons (~> 1.0, >= 1.0.9)
80
+ eventmachine (~> 1.0, >= 1.0.4)
81
+ rack (>= 1, < 3)
63
82
  tzinfo (2.0.4)
64
83
  concurrent-ruby (~> 1.0)
84
+ websocket-driver (0.7.3)
85
+ websocket-extensions (>= 0.1.0)
86
+ websocket-extensions (0.1.5)
65
87
  xpath (3.2.0)
66
88
  nokogiri (~> 1.8)
67
89
  zeitwerk (2.4.2)
@@ -70,9 +92,14 @@ PLATFORMS
70
92
  ruby
71
93
 
72
94
  DEPENDENCIES
95
+ byebug
73
96
  capybara-lockstep!
97
+ chrome_remote
98
+ gemika
99
+ jasmine
74
100
  rake (~> 13.0)
75
101
  rspec (~> 3.0)
102
+ thin
76
103
 
77
104
  BUNDLED WITH
78
- 2.2.12
105
+ 2.2.15
data/README.md CHANGED
@@ -38,17 +38,13 @@ How capybara-lockstep helps
38
38
 
39
39
  capybara-lockstep waits until the browser is idle before moving on to the next Capybara command. This greatly relieves the pressure on Capybara's retry logic.
40
40
 
41
- Whenever Capybara visits a new URL:
41
+ Whenever Capybara visits a new URL or simulates a user interaction (clicking, typing, etc.):
42
42
 
43
43
  - capybara-lockstep waits for all document resources to load.
44
44
  - capybara-lockstep waits for client-side JavaScript to render or hydrate DOM elements.
45
45
  - capybara-lockstep waits for any AJAX requests.
46
46
  - capybara-lockstep waits for dynamically inserted `<script>`s to load (e.g. from [dynamic imports](https://webpack.js.org/guides/code-splitting/#dynamic-imports) or Analytics snippets).
47
-
48
- Whenever Capybara simulates a user interaction (clicking, typing, etc.):
49
-
50
- - capybara-lockstep waits for any AJAX requests.
51
- - capybara-lockstep waits for dynamically inserted `<script>`s to load (e.g. from [dynamic imports](https://webpack.js.org/guides/code-splitting/#dynamic-imports) or Analytics snippets).
47
+ - capybara-lockstep waits for dynamically `<img>` or `<iframe>` elements to load.
52
48
 
53
49
 
54
50
  Installation
@@ -102,9 +98,9 @@ If you're not using Rails you can `include Capybara::Lockstep::Helper` and acces
102
98
 
103
99
  ### Signaling the end of page initialization
104
100
 
105
- Most web applications run some JavaScript after the document was loaded. This JavaScript enhances existing DOM elements ("hydration") or renders additional element into the DOM.
101
+ Most web applications run some JavaScript after a document has initially loaded. Such JavaScript usually enhances existing DOM elements ("hydration") or renders additional element into the DOM.
106
102
 
107
- capybara-lockstep needs to know when your JavaScript is done hydrating and rendering, so it can automatically wait for initialization after every Capybara `visit()`.
103
+ capybara-lockstep will synchronize more reliably if you signal when your JavaScript is done rendering the initial document. After the initial rendering, capybara-lockstep will automatically detect when the browser is busy, even if content is changed dynamically later.
108
104
 
109
105
  To signal that JavaScript is still initializing, your application layouts should render the `<body>` element with an `[data-initializing]` attribute:
110
106
 
@@ -112,10 +108,14 @@ To signal that JavaScript is still initializing, your application layouts should
112
108
  <body data-initializing>
113
109
  ```
114
110
 
115
- Your application JavaScript should remove the `[data-initializing]` attribute when it is done hydrating and rendering.
111
+ Your application JavaScript should remove the `[data-initializing]` attribute when it is done rendering the initial page.
116
112
 
117
113
  More precisely, the attribute should be removed in the same [JavaScript task](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) ("tick") that will finish initializing. capybara-lockstep will assume that the page will be initialized by the end of this task.
118
114
 
115
+ **After the initial rendering, capybara-lockstep will automatically detect when the browser is busy, even if content is changed dynamically later. After the initial page load you no longer need to add or remove the `[data-initializing]` attribute.**
116
+
117
+ #### Example: Vanilla JS
118
+
119
119
  If all your initializing JavaScript runs synchronously on `DOMContentLoaded`, you can remove `[data-initializing]` in an event handler:
120
120
 
121
121
  ```js
@@ -125,26 +125,41 @@ document.addEventListener('DOMContentLoaded', function() {
125
125
  })
126
126
  ```
127
127
 
128
- If you do any asynchronous initialization work (like lazy-loading another script) you should only remove `[data-initializing]` once that is done:
128
+ If you call libraries during initialization, you may need to check the library code to see whether it finishes synchronously or asynchronously. Ideally a library offers a callback to notify you when it is done rendering:
129
129
 
130
130
  ```js
131
131
  document.addEventListener('DOMContentLoaded', function() {
132
- import('huge-library').then(function({ hugeLibrary }) {
133
- hugeLibrary.initialize()
134
- document.body.removeAttribute('data-initializing')
132
+ Libary.initialize({
133
+ onFinished: function() {
134
+ document.body.removeAttribute('data-initializing')
135
+ }
135
136
  })
136
137
  })
137
138
  ```
138
139
 
139
- If you call libraries during initialization, you may need to check the library code to see whether it finishes synchronously or asynchronously. E.g. if you discover that a library delays work for a task, you must also wait another task to remove `[data-initializing]`:
140
+ When a library offers no such callback, but you see in its code that the library delays work for a task, you must also wait another task to remove `[data-initializing]`:
140
141
 
141
142
  ```js
142
143
  document.addEventListener('DOMContentLoaded', function() {
143
- Libary.doWorkInNextTask()
144
+ Libary.initialize()
144
145
  setTimeout(function() { document.body.removeAttribute('data-initializing') })
145
146
  })
146
147
  ```
147
148
 
149
+ If your initialization code lazy-loads another script, you should only remove `[data-initializing]` once that is done:
150
+
151
+ ```js
152
+ document.addEventListener('DOMContentLoaded', function() {
153
+ import('huge-library').then(function({ HugeLibrary }) {
154
+ HugeLibrary.initialize()
155
+ document.body.removeAttribute('data-initializing')
156
+ })
157
+ })
158
+ ```
159
+
160
+
161
+ #### Example: Unpoly
162
+
148
163
  When you're using [Unpoly](https://unpoly.com/) initializing will usually happen synchronously in [compilers](https://unpoly.com/up.compiler). Hence a compiler is a good place to remove `[data-initializing]`:
149
164
 
150
165
  ```js
@@ -153,6 +168,8 @@ up.compiler('body', function(body) {
153
168
  })
154
169
  ```
155
170
 
171
+ #### Example: AngularJS 1
172
+
156
173
  When you're using [AngularJS 1](https://unpoly.com/) initializing will usually happen synchronously in [directives](https://docs.angularjs.org/guide/directive). Hence a directive is a good place to remove `[data-initializing]`:
157
174
 
158
175
  ```js
@@ -173,9 +190,9 @@ capybara-lockstep will automatically patch Capybara to wait for the browser afte
173
190
  Run your test suite to see if integration was successful and whether stability improves. During validation we recommend to activate `Capybara::Lockstep.debug = true` in your `spec_helper.rb` (RSpec) or `env.rb` (Cucumber). You should see messages like this in your console:
174
191
 
175
192
  ```text
176
- [Capybara::Lockstep] Synchronizing
177
- [Capybara::Lockstep] Finished waiting for JavaScript
178
- [Capybara::Lockstep] Synchronized successfully
193
+ [capybara-lockstep] Synchronizing
194
+ [capybara-lockstep] Finished waiting for JavaScript
195
+ [capybara-lockstep] Synchronized successfully
179
196
  ```
180
197
 
181
198
  Note that you may see some failures from tests with wrong assertions, which sometimes passed due to lucky timing.
@@ -192,30 +209,52 @@ In casual testing I experienced a performance impact between +/- 10%.
192
209
 
193
210
  ## Debugging log
194
211
 
195
- capybara-lockstep can print to the console whenever it waits for the browser. To enable the log:
212
+ You can enable extensive logging. This is useful to see whether capybara-lockstep has an effect on your tests, or to debug why synchronization is taking too long.
213
+
214
+ To enable the log, say this before or during a test:
196
215
 
197
216
  ```ruby
198
217
  Capybara::Lockstep.debug = true
199
218
  ```
200
219
 
201
- You should now see messages like this during your test runs:
220
+ You should now see messages like this on your standard output:
202
221
 
203
222
  ```
204
- [Capybara::Lockstep] Synchronizing
205
- [Capybara::Lockstep] Finished waiting for JavaScript
206
- [Capybara::Lockstep] Synchronized successfully
223
+ [capybara-lockstep] Synchronizing
224
+ [capybara-lockstep] Finished waiting for JavaScript
225
+ [capybara-lockstep] Synchronized successfully
207
226
  ```
208
227
 
228
+ You should also see messages like this in your browser's JavaScript console:
229
+
230
+ ```
231
+ [capybara-lockstep] Started work: fetch /path [3 jobs]
232
+ [capybara-lockstep] Finished work: fetch /path [2 jobs]
233
+ ```
234
+
235
+
236
+ ### Using a logger
237
+
209
238
  You may also configure logging to an existing logger object:
210
239
 
211
240
  ```ruby
212
241
  Capybara::Lockstep.debug = Rails.logger
213
242
  ```
214
243
 
244
+ ### Logging in the browser only
245
+
246
+ To enable logging in the browser console (but not STDOUT), include the snippet with `{ debug: true }`:
247
+
248
+ ```
249
+ capybara_lockstep(debug: true)
250
+ ```
251
+
215
252
 
216
253
  ## Disabling synchronization
217
254
 
218
- If for some reason you want to disable browser synchronization for a while, you can do it like this:
255
+ Sometimes you want to disable browser synchronization, e.g. to observe a loading spinner during a long-running request.
256
+
257
+ To disable synchronization:
219
258
 
220
259
  ```ruby
221
260
  begin
@@ -226,9 +265,11 @@ ensure
226
265
  end
227
266
  ```
228
267
 
229
- ## Timeout
268
+ ## Synchronization timeout
269
+
270
+ By default capybara-lockstep will wait `Capybara.default_max_wait_time` seconds for the page initialize and for JavaScript and AJAX request to finish.
230
271
 
231
- By default capybara-lockstep will wait up to 10 seconds for the page initialize and for JavaScript and AJAX request to finish.
272
+ When synchronization times out, capybara-lockstep will log but not raise an error.
232
273
 
233
274
  You can configure a different timeout:
234
275
 
@@ -236,70 +277,82 @@ You can configure a different timeout:
236
277
  Capybara::Lockstep.timeout = 5 # seconds
237
278
  ```
238
279
 
239
- ## Ruby API
280
+ To revert to defaulting to `Capybara.default_max_wait_time`, set the timeout to `nil`:
240
281
 
241
- capybara-lockstep will automatically patch Capybara to wait for the browser after every command. **This should be enough for most test suites**.
282
+ ```ruby
283
+ Capybara::Lockstep.timeout = nil
284
+ ```
242
285
 
243
- For additional edge cases you may interact with capybara-lockstep from your Ruby code.
244
286
 
287
+ ## Manual synchronization
245
288
 
246
- ### Waiting until the browser is idle
289
+ capybara-lockstep will automatically patch Capybara to wait for the browser after every command. **This should be enough for most test suites**.
247
290
 
248
- This will block until the document was loaded, the DOM has been hydrated and all AJAX requests have concluded:
291
+ For additional edge cases you may manually tell capybara-lockstep to wait. The following Ruby method will block until the browser is idle:
249
292
 
250
293
  ```ruby
251
294
  Capybara::Lockstep.synchronize
252
295
  ```
253
296
 
254
- An example use case is a Cucumber step that explicitely waits for JavaScript to finish, in the rare occasion where capybara-lockstep hasn't picked up an event or request:
297
+ You may also synchronize from your client-side JavaScript. The following will run the given callback once the browser is idle:
255
298
 
256
- ```gherkin
257
- When 'I wait for the page to load' do
258
- Capybara::Lockstep.synchronize
259
- end
299
+ ```js
300
+ CapybaraLockstep.synchronize(callback)
301
+ ```
302
+
303
+ ## Signaling asynchronous work
304
+
305
+ If for some reason you want capybara-lockstep to consider additional asynchronous work as "busy", you can do so:
306
+
307
+ ```js
308
+ CapybaraLockstep.startWork('Eject warp core')
309
+ doAsynchronousWork().then(function() {
310
+ CapybaraLockstep.stopWork('Eject warp core')
311
+ })
312
+ ```
313
+
314
+ The string argument is used for logging (when logging is enabled). It does **not** need to be unique per job. In this case you should see messages like this in your browser's JavaScript console:
315
+
316
+ ```text
317
+ [capybara-lockstep] Started work: Eject warp core [1 jobs]
318
+ [capybara-lockstep] Finished work: Eject warp core [0 jobs]
260
319
  ```
261
320
 
262
- ## JavaScript API
321
+ You may omit the string argument, in which case nothing will be logged, but the work will still be tracked.
263
322
 
264
- capybara-lockstep already hooks into [many JavaScript APIs](#how-capybara-lockstep-helps) like `XMLHttpRequest` or `fetch()` to mark the browser as "busy" until their work finishes. **This should be enough for most test suites**.
265
323
 
266
- For additional edge cases you may interact with capybara-lockstep from your own JavaScripts.
324
+ ## Note on interacting with the JavaScript API
267
325
 
268
- Note that when you only load the JavaScript snippet in tests you need check before calling any API functions:
326
+ If you only load capybara-lockstep in tests you, should check for the `CapybaraLockstep` global to be defined before you interact with the JavaScript API.
269
327
 
270
328
  ```js
271
329
  if (window.CapybaraLockstep) {
272
- CapybaraLockstep.startWork()
330
+ // interact with CapybaraLockstep
273
331
  }
274
332
  ```
275
333
 
276
- ### Signaling asynchronous work
334
+ ## Handling legacy promises
277
335
 
278
- If for some reason you want capybara-lockstep to consider additional asynchronous work as "busy", you can do so:
336
+ Legacy promise implementations (like jQuery's `$.Deferred` and AngularJS' `$q`) work using tasks instead of microtasks. Their AJAX implementations (like `$.ajax()` and `$http`) use these promises to signal that a request is done.
337
+
338
+ This means there is a time window in which all AJAX requests have finished, but their callbacks have not yet run:
279
339
 
280
340
  ```js
281
- CapybaraLockstep.startWork()
282
- doAsynchronousWork().then(function() {
283
- CapybaraLockstep.stopWork()
341
+ $.ajax('/foo').then(function() {
342
+ // This callback runs one task after the response was received
284
343
  })
285
344
  ```
286
345
 
287
- ### Checking if the browser is busy
288
-
289
- You can query capybara-lockstep whether it considers the browser to be busy or idle:
346
+ It is theoretically possible that your test will observe the browser in that window, and expect content that has not been rendered yet. 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:
290
347
 
291
348
  ```js
292
- CapybaraLockstep.isBusy() // => false
293
- CapybaraLockstep.isIdle() // => true
349
+ Capybara:Lockstep.wait_tasks = 1
294
350
  ```
295
351
 
296
- ### Waiting until the browser is idle
352
+ If you see longer `then()` chains in your code, you may need to configure a higher number of tasks to wait.
297
353
 
298
- This will run the given callback once the browser is considered to be idle:
354
+ This will have a negative performance impact on your test suite.
299
355
 
300
- ```js
301
- CapybaraLockstep.synchronize(callback)
302
- ```
303
356
 
304
357
  ## Development
305
358