@ralphralphai/playwright 0.1.0 → 1.1.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
@@ -1,134 +1,220 @@
1
1
  # @ralphralphai/playwright
2
2
 
3
- Opt-in Playwright fixtures for recording the page states a test visits. Ralph
4
- automatically captures URL changes, and explicit captures handle dialogs and
5
- other states at the same URL. Each capture contains a screenshot, the recorded
6
- and actual URLs, and `data-track-id` element positions.
3
+ Turn your Playwright tests into a map of your app for
4
+ [Ralph](https://ralphralph.ai).
7
5
 
8
- The fixture saves local artifacts and can upload a gzip-compressed tar bundle per
9
- test attempt. Graph construction runs on the server; ingestion currently returns
10
- an attempt receipt, with graph processing and the dashboard URL still pending.
6
+ Tag a test with `@ralph` and every page it visits is recorded: a full-page
7
+ screenshot, the URL, and the position of every element with a `data-track-id`.
8
+ Untagged tests are untouched, and recording is off unless you turn it on.
11
9
 
12
- ## Install and enable
10
+ ## Install
13
11
 
14
- Requires Node.js 20.19+ and Playwright Test 1.62.1+ within major version 1.
12
+ Requires Node.js 20.19+ and Playwright Test 1.62.1+ (major version 1).
15
13
 
16
14
  ```sh
17
15
  pnpm add -D @ralphralphai/playwright @playwright/test
18
16
  pnpm exec playwright install chromium
19
17
  ```
20
18
 
21
- Put a `ralph.jsonc` next to `playwright.config.ts`:
19
+ ## Quick start
22
20
 
23
- ```json
21
+ **1. Add a `ralph.jsonc`** next to `playwright.config.ts`:
22
+
23
+ ```jsonc
24
24
  {
25
- "screenSizes": []
25
+ "$schema": "./node_modules/@ralphralphai/config/schema/ralph.schema.json",
26
+ "screenSizes": [{ "width": 1280, "height": 720 }]
26
27
  }
27
28
  ```
28
29
 
29
- The actual viewport is controlled by Playwright; use `ralphProjects` to run
30
- tests at the config's `screenSizes` (see [Screen sizes](#screen-sizes)). The
31
- fixture preserves the Ralph config; it does not run its simple URL crawls.
30
+ See [`@ralphralphai/config`](https://www.npmjs.com/package/@ralphralphai/config)
31
+ for all fields.
32
32
 
33
- Use Ralph's extended `test` and tag the tests that should participate:
33
+ **2. Import `test` from this package and tag tests with `@ralph`:**
34
34
 
35
35
  ```ts
36
36
  import { test, expect } from '@ralphralphai/playwright';
37
37
 
38
- test('checkout', { tag: '@ralph' }, async ({ page, ralph }) => {
38
+ test('checkout', { tag: '@ralph' }, async ({ page }) => {
39
39
  await page.goto('https://example.com/cart');
40
- await ralph.flush();
40
+ await page.getByRole('link', { name: 'Checkout' }).click();
41
+ await expect(page).toHaveURL(/checkout/);
42
+ });
43
+ ```
44
+
45
+ **3. Add the Ralph reporter** in `playwright.config.ts`:
46
+
47
+ ```ts
48
+ export default defineConfig({
49
+ reporter: [['list'], ['@ralphralphai/playwright/reporter']],
50
+ });
51
+ ```
52
+
53
+ **4. Run:**
54
+
55
+ ```sh
56
+ RALPH_MODE=local pnpm exec playwright test
57
+ ```
58
+
59
+ The merged graph for the run is written to `test-results/ralph/`. To send it to
60
+ Ralph, see [Uploading to Ralph](#uploading-to-ralph).
61
+
62
+ ## Tag your elements
63
+
64
+ Add `data-track-id` to elements, using the same ids as your
65
+ [`@ralphralphai/tracker`](https://www.npmjs.com/package/@ralphralphai/tracker)
66
+ setup:
67
+
68
+ ```html
69
+ <button data-track-id="add-to-cart">Add to cart</button>
70
+ ```
71
+
72
+ ## Recording pages
73
+
74
+ ### Automatically
75
+
76
+ A page is recorded whenever the URL changes in any tab of the test: page loads,
77
+ redirects (the final page), SPA route changes, query and hash changes, and new
78
+ tabs and popups. Reloads, iframes, `about:blank`, and changes that keep the URL
79
+ are not recorded.
41
80
 
81
+ Each recording waits for the DOM to load plus `settleMs` (150 ms). If your app
82
+ needs longer, use `ready`:
83
+
84
+ ```ts
85
+ ralphOptions: {
86
+ ready: async (page, signal) => {
87
+ await page.getByTestId('app-ready').waitFor({ timeout: 3000 });
88
+ },
89
+ },
90
+ ```
91
+
92
+ CSS animations and transitions are frozen for the screenshot. For animations
93
+ driven from JavaScript, set `reduceMotion` if your app honors
94
+ `prefers-reduced-motion`.
95
+
96
+ ### Explicitly, for states at the same URL
97
+
98
+ For dialogs, menus, and tabs, call `ralph.recordNode` after your assertions:
99
+
100
+ ```ts
101
+ test('shipping options', { tag: '@ralph' }, async ({ page, ralph }) => {
102
+ await page.goto('https://example.com/cart');
42
103
  await page.getByRole('button', { name: 'Shipping options' }).click();
43
104
  await expect(page.getByRole('dialog')).toBeVisible();
44
105
 
45
- await ralph.captureNode(page, {
46
- state: 'shipping-options-open',
47
- url: '/checkout/shipping-options',
106
+ await ralph.recordNode(page, {
107
+ state: 'shipping-options-open', // a label for this state
108
+ url: '/checkout/shipping-options', // optional: the URL to record it under
48
109
  });
49
110
  });
111
+ ```
50
112
 
51
- test('ordinary validation', async ({ page }) => {
52
- await page.goto('https://example.com/login');
53
- await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible();
54
- });
113
+ `url` only changes what is recorded; the browser doesn't navigate.
114
+
115
+ ### Waiting for capture
116
+
117
+ Recordings run in the background. If the test leaves a page before its
118
+ screenshot is done, the page is `uncaptured`: it's in the graph without a
119
+ screenshot. To make sure a page is captured before leaving it:
120
+
121
+ ```ts
122
+ await page.goto('https://example.com/pricing');
123
+ await ralph.waitForCapture();
124
+ await page.goto('https://example.com/signup');
55
125
  ```
56
126
 
57
- ```sh
58
- RALPH_MODE=local pnpm exec playwright test
127
+ ### Pausing capture
128
+
129
+ To leave steps out of the graph:
130
+
131
+ ```ts
132
+ await page.goto('https://example.com/a');
133
+ ralph.pause();
134
+ await page.goto('https://example.com/b'); // not recorded
135
+ await page.goto('https://example.com/c'); // not recorded
136
+ ralph.resume();
137
+ await page.goto('https://example.com/d'); // recorded, linked from /a
59
138
  ```
60
139
 
61
- Recording defaults to off. Normal `pnpm exec playwright test` runs need no
62
- Ralph config or credentials. Unmarked tests stay unrecorded in every mode.
63
- Calling `ralph.capture` in an unmarked test while recording is enabled reports
64
- the missing `@ralph` tag.
65
-
66
- `RALPH_MODE=off` disables recording and makes explicit capture calls no-ops.
67
- Tests that import directly from `@playwright/test` continue to work alongside
68
- Ralph tests. Importing the integration does not launch a browser for API-only
69
- tests.
70
-
71
- `RALPH_MODE=upload`, or setting `RALPH_UPLOAD_KEY` without an explicit mode,
72
- enables uploading. Set `RALPH_API_URL` to your Ralph server origin (or set
73
- `ralphOptions.apiUrl`). The origin must use HTTPS; plain HTTP is accepted only
74
- for loopback hosts (`localhost`, `127.x.x.x`, `[::1]`) during local development.
75
- Issue a private upload key for your Ralph project with the authenticated
76
- `/api/project/playwright/key/create` endpoint and keep it in CI secrets. A key belongs to
77
- the project, so one key serves every app in it. Set `RALPH_APP_ID` (or
78
- `ralphOptions.appId`) to the app the captures belong to.
140
+ This works across tabs. While paused, `recordNode` does nothing. `resume` does
141
+ not record the current page.
79
142
 
80
- ```sh
81
- RALPH_MODE=upload RALPH_API_URL=https://your-ralph-server.example RALPH_APP_ID=<app id> pnpm exec playwright test
143
+ ### Browser contexts you create yourself
144
+
145
+ ```ts
146
+ const context = await browser.newContext();
147
+ ralph.observe(context);
148
+ // ...
149
+ await ralph.waitForCapture();
150
+ await context.close();
82
151
  ```
83
152
 
84
- This uses `RALPH_UPLOAD_KEY` from the environment. Each opted-in attempt uploads
85
- once during fixture teardown, after its local manifest and screenshots are saved.
86
- No reporter configuration is required. `off`, `local`, and unmarked tests do not
87
- upload, even if CI provides a key. Upload failures fail fixture teardown and leave
88
- local artifacts available according to Playwright's `preserveOutput` setting.
89
- Successful uploads attach a `ralph-upload-receipt`; credentials are never written
90
- to the manifest or receipt.
91
-
92
- ## Capture behavior
93
-
94
- Automatic capture watches main-frame HTTP(S) URLs in the standard `context`
95
- fixture, including new tabs and popups. It includes the first application URL,
96
- full-document navigation, SPA history changes, query changes, and hash changes.
97
- It skips `about:blank`, subframe navigation, same-URL reloads, and DOM-only changes.
98
-
99
- Automatic captures wait for DOM content loaded and then settle for 150 ms by
100
- default. A URL change does not prove application readiness. Supply `ready` for
101
- an application-specific condition, or explicitly capture after your assertions.
102
-
103
- Capture runs in the background and is serialized per browser page. A test can
104
- navigate again before a screenshot completes. Such nodes are retained as
105
- `superseded`, without a screenshot attributed to the wrong URL. Use
106
- `await ralph.flush()` to wait for currently queued captures before deliberately
107
- leaving a state whose screenshot you need. This is also useful before manually
108
- closing a page or context.
109
-
110
- The standard context fixture drains captures before closing its pages. Manually
111
- created contexts can be enrolled with `ralph.observe(context)`; their owner must
112
- flush before closing them. An explicit capture enrolls its page's context too.
113
-
114
- `await ralph.captureNode(page, { state?, url? })` always requests a node,
115
- even at the same URL. It uses the current state without the automatic settling
116
- delay or readiness hook. A relative URL override resolves against the actual
117
- browser URL. It does not navigate, change history, or affect subsequent automatic
118
- captures. Only HTTP(S) recorded URLs are accepted.
119
-
120
- Explicit capture errors reject the call. Automatic capture errors are written
121
- to the manifest and fail an otherwise passing opted-in test at fixture teardown.
122
- Superseded captures and detected geometry changes mark the manifest incomplete,
123
- without independently failing the test.
153
+ ### When recording fails
154
+
155
+ - A failed `recordNode` call rejects.
156
+ - A failed automatic recording fails the test at the end.
157
+ - Pages left before capture, and pages whose layout moved during the
158
+ screenshot, don't fail the test.
159
+
160
+ ## Modes
161
+
162
+ Set with `RALPH_MODE` or the `mode` option:
163
+
164
+ | Mode | What happens |
165
+ | -------- | --------------------------------------------------------------------------------------------------- |
166
+ | `off` | Default. Nothing is recorded, and no config or credentials are needed. |
167
+ | `local` | `@ralph` tests are recorded, and the reporter writes the merged graph locally. |
168
+ | `upload` | As `local`, and the reporter uploads the graph once the run ends. Default when `RALPH_UPLOAD_KEY` is set. |
169
+
170
+ Untagged tests are never recorded. In `local` or `upload` mode, calling
171
+ `ralph.recordNode` in an untagged test throws.
172
+
173
+ ## Uploading to Ralph
174
+
175
+ 1. Create an upload key for your project with `/api/project/key/create`, and
176
+ keep it in your CI secrets.
177
+ 2. Set these as environment variables, or `apiUrl` and `appId` as
178
+ [reporter options](#reporter-options):
179
+
180
+ | Variable | Value |
181
+ | ------------------ | ----------------------------------------------- |
182
+ | `RALPH_UPLOAD_KEY` | The upload key. Environment only. |
183
+ | `RALPH_API_URL` | Your Ralph server. HTTPS, or HTTP on localhost. |
184
+ | `RALPH_APP_ID` | The app the recordings belong to. |
185
+
186
+ 3. Run:
187
+
188
+ ```sh
189
+ RALPH_MODE=upload pnpm exec playwright test
190
+ ```
191
+
192
+ The reporter uploads the whole run once and prints the link:
193
+
194
+ ```
195
+ Ralph: uploaded the run's raw graph. https://dash.ralphralph.ai/uploads/0f6c6a2e-…
196
+ ```
197
+
198
+ - Retried tests contribute only their final attempt.
199
+ - Every test in a run must use the same Ralph config, `runId`, and `buildId`.
200
+ - If the upload fails, the run fails.
201
+
202
+ ### Sharded runs
203
+
204
+ Use the `blob` reporter on each shard, then merge with the Ralph reporter:
205
+
206
+ ```sh
207
+ # Each shard (no upload credentials needed):
208
+ RALPH_MODE=upload pnpm exec playwright test --shard=1/4 --reporter blob
209
+
210
+ # Once, after collecting every shard's blob-report/ into all-blob-reports/:
211
+ RALPH_MODE=upload RALPH_UPLOAD_KEY=… RALPH_API_URL=… RALPH_APP_ID=… \
212
+ pnpm exec playwright merge-reports --reporter @ralphralphai/playwright/reporter ./all-blob-reports
213
+ ```
124
214
 
125
215
  ## Screen sizes
126
216
 
127
- A viewport is fixed for a browser context, and a mobile flow is usually a
128
- different test from its desktop flow. So each `screenSizes` entry becomes its
129
- own Playwright project. `ralphProjects` reads the Ralph config synchronously
130
- and expands a base project into one project per size. Each project's viewport
131
- is that size:
217
+ Use `ralphProjects` to create one project per entry in `screenSizes`:
132
218
 
133
219
  ```ts
134
220
  import { defineConfig, devices } from '@playwright/test';
@@ -136,10 +222,8 @@ import { ralphProjects, type RalphFixtures } from '@ralphralphai/playwright';
136
222
 
137
223
  export default defineConfig<RalphFixtures>({
138
224
  projects: [
139
- // Ordinary tests keep their single project.
140
225
  { name: 'chromium', grepInvert: /@ralph\b/, use: devices['Desktop Chrome'] },
141
- // With screenSizes 375x812, 768x1024 and 1280x720, this yields the projects
142
- // "chromium 375x812", "chromium 768x1024" and "chromium 1280x720".
226
+ // Creates "chromium 375x812", "chromium 1280x720", …
143
227
  ...ralphProjects({
144
228
  name: 'chromium',
145
229
  grep: /@ralph\b/,
@@ -149,202 +233,72 @@ export default defineConfig<RalphFixtures>({
149
233
  });
150
234
  ```
151
235
 
152
- A relative `configPath` resolves against the current directory. Pass
153
- `{ root: import.meta.dirname }` (or `__dirname`) or an inline `config` as the
154
- second argument when Playwright runs from elsewhere. Keep it pointing at the
155
- same config as `ralphOptions`.
236
+ `ralphProjects` reads `ralph.jsonc` from the current directory. Otherwise pass
237
+ `{ root: import.meta.dirname }` or an inline `config` as the second argument.
156
238
 
157
- By default, a test runs at every screen size. Tag a test or a `describe` block
158
- with `@ralph-screen:WIDTHxHEIGHT`, once per size, to run it only at the listed
159
- sizes. Tags on a `describe` block and its tests combine. The other
160
- screen projects skip it:
239
+ A test runs at every size. To run it only at some sizes, tag it or its
240
+ `describe` block with `@ralph-screen:WIDTHxHEIGHT`, once per size:
161
241
 
162
242
  ```ts
163
- test(
164
- 'mobile navigation',
165
- { tag: ['@ralph', '@ralph-screen:375x812'] },
166
- async ({ page }) => {
167
- await page.getByRole('button', { name: 'Menu' }).click();
168
- },
169
- );
170
-
171
- // One tag per size: runs at 768x1024 and 1280x720, skipped at 375x812.
172
- test(
173
- 'data table',
174
- { tag: ['@ralph', '@ralph-screen:768x1024', '@ralph-screen:1280x720'] },
175
- async ({ page }) => {},
176
- );
243
+ test('mobile navigation', { tag: ['@ralph', '@ralph-screen:375x812'] }, async ({ page }) => {
244
+ await page.getByRole('button', { name: 'Menu' }).click();
245
+ });
177
246
 
178
247
  test.describe('desktop layouts', { tag: '@ralph-screen:1280x720' }, () => {
179
248
  test('sidebar', { tag: '@ralph' }, async ({ page }) => {});
180
249
  });
181
250
  ```
182
251
 
183
- Screen tags apply in every mode, including `off`, and to untagged tests, because
184
- they choose which flows run. A size the config does not declare fails the test,
185
- so typos don't silently skip it. Projects not created by `ralphProjects` ignore
186
- screen tags. To run one size from the command line, use Playwright's project
187
- filter: `playwright test --project "chromium 375x812"`.
188
-
189
- ## Options
252
+ A size missing from `screenSizes` fails the test.
190
253
 
191
- `WebRalphConfig` is re-exported as a type from this package for inline config
192
- annotations. Its definition remains in `@ralphralphai/config`:
193
-
194
- ```ts
195
- import type { WebRalphConfig } from '@ralphralphai/playwright';
254
+ To run one size: `playwright test --project "chromium 375x812"`.
196
255
 
197
- const config: WebRalphConfig = { screenSizes: [] };
198
- ```
256
+ ## Options
199
257
 
200
- Set `ralphOptions` with `test.use` or Playwright's configuration:
258
+ Set `ralphOptions` in `playwright.config.ts`, or per file with `test.use`:
201
259
 
202
260
  ```ts
203
- import { defineConfig } from '@playwright/test';
204
- import type { RalphFixtures } from '@ralphralphai/playwright';
205
-
206
261
  export default defineConfig<RalphFixtures>({
207
262
  use: {
208
- viewport: { width: 1280, height: 720 },
209
- ralphOptions: {
210
- mode: 'local',
211
- configPath: './ralph.jsonc',
212
- buildId: 'application-build-id',
213
- runId: 'ci-run-id',
214
- settleMs: 150,
215
- captureTimeoutMs: 5000,
216
- ready: async (page, signal) => {
217
- signal.throwIfAborted();
218
- await page.getByTestId('app-ready').waitFor({ timeout: 3000 });
219
- },
220
- },
263
+ ralphOptions: { mode: 'local', buildId: process.env.GIT_SHA, settleMs: 300 },
221
264
  },
222
265
  });
223
266
  ```
224
267
 
225
- | Option | Behavior |
226
- | --- | --- |
227
- | `mode` | `off`, `local`, or `upload`; overrides `RALPH_MODE` |
228
- | `apiUrl` | Server origin for uploads; falls back to `RALPH_API_URL` |
229
- | `uploadTimeoutMs` | Upload request deadline; defaults to 15000 ms |
230
- | `configPath` | Relative to the Playwright config directory; defaults to `ralph.jsonc` |
231
- | `config` | Inline `WebRalphConfig` instead of a config file |
232
- | `buildId` | Optional application build ID; falls back to `RALPH_BUILD_ID` |
233
- | `runId` | Optional shared CI run ID; falls back to `RALPH_RUN_ID` |
234
- | `settleMs` | Automatic settling delay; defaults to 150 ms |
235
- | `captureTimeoutMs` | Per-capture browser-work deadline; defaults to 5000 ms |
236
- | `ready` | Optional automatic-capture readiness callback with an abort signal |
237
-
238
- The deadline includes settling and readiness. Custom readiness work should
239
- honor the signal or use its own bounded Playwright operations. Ralph can stop
240
- waiting for a callback but cannot cancel arbitrary user code.
241
-
242
- Config files accept JSONC comments and trailing commas and are validated against
243
- the published config schema. The complete parsed values are snapshotted without
244
- injecting schema defaults, along with the config package version.
245
- Snapshots are cached per config source within a worker. Keep the config unchanged
246
- during a run; the server compares configs across workers before combining
247
- attempts. Run/build IDs are optional for local exploration, and unique
248
- attempt IDs are always generated.
249
-
250
- ## Existing fixtures
251
-
252
- Compose Ralph with the test object your project already uses:
268
+ | Option | Default | What it does |
269
+ | ----------------- | ------------------------ | ----------------------------------------------------------------------------------------------- |
270
+ | `mode` | `RALPH_MODE`, else `off` | `off`, `local`, or `upload`. See [Modes](#modes). |
271
+ | `configPath` | `ralph.jsonc` | Path to the config, relative to the Playwright config. |
272
+ | `config` | | An inline config instead of a file (type: `WebRalphConfig`). |
273
+ | `buildId` | `RALPH_BUILD_ID` | Your app's build, to line up recordings with its analytics. |
274
+ | `runId` | `RALPH_RUN_ID` | Identifies the CI run. |
275
+ | `settleMs` | 150 | Wait after the DOM loads before an automatic recording. |
276
+ | `recordTimeoutMs` | 5000 | Budget for one recording, including `settleMs` and `ready`. Must exceed `settleMs`. |
277
+ | `ready` | | `(page, signal) => Promise<void>`. Waits for your app before an automatic recording. Honor `signal`. |
278
+ | `reduceMotion` | `false` | Emulates `prefers-reduced-motion: reduce` and waits for finite animations before recording. |
253
279
 
254
- ```ts
255
- import { mergeTests } from '@playwright/test';
256
- import { test as ralphTest } from '@ralphralphai/playwright';
257
- import { test as applicationTest } from './application-fixtures';
280
+ ## Reporter options
258
281
 
259
- export const test = mergeTests(applicationTest, ralphTest);
282
+ ```ts
283
+ reporter: [['list'], ['@ralphralphai/playwright/reporter', { appId: 'my-app' }]],
260
284
  ```
261
285
 
262
- If a custom fixture replaces the standard context entirely, enroll that context
263
- using `ralph.observe(context)`. Capture it while it is still alive.
264
-
265
- ## Artifacts
266
-
267
- Each opted-in attempt writes `ralph/captures.json` and full-page screenshots within
268
- Playwright's per-test output directory. The JSON is attached as
269
- `ralph-captures`; screenshots are attached with unique names referenced by the
270
- manifest. Copy the full test output or retain the Playwright attachments.
271
- Configure Playwright to preserve successful test output when collecting captures.
272
-
273
- The exported `CaptureManifest` and `RawNode` types describe format
274
- version 1. The manifest includes the config snapshot, producer versions, optional run and
275
- build IDs, test/project/retry/repeat/shard identity, separate browser-page streams,
276
- opener relationships, and the `nodes` the test produced.
277
-
278
- Each entry in `nodes` is a raw node: one page state as the test saw it, with a
279
- sequence within its page. The same page visited twice produces two raw nodes,
280
- and superseded or failed captures are kept too. The server merges raw nodes
281
- into the graph's nodes; this package does no normalization or merging.
282
-
283
- Each node records `previousNodeId`, the node its page state was reached from:
284
- the previous one on the same page, or for a popup's first node, its opener's
285
- latest. Superseded nodes are skipped. No code is injected into
286
- the page; the flow comes from the order of URL changes.
287
-
288
- Screenshots are WebP at quality 80, falling back to PNG for pages over 16,383
289
- pixels in either dimension, which WebP cannot encode. They use one image pixel
290
- per CSS pixel, including on high-DPI devices.
291
- Tracked-element boxes use document CSS coordinates and preserve duplicate track
292
- IDs as separate boxes. Collection includes visible elements in the main frame,
293
- including open shadow roots; it does not collect child-frame geometry. Elements
294
- with zero width or height, or entirely off-screen horizontally, are dropped;
295
- elements below the fold are kept.
296
- The manifest records viewport, document extent, scroll position, screenshot size,
297
- and device pixel ratio.
298
-
299
- Geometry is measured before and after the screenshot. Differences set
300
- `geometryStable: false`. This detects layout drift, not every visual change;
301
- animations, sticky elements, and virtualized content can still need explicit
302
- application preparation. The package does not freeze or alter the application.
303
-
304
- An attempt is `complete` only when the test has passed at fixture finalization,
305
- there is at least one node, and every node has a screenshot with
306
- stable measured geometry. A future reporter must reconcile this with the final
307
- Playwright result if another fixture fails later. Retries have distinct manifests
308
- and attempt IDs; partial nodes are preserved.
309
-
310
- ## Upload format and retries
311
-
312
- The HTTP body is one `application/gzip` tar archive. `capture.json` holds UTF-8
313
- JSON `{ manifest, screenshots: [{ nodeId, path }] }`, and each `path` points to
314
- a raw WebP (or PNG fallback) under `assets/images/`. The manifest includes the exact config
315
- snapshot.
316
- The package emits only its current `formatVersion: 1`; the server independently
317
- keeps versioned Zod schemas and selects one by `formatVersion`. No crawler API
318
- package or server schema is imported by this integration.
319
-
320
- The limits per attempt are 64 MiB compressed, 2 MiB manifest JSON, 64 MiB total
321
- screenshot bytes, and 500 screenshots. Server validation
322
- also limits nodes to 5,000. Split larger scenarios into smaller tests.
323
- Screenshots are already compressed; gzip mainly compresses the manifest.
324
-
325
- `uploadCapture(manifest, screenshots, { apiUrl, uploadKey, timeoutMs? })` can retry
326
- saved artifacts, where each screenshot is `{ nodeId, contentType, bytes: Uint8Array }`.
327
- `createCaptureBundle(manifest, screenshots)` returns the gzip bytes when a caller
328
- needs to handle transport itself. An identical retry preserves `attemptId` and
329
- returns `replayed: true`; changed contents under the same ID are rejected. There
330
- are no automatic HTTP retries. Playwright test retries create new attempt IDs.
331
- The manifest's status reflects fixture finalization; a future reporter can
332
- reconcile failures in fixtures that finish later.
333
-
334
- ## Development
335
-
336
- From the repository root:
286
+ | Option | Default | What it does |
287
+ | ----------------- | ------------------------------------------------- | ----------------------------------------------- |
288
+ | `mode` | `RALPH_MODE`, else `upload` if `RALPH_UPLOAD_KEY` | `upload` uploads the run. |
289
+ | `apiUrl` | `RALPH_API_URL` | Your Ralph server. |
290
+ | `appId` | `RALPH_APP_ID` | The app the recordings belong to. |
291
+ | `uploadTimeoutMs` | 120000 | Upload timeout. |
292
+ | `outputDir` | `ralph/` in the first project's output directory | Where the merged graph is written. |
337
293
 
338
- ```sh
339
- pnpm --filter @ralphralphai/config build
340
- pnpm --filter @ralphralphai/playwright build
341
- pnpm --filter @ralphralphai/playwright check
342
- pnpm --filter @ralphralphai/playwright lint
343
- pnpm --filter @ralphralphai/playwright test
344
- pnpm --filter @ralphralphai/playwright exec playwright install chromium
345
- pnpm --filter @ralphralphai/playwright test:browser
346
- ```
294
+ The run is also uploaded when any test ran in `upload` mode.
295
+
296
+ ## Limits
297
+
298
+ Per run: 5,000 screenshots, 256 MiB of screenshots, 16 MiB of other recorded
299
+ data, 256 MiB compressed, 20,000 recorded pages, and 5,000 recorded pages per
300
+ test.
301
+
302
+ ## License
347
303
 
348
- The browser suite runs real Playwright tests against locally supplied pages,
349
- then checks the emitted manifests and screenshot attachments. It includes an
350
- intentional failed first attempt to verify retry isolation.
304
+ Apache-2.0