craftdriver 1.2.0 → 1.3.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.
@@ -0,0 +1,372 @@
1
+ /**
2
+ * Export Craftdriver's crash-resilient trace directory as the
3
+ * Playwright-compatible recording layout consumed by Vibium Player.
4
+ */
5
+ import { createWriteStream, existsSync, mkdirSync, readFileSync } from 'node:fs';
6
+ import { createRequire } from 'node:module';
7
+ import { dirname, join } from 'node:path';
8
+ import { randomBytes } from 'node:crypto';
9
+ import yazl from 'yazl';
10
+ const require = createRequire(import.meta.url);
11
+ const pkg = require('../../package.json');
12
+ const ACTIONS = {
13
+ navigateTo: { class: 'Page', method: 'navigate' },
14
+ goBack: { class: 'Page', method: 'goBack' },
15
+ goForward: { class: 'Page', method: 'goForward' },
16
+ reload: { class: 'Page', method: 'reload' },
17
+ setContent: { class: 'Page', method: 'setContent' },
18
+ click: { class: 'Element', method: 'click' },
19
+ fill: { class: 'Element', method: 'fill' },
20
+ clear: { class: 'Element', method: 'clear' },
21
+ acceptDialog: { class: 'Dialog', method: 'accept' },
22
+ dismissDialog: { class: 'Dialog', method: 'dismiss' },
23
+ };
24
+ /** Write a Vibium/Playwright-compatible trace zip from a stopped raw trace. */
25
+ export async function writeVibiumTraceZip(opts) {
26
+ if (!opts.path)
27
+ throw new Error('stopTrace({ path }) requires a non-empty zip path.');
28
+ const raw = readRawTrace(join(opts.sourceDir, 'trace.ndjson'));
29
+ const started = raw.find((event) => event.type === 'meta' && typeof event.startedAt === 'string');
30
+ const startWallTime = started?.startedAt ? Date.parse(started.startedAt) : Date.now();
31
+ const id = randomBytes(6).toString('hex');
32
+ const contextId = `context@${id}`;
33
+ const pageId = `page@${id}`;
34
+ const resources = [];
35
+ const ordered = [];
36
+ const exportedActions = [];
37
+ let sequence = 0;
38
+ let callCounter = 0;
39
+ const screenshots = raw.filter((event) => event.type === 'screenshot');
40
+ const firstScreenshot = screenshots.find((event) => existsSync(join(opts.sourceDir, event.file)));
41
+ const viewport = firstScreenshot
42
+ ? readPngSize(readFileSync(join(opts.sourceDir, firstScreenshot.file)))
43
+ : { width: 1280, height: 720 };
44
+ const actionTimes = [];
45
+ const actionEnds = new Map(raw.filter((event) => event.type === 'action-end').map((event) => [event.actionIndex, event]));
46
+ for (const event of raw) {
47
+ if (event.type !== 'action')
48
+ continue;
49
+ const callId = `call@${++callCounter}`;
50
+ const actionIndex = event.actionIndex ?? callCounter;
51
+ const completed = actionEnds.get(actionIndex);
52
+ const endTime = Math.max(event.t + 1, completed?.t ?? event.t + 1);
53
+ const mapping = ACTIONS[event.name] ?? { class: 'Browser', method: event.name };
54
+ const params = actionParams(event);
55
+ actionTimes.push(event.t);
56
+ const before = {
57
+ type: 'before',
58
+ callId,
59
+ startTime: event.t,
60
+ class: mapping.class,
61
+ method: mapping.method,
62
+ pageId,
63
+ params,
64
+ title: actionTitle(mapping, params),
65
+ };
66
+ const after = { type: 'after', callId, endTime };
67
+ if (completed?.error) {
68
+ after.error = { name: 'Error', message: completed.error };
69
+ }
70
+ exportedActions.push({ callId, before, after });
71
+ ordered.push({
72
+ time: event.t,
73
+ order: 3,
74
+ sequence: sequence++,
75
+ value: before,
76
+ });
77
+ // Older raw traces have no completion marker. Use WDIO's conservative
78
+ // 1 ms minimum for those; current traces carry the real end timestamp.
79
+ ordered.push({
80
+ time: endTime,
81
+ order: 1,
82
+ sequence: sequence++,
83
+ value: after,
84
+ });
85
+ }
86
+ const usedResourceNames = new Set();
87
+ const addFrame = (sourcePath, frameTime) => {
88
+ if (!existsSync(sourcePath))
89
+ return undefined;
90
+ const data = readFileSync(sourcePath);
91
+ const size = readPngSize(data);
92
+ let wallTime = startWallTime + Math.max(0, Math.floor(frameTime));
93
+ let resourceName = `${pageId}-${wallTime}.png`;
94
+ while (usedResourceNames.has(resourceName)) {
95
+ resourceName = `${pageId}-${++wallTime}.png`;
96
+ }
97
+ usedResourceNames.add(resourceName);
98
+ resources.push({ sourcePath, name: resourceName });
99
+ ordered.push({
100
+ time: frameTime,
101
+ order: 2,
102
+ sequence: sequence++,
103
+ value: {
104
+ type: 'screencast-frame',
105
+ pageId,
106
+ sha1: resourceName,
107
+ width: size.width,
108
+ height: size.height,
109
+ timestamp: frameTime,
110
+ },
111
+ });
112
+ return {
113
+ time: frameTime,
114
+ name: resourceName,
115
+ width: size.width,
116
+ height: size.height,
117
+ dataUri: `data:image/png;base64,${data.toString('base64')}`,
118
+ url: pageUrlAt(raw, frameTime),
119
+ };
120
+ };
121
+ const actionFrames = new Map();
122
+ let finalFrame;
123
+ for (const event of screenshots) {
124
+ const frameTime = event.actionIndex
125
+ ? (actionTimes[event.actionIndex - 1] ?? event.t)
126
+ : event.t;
127
+ const frame = addFrame(join(opts.sourceDir, event.file), frameTime);
128
+ if (!frame)
129
+ continue;
130
+ if (event.actionIndex !== undefined)
131
+ actionFrames.set(event.actionIndex, frame);
132
+ if (event.reason === 'final')
133
+ finalFrame = frame;
134
+ }
135
+ // Backwards compatibility for traces produced by the first recipe draft.
136
+ const finalScreenshot = join(opts.sourceDir, 'final.png');
137
+ if (!finalFrame && existsSync(finalScreenshot)) {
138
+ const finalTime = Math.max(0, ...raw.map((event) => event.t)) + 1;
139
+ finalFrame = addFrame(finalScreenshot, finalTime);
140
+ }
141
+ // Vibium uses a minimal HTML document containing the screenshot as its
142
+ // Playwright-compatible frame snapshot. This makes the main viewer panel
143
+ // useful without pretending Craftdriver captured a restorable page DOM.
144
+ for (let index = 0; index < exportedActions.length; index++) {
145
+ const action = exportedActions[index];
146
+ const beforeFrame = actionFrames.get(index + 1);
147
+ const afterFrame = actionFrames.get(index + 2) ?? finalFrame;
148
+ if (beforeFrame) {
149
+ const name = `before@${action.callId}`;
150
+ action.before.beforeSnapshot = name;
151
+ addFrameSnapshot(ordered, action.callId, name, pageId, beforeFrame, sequence++);
152
+ }
153
+ if (afterFrame) {
154
+ const name = `after@${action.callId}`;
155
+ action.after.afterSnapshot = name;
156
+ addFrameSnapshot(ordered, action.callId, name, pageId, afterFrame, sequence++);
157
+ }
158
+ }
159
+ for (const event of raw) {
160
+ const value = bidiEvent(event);
161
+ if (!value)
162
+ continue;
163
+ ordered.push({ time: event.t, order: 2, sequence: sequence++, value });
164
+ }
165
+ ordered.sort((a, b) => a.time - b.time || a.order - b.order || a.sequence - b.sequence);
166
+ const contextOptions = {
167
+ version: 8,
168
+ type: 'context-options',
169
+ origin: 'library',
170
+ libraryName: 'craftdriver',
171
+ libraryVersion: pkg.version,
172
+ browserName: opts.browserName === 'chrome' ? 'chromium' : opts.browserName,
173
+ platform: process.platform === 'darwin' ? 'darwin' : process.platform === 'win32' ? 'windows' : 'linux',
174
+ wallTime: startWallTime,
175
+ monotonicTime: 0,
176
+ sdkLanguage: 'javascript',
177
+ title: opts.title ?? 'Craftdriver trace',
178
+ contextId,
179
+ options: { viewport },
180
+ };
181
+ const traceText = [contextOptions, ...ordered.map((event) => event.value)]
182
+ .map((event) => JSON.stringify(event))
183
+ .join('\n');
184
+ const networkText = buildNetworkTrace(raw, startWallTime, pageId);
185
+ mkdirSync(dirname(opts.path), { recursive: true });
186
+ await writeZip(opts.path, traceText, networkText, resources);
187
+ }
188
+ function addFrameSnapshot(ordered, callId, snapshotName, pageId, frame, sequence) {
189
+ ordered.push({
190
+ time: frame.time,
191
+ order: 2.5,
192
+ sequence,
193
+ value: {
194
+ type: 'frame-snapshot',
195
+ snapshot: {
196
+ callId,
197
+ snapshotName,
198
+ pageId,
199
+ frameId: pageId,
200
+ frameUrl: frame.url,
201
+ doctype: 'html',
202
+ html: [
203
+ 'HTML', {},
204
+ ['HEAD', {}],
205
+ ['BODY', { style: 'margin:0;overflow:hidden' }, [
206
+ 'IMG', { src: frame.dataUri, style: 'width:100%' },
207
+ ]],
208
+ ],
209
+ viewport: { width: frame.width, height: frame.height },
210
+ timestamp: frame.time,
211
+ wallTime: frame.time,
212
+ resourceOverrides: [{ url: frame.dataUri, sha1: frame.name }],
213
+ isMainFrame: true,
214
+ },
215
+ },
216
+ });
217
+ }
218
+ function pageUrlAt(events, time) {
219
+ let url = 'about:blank';
220
+ for (const event of events) {
221
+ if (event.t > time)
222
+ continue;
223
+ if (event.type === 'navigation' && event.url)
224
+ url = event.url;
225
+ }
226
+ return url;
227
+ }
228
+ function readRawTrace(path) {
229
+ return readFileSync(path, 'utf8')
230
+ .split('\n')
231
+ .filter(Boolean)
232
+ .flatMap((line) => {
233
+ try {
234
+ return [JSON.parse(line)];
235
+ }
236
+ catch {
237
+ return [];
238
+ }
239
+ });
240
+ }
241
+ function actionParams(event) {
242
+ if (event.name === 'navigateTo')
243
+ return { url: event.selector ?? event.args?.[0] };
244
+ if (event.name === 'fill')
245
+ return { selector: event.selector, value: event.args?.[0] };
246
+ if (event.selector)
247
+ return { selector: event.selector };
248
+ if (event.name === 'acceptDialog' && event.args?.length)
249
+ return { text: event.args[0] };
250
+ if (event.args?.length)
251
+ return { args: event.args };
252
+ return {};
253
+ }
254
+ function actionTitle(mapping, params) {
255
+ const label = params.selector ?? params.url ?? params.text;
256
+ if (label === undefined)
257
+ return `${mapping.class}.${mapping.method}()`;
258
+ return `${mapping.class}.${mapping.method}("${String(label).slice(0, 80)}")`;
259
+ }
260
+ function bidiEvent(event) {
261
+ if (event.type === 'console') {
262
+ return {
263
+ type: 'event',
264
+ method: 'log.entryAdded',
265
+ params: { type: 'console', level: event.level, text: event.text },
266
+ time: event.t,
267
+ class: 'BrowserContext',
268
+ };
269
+ }
270
+ if (event.type === 'error') {
271
+ return {
272
+ type: 'event',
273
+ method: 'log.entryAdded',
274
+ params: { type: 'javascript', level: 'error', text: event.text },
275
+ time: event.t,
276
+ class: 'BrowserContext',
277
+ };
278
+ }
279
+ if (event.type === 'navigation') {
280
+ return {
281
+ type: 'event',
282
+ method: 'browsingContext.navigationStarted',
283
+ params: { url: event.url, context: event.context },
284
+ time: event.t,
285
+ class: 'BrowserContext',
286
+ };
287
+ }
288
+ return null;
289
+ }
290
+ function buildNetworkTrace(events, startWallTime, pageId) {
291
+ const requests = events
292
+ .filter((event) => event.type === 'request')
293
+ .map((event) => ({ ...event }));
294
+ const snapshots = [];
295
+ for (const response of events) {
296
+ if (response.type !== 'response')
297
+ continue;
298
+ const request = requests.find((candidate) => !candidate.used && ((response.requestId !== undefined && candidate.requestId === response.requestId) ||
299
+ (response.requestId === undefined && candidate.url === response.url)));
300
+ if (!request)
301
+ continue;
302
+ request.used = true;
303
+ const duration = Math.max(0, response.t - request.t);
304
+ const contentTypeHeaders = response.mimeType
305
+ ? [{ name: 'Content-Type', value: response.mimeType }]
306
+ : [];
307
+ snapshots.push({
308
+ type: 'resource-snapshot',
309
+ snapshot: {
310
+ startedDateTime: new Date(startWallTime + request.t).toISOString(),
311
+ time: duration,
312
+ request: {
313
+ method: request.method,
314
+ url: request.url,
315
+ httpVersion: 'HTTP/1.1',
316
+ cookies: [],
317
+ headers: [],
318
+ queryString: queryString(request.url),
319
+ headersSize: -1,
320
+ bodySize: -1,
321
+ },
322
+ response: {
323
+ status: response.status,
324
+ statusText: '',
325
+ httpVersion: 'HTTP/1.1',
326
+ cookies: [],
327
+ headers: contentTypeHeaders,
328
+ content: { size: 0, mimeType: response.mimeType ?? '' },
329
+ redirectURL: '',
330
+ headersSize: -1,
331
+ bodySize: -1,
332
+ },
333
+ cache: response.fromCache ? { _fromCache: true } : {},
334
+ timings: { send: -1, wait: duration, receive: -1 },
335
+ _monotonicTime: request.t,
336
+ _frameref: pageId,
337
+ },
338
+ });
339
+ }
340
+ return snapshots.map((snapshot) => JSON.stringify(snapshot)).join('\n');
341
+ }
342
+ function queryString(url) {
343
+ try {
344
+ return [...new URL(url).searchParams].map(([name, value]) => ({ name, value }));
345
+ }
346
+ catch {
347
+ return [];
348
+ }
349
+ }
350
+ function readPngSize(data) {
351
+ const isPng = data.length >= 24 && data.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]));
352
+ if (!isPng)
353
+ return { width: 1280, height: 720 };
354
+ return { width: data.readUInt32BE(16), height: data.readUInt32BE(20) };
355
+ }
356
+ function writeZip(path, traceText, networkText, resources) {
357
+ return new Promise((resolve, reject) => {
358
+ const zip = new yazl.ZipFile();
359
+ zip.addBuffer(Buffer.from(traceText, 'utf8'), 'trace.trace');
360
+ zip.addBuffer(Buffer.from(networkText, 'utf8'), 'trace.network');
361
+ for (const resource of resources) {
362
+ zip.addFile(resource.sourcePath, `resources/${resource.name}`);
363
+ }
364
+ const output = createWriteStream(path);
365
+ zip.outputStream.on('error', reject);
366
+ output.on('error', reject);
367
+ output.on('close', resolve);
368
+ zip.outputStream.pipe(output);
369
+ zip.end();
370
+ });
371
+ }
372
+ //# sourceMappingURL=vibiumTrace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vibiumTrace.js","sourceRoot":"","sources":["../../src/lib/vibiumTrace.ts"],"names":[],"mappings":"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"}
@@ -82,6 +82,7 @@ Capture console output, JavaScript errors, and trace artifacts.
82
82
  | `JavaScriptError` | type | — | [browser-logs](browser-logs.md) |
