@heal-dev/heal-playwright-tracer 1.0.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/LICENSE +661 -0
- package/README.md +245 -0
- package/dist/application/babel-playwright-tracer-plugin/index.d.ts +16 -0
- package/dist/application/babel-playwright-tracer-plugin/index.js +111 -0
- package/dist/application/heal-config/index.d.ts +8 -0
- package/dist/application/heal-config/index.js +22 -0
- package/dist/application/heal-config/registry.d.ts +37 -0
- package/dist/application/heal-config/registry.js +64 -0
- package/dist/application/heal-config/types.d.ts +73 -0
- package/dist/application/heal-config/types.js +7 -0
- package/dist/application/playwright-fixture/index.d.ts +14 -0
- package/dist/application/playwright-fixture/index.js +234 -0
- package/dist/application/trace-event-recorder-runtime/index.d.ts +15 -0
- package/dist/application/trace-event-recorder-runtime/index.js +68 -0
- package/dist/domain/code-hook-injector/service/meta-fields/enclosing-scope-labeler.d.ts +12 -0
- package/dist/domain/code-hook-injector/service/meta-fields/enclosing-scope-labeler.js +53 -0
- package/dist/domain/code-hook-injector/service/meta-fields/leading-comment-extractor.d.ts +14 -0
- package/dist/domain/code-hook-injector/service/meta-fields/leading-comment-extractor.js +20 -0
- package/dist/domain/code-hook-injector/service/meta-fields/relative-file-path.d.ts +6 -0
- package/dist/domain/code-hook-injector/service/meta-fields/relative-file-path.js +57 -0
- package/dist/domain/code-hook-injector/service/meta-fields/source-snippet-extractor.d.ts +12 -0
- package/dist/domain/code-hook-injector/service/meta-fields/source-snippet-extractor.js +28 -0
- package/dist/domain/code-hook-injector/service/playwright-import-rewriter.d.ts +10 -0
- package/dist/domain/code-hook-injector/service/playwright-import-rewriter.js +21 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/cjs-artifact-detector.d.ts +14 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/cjs-artifact-detector.js +30 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/for-head-declaration-detector.d.ts +10 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/for-head-declaration-detector.js +18 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/leaf-statement-classifier.d.ts +15 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/leaf-statement-classifier.js +66 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/non-wrappable-statement.d.ts +11 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/non-wrappable-statement.js +20 -0
- package/dist/domain/code-hook-injector/service/trace-hook/enter-meta-literal.d.ts +20 -0
- package/dist/domain/code-hook-injector/service/trace-hook/enter-meta-literal.js +34 -0
- package/dist/domain/code-hook-injector/service/trace-hook/global-trace-call.d.ts +10 -0
- package/dist/domain/code-hook-injector/service/trace-hook/global-trace-call.js +16 -0
- package/dist/domain/code-hook-injector/service/trace-hook/try-finally-wrapper.d.ts +18 -0
- package/dist/domain/code-hook-injector/service/trace-hook/try-finally-wrapper.js +44 -0
- package/dist/domain/code-hook-injector/service/trace-hook/variable-declaration-hoister.d.ts +20 -0
- package/dist/domain/code-hook-injector/service/trace-hook/variable-declaration-hoister.js +27 -0
- package/dist/domain/code-hook-injector/service/traced-file-matcher.d.ts +10 -0
- package/dist/domain/code-hook-injector/service/traced-file-matcher.js +26 -0
- package/dist/domain/trace-event-recorder/model/enter-meta.d.ts +24 -0
- package/dist/domain/trace-event-recorder/model/enter-meta.js +7 -0
- package/dist/domain/trace-event-recorder/model/global-names.d.ts +8 -0
- package/dist/domain/trace-event-recorder/model/global-names.js +20 -0
- package/dist/domain/trace-event-recorder/model/serialized-error.d.ts +16 -0
- package/dist/domain/trace-event-recorder/model/serialized-error.js +7 -0
- package/dist/domain/trace-event-recorder/model/statement-trace-schema.d.ts +171 -0
- package/dist/domain/trace-event-recorder/model/statement-trace-schema.js +33 -0
- package/dist/domain/trace-event-recorder/model/trace-schema.d.ts +114 -0
- package/dist/domain/trace-event-recorder/model/trace-schema.js +16 -0
- package/dist/domain/trace-event-recorder/port/clock.d.ts +9 -0
- package/dist/domain/trace-event-recorder/port/clock.js +7 -0
- package/dist/domain/trace-event-recorder/port/heal-trace-exporter.d.ts +11 -0
- package/dist/domain/trace-event-recorder/port/heal-trace-exporter.js +7 -0
- package/dist/domain/trace-event-recorder/port/system-info-provider.d.ts +18 -0
- package/dist/domain/trace-event-recorder/port/system-info-provider.js +7 -0
- package/dist/domain/trace-event-recorder/port/trace-event-consumer.d.ts +11 -0
- package/dist/domain/trace-event-recorder/port/trace-event-consumer.js +7 -0
- package/dist/domain/trace-event-recorder/service/active-enter-stack.d.ts +15 -0
- package/dist/domain/trace-event-recorder/service/active-enter-stack.js +34 -0
- package/dist/domain/trace-event-recorder/service/event-builders/enter-event-builder.d.ts +8 -0
- package/dist/domain/trace-event-recorder/service/event-builders/enter-event-builder.js +37 -0
- package/dist/domain/trace-event-recorder/service/event-builders/meta-event-builder.d.ts +7 -0
- package/dist/domain/trace-event-recorder/service/event-builders/meta-event-builder.js +19 -0
- package/dist/domain/trace-event-recorder/service/event-builders/ok-event-builder.d.ts +7 -0
- package/dist/domain/trace-event-recorder/service/event-builders/ok-event-builder.js +27 -0
- package/dist/domain/trace-event-recorder/service/event-builders/throw-event-builder.d.ts +7 -0
- package/dist/domain/trace-event-recorder/service/event-builders/throw-event-builder.js +23 -0
- package/dist/domain/trace-event-recorder/service/exporters/composite-heal-trace-exporter.d.ts +12 -0
- package/dist/domain/trace-event-recorder/service/exporters/composite-heal-trace-exporter.js +32 -0
- package/dist/domain/trace-event-recorder/service/index.d.ts +10 -0
- package/dist/domain/trace-event-recorder/service/index.js +15 -0
- package/dist/domain/trace-event-recorder/service/projectors/index.d.ts +6 -0
- package/dist/domain/trace-event-recorder/service/projectors/index.js +10 -0
- package/dist/domain/trace-event-recorder/service/projectors/statement-projector.d.ts +26 -0
- package/dist/domain/trace-event-recorder/service/projectors/statement-projector.js +183 -0
- package/dist/domain/trace-event-recorder/service/serializers/error-serializer.d.ts +8 -0
- package/dist/domain/trace-event-recorder/service/serializers/error-serializer.js +49 -0
- package/dist/domain/trace-event-recorder/service/serializers/variable-snapshot-serializer.d.ts +7 -0
- package/dist/domain/trace-event-recorder/service/serializers/variable-snapshot-serializer.js +102 -0
- package/dist/domain/trace-event-recorder/service/trace-event-recorder-state.d.ts +19 -0
- package/dist/domain/trace-event-recorder/service/trace-event-recorder-state.js +7 -0
- package/dist/domain/trace-event-recorder/service/trace-event-recorder.d.ts +56 -0
- package/dist/domain/trace-event-recorder/service/trace-event-recorder.js +80 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +43 -0
- package/dist/infrastructure/ndjson-exporter-adapter/index.d.ts +6 -0
- package/dist/infrastructure/ndjson-exporter-adapter/index.js +10 -0
- package/dist/infrastructure/ndjson-exporter-adapter/ndjson-exporter.d.ts +13 -0
- package/dist/infrastructure/ndjson-exporter-adapter/ndjson-exporter.js +77 -0
- package/dist/infrastructure/perf-hooks-clock-adapter/index.d.ts +6 -0
- package/dist/infrastructure/perf-hooks-clock-adapter/index.js +10 -0
- package/dist/infrastructure/perf-hooks-clock-adapter/perf-hooks-clock.d.ts +11 -0
- package/dist/infrastructure/perf-hooks-clock-adapter/perf-hooks-clock.js +22 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/assertion-wrapper.d.ts +6 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/assertion-wrapper.js +109 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/index.d.ts +9 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/index.js +21 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/locator-patch.d.ts +11 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/locator-patch.js +79 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/overlay-helpers.d.ts +15 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/overlay-helpers.js +33 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/screenshot-capture-session.d.ts +26 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/screenshot-capture-session.js +125 -0
- package/dist/infrastructure/playwright-step-tracking-adapter/index.d.ts +7 -0
- package/dist/infrastructure/playwright-step-tracking-adapter/index.js +10 -0
- package/dist/infrastructure/playwright-step-tracking-adapter/playwright-step-tracking-adapter.d.ts +14 -0
- package/dist/infrastructure/playwright-step-tracking-adapter/playwright-step-tracking-adapter.js +51 -0
- package/dist/infrastructure/playwright-test-context-adapter/heal-tag-prefix.d.ts +25 -0
- package/dist/infrastructure/playwright-test-context-adapter/heal-tag-prefix.js +28 -0
- package/dist/infrastructure/playwright-test-context-adapter/index.d.ts +8 -0
- package/dist/infrastructure/playwright-test-context-adapter/index.js +12 -0
- package/dist/infrastructure/playwright-test-context-adapter/playwright-test-context-adapter.d.ts +19 -0
- package/dist/infrastructure/playwright-test-context-adapter/playwright-test-context-adapter.js +43 -0
- package/dist/infrastructure/stdout-capture-adapter/index.d.ts +7 -0
- package/dist/infrastructure/stdout-capture-adapter/index.js +10 -0
- package/dist/infrastructure/stdout-capture-adapter/stdout-capture-session.d.ts +20 -0
- package/dist/infrastructure/stdout-capture-adapter/stdout-capture-session.js +47 -0
- package/dist/infrastructure/system-info-adapter/index.d.ts +6 -0
- package/dist/infrastructure/system-info-adapter/index.js +10 -0
- package/dist/infrastructure/system-info-adapter/system-info-adapter.d.ts +12 -0
- package/dist/infrastructure/system-info-adapter/system-info-adapter.js +83 -0
- package/package.json +95 -0
package/README.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<a href="https://heal.dev/">
|
|
3
|
+
<img width="240" src="assets/heal-logo.svg" alt="heal">
|
|
4
|
+
</a>
|
|
5
|
+
</h1>
|
|
6
|
+
<p align="center">
|
|
7
|
+
<p align="center">Statement-level execution tracing for Playwright tests, purpose-built for AI autopilots.</p>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<h4 align="center">
|
|
11
|
+
<a href="https://app.heal.dev/">SaaS</a> |
|
|
12
|
+
<a href="https://heal.dev/">Website</a> |
|
|
13
|
+
<a href="https://docs.heal.dev/">Docs</a>
|
|
14
|
+
</h4>
|
|
15
|
+
|
|
16
|
+
<h4 align="center">
|
|
17
|
+
<a href="https://github.com/heal-dev/heal-playwright-tracer/actions/workflows/ci.yml"><img src="https://github.com/heal-dev/heal-playwright-tracer/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI"></a>
|
|
18
|
+
<a href="https://codecov.io/gh/heal-dev/heal-playwright-tracer"><img src="https://codecov.io/gh/heal-dev/heal-playwright-tracer/branch/main/graph/badge.svg" alt="codecov"></a>
|
|
19
|
+
<a href="https://www.npmjs.com/package/@heal-dev/heal-playwright-tracer"><img src="https://img.shields.io/npm/v/@heal-dev/heal-playwright-tracer.svg" alt="npm version"></a>
|
|
20
|
+
<a href="https://www.npmjs.com/package/@heal-dev/heal-playwright-tracer"><img src="https://img.shields.io/node/v/@heal-dev/heal-playwright-tracer.svg" alt="node"></a>
|
|
21
|
+
<a href="https://www.npmjs.com/package/@playwright/test"><img src="https://img.shields.io/npm/dependency-version/@heal-dev/heal-playwright-tracer/peer/@playwright/test" alt="playwright"></a>
|
|
22
|
+
</h4>
|
|
23
|
+
|
|
24
|
+
# @heal-dev/heal-playwright-tracer
|
|
25
|
+
|
|
26
|
+
An AI-agent-first diagnostic layer for Playwright tests. Purpose-built
|
|
27
|
+
to give an autopilot agent everything it needs to reason about _why_
|
|
28
|
+
a test failed — statement-level execution traces with timing,
|
|
29
|
+
variable values, call depth, serialized errors, highlighted locator
|
|
30
|
+
screenshots, and Playwright API correlations — emitted as a
|
|
31
|
+
structured NDJSON stream per test, alongside Playwright's own HTML
|
|
32
|
+
report and trace viewer. Useful to humans too, but every design
|
|
33
|
+
decision optimizes for what an LLM needs to see.
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
npm install -D @heal-dev/heal-playwright-tracer
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Wire the Babel plugin in `playwright.config.ts`.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// playwright.config.ts
|
|
45
|
+
import { defineConfig } from '@playwright/test';
|
|
46
|
+
|
|
47
|
+
export default defineConfig({
|
|
48
|
+
// @ts-ignore — `babelPlugins` is a supported Playwright option not yet in its public types
|
|
49
|
+
'@playwright/test': {
|
|
50
|
+
babelPlugins: [
|
|
51
|
+
[
|
|
52
|
+
require.resolve('@heal-dev/heal-playwright-tracer/code-hook-injector'),
|
|
53
|
+
{ include: [/\/tests\//] },
|
|
54
|
+
],
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Or, if you prefer to keep the config fully typed, declare the
|
|
61
|
+
option once at the top of the file instead of using `@ts-ignore`:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
declare module '@playwright/test' {
|
|
65
|
+
interface Config {
|
|
66
|
+
'@playwright/test'?: {
|
|
67
|
+
babelPlugins?: Array<[string, object?]>;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Per-test output lands at
|
|
74
|
+
`test-results/<test>/heal-data/heal-traces.ndjson`.
|
|
75
|
+
|
|
76
|
+
### Extend: custom exporters and lifecycles
|
|
77
|
+
|
|
78
|
+
`configureTracer` registers extra exporters (fanned out alongside
|
|
79
|
+
the default NDJSON exporter) and per-test setup/teardown pairs —
|
|
80
|
+
useful for shipping traces to your own backend or installing
|
|
81
|
+
per-test globals:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
// playwright.config.ts
|
|
85
|
+
import { defineConfig } from '@playwright/test';
|
|
86
|
+
import { configureTracer } from '@heal-dev/heal-playwright-tracer';
|
|
87
|
+
|
|
88
|
+
configureTracer({
|
|
89
|
+
exporters: [(ctx) => new MyHttpExporter(ctx.transport)],
|
|
90
|
+
lifecycles: [
|
|
91
|
+
() => ({
|
|
92
|
+
setup: (ctx) => openTelemetrySession(ctx.testInfo),
|
|
93
|
+
teardown: () => closeTelemetrySession(),
|
|
94
|
+
}),
|
|
95
|
+
],
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
export default defineConfig({
|
|
99
|
+
/* ... */
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Full surface: [`src/application/heal-config/types.ts`](src/application/heal-config/types.ts).
|
|
104
|
+
Exporters implement [`HealTraceExporter`](src/domain/trace-event-recorder/port/heal-trace-exporter.ts)
|
|
105
|
+
(`write(record)` + `close()`).
|
|
106
|
+
|
|
107
|
+
## Sample output
|
|
108
|
+
|
|
109
|
+
`heal-data/heal-traces.ndjson` — one record per line:
|
|
110
|
+
|
|
111
|
+
```ndjson
|
|
112
|
+
{"kind":"test-header","schemaVersion":1,"test":{"title":"it works","file":"tests/example.spec.ts","context":{"testId":"...","attempt":1}}}
|
|
113
|
+
{"kind":"statement","statement":{"loc":{"line":5},"source":"await page.goto('https://example.com')","durationMs":412,"status":"ok","children":[...]}}
|
|
114
|
+
{"kind":"statement","statement":{"loc":{"line":6},"source":"await expect(page.getByRole('heading')).toBeVisible()","durationMs":73,"status":"ok"}}
|
|
115
|
+
{"kind":"test-result","status":"passed","duration":1234,"stdout":"...","stderr":""}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Schema: [`src/domain/trace-event-recorder/model/statement-trace-schema.ts`](src/domain/trace-event-recorder/model/statement-trace-schema.ts)
|
|
119
|
+
(also exported as `@heal-dev/heal-playwright-tracer/statement-trace-schema`).
|
|
120
|
+
|
|
121
|
+
### Screenshots
|
|
122
|
+
|
|
123
|
+
Every statement that calls a patched Playwright **locator action**
|
|
124
|
+
(`click`, `fill`, `hover`, `press`, …) or a **locator assertion**
|
|
125
|
+
(`expect(locator).toBeVisible()`, `toHaveText()`, …) produces a
|
|
126
|
+
PNG screenshot with the targeted element outlined via an overlay
|
|
127
|
+
drawn in-page — so the agent sees _what Playwright was actually
|
|
128
|
+
pointing at_ at the moment the action ran, not just the raw page.
|
|
129
|
+
|
|
130
|
+
Files are written to the per-test `heal-data/` directory and
|
|
131
|
+
referenced on the corresponding statement via the `screenshot`
|
|
132
|
+
field:
|
|
133
|
+
|
|
134
|
+
```ndjson
|
|
135
|
+
{"kind":"statement","statement":{"source":"await page.getByRole('button', { name: 'Submit' }).click()","status":"ok","screenshot":"stmt-0007.png"}}
|
|
136
|
+
{"kind":"statement","statement":{"source":"await expect(page.getByRole('alert')).toBeVisible()","status":"ok","screenshot":"stmt-0008.png"}}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Statements that don't touch a locator (plain JS, utility calls,
|
|
140
|
+
`page.goto`) have no `screenshot` field — capture is scoped to the
|
|
141
|
+
Playwright surface where it adds diagnostic signal.
|
|
142
|
+
|
|
143
|
+
## How it works
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
Build time (per worker) Runtime (per test)
|
|
147
|
+
─────────────────────── ──────────────────
|
|
148
|
+
|
|
149
|
+
test file instrumented test
|
|
150
|
+
│ │
|
|
151
|
+
▼ ▼
|
|
152
|
+
┌───────────────────┐ ┌────────────────┐
|
|
153
|
+
│ Babel plugin │ ─── instrumented ───► │ recorder │
|
|
154
|
+
│ code-hook- │ (__enter / │ enter/ok/ │
|
|
155
|
+
│ injector │ __ok / __throw) │ throw stream │
|
|
156
|
+
└───────────────────┘ └────────┬───────┘
|
|
157
|
+
│
|
|
158
|
+
▼
|
|
159
|
+
┌────────────────┐
|
|
160
|
+
│ statement │
|
|
161
|
+
│ projector │
|
|
162
|
+
└────────┬───────┘
|
|
163
|
+
│
|
|
164
|
+
▼
|
|
165
|
+
playwright.config.ts ┌──────────────────┐
|
|
166
|
+
configureTracer({ ─── extends ──────────► │ composite │
|
|
167
|
+
exporters, │ exporter │
|
|
168
|
+
lifecycles, └───┬──────────┬───┘
|
|
169
|
+
}) │ │
|
|
170
|
+
▼ ▼
|
|
171
|
+
NDJSON custom
|
|
172
|
+
file exporters
|
|
173
|
+
(HTTP, queue, …)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The Babel plugin wraps every leaf statement with a try/catch/finally
|
|
177
|
+
that calls three runtime hooks. The recorder pairs those calls into an
|
|
178
|
+
event stream, the projector folds them into `HealTraceRecord`s, and
|
|
179
|
+
a composite exporter fans them out to the default NDJSON file and
|
|
180
|
+
any exporters registered via `configureTracer`.
|
|
181
|
+
|
|
182
|
+
The plugin also rewrites `from '@playwright/test'` to
|
|
183
|
+
`from '@heal-dev/heal-playwright-tracer'` in every instrumented file,
|
|
184
|
+
so `test` and `expect` automatically resolve to the traced variants —
|
|
185
|
+
no manual import swap required.
|
|
186
|
+
|
|
187
|
+
## Why CommonJS?
|
|
188
|
+
|
|
189
|
+
The package ships as CommonJS (no `"type": "module"` in
|
|
190
|
+
`package.json`, `tsc` emits `module: commonjs`). This is deliberate:
|
|
191
|
+
Playwright's babel transform — the thing that actually loads
|
|
192
|
+
`code-hook-injector` — is itself a CJS module and consumes the plugin
|
|
193
|
+
via `require()`. Shipping ESM would force a dual build with no upside.
|
|
194
|
+
|
|
195
|
+
ESM consumers still work — use `createRequire` in
|
|
196
|
+
`playwright.config.ts` if you need to resolve the plugin path:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
// playwright.config.ts (package.json has "type": "module")
|
|
200
|
+
import { defineConfig } from '@playwright/test';
|
|
201
|
+
import { createRequire } from 'node:module';
|
|
202
|
+
|
|
203
|
+
const require = createRequire(import.meta.url);
|
|
204
|
+
|
|
205
|
+
export default defineConfig({
|
|
206
|
+
// @ts-ignore
|
|
207
|
+
'@playwright/test': {
|
|
208
|
+
babelPlugins: [[require.resolve('@heal-dev/heal-playwright-tracer/code-hook-injector')]],
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
> **The module format of `playwright.config.ts` must match the
|
|
214
|
+
> `"type"` field of its nearest `package.json`.** A mismatch causes
|
|
215
|
+
> Node to route the file through the wrong loader, typically surfacing
|
|
216
|
+
> as `ReferenceError: exports is not defined in ES module scope` —
|
|
217
|
+
> with a stack trace that blames this plugin even though it has never
|
|
218
|
+
> run. If that happens, fix the config format first.
|
|
219
|
+
|
|
220
|
+
## Caveats
|
|
221
|
+
|
|
222
|
+
The Babel plugin rewrites every leaf statement with a `try/catch/finally`
|
|
223
|
+
and three hook calls — the same shape of transformation Istanbul applies
|
|
224
|
+
for code coverage. Two consequences to be aware of:
|
|
225
|
+
|
|
226
|
+
- **Instrumented files are larger.** Each statement gains a wrapper, so
|
|
227
|
+
on-disk size of transformed test files grows noticeably (typically
|
|
228
|
+
~2–4×, depending on statement density). This affects the files
|
|
229
|
+
Playwright loads into workers, not your application bundle.
|
|
230
|
+
- **Tests run slightly slower.** The per-statement hook overhead is
|
|
231
|
+
small in absolute terms but not free — expect a modest slowdown on
|
|
232
|
+
CPU-bound test code. I/O-bound tests (the common case: `await
|
|
233
|
+
page.click(...)`, network, navigation) are dominated by the browser
|
|
234
|
+
and barely move.
|
|
235
|
+
|
|
236
|
+
Scope the `include` filter in `playwright.config.ts` so only your
|
|
237
|
+
`tests/` directory is instrumented — never your app code or
|
|
238
|
+
`node_modules` — to keep the cost contained.
|
|
239
|
+
|
|
240
|
+
## License
|
|
241
|
+
|
|
242
|
+
Copyright © 2026 **MYIA SAS**.
|
|
243
|
+
|
|
244
|
+
This project is licensed under the **GNU Affero General Public License v3.0 (AGPL-3.0)**.
|
|
245
|
+
See the [LICENSE](LICENSE) file for the full text.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
import type * as BabelTypes from '@babel/types';
|
|
7
|
+
import type { PluginObj, PluginPass } from '@babel/core';
|
|
8
|
+
import { type Include } from '../../domain/code-hook-injector/service/traced-file-matcher';
|
|
9
|
+
interface CodeHookInjectorOptions {
|
|
10
|
+
include?: Include;
|
|
11
|
+
rootDir?: string;
|
|
12
|
+
}
|
|
13
|
+
declare function codeHookInjector(api: {
|
|
14
|
+
types: typeof BabelTypes;
|
|
15
|
+
}, opts?: CodeHookInjectorOptions): PluginObj<PluginPass>;
|
|
16
|
+
export = codeHookInjector;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
const traced_file_matcher_1 = require("../../domain/code-hook-injector/service/traced-file-matcher");
|
|
8
|
+
const cjs_artifact_detector_1 = require("../../domain/code-hook-injector/service/statement-analysis/cjs-artifact-detector");
|
|
9
|
+
const leaf_statement_classifier_1 = require("../../domain/code-hook-injector/service/statement-analysis/leaf-statement-classifier");
|
|
10
|
+
const non_wrappable_statement_1 = require("../../domain/code-hook-injector/service/statement-analysis/non-wrappable-statement");
|
|
11
|
+
const for_head_declaration_detector_1 = require("../../domain/code-hook-injector/service/statement-analysis/for-head-declaration-detector");
|
|
12
|
+
const enclosing_scope_labeler_1 = require("../../domain/code-hook-injector/service/meta-fields/enclosing-scope-labeler");
|
|
13
|
+
const source_snippet_extractor_1 = require("../../domain/code-hook-injector/service/meta-fields/source-snippet-extractor");
|
|
14
|
+
const leading_comment_extractor_1 = require("../../domain/code-hook-injector/service/meta-fields/leading-comment-extractor");
|
|
15
|
+
const relative_file_path_1 = require("../../domain/code-hook-injector/service/meta-fields/relative-file-path");
|
|
16
|
+
const playwright_import_rewriter_1 = require("../../domain/code-hook-injector/service/playwright-import-rewriter");
|
|
17
|
+
const global_trace_call_1 = require("../../domain/code-hook-injector/service/trace-hook/global-trace-call");
|
|
18
|
+
const enter_meta_literal_1 = require("../../domain/code-hook-injector/service/trace-hook/enter-meta-literal");
|
|
19
|
+
const try_finally_wrapper_1 = require("../../domain/code-hook-injector/service/trace-hook/try-finally-wrapper");
|
|
20
|
+
const variable_declaration_hoister_1 = require("../../domain/code-hook-injector/service/trace-hook/variable-declaration-hoister");
|
|
21
|
+
const global_names_1 = require("../../domain/trace-event-recorder/model/global-names");
|
|
22
|
+
function codeHookInjector(api, opts = {}) {
|
|
23
|
+
const t = api.types;
|
|
24
|
+
const CWD = opts.rootDir || process.cwd();
|
|
25
|
+
const matches = (0, traced_file_matcher_1.buildMatcher)(opts.include);
|
|
26
|
+
const { isGeneratedModuleStatement } = (0, cjs_artifact_detector_1.createCjsArtifactDetector)(t);
|
|
27
|
+
const { isLeafStatement, kindOf, containsAwait } = (0, leaf_statement_classifier_1.createLeafStatementClassifier)(t);
|
|
28
|
+
const findScopeName = (0, enclosing_scope_labeler_1.createEnclosingScopeLabeler)(t);
|
|
29
|
+
const isNonWrappableStatement = (0, non_wrappable_statement_1.createNonWrappableStatementPredicate)(t, isGeneratedModuleStatement);
|
|
30
|
+
const isForHeadDeclaration = (0, for_head_declaration_detector_1.createForHeadDeclarationDetector)(t);
|
|
31
|
+
const rewritePlaywrightImports = (0, playwright_import_rewriter_1.createPlaywrightImportRewriter)(t);
|
|
32
|
+
const callStmt = (0, global_trace_call_1.createGlobalTraceCallBuilder)(t);
|
|
33
|
+
const buildMeta = (0, enter_meta_literal_1.createEnterMetaLiteralBuilder)(t, {
|
|
34
|
+
kindOf,
|
|
35
|
+
containsAwait,
|
|
36
|
+
findScopeName,
|
|
37
|
+
extractSource: source_snippet_extractor_1.extractSource,
|
|
38
|
+
extractLeadingComment: leading_comment_extractor_1.extractLeadingComment,
|
|
39
|
+
relFile: relative_file_path_1.relFile,
|
|
40
|
+
});
|
|
41
|
+
const { buildTryFinally, buildThrewDecl } = (0, try_finally_wrapper_1.createTryFinallyWrapperBuilder)(t, callStmt);
|
|
42
|
+
const hoistVariableDeclaration = (0, variable_declaration_hoister_1.createVariableDeclarationHoister)(t);
|
|
43
|
+
return {
|
|
44
|
+
name: 'heal-playwright-tracer',
|
|
45
|
+
visitor: {
|
|
46
|
+
// Rewrite `@playwright/test` → `@heal-dev/heal-playwright-tracer` at
|
|
47
|
+
// the top of every matched file. Runs before the Statement visitor
|
|
48
|
+
// because Program.enter fires first. The user keeps the standard
|
|
49
|
+
// Playwright import; our auto-fixture loads transparently.
|
|
50
|
+
Program(programPath, state) {
|
|
51
|
+
if (!matches(state.file.opts.filename || ''))
|
|
52
|
+
return;
|
|
53
|
+
rewritePlaywrightImports(programPath.node);
|
|
54
|
+
},
|
|
55
|
+
Statement(stmtPath, state) {
|
|
56
|
+
const node = stmtPath.node;
|
|
57
|
+
// Don't recurse into our own generated wrapper.
|
|
58
|
+
if (node._traced)
|
|
59
|
+
return;
|
|
60
|
+
// Babel sometimes hands us synthetic nodes without source locations.
|
|
61
|
+
if (!node.loc)
|
|
62
|
+
return;
|
|
63
|
+
// File-level filter: only touch files the consumer opted in to.
|
|
64
|
+
if (!matches(state.file.opts.filename || ''))
|
|
65
|
+
return;
|
|
66
|
+
// Skip statement kinds that no hook family should wrap.
|
|
67
|
+
if (isNonWrappableStatement(stmtPath))
|
|
68
|
+
return;
|
|
69
|
+
// Only leaf statements get wrapped. Compound statements
|
|
70
|
+
// (if/for/while/switch/try) are transparent — their inner
|
|
71
|
+
// leaves will be visited independently.
|
|
72
|
+
if (!isLeafStatement(node))
|
|
73
|
+
return;
|
|
74
|
+
// From here on it's trace-hook-specific. When a second hook
|
|
75
|
+
// family lands, extract the block below into a
|
|
76
|
+
// `applyTraceHookIfLeaf(stmtPath, state)` function in
|
|
77
|
+
// ./trace-hook/ and call it alongside the future families.
|
|
78
|
+
const meta = buildMeta(state, stmtPath, node, CWD);
|
|
79
|
+
if (t.isVariableDeclaration(node)) {
|
|
80
|
+
// `const x = EXPR` can't be wrapped as-is — the binding
|
|
81
|
+
// would be scoped to the try block and invisible downstream.
|
|
82
|
+
// Hoist the bindings out, assign inside the try, pass a
|
|
83
|
+
// vars object to __ok so the recorder can snapshot values.
|
|
84
|
+
if (isForHeadDeclaration(node, stmtPath.parent))
|
|
85
|
+
return;
|
|
86
|
+
const { hoistDecl, assignments, varsObject, bindingNames } = hoistVariableDeclaration(node);
|
|
87
|
+
const okArgs = bindingNames.size ? [varsObject] : [];
|
|
88
|
+
const { threwId, tryStmt } = buildTryFinally(stmtPath.scope, assignments, okArgs);
|
|
89
|
+
stmtPath.replaceWithMultiple([
|
|
90
|
+
callStmt(global_names_1.HEAL_ENTER, [meta]),
|
|
91
|
+
hoistDecl,
|
|
92
|
+
buildThrewDecl(threwId),
|
|
93
|
+
tryStmt,
|
|
94
|
+
]);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// Every other leaf statement: wrap in a block with the
|
|
98
|
+
// original statement inside the try body.
|
|
99
|
+
node._traced = true;
|
|
100
|
+
const { threwId, tryStmt } = buildTryFinally(stmtPath.scope, [node]);
|
|
101
|
+
const wrapper = t.blockStatement([
|
|
102
|
+
callStmt(global_names_1.HEAL_ENTER, [meta]),
|
|
103
|
+
buildThrewDecl(threwId),
|
|
104
|
+
tryStmt,
|
|
105
|
+
]);
|
|
106
|
+
stmtPath.replaceWith(wrapper);
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
module.exports = codeHookInjector;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
export { configureTracer, getTracerConfig, onTestTeardown } from './registry';
|
|
7
|
+
export { resetTeardownHooks, drainTeardownHooks } from './registry';
|
|
8
|
+
export type { HealTracerConfig, HealTracerTestContext, HealTraceExporterFactory, HealTestLifecycle, HealTestLifecycleFactory, } from './types';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.drainTeardownHooks = exports.resetTeardownHooks = exports.onTestTeardown = exports.getTracerConfig = exports.configureTracer = void 0;
|
|
9
|
+
// Public surface of the tracer's extension API.
|
|
10
|
+
//
|
|
11
|
+
// Re-exports what a user needs to extend the tracer from their own
|
|
12
|
+
// `playwright.config.ts`.
|
|
13
|
+
var registry_1 = require("./registry");
|
|
14
|
+
Object.defineProperty(exports, "configureTracer", { enumerable: true, get: function () { return registry_1.configureTracer; } });
|
|
15
|
+
Object.defineProperty(exports, "getTracerConfig", { enumerable: true, get: function () { return registry_1.getTracerConfig; } });
|
|
16
|
+
Object.defineProperty(exports, "onTestTeardown", { enumerable: true, get: function () { return registry_1.onTestTeardown; } });
|
|
17
|
+
// Internal-facing exports — consumed by the fixture only. Kept in the
|
|
18
|
+
// barrel because the fixture imports from this same file; external
|
|
19
|
+
// callers have no reason to touch them.
|
|
20
|
+
var registry_2 = require("./registry");
|
|
21
|
+
Object.defineProperty(exports, "resetTeardownHooks", { enumerable: true, get: function () { return registry_2.resetTeardownHooks; } });
|
|
22
|
+
Object.defineProperty(exports, "drainTeardownHooks", { enumerable: true, get: function () { return registry_2.drainTeardownHooks; } });
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
import type { HealTracerConfig } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Register the tracer's extension config. Typically called once at
|
|
9
|
+
* the top of `playwright.config.ts`, before `defineConfig(...)`. Later
|
|
10
|
+
* calls overwrite earlier ones — there is no merge.
|
|
11
|
+
*/
|
|
12
|
+
export declare function configureTracer(config: HealTracerConfig): void;
|
|
13
|
+
/**
|
|
14
|
+
* Read the currently-registered config. Returns an empty object when
|
|
15
|
+
* the user never called `configureTracer` — the fixture treats that
|
|
16
|
+
* as "NDJSON-only, no bindings."
|
|
17
|
+
*/
|
|
18
|
+
export declare function getTracerConfig(): HealTracerConfig;
|
|
19
|
+
/**
|
|
20
|
+
* Register a function to run when the current test tears down. Runs
|
|
21
|
+
* BEFORE user bindings' `stop()` so SDKs that use
|
|
22
|
+
* `onTestTeardown(...)` still see any globals the bindings installed.
|
|
23
|
+
*
|
|
24
|
+
* Errors raised by a hook are logged to stderr and swallowed.
|
|
25
|
+
*/
|
|
26
|
+
export declare function onTestTeardown(fn: () => void | Promise<void>): void;
|
|
27
|
+
/**
|
|
28
|
+
* Internal. Clears the teardown-hook registry. The fixture calls this
|
|
29
|
+
* at the start of every test to defend against a hook leaking across
|
|
30
|
+
* test boundaries if a prior test crashed before drain ran.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resetTeardownHooks(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Internal. Runs every registered teardown hook in registration order,
|
|
35
|
+
* then clears the registry. Errors are logged and swallowed.
|
|
36
|
+
*/
|
|
37
|
+
export declare function drainTeardownHooks(): Promise<void>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.configureTracer = configureTracer;
|
|
9
|
+
exports.getTracerConfig = getTracerConfig;
|
|
10
|
+
exports.onTestTeardown = onTestTeardown;
|
|
11
|
+
exports.resetTeardownHooks = resetTeardownHooks;
|
|
12
|
+
exports.drainTeardownHooks = drainTeardownHooks;
|
|
13
|
+
let currentConfig = {};
|
|
14
|
+
let teardownHooks = [];
|
|
15
|
+
/**
|
|
16
|
+
* Register the tracer's extension config. Typically called once at
|
|
17
|
+
* the top of `playwright.config.ts`, before `defineConfig(...)`. Later
|
|
18
|
+
* calls overwrite earlier ones — there is no merge.
|
|
19
|
+
*/
|
|
20
|
+
function configureTracer(config) {
|
|
21
|
+
currentConfig = config;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read the currently-registered config. Returns an empty object when
|
|
25
|
+
* the user never called `configureTracer` — the fixture treats that
|
|
26
|
+
* as "NDJSON-only, no bindings."
|
|
27
|
+
*/
|
|
28
|
+
function getTracerConfig() {
|
|
29
|
+
return currentConfig;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Register a function to run when the current test tears down. Runs
|
|
33
|
+
* BEFORE user bindings' `stop()` so SDKs that use
|
|
34
|
+
* `onTestTeardown(...)` still see any globals the bindings installed.
|
|
35
|
+
*
|
|
36
|
+
* Errors raised by a hook are logged to stderr and swallowed.
|
|
37
|
+
*/
|
|
38
|
+
function onTestTeardown(fn) {
|
|
39
|
+
teardownHooks.push(fn);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Internal. Clears the teardown-hook registry. The fixture calls this
|
|
43
|
+
* at the start of every test to defend against a hook leaking across
|
|
44
|
+
* test boundaries if a prior test crashed before drain ran.
|
|
45
|
+
*/
|
|
46
|
+
function resetTeardownHooks() {
|
|
47
|
+
teardownHooks = [];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Internal. Runs every registered teardown hook in registration order,
|
|
51
|
+
* then clears the registry. Errors are logged and swallowed.
|
|
52
|
+
*/
|
|
53
|
+
async function drainTeardownHooks() {
|
|
54
|
+
const hooks = teardownHooks;
|
|
55
|
+
teardownHooks = [];
|
|
56
|
+
for (const hook of hooks) {
|
|
57
|
+
try {
|
|
58
|
+
await hook();
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
console.error('[heal-playwright-tracer] teardown hook failed:', err);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
import type { TestInfo } from '@playwright/test';
|
|
7
|
+
import type { HealTraceExporter } from '../../domain/trace-event-recorder/port/heal-trace-exporter';
|
|
8
|
+
/**
|
|
9
|
+
* Everything the fixture hands to a exporter or lifecycle factory
|
|
10
|
+
* when a test starts. The `transport` subobject carries the per-test
|
|
11
|
+
* correlation identifiers any outbound exporter needs.
|
|
12
|
+
*/
|
|
13
|
+
export interface HealTracerTestContext {
|
|
14
|
+
testInfo: TestInfo;
|
|
15
|
+
/**
|
|
16
|
+
* Absolute path to the per-test `heal-data` directory. Created by
|
|
17
|
+
* the fixture before any factory runs.
|
|
18
|
+
*/
|
|
19
|
+
healDataDir: string;
|
|
20
|
+
transport: {
|
|
21
|
+
/**
|
|
22
|
+
* Playwright's `testInfo.testId` — stable hash of
|
|
23
|
+
* (file, title, project). Shared across attempts of the same
|
|
24
|
+
* test, unique per distinct test. Together with `attempt` it
|
|
25
|
+
* forms the per-test-attempt correlation key.
|
|
26
|
+
*/
|
|
27
|
+
testId: string;
|
|
28
|
+
attempt: number;
|
|
29
|
+
/** Absolute `testInfo.outputDir`. */
|
|
30
|
+
rootDir: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Called once per test. Returns the exporter for that test; the fixture
|
|
35
|
+
* closes it at teardown via `HealTraceExporter.close()`.
|
|
36
|
+
*/
|
|
37
|
+
export type HealTraceExporterFactory = (ctx: HealTracerTestContext) => HealTraceExporter;
|
|
38
|
+
/**
|
|
39
|
+
* Per-test setup/teardown pair. Use this to install per-test globals,
|
|
40
|
+
* open telemetry sessions, patch prototypes you'll unpatch later, etc.
|
|
41
|
+
*
|
|
42
|
+
* `setup` receives the `HealTracerTestContext` for the current test.
|
|
43
|
+
* `teardown` takes no arguments — close over any state you need via
|
|
44
|
+
* the enclosing factory or class fields.
|
|
45
|
+
*
|
|
46
|
+
* Errors in `setup` mark that lifecycle as uninstalled — its
|
|
47
|
+
* `teardown` will NOT run. Errors in `teardown` are logged and
|
|
48
|
+
* swallowed so they cannot mask a real test failure.
|
|
49
|
+
*/
|
|
50
|
+
export interface HealTestLifecycle {
|
|
51
|
+
setup(ctx: HealTracerTestContext): void | Promise<void>;
|
|
52
|
+
teardown(): void | Promise<void>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Factory for a `HealTestLifecycle`. Called once per test, before
|
|
56
|
+
* `setup`. Always a factory — not a singleton object — so closure
|
|
57
|
+
* state declared inside the factory is isolated between tests.
|
|
58
|
+
*
|
|
59
|
+
* The factory takes no arguments; the `HealTracerTestContext` arrives
|
|
60
|
+
* via `setup(ctx)` instead. One-place-for-ctx keeps the signature
|
|
61
|
+
* minimal and avoids the "which ctx do I use?" confusion that a
|
|
62
|
+
* two-injection design would create.
|
|
63
|
+
*/
|
|
64
|
+
export type HealTestLifecycleFactory = () => HealTestLifecycle;
|
|
65
|
+
/**
|
|
66
|
+
* Shape of the object passed to `configureTracer(...)`. Both fields
|
|
67
|
+
* are optional — an empty config yields the default behaviour
|
|
68
|
+
* (NDJSON-only output, no lifecycles).
|
|
69
|
+
*/
|
|
70
|
+
export interface HealTracerConfig {
|
|
71
|
+
exporters?: HealTraceExporterFactory[];
|
|
72
|
+
lifecycles?: HealTestLifecycleFactory[];
|
|
73
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
import { expect as rawExpect } from '@playwright/test';
|
|
7
|
+
import { reset } from '../trace-event-recorder-runtime';
|
|
8
|
+
declare const expect: typeof rawExpect;
|
|
9
|
+
type TraceFixtures = {
|
|
10
|
+
_traceAuto: void;
|
|
11
|
+
};
|
|
12
|
+
export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & TraceFixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
13
|
+
export { expect };
|
|
14
|
+
export { reset };
|