codeceptjs 4.2.0-beta.3 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,7 @@
10
10
  | 🌐 Web | Playwright | [![Playwright Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/playwright.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/playwright.yml) |
11
11
  | 🌐 Web | Puppeteer | [![Puppeteer Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/puppeteer.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/puppeteer.yml) |
12
12
  | 🌐 Web | WebDriver | [![WebDriver Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/webdriver.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/webdriver.yml) |
13
+ | 🌐 Web | Obscura | [![Obscura Helper Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/obscura.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/obscura.yml) |
13
14
  | 📱 Mobile | Appium | [![Appium Tests - Android](https://github.com/codeceptjs/CodeceptJS/actions/workflows/appium_Android.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/appium_Android.yml) |
14
15
 
15
16
  # CodeceptJS [![Made in Ukraine](https://img.shields.io/badge/made_in-ukraine-ffd700.svg?labelColor=0057b7)](https://stand-with-ukraine.pp.ua)
@@ -42,6 +43,7 @@ CodeceptJS uses **Helper** modules to provide actions to `I` object. Currently,
42
43
  - [**Playwright**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Playwright.md) - is a Node library to automate the Chromium, WebKit and Firefox browsers with a single API.
43
44
  - [**Puppeteer**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Puppeteer.md) - uses Google Chrome's Puppeteer for fast headless testing.
44
45
  - [**WebDriver**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/WebDriver.md) - uses [webdriverio](http://webdriver.io/) to run tests via WebDriver or Devtools protocol.
46
+ - [**Obscura**](https://codecept.io/helpers/Obscura) - drives the lightweight Obscura browser through Chrome DevTools Protocol. See [Alternative Browser Engines](https://codecept.io/alternative-browsers).
45
47
  - [**Appium**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Appium.md) - for **mobile testing** with Appium
46
48
  - [**Detox**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Detox.md) - This is a wrapper on top of Detox library, aimed to unify testing experience for CodeceptJS framework. Detox provides a grey box testing for mobile applications, playing especially well for React Native apps.
47
49
 
@@ -102,7 +104,7 @@ Later you can even automagically update Type Definitions to include your own cus
102
104
 
103
105
  Note:
104
106
 
105
- - CodeceptJS requires Node.js version `12+` or later.
107
+ - CodeceptJS 4.2 requires Node.js `22.12.0` or later.
106
108
 
107
109
  ## Usage
108
110
 
@@ -5,6 +5,10 @@ title: Alternative Browser Engines
5
5
 
6
6
  # Alternative Browser Engines
7
7
 
8
+ ::: warning Experimental
9
+ The `CDPBrowser`, `Obscura`, and `Kitesurf` helpers are experimental in CodeceptJS 4.2. Pin browser versions in CI and retain Playwright or WebDriver coverage for compatibility-critical tests.
10
+ :::
11
+
8
12
  Playwright and Puppeteer drive full Chromium — the most accurate way to test what users see.
9
13
  But a new class of lightweight, agent-era browsers has appeared, and CodeceptJS can drive them
10
14
  through the `CDPBrowser` helper family:
@@ -12,8 +16,7 @@ through the `CDPBrowser` helper family:
12
16
  - **[Obscura](https://github.com/h4ckf0r0day/obscura)** — an open-source Rust browser with a real
13
17
  V8 engine. From v0.2.0, the default release build also renders — real layout, computed styles,
14
18
  and screenshots — with `-no-render` builds still available for pure-speed, nothing-painted
15
- scraping mode. A single 70 MB binary, ~30 MB RAM per instance, page loads in tens of
16
- milliseconds.
19
+ scraping mode. Release archives are available for Linux, macOS, and Windows.
17
20
  - **[Kitesurf](https://blog.cloudflare.com/kitesurf/)** — Cloudflare's browser that runs in V8
18
21
  isolates on Cloudflare Workers, with a real layout and rendering pipeline. Cloud-only,
19
22
  free in beta, planned to be open-sourced.
@@ -24,10 +27,9 @@ on navigation races.
24
27
 
25
28
  ## When are they better than Playwright?
26
29
 
27
- **Smoke suites where seconds matter.** An Obscura scenario (navigate, fill a form, submit,
28
- assert) completes in 150–500 ms. There is no browser binary to download in CI — a 70 MB
29
- static binary starts instantly. If your PR gate runs 50 smoke scenarios, Obscura turns
30
- minutes into seconds.
30
+ **Smoke suites where startup and execution time matter.** Obscura is distributed as a standalone
31
+ binary and is designed for lightweight browser automation. Benchmark it against your own pages and
32
+ CI environment before choosing it for a PR gate.
31
33
 
32
34
  **Massive parallel scale.** Kitesurf sessions are Cloudflare Workers — they spawn in about a
33
35
  second, cost nothing while idle, and there is no practical ceiling on how many you run at once.
@@ -57,9 +59,8 @@ app's real JavaScript in real V8; it only skips painting. For API-adjacent flows
57
59
  **Constrained environments.** ARM CI runners, thin containers, air-gapped machines:
58
60
  a static binary with no system dependencies goes where Chromium will not.
59
61
 
60
- **Scraping-grade network realism.** Obscura's stealth mode presents a consistent Chrome TLS
61
- fingerprint — useful when your tests must pass through bot-protection layers that block
62
- headless Chromium.
62
+ **Optional stealth builds.** Obscura publishes separate `-stealth` archives. Treat their behaviour
63
+ as an Obscura capability rather than a browser-compatibility guarantee from CodeceptJS.
63
64
 
64
65
  ## When to stay with Playwright
65
66
 
@@ -77,6 +78,10 @@ headless Chromium.
77
78
 
78
79
  ## Configuration
79
80
 
81
+ CodeceptJS 4.2 is tested in CI with Obscura 0.2.2. Obscura 0.2.x is recommended; 0.1.x and
82
+ `-no-render` builds operate without layout, visibility assertions, or screenshots. See
83
+ [Installation](/installation#obscura-experimental) for platform-specific archive names.
84
+
80
85
  helpers: {
81
86
  Obscura: {
82
87
  url: 'http://localhost:3000',
@@ -144,7 +149,7 @@ process — there is nothing to start by hand in the common case:
144
149
  | Screenshots | yes | yes (v0.2.0+ default builds); no on `-no-render`/v0.1.x | yes |
145
150
  | Visibility assertions | yes | yes (v0.2.0+ default builds); no, DOM-presence only, on `-no-render`/v0.1.x | yes |
146
151
  | Screencast / video (`screencast` plugin) | yes — WebM via `page.screencast`, with caption burn-in | yes — APNG via CDP `Page.startScreencast`, assembled in-process (v0.2.0+ default builds; verified PNG frames on the live server); no caption burn-in | untested |
147
- | Startup cost | seconds + ~300 MB install | instant, 70 MB binary | ~1 s, zero local |
152
+ | Startup model | local browser process | standalone local binary | remote cloud session |
148
153
  | Parallel scale | machine-bound | machine-bound (light) | near-unlimited (cloud) |
149
154
  | Where it runs | local/grid | local | Cloudflare only |
150
155
  | License / cost | open source | Apache-2.0 | proprietary, free beta |
@@ -9,7 +9,7 @@ CodeceptJS runs in any CI that can install Node.js. This page covers the setup,
9
9
 
10
10
  ## Setup
11
11
 
12
- - **Node.js** — install it on the runner (`actions/setup-node`, the `node:20` image, `NodeTool@0` on Azure). Examples below use Node 20.
12
+ - **Node.js 22.12 or newer** — install it on the runner (`actions/setup-node`, the `node:22` image, `NodeTool@0` on Azure). Examples below use Node 22.
13
13
  - **Headless** — `codecept.conf.js` must contain `setHeadlessWhen(process.env.HEADLESS || process.env.CI)`. `codeceptjs init` adds it; since CI sets `CI=true`, the suite runs headless automatically.
14
14
 
15
15
  ```js
@@ -61,7 +61,7 @@ Use [`@testomatio/reporter`](https://github.com/testomatio/reporter). It ships p
61
61
 
62
62
  ## CI examples
63
63
 
64
- Each example uses Playwright by default; a WebDriver variant follows where it differs. WebdriverIO 9 downloads its own browser and driver, so the WebDriver variants run on a plain `node:20` image with no Selenium service and no browser-install step. For Playwright, a `node:20` base image plus `npx playwright install --with-deps` keeps these configs free of version pins.
64
+ Each example uses Playwright by default; a WebDriver variant follows where it differs. WebdriverIO 9 downloads its own browser and driver, so the WebDriver variants run on a plain `node:22` image with no Selenium service and no browser-install step. For Playwright, a `node:22` base image plus `npx playwright install --with-deps` keeps these configs free of version pins.
65
65
 
66
66
  ### GitHub Actions — Playwright
67
67
 
@@ -85,7 +85,7 @@ jobs:
85
85
  - uses: actions/checkout@v4
86
86
  - uses: actions/setup-node@v4
87
87
  with:
88
- node-version: 20
88
+ node-version: 22
89
89
  cache: npm
90
90
  - run: npm ci
91
91
  - run: npx playwright install --with-deps chromium
@@ -115,7 +115,7 @@ jobs:
115
115
  - uses: actions/checkout@v4
116
116
  - uses: actions/setup-node@v4
117
117
  with:
118
- node-version: 20
118
+ node-version: 22
119
119
  - run: npm ci
120
120
  - run: npx codeceptjs check
121
121
  - run: npx codeceptjs run-workers 2 --by pool
@@ -142,7 +142,7 @@ jobs:
142
142
  - uses: actions/checkout@v4
143
143
  - uses: actions/setup-node@v4
144
144
  with:
145
- node-version: 20
145
+ node-version: 22
146
146
  - run: npm ci
147
147
  - run: npx playwright install --with-deps chromium
148
148
  - run: npx codeceptjs check
@@ -173,7 +173,7 @@ jobs:
173
173
  - uses: actions/checkout@v4
174
174
  - uses: actions/setup-node@v4
175
175
  with:
176
- node-version: 20
176
+ node-version: 22
177
177
  - run: npm ci
178
178
  - run: npx playwright install --with-deps
179
179
  - run: npx codeceptjs check
@@ -194,7 +194,7 @@ stages: [test]
194
194
 
195
195
  playwright:
196
196
  stage: test
197
- image: node:20
197
+ image: node:22
198
198
  variables:
199
199
  FORCE_COLOR: "1"
200
200
  parallel: 4
@@ -211,7 +211,7 @@ playwright:
211
211
 
212
212
  webdriver:
213
213
  stage: test
214
- image: node:20 # WebdriverIO 9 downloads its own browser and driver
214
+ image: node:22 # WebdriverIO 9 downloads its own browser and driver
215
215
  script:
216
216
  - npm ci
217
217
  - npx codeceptjs check
@@ -228,7 +228,7 @@ webdriver:
228
228
  `bitbucket-pipelines.yml`:
229
229
 
230
230
  ```yaml
231
- image: node:20
231
+ image: node:22
232
232
 
233
233
  definitions:
234
234
  caches:
@@ -260,7 +260,7 @@ pipelines:
260
260
  For WebDriver, no Selenium service or browser image is needed — WebdriverIO 9 downloads its own browser and driver:
261
261
 
262
262
  ```yaml
263
- image: node:20
263
+ image: node:22
264
264
 
265
265
  pipelines:
266
266
  default:
@@ -280,7 +280,7 @@ pipelines:
280
280
  pipeline {
281
281
  agent {
282
282
  docker {
283
- image 'node:20'
283
+ image 'node:22'
284
284
  args '-u root'
285
285
  }
286
286
  }
@@ -311,7 +311,7 @@ pipeline {
311
311
  }
312
312
  ```
313
313
 
314
- For WebDriver, keep the same `node:20` agent — WebdriverIO 9 downloads its own browser and driver, so no Selenium container is needed:
314
+ For WebDriver, keep the same `node:22` agent — WebdriverIO 9 downloads its own browser and driver, so no Selenium container is needed:
315
315
 
316
316
  ```groovy
317
317
  stage('Test') {
@@ -332,7 +332,7 @@ version: 2.1
332
332
  jobs:
333
333
  test:
334
334
  docker:
335
- - image: cimg/node:20.18-browsers
335
+ - image: cimg/node:22.14-browsers
336
336
  parallelism: 4
337
337
  steps:
338
338
  - checkout
@@ -350,7 +350,7 @@ jobs:
350
350
  webdriver:
351
351
  docker:
352
352
  # WebdriverIO 9 downloads its own browser and driver
353
- - image: cimg/node:20.18
353
+ - image: cimg/node:22.14
354
354
  steps:
355
355
  - checkout
356
356
  - run: npm ci
@@ -22,6 +22,17 @@ This helper is a thin `CDPBrowser` subclass: it changes nothing about how locati
22
22
  elements works, it only pins the config presets Obscura requires and manages the `obscura serve`
23
23
  process lifecycle, the same way Playwright manages its own browser process.
24
24
 
25
+ > Obscura support is experimental in CodeceptJS 4.2. Pin the browser version in CI and keep a
26
+ > Playwright/WebDriver job for browser-compatibility coverage.
27
+
28
+ ## Compatibility
29
+
30
+ | CodeceptJS | Recommended Obscura | Notes |
31
+ | ---------- | -------------------- | --------------------------------------------------------------- |
32
+ | 4.2.x | 0.2.2 | Version used by the CodeceptJS Obscura CI workflow |
33
+ | 4.2.x | 0.2.x | Supported; capabilities are detected at runtime |
34
+ | 4.2.x | 0.1.x / `-no-render` | DOM-only mode; no layout, visibility assertions, or screenshots |
35
+
25
36
  ## Modes
26
37
 
27
38
  * **ATTACH** — `endpoint` is set explicitly in the config. The helper only connects to it; it
@@ -39,8 +50,20 @@ process lifecycle, the same way Playwright manages its own browser process.
39
50
 
40
51
  ## Install
41
52
 
42
- Download a release binary and put it on your `PATH` (or point `binaryPath`/`OBSCURA_PATH` at
43
- it directly) and the helper launches and tears it down for you automatically:
53
+ Download a release archive from [Obscura releases][2].
54
+ CodeceptJS 4.2 is tested with Obscura 0.2.2. Rendering archives are available for:
55
+
56
+ | platform | archive |
57
+ | ------------------- | ------------------------------ |
58
+ | Linux x64 | `obscura-x86_64-linux.tar.gz` |
59
+ | Linux ARM64 | `obscura-aarch64-linux.tar.gz` |
60
+ | macOS Intel | `obscura-x86_64-macos.tar.gz` |
61
+ | macOS Apple Silicon | `obscura-aarch64-macos.tar.gz` |
62
+ | Windows x64 | `obscura-x86_64-windows.zip` |
63
+
64
+ Extract the archive and put `obscura` (`obscura.exe` on Windows) on your `PATH`, or point
65
+ `binaryPath`/`OBSCURA_PATH` at it. The helper then launches and tears it down automatically.
66
+ For example, on Linux x64:
44
67
 
45
68
  ```sh
46
69
  curl -sL https://github.com/h4ckf0r0day/obscura/releases/download/v0.2.2/obscura-x86_64-linux.tar.gz | tar xz
@@ -84,19 +107,19 @@ Set them explicitly in your own config to skip probing or to force a mode.
84
107
  This helper should be configured in codecept.conf.js. It accepts everything `CDPBrowser`
85
108
  accepts (see its config table), plus:
86
109
 
87
- Type: [object][6]
110
+ Type: [object][7]
88
111
 
89
112
  ### Properties
90
113
 
91
- * `endpoint` **[string][4]?** explicit CDP endpoint. Setting this switches the helper to ATTACH
114
+ * `endpoint` **[string][5]?** explicit CDP endpoint. Setting this switches the helper to ATTACH
92
115
  mode: it only connects, and never spawns or kills a process, no matter what else is configured.
93
116
  Leave it unset for SELF-MANAGED mode (see below).
94
- * `binaryPath` **[string][4]?** path to the `obscura` executable, used in SELF-MANAGED mode
117
+ * `binaryPath` **[string][5]?** path to the `obscura` executable, used in SELF-MANAGED mode
95
118
  (`endpoint` unset). Checked before `OBSCURA_PATH` and `PATH`.
96
- * `port` **[number][3]?** port `obscura serve` listens on, in SELF-MANAGED mode. When unset, a
119
+ * `port` **[number][4]?** port `obscura serve` listens on, in SELF-MANAGED mode. When unset, a
97
120
  free port is picked automatically, which is what makes `run-workers` collision-free — every
98
121
  worker gets its own instance on its own port with zero config.
99
- * `serverStartTimeout` **[number][3]?** milliseconds to wait for a spawned `obscura serve`
122
+ * `serverStartTimeout` **[number][4]?** milliseconds to wait for a spawned `obscura serve`
100
123
  to answer `/json/version` before `_connect` gives up.
101
124
 
102
125
 
@@ -150,7 +173,7 @@ Picks a free TCP port on 127.0.0.1 by briefly listening on port 0 and reading ba
150
173
  port. Used as the SELF-LAUNCH default when `options.port` isn't explicitly set, so multiple
151
174
  `run-workers` workers never collide on the same port.
152
175
 
153
- Returns **[Promise][2]<[number][3]>** a free port.
176
+ Returns **[Promise][3]<[number][4]>** a free port.
154
177
 
155
178
  ### _finishTest
156
179
 
@@ -170,9 +193,9 @@ Probes a `/json/version`-style URL with a short timeout, used for the COURTESY-A
170
193
 
171
194
  #### Parameters
172
195
 
173
- * `url` **[string][4]**&#x20;
196
+ * `url` **[string][5]**&#x20;
174
197
 
175
- Returns **[Promise][2]<[boolean][5]>** true if the URL answered.
198
+ Returns **[Promise][3]<[boolean][6]>** true if the URL answered.
176
199
 
177
200
  ### _resolveBinary
178
201
 
@@ -181,7 +204,7 @@ Resolves the `obscura` binary to spawn, in priority order: `options.binaryPath`,
181
204
  directories itself instead of shelling out to `which`, which does not exist on Windows: on
182
205
  Windows every `PATHEXT` suffix is tried, so an `obscura.exe` on `PATH` is found too.
183
206
 
184
- Returns **([string][4] | null)** an absolute or relative path to the binary, or null if none resolved.
207
+ Returns **([string][5] | null)** an absolute or relative path to the binary, or null if none resolved.
185
208
 
186
209
  ### _resolveSelfManaged
187
210
 
@@ -200,12 +223,14 @@ is paid once per run and counts directly toward real-world startup latency.
200
223
 
201
224
  [1]: https://github.com/h4ckf0r0day/obscura
202
225
 
203
- [2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
226
+ [2]: https://github.com/h4ckf0r0day/obscura/releases
227
+
228
+ [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
204
229
 
205
- [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
230
+ [4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
206
231
 
207
- [4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
232
+ [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
208
233
 
209
- [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
234
+ [6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
210
235
 
211
- [6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
236
+ [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
@@ -7,6 +7,12 @@ title: Installation
7
7
 
8
8
  For the quickest start (CodeceptJS + Playwright) follow the [Quickstart](/quickstart). This page covers every browser, mobile, and API helper and what each one needs installed.
9
9
 
10
+ CodeceptJS 4.2 requires **Node.js 22.12 or newer**. Check your installed version before continuing:
11
+
12
+ ```sh
13
+ node --version
14
+ ```
15
+
10
16
  ## Set up a project
11
17
 
12
18
  ```sh
@@ -64,6 +70,35 @@ WebdriverIO 9 downloads and starts the matching driver automatically — no Sele
64
70
 
65
71
  To run against a cloud grid (Sauce Labs, BrowserStack, LambdaTest, and so on) instead, set the grid's `host`, `port`, `user`, and `key` (or `protocol` / `path`) in the helper config. For running this on CI, see [Continuous Integration](/continuous-integration).
66
72
 
73
+ ## Obscura (experimental)
74
+
75
+ Obscura is a lightweight browser driven through Chrome DevTools Protocol. CodeceptJS 4.2 is tested with Obscura 0.2.2. Obscura 0.2.x is the recommended version; older 0.1.x and `-no-render` builds have no layout, visibility assertions, or screenshots.
76
+
77
+ Download the archive for your platform from the [Obscura releases](https://github.com/h4ckf0r0day/obscura/releases):
78
+
79
+ | Platform | Rendering archive |
80
+ | --- | --- |
81
+ | Linux x64 | `obscura-x86_64-linux.tar.gz` |
82
+ | Linux ARM64 | `obscura-aarch64-linux.tar.gz` |
83
+ | macOS Intel | `obscura-x86_64-macos.tar.gz` |
84
+ | macOS Apple Silicon | `obscura-aarch64-macos.tar.gz` |
85
+ | Windows x64 | `obscura-x86_64-windows.zip` |
86
+
87
+ Extract the archive and either put `obscura` (`obscura.exe` on Windows) on `PATH`, set `OBSCURA_PATH`, or configure `binaryPath`. The helper then starts and stops `obscura serve` automatically:
88
+
89
+ ```js
90
+ export const config = {
91
+ helpers: {
92
+ Obscura: {
93
+ url: 'http://localhost:3000',
94
+ // binaryPath: '/absolute/path/to/obscura', // optional
95
+ },
96
+ },
97
+ }
98
+ ```
99
+
100
+ See [Alternative Browser Engines](/alternative-browsers) for connection modes and limitations, and the [Obscura helper reference](/helpers/Obscura) for every option.
101
+
67
102
  ## Appium (mobile)
68
103
 
69
104
  Native iOS and Android testing. Appium speaks the WebDriver protocol, so CodeceptJS drives it through `webdriverio`:
package/docs/mcp.md CHANGED
@@ -441,7 +441,7 @@ Storage capture is **enabled** for `run_code`, `snapshot`, `run_step_by_step` fa
441
441
 
442
442
  ### Server doesn't start
443
443
 
444
- - Node 18+ recommended.
444
+ - Node 22.12+ is required by CodeceptJS 4.2.
445
445
  - Verify the path / `npx` resolution in your client config.
446
446
 
447
447
  ### Config not found
@@ -35,7 +35,7 @@ The rest of this guide documents every change the skill makes — read it if you
35
35
 
36
36
  ## 1. Update Node and Package
37
37
 
38
- CodeceptJS 4.x supports Node 16+, but Node 20 or newer is recommended.
38
+ CodeceptJS 4.2 requires Node 22.12 or newer. This matches the minimum supported version of its current runtime dependencies. Upgrade Node before installing CodeceptJS 4.2.
39
39
 
40
40
  ```bash
41
41
  npm install codeceptjs@4
@@ -766,4 +766,4 @@ You don't need these to upgrade, but they unlock new workflows:
766
766
  4. TypeScript users: run with `tsx` installed and confirm error stack traces point at `.ts` files.
767
767
  5. If you removed `autoLogin`: confirm sessions restore under the `auth` plugin.
768
768
  6. If you used `tryTo` / `retryTo` / `eachElement` plugins: grep your tests for the old globals and switch to subpath imports.
769
- 7. CI: bump the Node version to 20+ if you were on 18 or below.
769
+ 7. CI: bump the Node version to 22.12+.
package/docs/parallel.md CHANGED
@@ -100,7 +100,7 @@ jobs:
100
100
  - uses: actions/checkout@v4
101
101
  - uses: actions/setup-node@v4
102
102
  with:
103
- node-version: 20
103
+ node-version: 22
104
104
  - run: npm ci
105
105
  - run: npx codeceptjs run --shard ${{ matrix.shard }}
106
106
  ```
@@ -1534,6 +1534,29 @@ class Appium extends Webdriver {
1534
1534
  return this.browser.closeApp()
1535
1535
  }
1536
1536
 
1537
+ /**
1538
+ * {{> clearClipboard }}
1539
+ *
1540
+ * Appium: support both Android and iOS
1541
+ */
1542
+ async clearClipboard() {
1543
+ if (typeof this.browser.setClipboard !== 'function') return super.clearClipboard()
1544
+ return this.browser.setClipboard('', 'plaintext')
1545
+ }
1546
+
1547
+ /**
1548
+ * {{> grabFromClipboard }}
1549
+ *
1550
+ * Appium: support both Android and iOS
1551
+ */
1552
+ async grabFromClipboard() {
1553
+ if (typeof this.browser.getClipboard !== 'function') return super.grabFromClipboard()
1554
+ const encoded = await this.browser.getClipboard('plaintext')
1555
+ const clipboard = Buffer.from(encoded || '', 'base64').toString('utf8')
1556
+ this.debugSection('Clipboard', clipboard)
1557
+ return clipboard
1558
+ }
1559
+
1537
1560
  /**
1538
1561
  * {{> appendField }}
1539
1562
  *
@@ -18,6 +18,7 @@ import { isColorProperty, convertColorToRGBA } from '../colorUtils.js'
18
18
  import WebElement from '../element/WebElement.js'
19
19
  import CDPElementHandle from './extras/CDPElementHandle.js'
20
20
  import { checkFocusBeforeType, checkFocusBeforePressKey } from './extras/focusCheck.js'
21
+ import { CLIPBOARD_READ_TIMEOUT_MS, readClipboardScript, writeClipboardScript, clipboardExpression } from './extras/clipboard.js'
21
22
  import { dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, flushNetworkTraffics } from './network/actions.js'
22
23
  import { assembleApng, isPng } from './extras/apngAssembler.js'
23
24
 
@@ -1940,6 +1941,89 @@ class CDPBrowser extends Helper {
1940
1941
  }
1941
1942
  }
1942
1943
 
1944
+ /**
1945
+ * Checks that the system clipboard contains the given text.
1946
+ *
1947
+ * ```js
1948
+ * I.click('Copy to clipboard');
1949
+ * I.seeInClipboard('https://codecept.io');
1950
+ * ```
1951
+ *
1952
+ * Reading the clipboard requires a secure context (`https` or `localhost`).
1953
+ *
1954
+ * @param {string} text value to check.
1955
+ * @returns {Promise<void>}
1956
+ */
1957
+ async seeInClipboard(text) {
1958
+ const clipboard = await this.grabFromClipboard()
1959
+ return stringIncludes('clipboard').assert(text, clipboard)
1960
+ }
1961
+
1962
+ /**
1963
+ * Checks that the system clipboard is equal to the given text.
1964
+ *
1965
+ * ```js
1966
+ * I.click('Copy to clipboard');
1967
+ * I.seeClipboardEquals('https://codecept.io');
1968
+ * ```
1969
+ *
1970
+ * Reading the clipboard requires a secure context (`https` or `localhost`).
1971
+ *
1972
+ * @param {string} text value to check.
1973
+ * @returns {Promise<void>}
1974
+ */
1975
+ async seeClipboardEquals(text) {
1976
+ const clipboard = await this.grabFromClipboard()
1977
+ return equals('clipboard').assert(clipboard, text)
1978
+ }
1979
+
1980
+ /**
1981
+ * Clears the system clipboard.
1982
+ *
1983
+ * ```js
1984
+ * I.clearClipboard();
1985
+ * I.seeClipboardEquals('');
1986
+ * ```
1987
+ *
1988
+ * @returns {Promise<void>}
1989
+ */
1990
+ async clearClipboard() {
1991
+ await this._grantClipboardAccess()
1992
+ await this._evaluate(clipboardExpression(writeClipboardScript, ''))
1993
+ }
1994
+
1995
+ /**
1996
+ * Grabs the text content of the system clipboard.
1997
+ * Resumes test execution, so **should be used inside async function with `await`** operator.
1998
+ *
1999
+ * ```js
2000
+ * I.click('Copy to clipboard');
2001
+ * const url = await I.grabFromClipboard();
2002
+ * ```
2003
+ *
2004
+ * @returns {Promise<string>} the system clipboard contents.
2005
+ */
2006
+ async grabFromClipboard() {
2007
+ await this._grantClipboardAccess()
2008
+ const clipboard = await this._evaluate(clipboardExpression(readClipboardScript, CLIPBOARD_READ_TIMEOUT_MS))
2009
+ this.debugSection('Clipboard', clipboard)
2010
+ return clipboard
2011
+ }
2012
+
2013
+ /**
2014
+ * Brings the current target to front and grants it clipboard read/write access, so
2015
+ * `navigator.clipboard` does not reject with a permission or focus error. Failures are ignored:
2016
+ * a browser without `Browser.grantPermissions` surfaces its own error from the read instead.
2017
+ *
2018
+ * @protected
2019
+ */
2020
+ async _grantClipboardAccess() {
2021
+ await this.cdp.send('Page.bringToFront', {}, this.sessionId).catch(() => null)
2022
+ const origin = await this._evaluate('window.location.origin').catch(() => null)
2023
+ if (!origin || !origin.startsWith('http')) return
2024
+ await this.cdp.send('Browser.grantPermissions', { origin, permissions: ['clipboardReadWrite', 'clipboardSanitizedWrite'] }).catch(() => null)
2025
+ }
2026
+
1943
2027
  /**
1944
2028
  * Saves a screenshot to the output folder (set in codecept.conf.ts or codecept.conf.js).
1945
2029
  * Filename is relative to the output folder.
@@ -39,6 +39,17 @@ const config = {}
39
39
  * elements works, it only pins the config presets Obscura requires and manages the `obscura serve`
40
40
  * process lifecycle, the same way Playwright manages its own browser process.
41
41
  *
42
+ * > Obscura support is experimental in CodeceptJS 4.2. Pin the browser version in CI and keep a
43
+ * > Playwright/WebDriver job for browser-compatibility coverage.
44
+ *
45
+ * ## Compatibility
46
+ *
47
+ * | CodeceptJS | Recommended Obscura | Notes |
48
+ * | --- | --- | --- |
49
+ * | 4.2.x | 0.2.2 | Version used by the CodeceptJS Obscura CI workflow |
50
+ * | 4.2.x | 0.2.x | Supported; capabilities are detected at runtime |
51
+ * | 4.2.x | 0.1.x / `-no-render` | DOM-only mode; no layout, visibility assertions, or screenshots |
52
+ *
42
53
  * ## Modes
43
54
  *
44
55
  * - **ATTACH** — `endpoint` is set explicitly in the config. The helper only connects to it; it
@@ -56,8 +67,20 @@ const config = {}
56
67
  *
57
68
  * ## Install
58
69
  *
59
- * Download a release binary and put it on your `PATH` (or point `binaryPath`/`OBSCURA_PATH` at
60
- * it directly) and the helper launches and tears it down for you automatically:
70
+ * Download a release archive from [Obscura releases](https://github.com/h4ckf0r0day/obscura/releases).
71
+ * CodeceptJS 4.2 is tested with Obscura 0.2.2. Rendering archives are available for:
72
+ *
73
+ * | platform | archive |
74
+ * | --- | --- |
75
+ * | Linux x64 | `obscura-x86_64-linux.tar.gz` |
76
+ * | Linux ARM64 | `obscura-aarch64-linux.tar.gz` |
77
+ * | macOS Intel | `obscura-x86_64-macos.tar.gz` |
78
+ * | macOS Apple Silicon | `obscura-aarch64-macos.tar.gz` |
79
+ * | Windows x64 | `obscura-x86_64-windows.zip` |
80
+ *
81
+ * Extract the archive and put `obscura` (`obscura.exe` on Windows) on your `PATH`, or point
82
+ * `binaryPath`/`OBSCURA_PATH` at it. The helper then launches and tears it down automatically.
83
+ * For example, on Linux x64:
61
84
  *
62
85
  * ```sh
63
86
  * curl -sL https://github.com/h4ckf0r0day/obscura/releases/download/v0.2.2/obscura-x86_64-linux.tar.gz | tar xz