83
83
  | `LogMessage` | type | — | [browser-logs](browser-logs.md) |
84
84
  | `TraceStartOptions` | type | — | [tracing](tracing.md) |
85
+ | `TraceStopOptions` | type | — | [tracing](tracing.md) |
85
86
  | `TraceScreenshotMode` | type | Screenshot mode for tracing. | [tracing](tracing.md) |
86
87
  | `TraceEvent` | type | — | [tracing](tracing.md) |
87
88
 
@@ -130,4 +131,4 @@ Handle stable CraftDriver errors or customize browser driver services.
130
131
  | `FirefoxService` | class | — | [getting-started](getting-started.md) |
131
132
  | `FirefoxServiceOptions` | type | — | [getting-started](getting-started.md) |
132
133
 
133
- Total exports: **60**.
134
+ Total exports: **61**.
package/docs/mcp.md CHANGED
@@ -53,7 +53,7 @@ goose configure # add craftdriver as a stdio server
53
53
 
54
54
  ## Tools
55
55
 
56
- Compact set — 14 tools, one line each. Long help lives in the schema
56
+ Compact set — 15 tools, one line each. Long help lives in the schema
57
57
  description; clients render it in the model's context once per session.
58
58
 
59
59
  | Tool | Purpose |
@@ -70,11 +70,25 @@ description; clients render it in the model's context once per session.
70
70
  | `browser_pages` | List open pages (id, url, title). |
