codeceptjs 4.2.0-beta.4 → 4.2.1-beta.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.
Files changed (65) hide show
  1. package/README.md +2 -0
  2. package/bin/codecept.js +11 -0
  3. package/docs/agents.md +26 -1
  4. package/docs/ai.md +57 -0
  5. package/docs/alternative-browsers.md +175 -148
  6. package/docs/assertions.md +74 -0
  7. package/docs/bootstrap.md +2 -0
  8. package/docs/commands.md +45 -0
  9. package/docs/configuration.md +37 -0
  10. package/docs/debugging.md +1 -1
  11. package/docs/helpers/ApiDataFactory.md +20 -20
  12. package/docs/helpers/Appium.md +1615 -670
  13. package/docs/helpers/Decision.md +146 -0
  14. package/docs/helpers/GraphQL.md +31 -31
  15. package/docs/helpers/GraphQLDataFactory.md +20 -20
  16. package/docs/helpers/Kitesurf.md +1808 -25
  17. package/docs/helpers/Lightpanda.md +139 -0
  18. package/docs/helpers/Obscura.md +1799 -74
  19. package/docs/helpers/Playwright.md +490 -428
  20. package/docs/helpers/Puppeteer.md +317 -255
  21. package/docs/helpers/REST.md +43 -43
  22. package/docs/helpers/WebDriver.md +237 -175
  23. package/docs/installation.md +16 -0
  24. package/docs/mcp.md +7 -1
  25. package/docs/parallel.md +35 -1
  26. package/docs/plugins/pause.md +2 -1
  27. package/docs/plugins/sitemap.md +48 -0
  28. package/docs/plugins.md +4 -0
  29. package/lib/ai.js +81 -2
  30. package/lib/codecept.js +32 -2
  31. package/lib/command/init.js +22 -0
  32. package/lib/command/initAgent.js +78 -0
  33. package/lib/command/run-multiple.js +3 -0
  34. package/lib/command/run-workers.js +10 -3
  35. package/lib/command/run.js +3 -2
  36. package/lib/command/utils.js +15 -0
  37. package/lib/command/workers/runTests.js +10 -10
  38. package/lib/container.js +4 -2
  39. package/lib/effects.js +19 -1
  40. package/lib/helper/Appium.js +23 -0
  41. package/lib/helper/CDPBrowser.js +387 -1338
  42. package/lib/helper/Decision.js +256 -0
  43. package/lib/helper/Kitesurf.js +3 -21
  44. package/lib/helper/Lightpanda.js +137 -0
  45. package/lib/helper/Obscura.js +21 -238
  46. package/lib/helper/Playwright.js +50 -4
  47. package/lib/helper/Puppeteer.js +62 -8
  48. package/lib/helper/WebDriver.js +45 -1
  49. package/lib/helper/extras/clipboard.js +31 -0
  50. package/lib/listener/result.js +4 -0
  51. package/lib/mocha/bdd.js +19 -1
  52. package/lib/plugin/junitReporter.js +4 -1
  53. package/lib/plugin/pause.js +4 -1
  54. package/lib/plugin/sitemap.js +228 -0
  55. package/lib/recorder.js +19 -18
  56. package/lib/result.js +16 -0
  57. package/lib/step/base.js +12 -0
  58. package/lib/utils.js +2 -10
  59. package/lib/webServer.js +193 -0
  60. package/lib/workers.js +118 -31
  61. package/package.json +4 -2
  62. package/typings/index.d.ts +60 -7
  63. package/typings/promiseBasedTypes.d.ts +985 -814
  64. package/typings/types.d.ts +1084 -815
  65. package/docs/helpers/CDPBrowser.md +0 -2138
@@ -11,16 +11,12 @@ title: Obscura
11
11
 
12
12
  **Extends CDPBrowser**
13
13
 
14
- Obscura drives [Obscura][1], a minimal headless
15
- browser exposed over the Chrome DevTools Protocol. From v0.2.0, default release builds ship a
16
- real rendering engine (layout, paint, screenshots); `-no-render` variants and v0.1.x builds keep
17
- the original single-V8-isolate, nothing-rendered mode. This helper does not hardcode which mode a
18
- given binary is in — `CDPBrowser._probeCapabilities` detects `layout`/`screenshot` per binary at
19
- runtime, so the same helper works against either.
14
+ Obscura drives [Obscura][1], a lightweight headless
15
+ browser controlled over the Chrome DevTools Protocol. Default builds from v0.2.0 render pages
16
+ (layout, screenshots); `-no-render` builds and v0.1.x run JavaScript and the DOM only. The helper
17
+ detects which build it runs against, so the same config works for both.
20
18
 
21
- This helper is a thin `CDPBrowser` subclass: it changes nothing about how locating or acting on
22
- elements works, it only pins the config presets Obscura requires and manages the `obscura serve`
23
- process lifecycle, the same way Playwright manages its own browser process.
19
+ The helper starts and stops `obscura serve` for you, the same way Playwright manages its browser.
24
20
 
25
21
  > Obscura support is experimental in CodeceptJS 4.2. Pin the browser version in CI and keep a
26
22
  > Playwright/WebDriver job for browser-compatibility coverage.
@@ -40,8 +36,8 @@ process lifecycle, the same way Playwright manages its own browser process.
40
36
  * **SELF-LAUNCH** — `endpoint` is unset and a binary can be resolved, in order: `binaryPath` in
41
37
  the config, then the `OBSCURA_PATH` environment variable, then `obscura` on `PATH`. The helper
42
38
  spawns `obscura serve --port <port> --allow-private-network --allow-file-access` (`port` from
43
- the config, or a free port picked automatically), waits for it to answer, connects, and kills
44
- it in `_finishTest`.
39
+ the config, or a free port picked automatically), waits for it to answer, connects, and stops
40
+ it when tests finish.
45
41
  * **COURTESY-ATTACH** — `endpoint` is unset and no binary can be resolved, but something already
46
42
  answers `http://127.0.0.1:9222/json/version` (e.g. `obscura serve` started by hand, or by CI
47
43
  before this process ever ran). The helper attaches to it and never kills it — it isn't the
@@ -78,15 +74,13 @@ default.
78
74
 
79
75
  These are set automatically and only need overriding for unusual setups:
80
76
 
81
- | option | value | why |
82
- | --------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
83
- | `input` | `synthetic` | coordinate-click navigation is unreliable over CDP on Obscura even on rendering builds (no `frameNavigated` event, stale `page.url()`); `click` always takes the `forceClick` path — on Obscura, `click` and `forceClick` are the same thing |
84
- | `xpathPolyfill` | `auto` | probed per binary/page: Obscura's native `document.evaluate` still doesn't support attribute selection or `not()`, so the polyfill is used until that lands |
77
+ | option | value | why |
78
+ | --------------- | ----------- | ------------------------------------------------------------------------------------------ |
79
+ | `input` | `synthetic` | clicks that navigate are unreliable in Obscura, so `click` behaves like `forceClick` |
80
+ | `xpathPolyfill` | `auto` | Obscura's XPath lacks attribute selection and `not()`, so the polyfill is used when needed |
85
81
 
86
- `capabilities.layout`/`capabilities.screenshot`/`capabilities.xpath` are intentionally left
87
- unset here — `CDPBrowser._probeCapabilities` detects them at runtime from the actual binary
88
- (`'real'`/`true` on v0.2.0+ default builds, `'none'`/`false` on `-no-render` builds and v0.1.x).
89
- Set them explicitly in your own config to skip probing or to force a mode.
82
+ `capabilities` are detected at runtime from the Obscura build. Set them in your config to skip
83
+ detection or to force a mode.
90
84
 
91
85
  ## Limitations
92
86
 
@@ -104,23 +98,26 @@ Set them explicitly in your own config to skip probing or to force a mode.
104
98
 
105
99
  ## Configuration
106
100
 
107
- This helper should be configured in codecept.conf.js. It accepts everything `CDPBrowser`
108
- accepts (see its config table), plus:
101
+ This helper should be configured in codecept.conf.js
109
102
 
110
- Type: [object][7]
103
+ Type: [object][4]
111
104
 
112
105
  ### Properties
113
106
 
114
- * `endpoint` **[string][5]?** explicit CDP endpoint. Setting this switches the helper to ATTACH
115
- mode: it only connects, and never spawns or kills a process, no matter what else is configured.
116
- Leave it unset for SELF-MANAGED mode (see below).
117
- * `binaryPath` **[string][5]?** path to the `obscura` executable, used in SELF-MANAGED mode
118
- (`endpoint` unset). Checked before `OBSCURA_PATH` and `PATH`.
119
- * `port` **[number][4]?** port `obscura serve` listens on, in SELF-MANAGED mode. When unset, a
120
- free port is picked automatically, which is what makes `run-workers` collision-free — every
121
- worker gets its own instance on its own port with zero config.
122
- * `serverStartTimeout` **[number][4]?** milliseconds to wait for a spawned `obscura serve`
123
- to answer `/json/version` before `_connect` gives up.
107
+ * `endpoint` **[string][3]?** connect to a running Obscura instead of starting one (ATTACH mode).
108
+ * `binaryPath` **[string][3]?** path to the `obscura` executable. Checked before `OBSCURA_PATH` and `PATH`.
109
+ * `port` **[number][8]?** port for `obscura serve`. A free port is picked when unset, so parallel workers never collide.
110
+ * `serverStartTimeout` **[number][8]?** how long to wait for `obscura serve` to start, in milliseconds.
111
+ * `url` **[string][3]?** base url of website to be tested.
112
+ * `headers` **[object][4]?** headers sent when connecting to the endpoint, e.g. for authenticated remote browsers.
113
+ * `input` **[string][3]?** how actions are dispatched: `cdp` (real mouse and keyboard events) or `synthetic` (DOM events). `auto` picks `cdp` when the browser renders layout.
114
+ * `xpathPolyfill` **([string][3] | [boolean][17])?** inject an XPath polyfill for browsers with incomplete XPath support. `auto` detects when it is needed.
115
+ * `capabilities` **[object][4]?** browser capabilities (`layout`, `xpath`, `screenshot`, `innerText`) to use instead of detecting them at runtime.
116
+ * `waitForTimeout` **[number][8]?** default timeout for wait* actions, in seconds.
117
+ * `waitForAction` **[number][8]?** fixed delay after each action, in milliseconds. When unset, actions wait only for the navigation they trigger.
118
+ * `pollInterval` **[number][8]?** interval between checks while waiting, in milliseconds.
119
+ * `getPageTimeout` **[number][8]?** maximum time to wait for a page to load, in seconds.
120
+ * `waitForNavigation` **[string][3]?** when a navigation is considered finished: `load`, `domcontentloaded`, or `networkidle`.
124
121
 
