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
package/README.md CHANGED
@@ -11,6 +11,7 @@
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
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) |
14
+ | 🌐 Web | Lightpanda | [![Lightpanda Helper Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/lightpanda.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/lightpanda.yml) |
14
15
  | πŸ“± 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) |
15
16
 
16
17
  # CodeceptJS [![Made in Ukraine](https://img.shields.io/badge/made_in-ukraine-ffd700.svg?labelColor=0057b7)](https://stand-with-ukraine.pp.ua)
@@ -44,6 +45,7 @@ CodeceptJS uses **Helper** modules to provide actions to `I` object. Currently,
44
45
  - [**Puppeteer**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Puppeteer.md) - uses Google Chrome's Puppeteer for fast headless testing.
45
46
  - [**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
47
  - [**Obscura**](https://codecept.io/helpers/Obscura) - drives the lightweight Obscura browser through Chrome DevTools Protocol. See [Alternative Browser Engines](https://codecept.io/alternative-browsers).
48
+ - [**Lightpanda**](https://codecept.io/helpers/Lightpanda) - drives the Lightpanda headless browser through Chrome DevTools Protocol. See [Alternative Browser Engines](https://codecept.io/alternative-browsers).
47
49
  - [**Appium**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Appium.md) - for **mobile testing** with Appium
48
50
  - [**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.
49
51
 
package/bin/codecept.js CHANGED
@@ -78,8 +78,16 @@ program
78
78
  .command('init [path]')
79
79
  .description('Creates dummy config in current dir or [path]')
80
80
  .option('-y, --yes', 'skip prompts and use defaults (Playwright + chromium, BASE_URL env for url)')
81
+ .option('--agent <name>', 'set up an AI coding agent: claude, codex, cursor, opencode')
81
82
  .action(commandHandler('../lib/command/init.js'))
82
83
 
84
+ program
85
+ .command('init:agent [agent]')
86
+ .alias('init-agent')
87
+ .description('Set up CodeceptJS MCP server and skills for a coding agent: claude, codex, cursor, opencode')
88
+ .option('-y, --yes', 'skip prompts, requires [agent]')
89
+ .action(commandHandler('../lib/command/initAgent.js'))
90
+
83
91
  program
84
92
  .command('check')
85
93
  .option(commandFlags.config.flag, commandFlags.config.description)
@@ -178,6 +186,7 @@ program
178
186
  .option('-p, --plugins <k=v,k2=v2,...>', 'enable plugins, comma-separated')
179
187
  .option('--shuffle', 'Shuffle the order in which test files run')
180
188
  .option('--shard <index/total>', 'run only a fraction of tests (e.g., --shard 1/4)')
189
+ .option('--last-failed', 'run only tests that failed in the previous run')
181
190
 
182
191
  // mocha options
183
192
  .option('--colors', 'force enabling of colors')
@@ -207,8 +216,10 @@ program
207
216
  .option(commandFlags.config.flag, commandFlags.config.description)
208
217
  .option('-g, --grep <pattern>', 'only run tests matching <pattern>')
209
218
  .option('-i, --invert', 'inverts --grep matches')
219
+ .option('--last-failed', 'run only tests that failed in the previous run')
210
220
  .option('-o, --override [value]', 'override current config options')
211
221
  .option('--suites', 'parallel execution of suites not single tests')
222
+ .option('--serial <pattern>', 'run tests matching <pattern> one by one after parallel workers finish')
212
223
  .option('--by <strategy>', 'test distribution strategy: "test" (pre-assign individual tests), "suite" (pre-assign test suites), or "pool" (dynamic distribution for optimal load balancing, recommended)')
213
224
  .option(commandFlags.debug.flag, commandFlags.debug.description)
214
225
  .option(commandFlags.verbose.flag, commandFlags.verbose.description)
package/docs/agents.md CHANGED
@@ -25,7 +25,15 @@ CodeceptJS is token-efficient: it stores HTML, ARIA, logs, and HTTP request data
25
25
 
26
26
  ## Essential Setup
27
27
 
28
- Two things make agent testing work: the **skills** that teach the agent CodeceptJS, and the **MCP server** that lets it drive the browser. Set both up once, from your project directory.
28
+ Two things make agent testing work: the **skills** that teach the agent CodeceptJS, and the **MCP server** that lets it drive the browser. Set both up once, from your project directory:
29
+
30
+ ```bash
31
+ npx codeceptjs init:agent claude
32
+ ```
33
+
34
+ Use `codex`, `cursor`, or `opencode` instead of `claude` for other agents, or omit the name to pick from a list. `npx codeceptjs init` offers the same step at the end.
35
+
36
+ ### Manual setup
29
37
 
30
38
  Install the skills:
31
39
 
@@ -165,6 +173,23 @@ After a failed run, the agent reads every trace under `output/`, clusters failur
165
173
 
166
174
  If the fix held, the PR goes green. If it didn't, every edit is rolled back with `git checkout` and the report says which patterns the agent couldn't safely handle. No half-applied fixes left behind, no `retries: 3` masking the problem.
167
175
 
176
+ ## Assertions in plain language
177
+
178
+ Some outcomes are hard to pin to a locator: "checkout form has all required fields", "success message is shown". Instead of building a fragile chain of `see*` checks, the agent can write the expected outcome as a statement with the [Decision helper](/assertions#decision-assertions):
179
+
180
+ ```js
181
+ I.decide([
182
+ 'order summary lists the purchased items',
183
+ 'success message is shown',
184
+ ])
185
+ ```
186
+
187
+ The agent runs the statement on the live page like any other command and keeps it only if it passes. The test then checks it on every run.
188
+
189
+ To let the agent use decisions, [configure a decision model](/ai#configure-decision-models) and enable the Decision helper.
190
+
191
+ Decision models like [Jev](https://openrouter.ai/typesafe/jev-1.13) are built for this. They answer in a fraction of a second, cost a fraction of a cent per request, and return a probability instead of free text. That makes them fast and cheap enough to run on every CI build, and predictable enough to keep in a test.
192
+
168
193
  ## Skills bundle
169
194
 
170
195
  Skills teach the agent best practices for using CodeceptJS. Plug them in when you develop tests with agents, and update them regularly to ensure you use CodeceptJS in the most effective way.
package/docs/ai.md CHANGED
@@ -23,6 +23,7 @@ CodeceptJS AI can do the following:
23
23
 
24
24
  - πŸ‹οΈβ€β™€οΈ **assist writing tests** in `pause()` or interactive shell mode
25
25
  - πŸš‘ **self-heal failing tests** (can be used on CI)
26
+ - βš–οΈ **assert statements in plain language** with [decision models](#decision-assertions)
26
27
 
27
28
  ![](/img/fill_form.gif)
28
29
 
@@ -338,6 +339,62 @@ Run tests with both AI and analyze enabled:
338
339
  npx codeceptjs run --ai
339
340
  ```
340
341
 
342
+ ## Decision Assertions
343
+
344
+ Some checks are hard to express with locators: "checkout form has all required fields", "success message is shown". The [Decision helper](/helpers/Decision) asserts them in plain language:
345
+
346
+ ```js
347
+ I.decide([
348
+ 'checkout form has all required fields',
349
+ 'submit button enabled',
350
+ ])
351
+ I.decideVisually('sidebar is shown')
352
+ ```
353
+
354
+ It uses a [decision model](https://openrouter.ai/models?output_modalities=decisions) like [Jev](https://openrouter.ai/typesafe/jev-1.13) instead of a chat model. A decision model reads the page and returns the probability that a statement is true. It is fast, costs a fraction of a cent per request, and gives a probability instead of free text, so a step passes or fails on a confidence threshold you set.
355
+
356
+ Decision models are separate from `ai.model`: decisions don't need `ai.model` or the `--ai` flag. CodeceptJS calls them with AI SDK [`experimental_decide`](https://ai-sdk.dev/docs/ai-sdk-core/decisions).
357
+
358
+ ### Configure Decision Models
359
+
360
+ Decision models are served by the [OpenRouter Decisions API](https://openrouter.ai/models?output_modalities=decisions). Install the [OpenRouter provider](https://ai-sdk.dev/providers/community-providers/openrouter) `@openrouter/ai-sdk-provider`, set `OPENROUTER_API_KEY`, and create the decision model with `evaluationModel()` in `codecept.conf.js`:
361
+
362
+ ```js
363
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider'
364
+
365
+ const openrouter = createOpenRouter({
366
+ apiKey: process.env.OPENROUTER_API_KEY,
367
+ })
368
+
369
+ export default {
370
+ ai: {
371
+ decisionModel: {
372
+ model: openrouter.evaluationModel('typesafe/jev-1.13'),
373
+ confidence: 0.8,
374
+ },
375
+ },
376
+ helpers: {
377
+ Playwright: { url: 'http://localhost' },
378
+ Decision: {},
379
+ },
380
+ }
381
+ ```
382
+
383
+ `model` is used by `I.decide`.
384
+
385
+ ### Visual Decision Model
386
+
387
+ `I.decideVisually` sends a screenshot, so it needs a separate decision model with image input. Set it as `visualModel`:
388
+
389
+ ```js
390
+ decisionModel: {
391
+ model: openrouter.evaluationModel('typesafe/jev-1.13'),
392
+ visualModel: openrouter.evaluationModel('cloudflare/clef'),
393
+ },
394
+ ```
395
+
396
+ See [Decision Assertions](/assertions#decision-assertions) for all options and usage.
397
+
341
398
  ## Advanced Configuration
342
399
 
343
400
  AI prompts and HTML compression can be configured inside `ai` section of `codecept.conf` file:
@@ -6,153 +6,180 @@ title: Alternative Browser Engines
6
6
  # Alternative Browser Engines
7
7
 
8
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.
9
+ The `Obscura`, `Lightpanda` and `Kitesurf` helpers are experimental. Keep a Playwright or WebDriver job for compatibility-critical tests.
10
10
  :::
11
11
 
12
- Playwright and Puppeteer drive full Chromium β€” the most accurate way to test what users see.
13
- But a new class of lightweight, agent-era browsers has appeared, and CodeceptJS can drive them
14
- through the `CDPBrowser` helper family:
15
-
16
- - **[Obscura](https://github.com/h4ckf0r0day/obscura)** β€” an open-source Rust browser with a real
17
- V8 engine. From v0.2.0, the default release build also renders β€” real layout, computed styles,
18
- and screenshots β€” with `-no-render` builds still available for pure-speed, nothing-painted
19
- scraping mode. Release archives are available for Linux, macOS, and Windows.
20
- - **[Kitesurf](https://blog.cloudflare.com/kitesurf/)** β€” Cloudflare's browser that runs in V8
21
- isolates on Cloudflare Workers, with a real layout and rendering pipeline. Cloud-only,
22
- free in beta, planned to be open-sourced.
23
-
24
- Both speak Chrome DevTools Protocol. CodeceptJS drives them with raw CDP β€” one round-trip per
25
- action, no stale element handles β€” which is why suites on these browsers run fast and never hang
26
- on navigation races.
27
-
28
- ## When are they better than Playwright?
29
-
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.
33
-
34
- **Massive parallel scale.** Kitesurf sessions are Cloudflare Workers β€” they spawn in about a
35
- second, cost nothing while idle, and there is no practical ceiling on how many you run at once.
36
- Combined with `run-workers`, every worker acquires its own cloud browser:
37
-
38
- // codecept.conf.js β€” each worker independently loads the config,
39
- // so each one gets its own Kitesurf session automatically
40
- export const config = {
41
- helpers: {
42
- Kitesurf: {
43
- url: 'https://staging.myapp.com',
44
- },
45
- },
46
- }
47
-
48
- npx codeceptjs run-workers 16
49
-
50
- Sixteen cloud browsers, zero local resources, feedback in the time of your slowest test.
51
- Scale the number up as far as your suite can split β€” the browsers are no longer
52
- the bottleneck, and your CI runner only coordinates.
53
-
54
- **Testing the DOM, not the pixels.** Most functional assertions β€” text appears, form submits,
55
- redirect happens, cookie is set β€” do not need a GPU raster pipeline. Obscura executes your
56
- app's real JavaScript in real V8; it only skips painting. For API-adjacent flows
57
- (login β†’ dashboard data appears), that is exactly the right amount of browser.
58
-
59
- **Constrained environments.** ARM CI runners, thin containers, air-gapped machines:
60
- a static binary with no system dependencies goes where Chromium will not.
61
-
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.
64
-
65
- ## When to stay with Playwright
66
-
67
- - Anything visual: visual regression, PDF (neither helper exposes PDF output). Obscura's v0.2.0+
68
- rendering/CSS engine is new and independently implemented β€” expect edge cases and gaps versus a
69
- real browser, especially around inherited properties and less common computed-style values.
70
- - Visibility semantics on `-no-render` Obscura builds (and v0.1.x): every element reports as
71
- visible β€” `seeElement`/`dontSeeElement` throw and point you to `seeElementInDOM`. On v0.2.0+
72
- default builds, `CDPBrowser` detects the real layout engine per binary and visibility works
73
- normally.
74
- - Complex input: drag-and-drop, hover chains, file uploads, iframes, multi-tab, service workers.
75
- - Cross-browser coverage (Firefox, WebKit).
76
- - Testing local apps with Kitesurf: the cloud browser must reach your app; use a tunnel
77
- (`cloudflared tunnel --url http://localhost:3000`) or a deployed environment.
78
-
79
- ## Configuration
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
-
85
- helpers: {
86
- Obscura: {
87
- url: 'http://localhost:3000',
88
- },
89
- }
90
-
91
- helpers: {
92
- Kitesurf: {
93
- url: 'https://staging.myapp.com',
94
- accountId: process.env.CF_ACCOUNT_ID,
95
- apiToken: process.env.CF_API_TOKEN,
96
- },
97
- }
98
-
99
- Any other CDP endpoint works through the base helper:
100
-
101
- helpers: {
102
- CDPBrowser: {
103
- url: 'http://localhost:3000',
104
- endpoint: 'http://127.0.0.1:9222',
105
- },
106
- }
107
-
108
- ### Obscura's three connection modes
109
-
110
- Obscura manages its own `obscura serve` process, the same way Playwright manages its own browser
111
- process β€” there is nothing to start by hand in the common case:
112
-
113
- - **Self-launch (default)** β€” leave `endpoint` unset. The helper resolves a binary
114
- (`binaryPath` in the config, then `OBSCURA_PATH`, then `obscura` on `PATH`), spawns
115
- `obscura serve` on a free port, and kills it when the run ends. Not setting `port` is
116
- intentional: a free port is picked automatically, which is what makes `run-workers`
117
- collision-free β€” every worker gets its own instance without any config.
118
-
119
- helpers: {
120
- Obscura: {
121
- url: 'http://localhost:3000',
122
- binaryPath: '/usr/local/bin/obscura', // optional override, like Playwright's executablePath
123
- },
124
- }
125
-
126
- - **Attach** β€” set `endpoint` explicitly to connect to an Obscura instance you manage yourself
127
- (already running locally, in a container, or on a remote host). The helper only connects; it
128
- never spawns or kills anything.
129
-
130
- helpers: {
131
- Obscura: {
132
- url: 'http://localhost:3000',
133
- endpoint: 'http://127.0.0.1:9222',
134
- },
135
- }
136
-
137
- - **Courtesy-attach** β€” only relevant when `endpoint` is unset and no binary can be resolved
138
- either. If something is already answering on the conventional `http://127.0.0.1:9222`, the
139
- helper attaches to it (and, again, never kills it) instead of failing outright. This exists so
140
- that "start Obscura by hand and just run the tests" keeps working without any config, while
141
- self-launch is still the default for everyone else.
142
-
143
- ## Capability matrix
144
-
145
- | | Playwright | Obscura | Kitesurf |
146
- |---|---|---|---|
147
- | Real JS execution (V8) | yes | yes | yes |
148
- | Layout / getBoundingClientRect | yes | yes (v0.2.0+ default builds); synthetic on `-no-render`/v0.1.x | yes |
149
- | Screenshots | yes | yes (v0.2.0+ default builds); no on `-no-render`/v0.1.x | yes |
150
- | Visibility assertions | yes | yes (v0.2.0+ default builds); no, DOM-presence only, on `-no-render`/v0.1.x | yes |
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 |
152
- | Startup model | local browser process | standalone local binary | remote cloud session |
153
- | Parallel scale | machine-bound | machine-bound (light) | near-unlimited (cloud) |
154
- | Where it runs | local/grid | local | Cloudflare only |
155
- | License / cost | open source | Apache-2.0 | proprietary, free beta |
156
-
157
- See helper reference pages: [CDPBrowser](/helpers/CDPBrowser), [Obscura](/helpers/Obscura),
158
- [Kitesurf](/helpers/Kitesurf).
12
+ Playwright drives full Chromium, Firefox and WebKit: the most accurate way to test what users see, at the cost of a heavy browser per worker. Alternative engines trade part of that accuracy for speed, a small footprint, or cloud scale. They are a good fit for functional tests (text appears, form submits, redirect happens, cookie is set) and a poor one for anything visual.
13
+
14
+ Your tests do not change. `I.amOnPage`, `I.click`, `I.fillField`, `I.see`, `I.seeElement` and the rest of the `I.*` web API work the same; you only swap the helper in the config. All engines below speak Chrome DevTools Protocol, so there is no `npx playwright install` step.
15
+
16
+ Compared to Playwright, none of them supports iframes (`switchTo`), multiple tabs, popups, `dragAndDrop`, `moveCursorTo`, or Playwright-only APIs such as `usePlaywrightTo` and `mockRoute`. Tag scenarios that need those and skip them on the alternative engine:
17
+
18
+ ```sh
19
+ npx codeceptjs run --grep @playwright-only --invert
20
+ ```
21
+
22
+ To see which `I.*` actions the configured engine supports:
23
+
24
+ ```sh
25
+ npx codeceptjs list
26
+ ```
27
+
28
+ ## Obscura
29
+
30
+ [Obscura](https://github.com/h4ckf0r0day/obscura) is a lightweight open-source browser with a real V8 engine and its own rendering engine, distributed as a single binary for Linux, macOS and Windows. Unlike Lightpanda it renders: layout, visibility checks, screenshots and the `screencast` plugin work.
31
+
32
+ Limitations:
33
+
34
+ - `attachFile` does not upload files.
35
+ - Clicks inside nested shadow DOM do not work.
36
+ - `focus` and `blur` have no effect.
37
+ - Clipboard actions do not work.
38
+ - A `<select multiple>` submits only its first selected option.
39
+ - An element inside a `visibility: hidden` parent is reported as visible.
40
+ - Some computed styles (`cursor`, `user-select`) differ from Chromium.
41
+ - Rich text editors TinyMCE, Trix, Monaco and ProseMirror do not work.
42
+
43
+ ### Setup
44
+
45
+ Install Obscura following the [official instructions](https://github.com/h4ckf0r0day/obscura#installation) and put `obscura` on `PATH`. Then enable the helper:
46
+
47
+ ```js
48
+ // codecept.conf.js
49
+ export const config = {
50
+ helpers: {
51
+ Obscura: {
52
+ url: 'http://localhost:3000',
53
+ },
54
+ },
55
+ }
56
+ ```
57
+
58
+ If the binary is not on `PATH`, set `binaryPath` in the config or the `OBSCURA_PATH` environment variable.
59
+
60
+ ### Usage
61
+
62
+ ```sh
63
+ npx codeceptjs run
64
+ ```
65
+
66
+ The helper starts `obscura serve` on a free port before the first test and stops it after the last one, like Playwright manages Chromium. Each worker gets its own instance:
67
+
68
+ ```sh
69
+ npx codeceptjs run-workers 8
70
+ ```
71
+
72
+ To connect to an Obscura you started yourself, set `endpoint`; the helper then never starts or stops it:
73
+
74
+ ```sh
75
+ obscura serve --port 9222 --allow-private-network --allow-file-access
76
+ ```
77
+
78
+ ```js
79
+ Obscura: {
80
+ url: 'http://localhost:3000',
81
+ endpoint: 'http://127.0.0.1:9222',
82
+ }
83
+ ```
84
+
85
+ All options: [Obscura helper reference](/helpers/Obscura).
86
+
87
+ ## Lightpanda
88
+
89
+ [Lightpanda](https://lightpanda.io) is an open-source headless browser built from scratch for automation. It runs your app's JavaScript in V8 but never paints anything, which makes it start in milliseconds and use a fraction of Chromium's memory. It computes enough layout for `seeElement`, `waitForVisible` and other visibility checks.
90
+
91
+ Limitations:
92
+
93
+ - No screenshots: `saveScreenshot`, failure screenshots and the `screencast` plugin do not work.
94
+ - No scrolling: `scrollTo` and `scrollPageToBottom` have no effect.
95
+ - `clickXY` does not work.
96
+ - Clipboard actions do not work.
97
+ - Computed styles cover `display`, `visibility` and `opacity`; other CSS properties are unreliable.
98
+ - Rich text editors TinyMCE, Trix and Monaco do not work.
99
+ - Linux and macOS only; on Windows use WSL2.
100
+ - Licensed under AGPL-3.0. It runs as a separate process, so it does not affect the license of your tests.
101
+
102
+ ### Setup
103
+
104
+ Install Lightpanda following the [official instructions](https://lightpanda.io/docs/open-source/installation) and put `lightpanda` on `PATH`. Then enable the helper:
105
+
106
+ ```js
107
+ // codecept.conf.js
108
+ export const config = {
109
+ helpers: {
110
+ Lightpanda: {
111
+ url: 'http://localhost:3000',
112
+ },
113
+ },
114
+ }
115
+ ```
116
+
117
+ If the binary is not on `PATH`, set `binaryPath` in the config or the `LIGHTPANDA_PATH` environment variable.
118
+
119
+ ### Usage
120
+
121
+ ```sh
122
+ npx codeceptjs run
123
+ ```
124
+
125
+ The helper starts `lightpanda serve` on a free port with telemetry turned off, and stops it after the last test. Each worker gets its own instance:
126
+
127
+ ```sh
128
+ npx codeceptjs run-workers 8
129
+ ```
130
+
131
+ To connect to a Lightpanda you started yourself, set `endpoint`; the helper then never starts or stops it:
132
+
133
+ ```sh
134
+ LIGHTPANDA_DISABLE_TELEMETRY=true lightpanda serve --host 127.0.0.1 --port 9222
135
+ ```
136
+
137
+ ```js
138
+ Lightpanda: {
139
+ url: 'http://localhost:3000',
140
+ endpoint: 'http://127.0.0.1:9222',
141
+ }
142
+ ```
143
+
144
+ All options: [Lightpanda helper reference](/helpers/Lightpanda).
145
+
146
+ ## Kitesurf
147
+
148
+ [Kitesurf](https://blog.cloudflare.com/kitesurf/) is Cloudflare's browser running on Cloudflare Workers, with a real layout and rendering pipeline. Sessions start in about a second and nothing runs on your machine, so the number of parallel browsers is limited only by how far your suite splits.
149
+
150
+ Limitations:
151
+
152
+ - Cloud only, currently a free beta.
153
+ - The browser cannot reach `localhost`: test a deployed environment or expose your app with a tunnel such as `cloudflared tunnel --url http://localhost:3000`.
154
+
155
+ ### Setup
156
+
157
+ Enable [Cloudflare Browser Run](https://developers.cloudflare.com/browser-run/) and create an API token with the **Browser Rendering β†’ Edit** permission. Export the credentials:
158
+
159
+ ```sh
160
+ export CF_ACCOUNT_ID=your-account-id
161
+ export CF_API_TOKEN=your-api-token
162
+ ```
163
+
164
+ Then enable the helper:
165
+
166
+ ```js
167
+ // codecept.conf.js
168
+ export const config = {
169
+ helpers: {
170
+ Kitesurf: {
171
+ url: 'https://staging.myapp.com',
172
+ },
173
+ },
174
+ }
175
+ ```
176
+
177
+ ### Usage
178
+
179
+ Every worker opens its own cloud session:
180
+
181
+ ```sh
182
+ npx codeceptjs run-workers 16
183
+ ```
184
+
185
+ All options: [Kitesurf helper reference](/helpers/Kitesurf).
@@ -397,6 +397,79 @@ If two checks failed, the scenario fails with a single aggregated message like:
397
397
  expected soft assertions '[expected web application to include "You must accept the terms", expected element (.summary-error) to be visible]' to be empty
398
398
  ```
399
399
 
400
+ ## Decision Assertions
401
+
402
+ Some checks are hard to express with locators: "checkout form has all required fields", "success message is shown", "sidebar is shown". The [Decision helper](/helpers/Decision) asserts such statements in plain language with a decision model.
403
+
404
+ A [decision model](https://openrouter.ai/models?output_modalities=decisions), like [Jev](https://openrouter.ai/typesafe/jev-1.13), does not generate text. It reads the page and returns the probability that a statement is true. This makes it a good fit for assertions:
405
+
406
+ - **Fast.** One request returns in a fraction of a second, so a decision step runs about as fast as a regular browser step.
407
+ - **Cost-efficient.** A request costs a fraction of a cent. You can run decision assertions in every CI build.
408
+ - **Reliable.** The answer is a probability, not free text. There is nothing to parse, and you choose how confident the model must be for the step to pass.
409
+
410
+ Configure the decision model in `ai.decisionModel` as described in [Configure Decision Models](/ai#configure-decision-models), and enable the helper next to your browser helper:
411
+
412
+ ```js
413
+ helpers: {
414
+ Playwright: { url: 'http://localhost' },
415
+ Decision: {},
416
+ }
417
+ ```
418
+
419
+ `ai.decisionModel` accepts:
420
+
421
+ | Option | Default | Description |
422
+ |---|---|---|
423
+ | `model` | | decision model for `I.decide` |
424
+ | `visualModel` | | decision model with image input for `I.decideVisually` |
425
+ | `confidence` | `0.7` | minimal probability for a statement to pass |
426
+ | `timeout` | `15000` | request timeout in ms |
427
+ | `maxLength` | `12000` | maximal length of ARIA snapshot or HTML sent to the model |
428
+
429
+ Any model from the [OpenRouter decision models](https://openrouter.ai/models?output_modalities=decisions) list can be used with `openrouter.evaluationModel()`. Decisions don't need the `--ai` flag, and `ai.model` is not required.
430
+
431
+ Then assert statements about the current page:
432
+
433
+ ```js
434
+ I.decide('top level navigation is available')
435
+
436
+ I.decide([
437
+ 'checkout form has all required fields',
438
+ 'success message is shown',
439
+ 'submit button enabled',
440
+ 'cancel button present',
441
+ ])
442
+
443
+ I.decideVisually('sidebar is shown')
444
+ ```
445
+
446
+ `I.decide` sends the page URL, title and ARIA snapshot to the model. A statement passes when its probability reaches `confidence`. A list of statements is checked in one request, and every statement must pass. The failure message lists the statements that failed, with their probabilities:
447
+
448
+ ```
449
+ expected page to satisfy "success message is shown" (12%) with confidence of 70%
450
+ ```
451
+
452
+ `I.decideVisually` also sends a screenshot, so it needs a [visual decision model](/ai#visual-decision-model) with image input, like [Clef](https://openrouter.ai/cloudflare/clef), set as `visualModel`. Visual decisions are experimental.
453
+
454
+ To turn decisions off without removing the helper, set its `mode`:
455
+
456
+ | Mode | Behavior |
457
+ |---|---|
458
+ | `assert` | default, fails the step when a statement is not confirmed |
459
+ | `report` | requests the model but never fails, even on API errors; results and errors are added to the step as a comment |
460
+ | `skip` | does not request the model, every decision passes |
461
+
462
+ ```js
463
+ helpers: {
464
+ Playwright: { url: 'http://localhost' },
465
+ Decision: { mode: process.env.CI ? 'assert' : 'skip' },
466
+ }
467
+ ```
468
+
469
+ A failed decision is not retried by the [retryFailedStep](/plugins/retryFailedStep) plugin: asking again would cost another request and return the same answer. Only connection errors and timeouts are retried.
470
+
471
+ Use decision assertions for what a page means, and built-in assertions for exact values. `I.see('Total: $42.00')` is still the right check for a price.
472
+
400
473
  ## Choosing an Approach
401
474
 
402
475
  | You want to check… | Use |
@@ -412,4 +485,5 @@ expected soft assertions '[expected web application to include "You must accept
412
485
  | A matcher the above do not cover | `grab*` + `chai` / `jest` / `node:assert` |
413
486
  | A **reusable, project-specific** check | [Custom helper](/custom-helpers) with `see*` method using `codeceptjs/assertions` |
414
487
  | Many independent checks in one run | `hopeThat` from `codeceptjs/effects` |
488
+ | A statement that is hard to express with locators | [Decision helper](#decision-assertions) β€” `I.decide`, `I.decideVisually` |
415
489
  | Hiding values from logs | `secret()` |
package/docs/bootstrap.md CHANGED
@@ -10,6 +10,8 @@ you can use the `bootstrap` and `teardown` config. Use it to start and stop a we
10
10
 
11
11
  When using the [parallel execution](/parallel) mode, there are two additional hooks available; `bootstrapAll` and `teardownAll`. See [bootstrapAll & teardownAll](#bootstrapall-teardownall) for more information.
12
12
 
13
+ > To start and stop the application under test, use the [`webServer`](/configuration#web-server) option instead of writing bootstrap code.
14
+
13
15
 
14
16
  ### Example: Bootstrap & Teardown
15
17