71
71
  | `browser_snapshot` | **Sanitized DOM summary with refs.** Use `ref=eN` as the selector for subsequent calls. |
72
72
  | `browser_screenshot` | Capture PNG to a file (auto-allocated under the per-session artifact dir; never inlined). |
73
+ | `browser_trace` | Start/stop tracing and export a Vibium Player compatible zip. |
73
74
  | `browser_status` | Browser up? Which URL is active? |
74
75
  | `browser_advanced_eval` | Evaluate JS in the page. Last resort. |
75
76
 
76
- `browser_trace` (start/stop/explain) and trace resources are slated
77
- for a future release alongside richer trace introspection.
77
+ Trace a complete agent-driven session with two calls:
78
+
79
+ ```jsonc
80
+ { "name": "browser_trace", "arguments": {
81
+ "action": "start", "out_dir": "./traces/agent-raw", "title": "Agent flow"
82
+ } }
83
+ // ...browser_navigate / browser_fill / browser_click calls...
84
+ { "name": "browser_trace", "arguments": {
85
+ "action": "stop", "path": "./traces/agent-flow.zip"
86
+ } }
87
+ ```
88
+
89
+ The zip opens at [player.vibium.dev](https://player.vibium.dev/). The raw
90
+ directory remains available if the MCP client disconnects before the stop
91
+ call; in that case there is no finalized zip.
78
92
 
79
93
  ## Selector syntax
80
94
 
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="refresh" content="0; url=./debug-failing-tests-with-traces">
6
+ <link
7
+ rel="canonical"
8
+ href="https://dtopuzov.github.io/craftdriver/recipes/debug-failing-tests-with-traces"
9
+ >
10
+ <title>Vitest traces moved</title>
11
+ <script>location.replace('./debug-failing-tests-with-traces')</script>
12
+ </head>
13
+ <body>
14
+ <p>This recipe moved to <a href="./debug-failing-tests-with-traces">Debug With Traces</a>.</p>
15
+ </body>
16
+ </html>
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="refresh" content="0; url=./debug-failing-tests-with-traces">
6
+ <link
7
+ rel="canonical"
8
+ href="https://dtopuzov.github.io/craftdriver/recipes/debug-failing-tests-with-traces"
9
+ >
10
+ <title>Vitest trace recipe moved</title>
11
+ <script>location.replace('./debug-failing-tests-with-traces')</script>
12
+ </head>
13
+ <body>
14
+ <p>This recipe moved to <a href="./debug-failing-tests-with-traces">Debug With Traces</a>.</p>
15
+ </body>
16
+ </html>
@@ -0,0 +1,117 @@
1
+ # Use Traces To Debug Failing Tests
2
+
3
+ A failed assertion tells you what was wrong at the end of a test, but often not
4
+ how the browser got there. A trace preserves the actions, screenshots, console
5
+ and JavaScript events, navigation, and network activity that led to the
6
+ failure.
7
+
8
+ ## A Shared Trace Format
9
+
10
+ [Jason Huggins' SeleniumConf talk](https://www.youtube.com/watch?v=c-OGZK3F0tk&t=1530s)
11
+ was one of the reasons Craftdriver adopted portable browser traces instead of
12
+ a Craftdriver-only viewer format.
13
+
14
+ The exported zip follows the Playwright-style
15
+ recording layout also used by tools like
16
+ [Vibium](https://github.com/VibiumDev/vibium/blob/main/docs/explanation/recording-format.md)
17
+ and WDIO, so the same artifact can be opened in viewers such as
18
+ [Vibium Player](https://player.vibium.dev/).
19
+
20
+ Craftdriver still records a crash-resilient raw NDJSON trace first, then
21
+ packages it into the shared zip format when a test runner asks for an artifact.
22
+
23
+ ## Keep A Trace When A Vitest Test Fails
24
+
25
+ Start one browser for the suite, but scope tracing to the test hooks.
26
+ `afterEach()` knows whether the test failed, so it can keep only the useful zip:
27
+
28
+ ```ts
29
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, it } from 'vitest';
30
+ import { rmSync } from 'node:fs';
31
+ import path from 'node:path';
32
+ import { Browser } from 'craftdriver';
33
+
34
+ describe('login', () => {
35
+ let browser: Browser;
36
+ const rawTraceDir = path.resolve('test-results/traces/login-raw');
37
+ const traceZip = path.resolve('test-results/traces/login-failure.zip');
38
+
39
+ beforeAll(async () => {
40
+ browser = await Browser.launch();
41
+ });
42
+
43
+ beforeEach(async () => {
44
+ await browser.startTrace({
45
+ outDir: rawTraceDir,
46
+ title: 'Failing login test',
47
+ });
48
+ });
49
+
50
+ afterEach(async ({ task }) => {
51
+ const failed = task.result?.state === 'fail';
52
+ await browser.stopTrace(failed ? { path: traceZip } : undefined);
53
+ if (!failed) rmSync(rawTraceDir, { recursive: true, force: true });
54
+ });
55
+
56
+ afterAll(async () => browser.quit());
57
+
58
+ it('fills and submits the login form', async () => {
59
+ await browser.navigateTo(
60
+ 'https://dtopuzov.github.io/craftdriver/examples/login.html',
61
+ );
62
+ await browser.fill('#username', 'alice');
63
+ await browser.fill('#password', 'secret');
64
+ await browser.click('#submit');
65
+ await browser.expect('#welcome').toContainText('Welcome back, alice!');
66
+ });
67
+ });
68
+ ```
69
+
70
+ A passing run removes the raw trace and leaves no artifact. After a normal
71
+ Vitest failure, the evidence is kept here:
72
+
73
+ ```text
74
+ test-results/
75
+ └── traces/
76
+ ├── login-raw/ # trace.ndjson and evidence screenshots
77
+ └── login-failure.zip # open this in Vibium Player
78
+ ```
79
+
80
+ For the best online experience, drop the zip into
81
+ [Vibium Player](https://player.vibium.dev/). To keep the trace entirely local,
82
+ use Playwright Trace Viewer:
83
+
84
+ ```sh
85
+ npx playwright show-trace test-results/traces/login-failure.zip
86
+ ```
87
+
88
+ Craftdriver includes screenshot-backed frame snapshots, so Playwright's main
89
+ browser panel shows the captured page state. It is a visual snapshot rather
90
+ than a restorable DOM, so the DOM/locator inspector is intentionally limited.
91
+
92
+ If the test process is killed before `afterEach()` runs, a zip cannot be
93
+ finalized, but the append-only `trace.ndjson` and completed screenshots remain
94
+ in `login-raw/`.
95
+
96
+ ## Try A Trace Before Creating A Failure
97
+
98
+ 1. [Download the sample login trace](https://dtopuzov.github.io/craftdriver/traces/vitest-login.zip).
99
+ 2. Open [Vibium Player](https://player.vibium.dev/).
100
+ 3. Drop `vitest-login.zip` onto the player and step through the login.
101
+
102
+ `stopTrace()` captures the final page state, so a failed assertion is visible
103
+ as the last player frame. The sample was generated by the runnable Vitest proof
104
+ for this recipe against the same published login page. To exercise the failure
105
+ workflow yourself, change the expected message to `Welcome back, bob!`, run the
106
+ test, and open the resulting `login-failure.zip`.
107
+
108
+ Trace files can contain screenshots, URLs, console messages, network metadata,
109
+ selectors, and entered values. Use test credentials and review a trace before
110
+ publishing it outside your team.
111
+
112
+ ## Learn More
113
+
114
+ - [Tracing](../tracing.md)
115
+ - [Use CraftDriver With Vitest Hooks](./vitest-browser-lifecycle.md)
116
+ - [Vibium Player](https://player.vibium.dev/)
117
+ - [Jason Huggins on standardized tracing](https://www.youtube.com/watch?v=c-OGZK3F0tk&t=1530s)
package/docs/recipes.md CHANGED
@@ -49,4 +49,4 @@ For exact signatures, use the linked feature docs and the
49
49
  | ----------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
50
50
  | Accessibility regression gate | CI should fail on serious page or component accessibility issues. | [Run Accessibility Gates](./recipes/accessibility-gate.md) |
51
51
  | Console and JavaScript errors | Tests should fail if the browser reports unexpected client-side errors. | [Fail On Console And JavaScript Errors](./recipes/console-error-gate.md) |
52
- | Evidence on failure | You want a replayable trail of actions, network, logs, errors, and screenshots. | [Capture Failure Evidence With Tracing](./recipes/trace-failing-test.md) |
52
+ | Debug failing tests | You need the actions, screenshots, logs, and network activity behind a failure. | [Use Traces To Debug Failing Tests](./recipes/debug-failing-tests-with-traces.md) |