125
122
 
126
123
 
@@ -157,80 +154,1808 @@ Type: [object][7]
157
154
 
158
155
  * `config` **ObscuraConfig**&#x20;
159
156
 
160
- ### _connect
157
+ ### amOnPage
158
+
159
+ Opens a web page in a browser. Requires relative or absolute url.
160
+ If url starts with `/`, opens a web page of a site defined in `url` config parameter.
161
+
162
+ ```js
163
+ I.amOnPage('/'); // opens main page of website
164
+ I.amOnPage('https://github.com'); // opens github
165
+ I.amOnPage('/login'); // opens a login page
166
+ ```
167
+
168
+ #### Parameters
169
+
170
+ * `url` **[string][3]** url path or global url.
171
+
172
+ Returns **void** automatically synchronized promise through #recorder
173
+
174
+ ### appendField
175
+
176
+ Appends text to a input field or textarea.
177
+ Field is located by name, label, CSS or XPath
178
+
179
+ The third parameter is an optional context (CSS or XPath locator) to narrow the search.
180
+
181
+ ```js
182
+ I.appendField('#myTextField', 'appended');
183
+ // typing secret
184
+ I.appendField('password', secret('123456'));
185
+ // within a context
186
+ I.appendField('name', 'John', '.form-container');
187
+ ```
188
+
189
+ #### Parameters
190
+
191
+ * `field` **([string][3] | [object][4])** located by label|name|CSS|XPath|strict locator
192
+ * `value` **[string][3]** text value to append.
193
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
194
+
195
+ Returns **void** automatically synchronized promise through #recorder
196
+
197
+ ### attachFile
198
+
199
+ Attaches a file to element located by label, name, CSS or XPath
200
+ Path to file is relative current codecept directory (where codecept.conf.ts or codecept.conf.js is located).
201
+ File will be uploaded to remote system (if tests are running remotely).
202
+
203
+ The third parameter is an optional context (CSS or XPath locator) to narrow the search.
204
+
205
+ ```js
206
+ I.attachFile('Avatar', 'data/avatar.jpg');
207
+ I.attachFile('form input[name=avatar]', 'data/avatar.jpg');
208
+ // within a context
209
+ I.attachFile('Avatar', 'data/avatar.jpg', '.form-container');
210
+ ```
211
+
212
+ If the locator points to a non-file-input element (e.g., a dropzone area),
213
+ the file will be dropped onto that element using drag-and-drop events.
214
+
215
+ ```js
216
+ I.attachFile('#dropzone', 'data/avatar.jpg');
217
+ ```
218
+
219
+ #### Parameters
220
+
221
+ * `field` &#x20;
222
+ * `pathToFile` **[string][3]** local file path relative to codecept.conf.ts or codecept.conf.js config file.
223
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
224
+ * `locator` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator.
225
+
226
+ Returns **void** automatically synchronized promise through #recorder
227
+
228
+ ### blur
229
+
230
+ Remove focus from a text input, button, etc.
231
+ Calls [blur][5] on the element.
232
+
233
+ Examples:
234
+
235
+ ```js
236
+ I.blur('.text-area')
237
+ ```
238
+
239
+ ```js
240
+ //element `#product-tile` is focused
241
+ I.see('#add-to-cart-btn');
242
+ I.blur('#product-tile')
243
+ I.dontSee('#add-to-cart-btn');
244
+ ```
245
+
246
+ #### Parameters
247
+
248
+ * `locator` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator.
249
+ * `options` **any?** Playwright only: [Additional options][6] for available options object as 2nd argument.
250
+
251
+ Returns **void** automatically synchronized promise through #recorder
252
+
253
+ ### checkOption
254
+
255
+ Selects a checkbox or radio button.
256
+ Element is located by label or name or CSS or XPath.
257
+
258
+ The second parameter is an optional context (CSS or XPath locator) to narrow the search.
259
+
260
+ ```js
261
+ I.checkOption('#agree');
262
+ I.checkOption('I Agree to Terms and Conditions');
263
+ I.checkOption('agree', '//form');
264
+ ```
265
+
266
+ #### Parameters
267
+
268
+ * `field` **([string][3] | [object][4])** checkbox located by label | name | CSS | XPath | strict locator.
269
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
270
+
271
+ Returns **void** automatically synchronized promise through #recorder
272
+
273
+ ### clearClipboard
274
+
275
+ Clears the system clipboard.
276
+
277
+ ```js
278
+ I.clearClipboard();
279
+ I.seeClipboardEquals('');
280
+ ```
281
+
282
+ Returns **void** automatically synchronized promise through #recorder
283
+
284
+ ### clearCookie
285
+
286
+ Clears a cookie by name,
287
+ if none provided clears all cookies.
288
+
289
+ ```js
290
+ I.clearCookie();
291
+ I.clearCookie('test');
292
+ ```
293
+
294
+ #### Parameters
295
+
296
+ * `name` &#x20;
297
+ * `cookie` **[string][3]?** (optional, `null` by default) cookie name
298
+
299
+ ### clearField
300
+
301
+ Clears a `<textarea>` or text `<input>` element's value.
302
+
303
+ The second parameter is an optional context (CSS or XPath locator) to narrow the search.
304
+
305
+ ```js
306
+ I.clearField('Email');
307
+ I.clearField('user[email]');
308
+ I.clearField('#email');
309
+ // within a context
310
+ I.clearField('Email', '.form-container');
311
+ ```
312
+
313
+ #### Parameters
314
+
315
+ * `field` &#x20;
316
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
317
+ * `editable` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator.
318
+
319
+ Returns **void** automatically synchronized promise through #recorder.
320
+
321
+ ### click
322
+
323
+ Perform a click on a link or a button, given by a locator.
324
+ If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
325
+ For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched.
326
+ For images, the "alt" attribute and inner text of any parent links are searched.
327
+
328
+ If no locator is provided, defaults to clicking the body element (`'//body'`).
329
+
330
+ The second parameter is a context (CSS or XPath locator) to narrow the search.
331
+
332
+ ```js
333
+ // click body element (default)
334
+ I.click();
335
+ // simple link
336
+ I.click('Logout');
337
+ // button of form
338
+ I.click('Submit');
339
+ // CSS button
340
+ I.click('#form input[type=submit]');
341
+ // XPath
342
+ I.click('//form/*[@type=submit]');
343
+ // link in context
344
+ I.click('Logout', '#nav');
345
+ // using strict locator
346
+ I.click({css: 'nav a.login'});
347
+ // using ARIA role locator
348
+ I.click({role: 'button', name: 'Submit'});
349
+ ```
350
+
351
+ > ℹ️ ARIA role locators (`{role, name}`) match elements the way assistive technology does and survive markup refactors. See [Locators][7].
352
+
353
+ #### Parameters
354
+
355
+ * `locator` **([string][3] | [object][4])** (optional, `'//body'` by default) clickable link or button located by text, or any element located by CSS|XPath|strict locator.
356
+ * `context` **([string][3]? | [object][4] | null)** (optional, `null` by default) element to search in CSS|XPath|Strict locator.
357
+
358
+ Returns **void** automatically synchronized promise through #recorder
359
+
360
+ ### clickXY
361
+
362
+ Clicks at page coordinates, or at coordinates relative to an element.
363
+ Requires a browser that renders layout.
364
+
365
+ ```js
366
+ I.clickXY(100, 200); // page coordinates
367
+ I.clickXY('#area', 50, 30); // relative to #area
368
+ ```
369
+
370
+ #### Parameters
371
+
372
+ * `locator` **([string][3] | [object][4] | [number][8])** element to click relative to, or the X page coordinate.
373
+ * `x` **[number][8]?** X coordinate relative to the element, or the Y page coordinate if `locator` is a number.
374
+ * `y` **[number][8]?** Y coordinate relative to the element.
375
+
376
+ Returns **void** automatically synchronized promise through #recorder
377
+
378
+ ### dontSee
379
+
380
+ Opposite to `see`. Checks that a text is not present on a page.
381
+ Use context parameter to narrow down the search.
382
+
383
+ ```js
384
+ I.dontSee('Login'); // assume we are already logged in.
385
+ I.dontSee('Login', '.nav'); // no login inside .nav element
386
+ ```
387
+
388
+ #### Parameters
389
+
390
+ * `text` **[string][3]** which is not present.
391
+ * `context` **([string][3] | [object][4])?** (optional) element located by CSS|XPath|strict locator in which to perfrom search.
392
+
393
+ Returns **void** automatically synchronized promise through #recorder
394
+
395
+ ### dontSeeCheckboxIsChecked
396
+
397
+ Verifies that the specified checkbox is not checked.
398
+
399
+ ```js
400
+ I.dontSeeCheckboxIsChecked('#agree'); // located by ID
401
+ I.dontSeeCheckboxIsChecked('I agree to terms'); // located by label
402
+ I.dontSeeCheckboxIsChecked('agree'); // located by name
403
+ ```
404
+
405
+ #### Parameters
406
+
407
+ * `locator` &#x20;
408
+ * `field` **([string][3] | [object][4])** located by label|name|CSS|XPath|strict locator.
409
+
410
+ Returns **void** automatically synchronized promise through #recorder
411
+
412
+ ### dontSeeCookie
413
+
414
+ Checks that cookie with given name does not exist.
415
+
416
+ ```js
417
+ I.dontSeeCookie('auth'); // no auth cookie
418
+ ```
419
+
420
+ #### Parameters
421
+
422
+ * `name` **[string][3]** cookie name.
423
+
424
+ Returns **void** automatically synchronized promise through #recorder
425
+
426
+ ### dontSeeCurrentPathEquals
427
+
428
+ Checks that current URL path does NOT match the expected path.
429
+ Query strings and URL fragments are ignored.
430
+
431
+ ```js
432
+ I.dontSeeCurrentPathEquals('/form'); // fails for '/form', '/form?user=1', '/form#section'
433
+ I.dontSeeCurrentPathEquals('/'); // fails for '/', '/?user=ok', '/#top'
434
+ ```
435
+
436
+ #### Parameters
437
+
438
+ * `path` **[string][3]** value to check.
439
+
440
+ Returns **void** automatically synchronized promise through #recorder
441
+
442
+ ### dontSeeCurrentUrlEquals
443
+
444
+ Checks that current url is not equal to provided one.
445
+ If a relative url provided, a configured url will be prepended to it.
446
+
447
+ ```js
448
+ I.dontSeeCurrentUrlEquals('/login'); // relative url are ok
449
+ I.dontSeeCurrentUrlEquals('http://mysite.com/login'); // absolute urls are also ok
450
+ ```
451
+
452
+ #### Parameters
453
+
454
+ * `url` **[string][3]** value to check.
455
+
456
+ Returns **void** automatically synchronized promise through #recorder
457
+
458
+ ### dontSeeElement
459
+
460
+ Opposite to `seeElement`. Checks that element is not visible (or in DOM)
461
+
462
+ The second parameter is a context (CSS or XPath locator) to narrow the search.
463
+
464
+ ```js
465
+ I.dontSeeElement('.modal'); // modal is not shown
466
+ I.dontSeeElement('.modal', '#container');
467
+ ```
468
+
469
+ #### Parameters
470
+
471
+ * `locator` **([string][3] | [object][4])** located by CSS|XPath|Strict locator.
472
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
473
+
474
+ Returns **void** automatically synchronized promise through #recorder
475
+
476
+ ### dontSeeElementInDOM
477
+
478
+ Opposite to `seeElementInDOM`. Checks that element is not on page.
479
+
480
+ ```js
481
+ I.dontSeeElementInDOM('.nav'); // checks that element is not on page visible or not
482
+ ```
483
+
484
+ #### Parameters
485
+
486
+ * `locator` **([string][3] | [object][4])** located by CSS|XPath|Strict locator.
487
+
488
+ Returns **void** automatically synchronized promise through #recorder
489
+
490
+ ### dontSeeInCurrentUrl
491
+
492
+ Checks that current url does not contain a provided fragment.
493
+
494
+ #### Parameters
495
+
496
+ * `url` **[string][3]** value to check.
497
+
498
+ Returns **void** automatically synchronized promise through #recorder
499
+
500
+ ### dontSeeInField
501
+
502
+ Checks that value of input field or textarea doesn't equal to given value
503
+ Opposite to `seeInField`.
504
+
505
+ The third parameter is an optional context (CSS or XPath locator) to narrow the search.
506
+
507
+ ```js
508
+ I.dontSeeInField('email', 'user@user.com'); // field by name
509
+ I.dontSeeInField({ css: 'form input.email' }, 'user@user.com'); // field by CSS
510
+ // within a context
511
+ I.dontSeeInField('Name', 'old_value', '.form-container');
512
+ ```
513
+
514
+ #### Parameters
515
+
516
+ * `field` **([string][3] | [object][4])** located by label|name|CSS|XPath|strict locator.
517
+ * `value` **([string][3] | [object][4])** value to check.
518
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
519
+
520
+ Returns **void** automatically synchronized promise through #recorder
521
+
522
+ ### dontSeeInSource
523
+
524
+ Checks that the current page does not contains the given string in its raw source code.
525
+
526
+ ```js
527
+ I.dontSeeInSource('<!--'); // no comments in source
528
+ ```
529
+
530
+ #### Parameters
531
+
532
+ * `text` &#x20;
533
+ * `value` **[string][3]** to check.
534
+
535
+ Returns **void** automatically synchronized promise through #recorder
536
+
537
+ ### dontSeeInTitle
538
+
539
+ Checks that title does not contain text.
540
+
541
+ ```js
542
+ I.dontSeeInTitle('Error');
543
+ ```
544
+
545
+ #### Parameters
546
+
547
+ * `text` **[string][3]** value to check.
548
+
549
+ Returns **void** automatically synchronized promise through #recorder
550
+
551
+ ### dontSeeTraffic
552
+
553
+ Verifies that a certain request is not part of network traffic.
554
+
555
+ Examples:
556
+
557
+ ```js
558
+ I.dontSeeTraffic({ name: 'Unexpected API Call', url: 'https://api.example.com' });
559
+ I.dontSeeTraffic({ name: 'Unexpected API Call of "user" endpoint', url: /api.example.com.*user/ });
560
+ ```
561
+
562
+ #### Parameters
563
+
564
+ * `opts` **[Object][4]** options when checking the traffic network.
565
+
566
+ * `opts.name` **[string][3]** A name of that request. Can be any value. Only relevant to have a more meaningful error message in case of fail.
567
+ * `opts.url` **([string][3] | [RegExp][9])** Expected URL of request in network traffic. Can be a string or a regular expression.
568
+
569
+ Returns **void** automatically synchronized promise through #recorder
570
+
571
+ ### doubleClick
572
+
573
+ Performs a double-click on an element matched by link|button|label|CSS or XPath.
574
+ Context can be specified as second parameter to narrow search.
575
+
576
+ ```js
577
+ I.doubleClick('Edit');
578
+ I.doubleClick('Edit', '.actions');
579
+ I.doubleClick({css: 'button.accept'});
580
+ I.doubleClick('.btn.edit');
581
+ ```
582
+
583
+ #### Parameters
584
+
585
+ * `locator` **([string][3] | [object][4])** clickable link or button located by text, or any element located by CSS|XPath|strict locator.
586
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element to search in CSS|XPath|Strict locator.
587
+
588
+ Returns **void** automatically synchronized promise through #recorder
589
+
590
+ ### executeAsyncScript
591
+
592
+ Executes async script on page.
593
+ Provided function should execute a passed callback (as first argument) to signal it is finished.
594
+
595
+ Example: In Vue.js to make components completely rendered we are waiting for [nextTick][10].
596
+
597
+ ```js
598
+ I.executeAsyncScript(function(done) {
599
+ Vue.nextTick(done); // waiting for next tick
600
+ });
601
+ ```
602
+
603
+ By passing value to `done()` function you can return values.
604
+ Additional arguments can be passed as well, while `done` function is always last parameter in arguments list.
605
+
606
+ ```js
607
+ let val = await I.executeAsyncScript(function(url, done) {
608
+ // in browser context
609
+ $.ajax(url, { success: (data) => done(data); }
610
+ }, 'http://ajax.callback.url/');
611
+ ```
612
+
613
+ #### Parameters
614
+
615
+ * `fn` **([string][3] | [function][11])** function to be executed in browser context.
616
+ * `args` **...any** to be passed to function.
617
+
618
+ Returns **[Promise][12]<any>** script return value
619
+
620
+ ### executeScript
621
+
622
+ Executes sync script on a page.
623
+ Pass arguments to function as additional parameters.
624
+ Will return execution result to a test.
625
+ In this case you should use async function and await to receive results.
626
+
627
+ Example with jQuery DatePicker:
628
+
629
+ ```js
630
+ // change date of jQuery DatePicker
631
+ I.executeScript(function() {
632
+ // now we are inside browser context
633
+ $('date').datetimepicker('setDate', new Date());
634
+ });
635
+ ```
636
+
637
+ Can return values. Don't forget to use `await` to get them.
638
+
639
+ ```js
640
+ let date = await I.executeScript(function(el) {
641
+ // only basic types can be returned
642
+ return $(el).datetimepicker('getDate').toString();
643
+ }, '#date'); // passing jquery selector
644
+ ```
645
+
646
+ #### Parameters
647
+
648
+ * `fn` **([string][3] | [function][11])** function to be executed in browser context.
649
+ * `args` **...any** to be passed to function.
650
+
651
+ Returns **[Promise][12]<any>** script return value
652
+
653
+ ### fillField
654
+
655
+ Fills a text field or textarea, after clearing its value, with the given string.
656
+ Field is located by name, label, CSS, or XPath.
657
+
658
+ The third parameter is an optional context (CSS or XPath locator) to narrow the search.
659
+
660
+ ```js
661
+ // by label
662
+ I.fillField('Email', 'hello@world.com');
663
+ // by name
664
+ I.fillField('password', secret('123456'));
665
+ // by CSS
666
+ I.fillField('form#login input[name=username]', 'John');
667
+ // or by strict locator
668
+ I.fillField({css: 'form#login input[name=username]'}, 'John');
669
+ // by ARIA role locator
670
+ I.fillField({role: 'textbox', name: 'Email'}, 'hello@world.com');
671
+ // within a context
672
+ I.fillField('Name', 'John', '#section2');
673
+ ```
674
+
675
+ > ℹ️ ARIA role locators (`{role, name}`) match fields by their accessible name and survive markup refactors. See [Locators][7].
676
+
677
+ #### Parameters
678
+
679
+ * `field` **([string][3] | [object][4])** located by label|name|CSS|XPath|strict locator.
680
+ * `value` **([string][3] | [object][4])** text value to fill.
681
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
682
+
683
+ Returns **void** automatically synchronized promise through #recorder
684
+
685
+ ### flushNetworkTraffics
686
+
687
+ Resets all recorded network requests.
688
+
689
+ ```js
690
+ I.flushNetworkTraffics();
691
+ ```
692
+
693
+ ### focus
694
+
695
+ Calls [focus][5] on the matching element.
696
+
697
+ Examples:
698
+
699
+ ```js
700
+ I.dontSee('#add-to-cart-btn');
701
+ I.focus('#product-tile')
702
+ I.see('#add-to-cart-bnt');
703
+ ```
704
+
705
+ #### Parameters
706
+
707
+ * `locator` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator.
708
+ * `options` **any?** Playwright only: [Additional options][13] for available options object as 2nd argument.
709
+
710
+ Returns **void** automatically synchronized promise through #recorder
711
+
712
+ ### forceClick
713
+
714
+ Perform an emulated click on a link or a button, given by a locator.
715
+ Unlike normal click instead of sending native event, emulates a click with JavaScript.
716
+ This works on hidden, animated or inactive elements as well.
717
+
718
+ If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
719
+ For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched.
720
+ For images, the "alt" attribute and inner text of any parent links are searched.
721
+
722
+ The second parameter is a context (CSS or XPath locator) to narrow the search.
723
+
724
+ ```js
725
+ // simple link
726
+ I.forceClick('Logout');
727
+ // button of form
728
+ I.forceClick('Submit');
729
+ // CSS button
730
+ I.forceClick('#form input[type=submit]');
731
+ // XPath
732
+ I.forceClick('//form/*[@type=submit]');
733
+ // link in context
734
+ I.forceClick('Logout', '#nav');
735
+ // using strict locator
736
+ I.forceClick({css: 'nav a.login'});
737
+ ```
738
+
739
+ #### Parameters
740
+
741
+ * `locator` **([string][3] | [object][4])** clickable link or button located by text, or any element located by CSS|XPath|strict locator.
742
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element to search in CSS|XPath|Strict locator.
743
+
744
+ Returns **void** automatically synchronized promise through #recorder
745
+
746
+ ### grabAttributeFrom
747
+
748
+ Retrieves an attribute from an element located by CSS or XPath and returns it to test.
749
+ Resumes test execution, so **should be used inside async with `await`** operator.
750
+ If more than one element is found - attribute of first element is returned.
751
+
752
+ ```js
753
+ let hint = await I.grabAttributeFrom('#tooltip', 'title');
754
+ ```
755
+
756
+ #### Parameters
757
+
758
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
759
+ * `attr` **[string][3]** attribute name.
760
+
761
+ Returns **[Promise][12]<[string][3]>** attribute value
762
+
763
+ ### grabAttributeFromAll
764
+
765
+ Retrieves an array of attributes from elements located by CSS or XPath and returns it to test.
766
+ Resumes test execution, so **should be used inside async with `await`** operator.
767
+
768
+ ```js
769
+ let hints = await I.grabAttributeFromAll('.tooltip', 'title');
770
+ ```
771
+
772
+ #### Parameters
773
+
774
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
775
+ * `attr` **[string][3]** attribute name.
776
+
777
+ Returns **[Promise][12]<[Array][14]<[string][3]>>** attribute value
778
+
779
+ ### grabCookie
780
+
781
+ Gets a cookie object by name.
782
+ If none provided gets all cookies.
783
+ Resumes test execution, so **should be used inside async function with `await`** operator.
784
+
785
+ ```js
786
+ let cookie = await I.grabCookie('auth');
787
+ assert(cookie.value, '123456');
788
+ ```
789
+
790
+ #### Parameters
791
+
792
+ * `name` **[string][3]?** cookie name.
793
+
794
+ Returns **any** attribute value
795
+
796
+ ### grabCookies
797
+
798
+ Retrieves all cookies visible to the current page.
799
+ Resumes test execution, so **should be used inside async function with `await`** operator.
800
+
801
+ ```js
802
+ let cookies = await I.grabCookies();
803
+ ```
804
+
805
+ Returns **[Promise][12]<[Array][14]<CodeceptJS.Cookie>>** array of cookie objects.
806
+
807
+ ### grabCssPropertyFrom
808
+
809
+ Grab CSS property for given locator
810
+ Resumes test execution, so **should be used inside an async function with `await`** operator.
811
+ If more than one element is found - value of first element is returned.
812
+
813
+ ```js
814
+ const value = await I.grabCssPropertyFrom('h3', 'font-weight');
815
+ ```
816
+
817
+ #### Parameters
818
+
819
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
820
+ * `cssProperty` **[string][3]** CSS property name.
821
+
822
+ Returns **[Promise][12]<[string][3]>** CSS value
823
+
824
+ ### grabCssPropertyFromAll
825
+
826
+ Grab array of CSS properties for given locator
827
+ Resumes test execution, so **should be used inside an async function with `await`** operator.
828
+
829
+ ```js
830
+ const values = await I.grabCssPropertyFromAll('h3', 'font-weight');
831
+ ```
832
+
833
+ #### Parameters
834
+
835
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
836
+ * `cssProperty` **[string][3]** CSS property name.
837
+
838
+ Returns **[Promise][12]<[Array][14]<[string][3]>>** CSS value
839
+
840
+ ### grabCurrentUrl
841
+
842
+ Get current URL from browser.
843
+ Resumes test execution, so should be used inside an async function.
844
+
845
+ ```js
846
+ let url = await I.grabCurrentUrl();
847
+ console.log(`Current URL is [${url}]`);
848
+ ```
849
+
850
+ Returns **[Promise][12]<[string][3]>** current URL
851
+
852
+ ### grabFromClipboard
853
+
854
+ Grabs the text content of the system clipboard and returns it to test.
855
+ Resumes test execution, so **should be used inside async function with `await`** operator.
856
+
857
+ ```js
858
+ I.click('Copy to clipboard');
859
+ let url = await I.grabFromClipboard();
860
+ ```
861
+
862
+ Reading the clipboard requires a secure context (`https` or `localhost`) and is supported
863
+ in Chromium-based browsers, where read access is granted automatically.
864
+
865
+ Returns **[Promise][12]<[string][3]>** the system clipboard contents.
866
+
867
+ ### grabHTMLFrom
868
+
869
+ Retrieves the innerHTML from an element located by CSS or XPath and returns it to test.
870
+ Resumes test execution, so **should be used inside async function with `await`** operator.
871
+ If more than one element is found - HTML of first element is returned.
872
+
873
+ ```js
874
+ let postHTML = await I.grabHTMLFrom('#post');
875
+ ```
876
+
877
+ #### Parameters
878
+
879
+ * `locator` &#x20;
880
+ * `element` **([string][3] | [object][4])** located by CSS|XPath|strict locator.
881
+
882
+ Returns **[Promise][12]<[string][3]>** HTML code for an element
883
+
884
+ ### grabHTMLFromAll
885
+
886
+ Retrieves all the innerHTML from elements located by CSS or XPath and returns it to test.
887
+ Resumes test execution, so **should be used inside async function with `await`** operator.
888
+
889
+ ```js
890
+ let postHTMLs = await I.grabHTMLFromAll('.post');
891
+ ```
892
+
893
+ #### Parameters
894
+
895
+ * `locator` &#x20;
896
+ * `element` **([string][3] | [object][4])** located by CSS|XPath|strict locator.
897
+
898
+ Returns **[Promise][12]<[Array][14]<[string][3]>>** HTML code for an element
899
+
900
+ ### grabNumberOfElements
901
+
902
+ Grab number of elements by locator.
903
+ Resumes test execution, so **should be used inside async function with `await`** operator.
904
+
905
+ ```js
906
+ let numOfElements = await I.grabNumberOfElements('p');
907
+ ```
908
+
909
+ #### Parameters
910
+
911
+ * `locator` **([string][3] | [object][4])** located by CSS|XPath|strict locator.
912
+
913
+ Returns **[Promise][12]<[number][8]>** number of matched elements.
914
+
915
+ ### grabNumberOfVisibleElements
916
+
917
+ Grab number of visible elements by locator.
918
+ Resumes test execution, so **should be used inside async function with `await`** operator.
919
+
920
+ ```js
921
+ let numOfElements = await I.grabNumberOfVisibleElements('p');
922
+ ```
923
+
924
+ #### Parameters
925
+
926
+ * `locator` **([string][3] | [object][4])** located by CSS|XPath|strict locator.
927
+
928
+ Returns **[Promise][12]<[number][8]>** number of visible elements
929
+
930
+ ### grabPageScrollPosition
931
+
932
+ Retrieves a page scroll position and returns it to test.
933
+ Resumes test execution, so **should be used inside an async function with `await`** operator.
934
+
935
+ ```js
936
+ let { x, y } = await I.grabPageScrollPosition();
937
+ ```
938
+
939
+ Returns **[Promise][12]<PageScrollPosition>** scroll position
940
+
941
+ ### grabRecordedNetworkTraffics
942
+
943
+ Grab the recording network traffics
944
+
945
+ ```js
946
+ const traffics = await I.grabRecordedNetworkTraffics();
947
+ expect(traffics[0].url).to.equal('https://reqres.in/api/comments/1');
948
+ expect(traffics[0].response.status).to.equal(200);
949
+ expect(traffics[0].response.body).to.contain({ name: 'this was mocked' });
950
+ ```
951
+
952
+ Returns **[Array][14]** recorded network traffics
953
+
954
+ ### grabSource
955
+
956
+ Retrieves page source and returns it to test.
957
+ Resumes test execution, so **should be used inside async function with `await`** operator.
958
+
959
+ ```js
960
+ let pageSource = await I.grabSource();
961
+ ```
962
+
963
+ Returns **[Promise][12]<[string][3]>** source code
964
+
965
+ ### grabTextFrom
966
+
967
+ Retrieves a text from an element located by CSS or XPath and returns it to test.
968
+ Resumes test execution, so **should be used inside async with `await`** operator.
969
+
970
+ ```js
971
+ let pin = await I.grabTextFrom('#pin');
972
+ ```
973
+
974
+ If multiple elements found returns first element.
975
+
976
+ #### Parameters
977
+
978
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
979
+
980
+ Returns **[Promise][12]<[string][3]>** attribute value
981
+
982
+ ### grabTextFromAll
983
+
984
+ Retrieves all texts from an element located by CSS or XPath and returns it to test.
985
+ Resumes test execution, so **should be used inside async with `await`** operator.
986
+
987
+ ```js
988
+ let pins = await I.grabTextFromAll('#pin li');
989
+ ```
990
+
991
+ #### Parameters
992
+
993
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
994
+
995
+ Returns **[Promise][12]<[Array][14]<[string][3]>>** attribute value
996
+
997
+ ### grabTitle
998
+
999
+ Retrieves a page title and returns it to test.
1000
+ Resumes test execution, so **should be used inside async with `await`** operator.
1001
+
1002
+ ```js
1003
+ let title = await I.grabTitle();
1004
+ ```
1005
+
1006
+ Returns **[Promise][12]<[string][3]>** title
1007
+
1008
+ ### grabValueFrom
1009
+
1010
+ Retrieves a value from a form element located by CSS or XPath and returns it to test.
1011
+ Resumes test execution, so **should be used inside async function with `await`** operator.
1012
+ If more than one element is found - value of first element is returned.
1013
+
1014
+ ```js
1015
+ let email = await I.grabValueFrom('input[name=email]');
1016
+ ```
1017
+
1018
+ #### Parameters
1019
+
1020
+ * `locator` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator.
1021
+
1022
+ Returns **[Promise][12]<[string][3]>** attribute value
1023
+
1024
+ ### grabValueFromAll
1025
+
1026
+ Retrieves an array of value from a form located by CSS or XPath and returns it to test.
1027
+ Resumes test execution, so **should be used inside async function with `await`** operator.
1028
+
1029
+ ```js
1030
+ let inputs = await I.grabValueFromAll('//form/input');
1031
+ ```
1032
+
1033
+ #### Parameters
1034
+
1035
+ * `locator` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator.
1036
+
1037
+ Returns **[Promise][12]<[Array][14]<[string][3]>>** attribute value
1038
+
1039
+ ### grabWebElement
1040
+
1041
+ Grab WebElement for given locator
1042
+ Resumes test execution, so **should be used inside an async function with `await`** operator.
1043
+
1044
+ ```js
1045
+ const webElement = await I.grabWebElement('#button');
1046
+ ```
1047
+
1048
+ #### Parameters
1049
+
1050
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
1051
+
1052
+ Returns **[Promise][12]<any>** WebElement of being used Web helper
1053
+
1054
+ ### grabWebElements
1055
+
1056
+ Grab WebElements for given locator
1057
+ Resumes test execution, so **should be used inside an async function with `await`** operator.
1058
+
1059
+ ```js
1060
+ const webElements = await I.grabWebElements('#button');
1061
+ ```
1062
+
1063
+ #### Parameters
1064
+
1065
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
1066
+
1067
+ Returns **[Promise][12]<any>** WebElement of being used Web helper
1068
+
1069
+ ### pressKey
1070
+
1071
+ Presses a key or a key combination on the focused element.
1072
+
1073
+ ```js
1074
+ I.pressKey('Enter');
1075
+ I.pressKey(['Control', 'a']);
1076
+ ```
1077
+
1078
+ #### Parameters
1079
+
1080
+ * `key` **([string][3] | [Array][14]<[string][3]>)** a key or an array of keys to combine (modifiers first).
1081
+
1082
+ Returns **void** automatically synchronized promise through #recorder
1083
+
1084
+ ### refreshPage
1085
+
1086
+ Reload the current page.
1087
+
1088
+ ```js
1089
+ I.refreshPage();
1090
+ ```
1091
+
1092
+ Returns **void** automatically synchronized promise through #recorder
1093
+
1094
+ ### resizeWindow
1095
+
1096
+ Resize the current window to provided width and height.
1097
+ First parameter can be set to `maximize`.
1098
+
1099
+ #### Parameters
1100
+
1101
+ * `width` **[number][8]** width in pixels or `maximize`.
1102
+ * `height` **[number][8]** height in pixels.
1103
+
1104
+ Returns **void** automatically synchronized promise through #recorder
1105
+
1106
+ ### rightClick
1107
+
1108
+ Performs right click on a clickable element matched by semantic locator, CSS or XPath.
1109
+
1110
+ ```js
1111
+ // right click element with id el
1112
+ I.rightClick('#el');
1113
+ // right click link or button with text "Click me"
1114
+ I.rightClick('Click me');
1115
+ // right click button with text "Click me" inside .context
1116
+ I.rightClick('Click me', '.context');
1117
+ ```
1118
+
1119
+ #### Parameters
1120
+
1121
+ * `locator` **([string][3] | [object][4])** clickable element located by CSS|XPath|strict locator.
1122
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS|XPath|strict locator.
1123
+
1124
+ Returns **void** automatically synchronized promise through #recorder
1125
+
1126
+ ### saveElementScreenshot
1127
+
1128
+ Saves screenshot of the specified locator to ouput folder (set in codecept.conf.ts or codecept.conf.js).
1129
+ Filename is relative to output folder.
1130
+
1131
+ ```js
1132
+ I.saveElementScreenshot(`#submit`,'debug.png');
1133
+ ```
1134
+
1135
+ #### Parameters
1136
+
1137
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
1138
+ * `fileName` **[string][3]** file name to save.
1139
+
1140
+ Returns **void** automatically synchronized promise through #recorder
1141
+
1142
+ ### saveScreenshot
1143
+
1144
+ Saves a screenshot to the output folder (set in codecept.conf.ts or codecept.conf.js).
1145
+ Filename is relative to the output folder.
1146
+
1147
+ ```js
1148
+ I.saveScreenshot('debug.png');
1149
+ ```
1150
+
1151
+ #### Parameters
1152
+
1153
+ * `fileName` **[string][3]** file name to save.
1154
+
1155
+ Returns **void** automatically synchronized promise through #recorder
1156
+
1157
+ ### scrollPageToBottom
1158
+
1159
+ Scroll page to the bottom.
1160
+
1161
+ ```js
1162
+ I.scrollPageToBottom();
1163
+ ```
1164
+
1165
+ Returns **void** automatically synchronized promise through #recorder
1166
+
1167
+ ### scrollPageToTop
1168
+
1169
+ Scroll page to the top.
1170
+
1171
+ ```js
1172
+ I.scrollPageToTop();
1173
+ ```
1174
+
1175
+ Returns **void** automatically synchronized promise through #recorder
1176
+
1177
+ ### scrollTo
1178
+
1179
+ Scrolls to element matched by locator.
1180
+ Extra shift can be set with offsetX and offsetY options.
1181
+
1182
+ ```js
1183
+ I.scrollTo('footer');
1184
+ I.scrollTo('#submit', 5, 5);
1185
+ ```
1186
+
1187
+ #### Parameters
1188
+
1189
+ * `locator` **([string][3] | [object][4])** located by CSS|XPath|strict locator.
1190
+ * `offsetX` **[number][8]** (optional, `0` by default) X-axis offset.
1191
+ * `offsetY` **[number][8]** (optional, `0` by default) Y-axis offset.
1192
+
1193
+ Returns **void** automatically synchronized promise through #recorder
1194
+
1195
+ ### see
1196
+
1197
+ Checks that a page contains a visible text.
1198
+ Use context parameter to narrow down the search.
1199
+
1200
+ ```js
1201
+ I.see('Welcome'); // text welcome on a page
1202
+ I.see('Welcome', '.content'); // text inside .content div
1203
+ I.see('Register', {css: 'form.register'}); // use strict locator
1204
+ ```
1205
+
1206
+ #### Parameters
1207
+
1208
+ * `text` **[string][3]** expected on page.
1209
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text.
1210
+
1211
+ Returns **void** automatically synchronized promise through #recorder
1212
+
1213
+ ### seeAttributesOnElements
1214
+
1215
+ Checks that all elements with given locator have given attributes.
1216
+
1217
+ ```js
1218
+ I.seeAttributesOnElements('//form', { method: "post"});
1219
+ ```
1220
+
1221
+ #### Parameters
1222
+
1223
+ * `locator` **([string][3] | [object][4])** located by CSS|XPath|strict locator.
1224
+ * `attributes` **[object][4]** attributes and their values to check.
1225
+
1226
+ Returns **void** automatically synchronized promise through #recorder
1227
+
1228
+ ### seeCheckboxIsChecked
1229
+
1230
+ Verifies that the specified checkbox is checked.
1231
+
1232
+ ```js
1233
+ I.seeCheckboxIsChecked('Agree');
1234
+ I.seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms
1235
+ I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'});
1236
+ ```
1237
+
1238
+ #### Parameters
1239
+
1240
+ * `locator` &#x20;
1241
+ * `field` **([string][3] | [object][4])** located by label|name|CSS|XPath|strict locator.
1242
+
1243
+ Returns **void** automatically synchronized promise through #recorder
1244
+
1245
+ ### seeClipboardEquals
1246
+
1247
+ Checks that the system clipboard is equal to the given text.
1248
+
1249
+ ```js
1250
+ I.click('Copy to clipboard');
1251
+ I.seeClipboardEquals('https://codecept.io');
1252
+ ```
1253
+
1254
+ Reading the clipboard requires a secure context (`https` or `localhost`) and is supported
1255
+ in Chromium-based browsers, where read access is granted automatically.
1256
+
1257
+ #### Parameters
1258
+
1259
+ * `text` **[string][3]** value to check.
1260
+
1261
+ Returns **void** automatically synchronized promise through #recorder
1262
+
1263
+ ### seeCookie
1264
+
1265
+ Checks that cookie with given name exists.
1266
+
1267
+ ```js
1268
+ I.seeCookie('Auth');
1269
+ ```
1270
+
1271
+ #### Parameters
1272
+
1273
+ * `name` **[string][3]** cookie name.
1274
+
1275
+ Returns **void** automatically synchronized promise through #recorder
1276
+
1277
+ ### seeCssPropertiesOnElements
1278
+
1279
+ Checks that all elements with given locator have given CSS properties.
1280
+
1281
+ ```js
1282
+ I.seeCssPropertiesOnElements('h3', { 'font-weight': "bold"});
1283
+ ```
1284
+
1285
+ #### Parameters
1286
+
1287
+ * `locator` **([string][3] | [object][4])** located by CSS|XPath|strict locator.
1288
+ * `cssProperties` **[object][4]** object with CSS properties and their values to check.
1289
+
1290
+ Returns **void** automatically synchronized promise through #recorder
1291
+
1292
+ ### seeCurrentPathEquals
1293
+
1294
+ Checks that current URL path matches the expected path.
1295
+ Query strings and URL fragments are ignored.
1296
+
1297
+ ```js
1298
+ I.seeCurrentPathEquals('/info'); // passes for '/info', '/info?user=1', '/info#section'
1299
+ I.seeCurrentPathEquals('/'); // passes for '/', '/?user=ok', '/#top'
1300
+ ```
1301
+
1302
+ #### Parameters
1303
+
1304
+ * `path` **[string][3]** value to check.
1305
+
1306
+ Returns **void** automatically synchronized promise through #recorder
1307
+
1308
+ ### seeCurrentUrlEquals
1309
+
1310
+ Checks that current url is equal to provided one.
1311
+ If a relative url provided, a configured url will be prepended to it.
1312
+ So both examples will work:
1313
+
1314
+ ```js
1315
+ I.seeCurrentUrlEquals('/register');
1316
+ I.seeCurrentUrlEquals('http://my.site.com/register');
1317
+ ```
1318
+
1319
+ #### Parameters
1320
+
1321
+ * `url` **[string][3]** value to check.
1322
+
1323
+ Returns **void** automatically synchronized promise through #recorder
1324
+
1325
+ ### seeElement
1326
+
1327
+ Checks that a given Element is visible
1328
+ Element is located by CSS or XPath.
1329
+
1330
+ The second parameter is a context (CSS or XPath locator) to narrow the search.
1331
+
1332
+ ```js
1333
+ I.seeElement('#modal');
1334
+ I.seeElement('#modal', '#container');
1335
+ // using ARIA role locator
1336
+ I.seeElement({role: 'dialog'});
1337
+ ```
1338
+
1339
+ > ℹ️ ARIA role locators (`{role, name}`) match elements the way assistive technology does and survive markup refactors. See [Locators][7].
1340
+
1341
+ #### Parameters
1342
+
1343
+ * `locator` **([string][3] | [object][4])** located by CSS|XPath|strict locator.
1344
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
1345
+
1346
+ Returns **void** automatically synchronized promise through #recorder
1347
+
1348
+ ### seeElementInDOM
1349
+
1350
+ Checks that a given Element is present in the DOM
1351
+ Element is located by CSS or XPath.
1352
+
1353
+ ```js
1354
+ I.seeElementInDOM('#modal');
1355
+ ```
1356
+
1357
+ #### Parameters
1358
+
1359
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
1360
+
1361
+ Returns **void** automatically synchronized promise through #recorder
1362
+
1363
+ ### seeInClipboard
1364
+
1365
+ Checks that the system clipboard contains the given text.
1366
+
1367
+ ```js
1368
+ I.click('Copy to clipboard');
1369
+ I.seeInClipboard('https://codecept.io');
1370
+ ```
1371
+
1372
+ Reading the clipboard requires a secure context (`https` or `localhost`) and is supported
1373
+ in Chromium-based browsers, where read access is granted automatically.
1374
+
1375
+ #### Parameters
1376
+
1377
+ * `text` **[string][3]** value to check.
1378
+
1379
+ Returns **void** automatically synchronized promise through #recorder
1380
+
1381
+ ### seeInCurrentUrl
1382
+
1383
+ Checks that current url contains a provided fragment.
1384
+
1385
+ ```js
1386
+ I.seeInCurrentUrl('/register'); // we are on registration page
1387
+ ```
1388
+
1389
+ #### Parameters
161
1390
 
162
- In ATTACH mode, connects exactly as `CDPBrowser._connect` would. In SELF-MANAGED mode,
163
- resolves and spawns `obscura serve` (or courtesy-attaches to an already-running one on
164
- :9222) exactly once via `_resolveSelfManaged`, then connects.
1391
+ * `url` **[string][3]** a fragment to check
165
1392
 
166
- A spawn failure (e.g. a bad binary) is delivered asynchronously by Node as an `error`
167
- event; it is recorded on `this.serverError` and surfaced as a rejection from `_waitForServer`
168
- instead of crashing the process as an uncaught exception.
1393
+ Returns **void** automatically synchronized promise through #recorder
1394
+
1395
+ ### seeInField
1396
+
1397
+ Checks that the given input field or textarea equals to given value.
1398
+ For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath.
1399
+
1400
+ The third parameter is an optional context (CSS or XPath locator) to narrow the search.
1401
+
1402
+ ```js
1403
+ I.seeInField('Username', 'davert');
1404
+ I.seeInField({css: 'form textarea'},'Type your comment here');
1405
+ I.seeInField('form input[type=hidden]','hidden_value');
1406
+ I.seeInField('#searchform input','Search');
1407
+ // within a context
1408
+ I.seeInField('Name', 'John', '.form-container');
1409
+ ```
1410
+
1411
+ #### Parameters
1412
+
1413
+ * `field` **([string][3] | [object][4])** located by label|name|CSS|XPath|strict locator.
1414
+ * `value` **([string][3] | [object][4])** value to check.
1415
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
1416
+
1417
+ Returns **void** automatically synchronized promise through #recorder
1418
+
1419
+ ### seeInSource
1420
+
1421
+ Checks that the current page contains the given string in its raw source code.
1422
+
1423
+ ```js
1424
+ I.seeInSource('<h1>Green eggs &amp; ham</h1>');
1425
+ ```
1426
+
1427
+ #### Parameters
1428
+
1429
+ * `text` **[string][3]** value to check.
1430
+
1431
+ Returns **void** automatically synchronized promise through #recorder
1432
+
1433
+ ### seeInTitle
1434
+
1435
+ Checks that title contains text.
1436
+
1437
+ ```js
1438
+ I.seeInTitle('Home Page');
1439
+ ```
1440
+
1441
+ #### Parameters
1442
+
1443
+ * `text` **[string][3]** text value to check.
1444
+
1445
+ Returns **void** automatically synchronized promise through #recorder
1446
+
1447
+ ### seeNumberOfVisibleElements
1448
+
1449
+ Asserts that an element is visible a given number of times.
1450
+ Element is located by CSS or XPath.
1451
+
1452
+ ```js
1453
+ I.seeNumberOfVisibleElements('.buttons', 3);
1454
+ ```
1455
+
1456
+ #### Parameters
1457
+
1458
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
1459
+ * `num` **[number][8]** number of elements.
1460
+
1461
+ Returns **void** automatically synchronized promise through #recorder
1462
+
1463
+ ### seeTraffic
1464
+
1465
+ Verifies that a certain request is part of network traffic.
1466
+
1467
+ ```js
1468
+ // checking the request url contains certain query strings
1469
+ I.amOnPage('https://openai.com/blog/chatgpt');
1470
+ I.startRecordingTraffic();
1471
+ await I.seeTraffic({
1472
+ name: 'sentry event',
1473
+ url: 'https://images.openai.com/blob/cf717bdb-0c8c-428a-b82b-3c3add87a600',
1474
+ parameters: {
1475
+ width: '1919',
1476
+ height: '1138',
1477
+ },
1478
+ });
1479
+ ```
1480
+
1481
+ ```js
1482
+ // checking the request url contains certain post data
1483
+ I.amOnPage('https://openai.com/blog/chatgpt');
1484
+ I.startRecordingTraffic();
1485
+ await I.seeTraffic({
1486
+ name: 'event',
1487
+ url: 'https://cloudflareinsights.com/cdn-cgi/rum',
1488
+ requestPostData: {
1489
+ st: 2,
1490
+ },
1491
+ });
1492
+ ```
1493
+
1494
+ #### Parameters
1495
+
1496
+ * `opts` **[Object][4]** options when checking the traffic network.
1497
+
1498
+ * `opts.name` **[string][3]** A name of that request. Can be any value. Only relevant to have a more meaningful error message in case of fail.
1499
+ * `opts.url` **[string][3]** Expected URL of request in network traffic
1500
+ * `opts.parameters` **[Object][4]?** Expected parameters of that request in network traffic
1501
+ * `opts.requestPostData` **[Object][4]?** Expected that request contains post data in network traffic
1502
+ * `opts.timeout` **[number][8]?** Timeout to wait for request in seconds. Default is 10 seconds.
1503
+
1504
+ Returns **void** automatically synchronized promise through #recorder
1505
+
1506
+ ### selectOption
1507
+
1508
+ Selects an option in a drop-down select.
1509
+ Field is searched by label | name | CSS | XPath.
1510
+ Option is selected by visible text or by value.
1511
+
1512
+ The third parameter is an optional context (CSS or XPath locator) to narrow the search.
1513
+
1514
+ ```js
1515
+ I.selectOption('Choose Plan', 'Monthly'); // select by label
1516
+ I.selectOption('subscription', 'Monthly'); // match option by text
1517
+ I.selectOption('subscription', '0'); // or by value
1518
+ I.selectOption('//form/select[@name=account]','Premium');
1519
+ I.selectOption('form select[name=account]', 'Premium');
1520
+ I.selectOption({css: 'form select[name=account]'}, 'Premium');
1521
+ // within a context
1522
+ I.selectOption('age', '21-60', '#section2');
1523
+ ```
1524
+
1525
+ Provide an array for the second argument to select multiple options.
1526
+
1527
+ ```js
1528
+ I.selectOption('Which OS do you use?', ['Android', 'iOS']);
1529
+ ```
1530
+
1531
+ #### Parameters
1532
+
1533
+ * `select` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator.
1534
+ * `option` **([string][3] | [Array][14]<any>)** visible text or value of option.
1535
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
1536
+
1537
+ Returns **void** automatically synchronized promise through #recorder
1538
+
1539
+ ### setCookie
1540
+
1541
+ Sets cookie(s).
1542
+
1543
+ Can be a single cookie object or an array of cookies:
1544
+
1545
+ ```js
1546
+ I.setCookie({name: 'auth', value: true});
1547
+
1548
+ // as array
1549
+ I.setCookie([
1550
+ {name: 'auth', value: true},
1551
+ {name: 'agree', value: true}
1552
+ ]);
1553
+ ```
1554
+
1555
+ #### Parameters
1556
+
1557
+ * `cookie` **(Cookie | [Array][14]<Cookie>)** a cookie object or array of cookie objects.
1558
+
1559
+ Returns **void** automatically synchronized promise through #recorder
1560
+
1561
+ ### startRecordingTraffic
1562
+
1563
+ Starts recording the network traffics.
1564
+ This also resets recorded network requests.
1565
+
1566
+ ```js
1567
+ I.startRecordingTraffic();
1568
+ ```
1569
+
1570
+ Returns **void** automatically synchronized promise through #recorder
1571
+
1572
+ ### startScreencast
1573
+
1574
+ Starts recording a video of the page. Stop it with `stopScreencast`.
1575
+ Usually enabled through the `screencast` plugin rather than called directly.
1576
+
1577
+ ```js
1578
+ I.startScreencast();
1579
+ ```
1580
+
1581
+ #### Parameters
1582
+
1583
+ * `options` **[object][4]?** `{ maxWidth, maxHeight, quality, everyNthFrame }`
1584
+
1585
+ Returns **void** automatically synchronized promise through #recorder
1586
+
1587
+ ### stopRecordingTraffic
1588
+
1589
+ Stops recording of network traffic. Recorded traffic is not flashed.
1590
+
1591
+ ```js
1592
+ I.stopRecordingTraffic();
1593
+ ```
1594
+
1595
+ ### stopScreencast
1596
+
1597
+ Stops the recording started by `startScreencast` and returns it as an animated PNG.
1598
+
1599
+ ```js
1600
+ const video = await I.stopScreencast();
1601
+ ```
1602
+
1603
+ #### Parameters
1604
+
1605
+ * `options` **[object][4]?** `{ lastFrameDelayMs }`: how long the last frame is shown, in milliseconds (1000 by default).
1606
+
1607
+ Returns **[Promise][12]<([Buffer][15] | null)>** APNG data, or `null` if no frames were recorded.
1608
+
1609
+ ### type
1610
+
1611
+ Types out the given text into an active field.
1612
+ To slow down typing use a second parameter, to set interval between key presses.
1613
+ *Note:* Should be used when [`fillField`][16] is not an option.
1614
+
1615
+ ```js
1616
+ // passing in a string
1617
+ I.type('Type this out.');
1618
+
1619
+ // typing values with a 100ms interval
1620
+ I.type('4141555311111111', 100);
1621
+
1622
+ // passing in an array
1623
+ I.type(['T', 'E', 'X', 'T']);
1624
+
1625
+ // passing a secret
1626
+ I.type(secret('123456'));
1627
+ ```
1628
+
1629
+ #### Parameters
1630
+
1631
+ * `keys` &#x20;
1632
+ * `delay` **[number][8]?** (optional) delay in ms between key presses
1633
+ * `key` **([string][3] | [Array][14]<[string][3]>)** or array of keys to type.
1634
+
1635
+ Returns **void** automatically synchronized promise through #recorder
1636
+
1637
+ ### uncheckOption
1638
+
1639
+ Unselects a checkbox or radio button.
1640
+ Element is located by label or name or CSS or XPath.
1641
+
1642
+ The second parameter is an optional context (CSS or XPath locator) to narrow the search.
1643
+
1644
+ ```js
1645
+ I.uncheckOption('#agree');
1646
+ I.uncheckOption('I Agree to Terms and Conditions');
1647
+ I.uncheckOption('agree', '//form');
1648
+ ```
1649
+
1650
+ #### Parameters
1651
+
1652
+ * `field` **([string][3] | [object][4])** checkbox located by label | name | CSS | XPath | strict locator.
1653
+ * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
1654
+
1655
+ Returns **void** automatically synchronized promise through #recorder
1656
+
1657
+ ### wait
1658
+
1659
+ Pauses execution for a number of seconds.
1660
+
1661
+ ```js
1662
+ I.wait(2); // wait 2 secs
1663
+ ```
1664
+
1665
+ #### Parameters
1666
+
1667
+ * `sec` **[number][8]** number of second to wait.
1668
+
1669
+ Returns **void** automatically synchronized promise through #recorder
1670
+
1671
+ ### waitCurrentPathEquals
1672
+
1673
+ Waits for the current URL path to match the expected path.
1674
+ Query strings and URL fragments are ignored.
1675
+
1676
+ ```js
1677
+ I.waitCurrentPathEquals('/info', 5);
1678
+ ```
1679
+
1680
+ #### Parameters
1681
+
1682
+ * `path` **[string][3]** value to check.
1683
+ * `sec` **[number][8]?** (optional, `waitForTimeout` by default) time in seconds to wait
1684
+
1685
+ Returns **void** automatically synchronized promise through #recorder
1686
+
1687
+ ### waitForCookie
1688
+
1689
+ Waits for the specified cookie in the cookies.
1690
+
1691
+ ```js
1692
+ I.waitForCookie("token");
1693
+ ```
1694
+
1695
+ #### Parameters
1696
+
1697
+ * `name` **[string][3]** expected cookie name.
1698
+ * `sec` **[number][8]** (optional, `3` by default) time in seconds to wait
1699
+
1700
+ Returns **void** automatically synchronized promise through #recorder
1701
+
1702
+ ### waitForDetached
1703
+
1704
+ Waits for an element to become not attached to the DOM on a page (by default waits for 1sec).
1705
+ Element can be located by CSS or XPath.
1706
+
1707
+ ```js
1708
+ I.waitForDetached('#popup');
1709
+ ```
1710
+
1711
+ #### Parameters
1712
+
1713
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
1714
+ * `sec` **[number][8]** (optional, `1` by default) time in seconds to wait
1715
+
1716
+ Returns **void** automatically synchronized promise through #recorder
1717
+
1718
+ ### waitForElement
1719
+
1720
+ Waits for element to be present on page (by default waits for 1sec).
1721
+ Element can be located by CSS or XPath.
1722
+
1723
+ ```js
1724
+ I.waitForElement('.btn.continue');
1725
+ I.waitForElement('.btn.continue', 5); // wait for 5 secs
1726
+ ```
1727
+
1728
+ #### Parameters
1729
+
1730
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
1731
+ * `sec` **[number][8]?** (optional, `1` by default) time in seconds to wait
1732
+
1733
+ Returns **void** automatically synchronized promise through #recorder
1734
+
1735
+ ### waitForFunction
1736
+
1737
+ Waits for a function to return true (waits for 1 sec by default).
1738
+ Running in browser context.
1739
+
1740
+ ```js
1741
+ I.waitForFunction(fn[, [args[, timeout]])
1742
+ ```
1743
+
1744
+ ```js
1745
+ I.waitForFunction(() => window.requests == 0);
1746
+ I.waitForFunction(() => window.requests == 0, 5); // waits for 5 sec
1747
+ I.waitForFunction((count) => window.requests == count, [3], 5) // pass args and wait for 5 sec
1748
+ ```
1749
+
1750
+ #### Parameters
1751
+
1752
+ * `fn` **([string][3] | [function][11])** to be executed in browser context.
1753
+ * `argsOrSec` **([Array][14]<any> | [number][8])?** (optional, `1` by default) arguments for function or seconds.
1754
+ * `sec` **[number][8]?** (optional, `1` by default) time in seconds to wait
1755
+
1756
+ Returns **void** automatically synchronized promise through #recorder
1757
+
1758
+ ### waitForInvisible
1759
+
1760
+ Waits for an element to be removed or become invisible on a page (by default waits for 1sec).
1761
+ Element can be located by CSS or XPath.
1762
+
1763
+ ```js
1764
+ I.waitForInvisible('#popup');
1765
+ ```
1766
+
1767
+ #### Parameters
1768
+
1769
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
1770
+ * `sec` **[number][8]** (optional, `1` by default) time in seconds to wait
1771
+
1772
+ Returns **void** automatically synchronized promise through #recorder
1773
+
1774
+ ### waitForText
1775
+
1776
+ Waits for a text to appear (by default waits for 1sec).
1777
+ Element can be located by CSS or XPath.
1778
+ Narrow down search results by providing context.
1779
+
1780
+ ```js
1781
+ I.waitForText('Thank you, form has been submitted');
1782
+ I.waitForText('Thank you, form has been submitted', 5, '#modal');
1783
+ ```
1784
+
1785
+ #### Parameters
1786
+
1787
+ * `text` **[string][3]** to wait for.
1788
+ * `sec` **[number][8]** (optional, `1` by default) time in seconds to wait
1789
+ * `context` **([string][3] | [object][4])?** (optional) element located by CSS|XPath|strict locator.
1790
+
1791
+ Returns **void** automatically synchronized promise through #recorder
1792
+
1793
+ ### waitForVisible
1794
+
1795
+ Waits for an element to become visible on a page (by default waits for 1sec).
1796
+ Element can be located by CSS or XPath.
1797
+
1798
+ ```js
1799
+ I.waitForVisible('#popup');
1800
+ ```
1801
+
1802
+ #### Parameters
1803
+
1804
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
1805
+ * `sec` **[number][8]** (optional, `1` by default) time in seconds to wait
1806
+
1807
+ Returns **void** automatically synchronized promise through #recorder
1808
+
1809
+ ### waitInUrl
1810
+
1811
+ Waiting for the part of the URL to match the expected. Useful for SPA to understand that page was changed.
1812
+
1813
+ ```js
1814
+ I.waitInUrl('/info', 2);
1815
+ ```
1816
+
1817
+ #### Parameters
1818
+
1819
+ * `urlPart` **[string][3]** value to check.
1820
+ * `sec` **[number][8]** (optional, `1` by default) time in seconds to wait
1821
+
1822
+ Returns **void** automatically synchronized promise through #recorder
1823
+
1824
+ ### waitToHide
1825
+
1826
+ Waits for an element to hide (by default waits for 1sec).
1827
+ Element can be located by CSS or XPath.
1828
+
1829
+ ```js
1830
+ I.waitToHide('#popup');
1831
+ ```
1832
+
1833
+ #### Parameters
1834
+
1835
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
1836
+ * `sec` **[number][8]** (optional, `1` by default) time in seconds to wait
1837
+
1838
+ Returns **void** automatically synchronized promise through #recorder
1839
+
1840
+ ### waitUrlEquals
1841
+
1842
+ Waits for the entire URL to match the expected
1843
+
1844
+ ```js
1845
+ I.waitUrlEquals('/info', 2);
1846
+ I.waitUrlEquals('http://127.0.0.1:8000/info');
1847
+ ```
1848
+
1849
+ #### Parameters
1850
+
1851
+ * `urlPart` **[string][3]** value to check.
1852
+ * `sec` **[number][8]** (optional, `1` by default) time in seconds to wait
1853
+
1854
+ Returns **void** automatically synchronized promise through #recorder
1855
+
1856
+ ### _connect
1857
+
1858
+ In SELF-MANAGED mode, resolves and spawns the browser server (or courtesy-attaches to an
1859
+ already-running one on :9222) exactly once via `_resolveSelfManaged`. Then resolves the CDP
1860
+ endpoint and opens the underlying `CDPConnection`, storing it on `this.cdp`.
169
1861
 
170
1862
  ### _findFreePort
171
1863
 
172
- Picks a free TCP port on 127.0.0.1 by briefly listening on port 0 and reading back the OS-assigned
173
- port. Used as the SELF-LAUNCH default when `options.port` isn't explicitly set, so multiple
174
- `run-workers` workers never collide on the same port.
1864
+ Picks a free TCP port on 127.0.0.1 by briefly listening on port 0 and reading back the
1865
+ OS-assigned port. Used when `options.port` isn't explicitly set, so multiple `run-workers`
1866
+ workers never collide on the same port.
175
1867
 
176
- Returns **[Promise][3]<[number][4]>** a free port.
1868
+ Returns **[Promise][12]<[number][8]>** a free port.
177
1869
 
178
- ### _finishTest
1870
+ ### _manageServer
179
1871
 
180
- Closes the CDP connection (via `CDPBrowser._finishTest`), then kills the `obscura serve`
181
- process spawned by `_connect`, if any (never runs in ATTACH or COURTESY-ATTACH mode, since
182
- `this.serverProcess` is only ever set in SELF-LAUNCH mode). Runs in a `finally` so the process
183
- is always reaped even if closing the CDP connection throws. Sends `SIGTERM` first and waits for
184
- the process to exit; a process that ignores `SIGTERM` is escalated to `SIGKILL` after 5s. The
185
- promise only resolves once the child has actually exited (confirmed via the `exit` event, not
186
- merely once `SIGKILL` was sent — the kernel needs a moment to reap it), with a final safety-net
187
- timeout so a stuck child can never keep the event loop alive even if that confirmation is
188
- somehow lost.
1872
+ Opts a subclass into managing its own browser server process. Called from a subclass
1873
+ constructor with the raw user config and a server descriptor:
1874
+
1875
+ * `name` — binary name looked up on `PATH`, also used in messages
1876
+ * `envVar` — environment variable that may point at the binary
1877
+ * `args(port)` — arguments the binary is spawned with to serve CDP on `port`
1878
+ * `env` — extra environment variables for the spawned process
1879
+ * `releases` — URL shown when no binary can be resolved
1880
+
1881
+ An explicit `endpoint` in the user config always wins: the helper stays in ATTACH mode and
1882
+ never spawns or kills anything. Otherwise the helper becomes SELF-MANAGED and the default
1883
+ `endpoint` is cleared until `_resolveSelfManaged` sets the real one.
1884
+
1885
+ #### Parameters
1886
+
1887
+ * `config` **[object][4]** the config object the helper was constructed with.
1888
+ * `server` **[object][4]** the server descriptor described above.
189
1889
 
190
1890
  ### _probeUp
191
1891
 
192
- Probes a `/json/version`-style URL with a short timeout, used for the COURTESY-ATTACH check.
1892
+ Probes a `/json/version`-style URL with a short timeout, used for the courtesy-attach check.
193
1893
 
194
1894
  #### Parameters
195
1895
 
196
- * `url` **[string][5]**&#x20;
1896
+ * `url` **[string][3]**&#x20;
197
1897
 
198
- Returns **[Promise][3]<[boolean][6]>** true if the URL answered.
1898
+ Returns **[Promise][12]<[boolean][17]>** true if the URL answered.
199
1899
 
200
1900
  ### _resolveBinary
201
1901
 
202
- Resolves the `obscura` binary to spawn, in priority order: `options.binaryPath`, then the
203
- `OBSCURA_PATH` environment variable, then `obscura` on `PATH`. The `PATH` lookup walks the
1902
+ Resolves the binary to spawn, in priority order: `options.binaryPath`, then the server
1903
+ descriptor's environment variable, then its name on `PATH`. The `PATH` lookup walks the
204
1904
  directories itself instead of shelling out to `which`, which does not exist on Windows: on
205
- Windows every `PATHEXT` suffix is tried, so an `obscura.exe` on `PATH` is found too.
1905
+ Windows every `PATHEXT` suffix is tried, so a `.exe` on `PATH` is found too.
206
1906
 
207
- Returns **([string][5] | null)** an absolute or relative path to the binary, or null if none resolved.
1907
+ Returns **([string][3] | null)** an absolute or relative path to the binary, or null if none resolved.
208
1908
 
209
1909
  ### _resolveSelfManaged
210
1910
 
211
- Resolves how to reach Obscura when no explicit `endpoint` was configured, trying, in order:
212
- spawn a binary (`binaryPath` config, then `OBSCURA_PATH` env, then `obscura` on `PATH`),
213
- courtesy-attach to `http://127.0.0.1:9222` if something already answers there, or throw a
214
- loud, actionable error. Sets `this.options.endpoint` as a side effect.
1911
+ Resolves how to reach a SELF-MANAGED browser, trying, in order: spawn a binary
1912
+ (`binaryPath` config, then the descriptor's `envVar`, then its `name` on `PATH`) on
1913
+ `options.port` or a free port, courtesy-attach to `http://127.0.0.1:9222` if something already
1914
+ answers there (never killed by this helper), or throw a loud, actionable error. Sets
1915
+ `this.options.endpoint` as a side effect.
1916
+
1917
+ A spawn failure (e.g. a bad binary) is delivered asynchronously by Node as an `error` event;
1918
+ it is recorded on `this.serverError` and surfaced as a rejection from `_waitForServer` instead
1919
+ of crashing the process as an uncaught exception.
215
1920
 
216
1921
  ### _waitForServer
217
1922
 
218
- Polls `http://127.0.0.1:<port>/json/version` until `obscura serve` responds, `this.serverError`
219
- is set by the spawned process' `error` event, or `options.serverStartTimeout` elapses. The
220
- process typically comes up within tens of milliseconds — a 20ms retry interval (down from a
221
- previous 200ms) keeps the wasted tail after the server is actually ready small, since this cost
222
- is paid once per run and counts directly toward real-world startup latency.
1923
+ Polls `http://127.0.0.1:<port>/json/version` until the spawned server responds,
1924
+ `this.serverError` is set by the process' `error` event, or `options.serverStartTimeout`
1925
+ elapses. The process typically comes up within tens of milliseconds — a 20ms retry interval
1926
+ keeps the wasted tail after the server is actually ready small, since this cost is paid once
1927
+ per run and counts directly toward real-world startup latency.
223
1928
 
224
1929
  [1]: https://github.com/h4ckf0r0day/obscura
225
1930
 
226
1931
  [2]: https://github.com/h4ckf0r0day/obscura/releases
227
1932
 
228
- [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
1933
+ [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
1934
+
1935
+ [4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
1936
+
1937
+ [5]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
1938
+
1939
+ [6]: https://playwright.dev/docs/api/class-locator#locator-blur
1940
+
1941
+ [7]: /locators#aria-locators
1942
+
1943
+ [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
1944
+
1945
+ [9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RegExp
1946
+
1947
+ [10]: https://vuejs.org/v2/api/#Vue-nextTick
1948
+
1949
+ [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function
1950
+
1951
+ [12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
1952
+
1953
+ [13]: https://playwright.dev/docs/api/class-locator#locator-focus
229
1954
 
230
- [4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
1955
+ [14]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
231
1956
 
232
- [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
1957
+ [15]: https://nodejs.org/api/buffer.html
233
1958
 
234
- [6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
1959
+ [16]: #fillfield
235
1960
 
236
- [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
1961
+ [17]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean