@opice/harness 0.2.1 → 0.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.
- package/dist/context.d.ts +12 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +47 -12
- package/dist/context.js.map +1 -1
- package/dist/reporter.d.ts +8 -1
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +1 -0
- package/dist/reporter.js.map +1 -1
- package/dist/scenario.d.ts +11 -1
- package/dist/scenario.d.ts.map +1 -1
- package/dist/scenario.js +38 -11
- package/dist/scenario.js.map +1 -1
- package/package.json +1 -1
- package/src/context.ts +49 -12
- package/src/reporter.ts +9 -1
- package/src/scenario.ts +44 -12
package/dist/context.d.ts
CHANGED
|
@@ -3,8 +3,18 @@ import { type BrowserContext, type Page } from 'playwright';
|
|
|
3
3
|
export declare function getPage(): Page;
|
|
4
4
|
/** The active browser context (for cookies/storage, new tabs, etc.). */
|
|
5
5
|
export declare function getContext(): BrowserContext;
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Open a fresh isolated context + page for a scenario, reusing the shared
|
|
8
|
+
* browser. Called from `beforeAll`. Any context left over from a previous
|
|
9
|
+
* scenario whose teardown didn't complete is closed first so state never
|
|
10
|
+
* bleeds across scenarios.
|
|
11
|
+
*/
|
|
7
12
|
export declare function launchPage(): Promise<Page>;
|
|
8
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Close the scenario's context (and page); keep the shared browser alive for
|
|
15
|
+
* the next scenario. Called from `afterAll`. The browser itself is launched
|
|
16
|
+
* once and reaped by Playwright's own process-exit handler when `bun test`
|
|
17
|
+
* exits — see the `beforeExit` hook below for the graceful path.
|
|
18
|
+
*/
|
|
9
19
|
export declare function closePage(): Promise<void>;
|
|
10
20
|
//# sourceMappingURL=context.d.ts.map
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,cAAc,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,cAAc,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAA;AA2BnF,4EAA4E;AAC5E,wBAAgB,OAAO,IAAI,IAAI,CAK9B;AAED,wEAAwE;AACxE,wBAAgB,UAAU,IAAI,cAAc,CAK3C;AAUD;;;;;GAKG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAUhD;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAO/C"}
|
package/dist/context.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { chromium } from 'playwright';
|
|
2
2
|
/**
|
|
3
|
-
* The live Playwright page for the running scenario.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
3
|
+
* The live Playwright page for the running scenario.
|
|
4
|
+
*
|
|
5
|
+
* The browser process is launched **once** and reused across every scenario;
|
|
6
|
+
* each `browserTest` only opens a fresh isolated `context` + `page` in
|
|
7
|
+
* `beforeAll` and closes that context in `afterAll`. Launching (and tearing
|
|
8
|
+
* down) a whole chromium per scenario is expensive — on a constrained CI runner
|
|
9
|
+
* that per-scenario launch competes with the app/server for CPU and, when a
|
|
10
|
+
* teardown stalls, leaks a zombie browser that drags the rest of the suite
|
|
11
|
+
* down. A fresh context per scenario keeps the same isolation (separate
|
|
12
|
+
* storage/cookies) at a fraction of the cost.
|
|
13
|
+
*
|
|
14
|
+
* The DSL — `el`, `byRole`, navigation — reads the current page from here. The
|
|
15
|
+
* browser runs in-process under `bun test`; there is no shell-out and no daemon.
|
|
9
16
|
*/
|
|
10
17
|
let browser = null;
|
|
11
18
|
let context = null;
|
|
@@ -28,23 +35,51 @@ export function getContext() {
|
|
|
28
35
|
}
|
|
29
36
|
return context;
|
|
30
37
|
}
|
|
31
|
-
/** Launch
|
|
38
|
+
/** Launch the shared browser once; reuse it on subsequent scenarios. */
|
|
39
|
+
async function getBrowser() {
|
|
40
|
+
if (!browser || !browser.isConnected()) {
|
|
41
|
+
browser = await chromium.launch({ headless: !headed() });
|
|
42
|
+
}
|
|
43
|
+
return browser;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Open a fresh isolated context + page for a scenario, reusing the shared
|
|
47
|
+
* browser. Called from `beforeAll`. Any context left over from a previous
|
|
48
|
+
* scenario whose teardown didn't complete is closed first so state never
|
|
49
|
+
* bleeds across scenarios.
|
|
50
|
+
*/
|
|
32
51
|
export async function launchPage() {
|
|
33
|
-
|
|
34
|
-
|
|
52
|
+
if (context) {
|
|
53
|
+
await context.close().catch(() => { });
|
|
54
|
+
context = null;
|
|
55
|
+
page = null;
|
|
56
|
+
}
|
|
57
|
+
const b = await getBrowser();
|
|
58
|
+
context = await b.newContext();
|
|
35
59
|
page = await context.newPage();
|
|
36
60
|
return page;
|
|
37
61
|
}
|
|
38
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Close the scenario's context (and page); keep the shared browser alive for
|
|
64
|
+
* the next scenario. Called from `afterAll`. The browser itself is launched
|
|
65
|
+
* once and reaped by Playwright's own process-exit handler when `bun test`
|
|
66
|
+
* exits — see the `beforeExit` hook below for the graceful path.
|
|
67
|
+
*/
|
|
39
68
|
export async function closePage() {
|
|
40
69
|
try {
|
|
41
70
|
await context?.close();
|
|
42
71
|
}
|
|
43
72
|
finally {
|
|
44
|
-
await browser?.close();
|
|
45
73
|
page = null;
|
|
46
74
|
context = null;
|
|
47
|
-
browser = null;
|
|
48
75
|
}
|
|
49
76
|
}
|
|
77
|
+
// Graceful shutdown of the shared browser when the test process winds down. If
|
|
78
|
+
// this doesn't fire (hard exit/signal), Playwright's own exit handler still
|
|
79
|
+
// kills the chromium child, so the process never outlives the run.
|
|
80
|
+
process.once('beforeExit', () => {
|
|
81
|
+
const b = browser;
|
|
82
|
+
browser = null;
|
|
83
|
+
void b?.close().catch(() => { });
|
|
84
|
+
});
|
|
50
85
|
//# sourceMappingURL=context.js.map
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAgD,MAAM,YAAY,CAAA;AAEnF
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAgD,MAAM,YAAY,CAAA;AAEnF;;;;;;;;;;;;;;GAcG;AAEH,IAAI,OAAO,GAAmB,IAAI,CAAA;AAClC,IAAI,OAAO,GAA0B,IAAI,CAAA;AACzC,IAAI,IAAI,GAAgB,IAAI,CAAA;AAE5B,oFAAoF;AACpF,SAAS,MAAM;IACd,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAA;AACjE,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,OAAO;IACtB,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAA;IAC3F,CAAC;IACD,OAAO,IAAI,CAAA;AACZ,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,UAAU;IACzB,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAA;IAC1F,CAAC;IACD,OAAO,OAAO,CAAA;AACf,CAAC;AAED,wEAAwE;AACxE,KAAK,UAAU,UAAU;IACxB,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;QACxC,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACzD,CAAC;IACD,OAAO,OAAO,CAAA;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC/B,IAAI,OAAO,EAAE,CAAC;QACb,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACrC,OAAO,GAAG,IAAI,CAAA;QACd,IAAI,GAAG,IAAI,CAAA;IACZ,CAAC;IACD,MAAM,CAAC,GAAG,MAAM,UAAU,EAAE,CAAA;IAC5B,OAAO,GAAG,MAAM,CAAC,CAAC,UAAU,EAAE,CAAA;IAC9B,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;IAC9B,OAAO,IAAI,CAAA;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC9B,IAAI,CAAC;QACJ,MAAM,OAAO,EAAE,KAAK,EAAE,CAAA;IACvB,CAAC;YAAS,CAAC;QACV,IAAI,GAAG,IAAI,CAAA;QACX,OAAO,GAAG,IAAI,CAAA;IACf,CAAC;AACF,CAAC;AAED,+EAA+E;AAC/E,4EAA4E;AAC5E,mEAAmE;AACnE,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,EAAE;IAC/B,MAAM,CAAC,GAAG,OAAO,CAAA;IACjB,OAAO,GAAG,IAAI,CAAA;IACd,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;AAChC,CAAC,CAAC,CAAA"}
|
package/dist/reporter.d.ts
CHANGED
|
@@ -27,9 +27,16 @@ export interface StepEvent {
|
|
|
27
27
|
/** Authoring order within the scenario, assigned at step() call time. */
|
|
28
28
|
sequence: number;
|
|
29
29
|
name: string;
|
|
30
|
-
|
|
30
|
+
/**
|
|
31
|
+
* 'fixme' (a step.fixme that failed, as expected) and 'fixmepass' (a
|
|
32
|
+
* step.fixme that unexpectedly passed) are tolerated warnings — neither
|
|
33
|
+
* fails the scenario.
|
|
34
|
+
*/
|
|
35
|
+
status: 'passed' | 'failed' | 'fixme' | 'fixmepass';
|
|
31
36
|
durationMs: number;
|
|
32
37
|
error?: string;
|
|
38
|
+
/** Mandatory note from step.fixme — why the failure is tolerated. */
|
|
39
|
+
reason?: string;
|
|
33
40
|
screenshotPath?: string;
|
|
34
41
|
}
|
|
35
42
|
export interface ScenarioStart {
|
package/dist/reporter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAaH,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oEAAoE;IACpE,MAAM,CAAC,EAAE,IAAI,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,SAAS;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAaH,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oEAAoE;IACpE,MAAM,CAAC,EAAE,IAAI,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,SAAS;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,CAAA;IACnD,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,cAAc,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,cAAc;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC3B,UAAU,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,QAAQ;IACxB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACpD,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3C,cAAc,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACtB;AAWD,eAAO,MAAM,WAAW,QAAwC,CAAA;AAMhE,MAAM,WAAW,UAAU;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACb;AA+JD,wBAAgB,WAAW,IAAI,QAAQ,CAEtC;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,QAAQ,CA8B/E"}
|
package/dist/reporter.js
CHANGED
package/dist/reporter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,+EAA+E;AAC/E,MAAM,kBAAkB,GAAG,MAAM,CAAA;AACjC,kFAAkF;AAClF,MAAM,eAAe,GAAG,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"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"}
|
package/dist/scenario.d.ts
CHANGED
|
@@ -25,6 +25,16 @@ export declare function browserTest(name: string, fn: () => void, options?: Brow
|
|
|
25
25
|
*
|
|
26
26
|
* The body may be sync or async; `step` always returns a promise, so call it
|
|
27
27
|
* with `await step('…', async () => { … })`.
|
|
28
|
+
*
|
|
29
|
+
* `step.fixme(name, reason, fn)` marks a **known, tolerated failure**: the body
|
|
30
|
+
* still runs, but a failure inside it does NOT fail the scenario or the CI run —
|
|
31
|
+
* it's reported as an amber warning instead. The `reason` is mandatory (use it
|
|
32
|
+
* to reference a ticket, e.g. 'BUG-123: tax rounding off by 1c'). If a fixme
|
|
33
|
+
* step unexpectedly *passes*, it's flagged too ('fixmepass') so a stale marker
|
|
34
|
+
* doesn't linger. Unlike Playwright's `test.fixme()`, which **skips** the test,
|
|
35
|
+
* `step.fixme` **runs** it — the mandatory reason is there to keep them apart.
|
|
28
36
|
*/
|
|
29
|
-
export declare
|
|
37
|
+
export declare const step: ((name: string, fn: () => void | Promise<void>) => Promise<void>) & {
|
|
38
|
+
fixme: (name: string, reason: string, fn: () => void | Promise<void>) => Promise<void>;
|
|
39
|
+
};
|
|
30
40
|
//# sourceMappingURL=scenario.d.ts.map
|
package/dist/scenario.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../src/scenario.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,kBAAkB;IAClC,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACrB;AAuCD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,EAAE,OAAO,GAAE,kBAAkB,GAAG,MAAW,GAAG,IAAI,CA6DzG;
|
|
1
|
+
{"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../src/scenario.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,kBAAkB;IAClC,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACrB;AAuCD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,EAAE,OAAO,GAAE,kBAAkB,GAAG,MAAW,GAAG,IAAI,CA6DzG;AAsDD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,IAAI,UACT,MAAM,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAG,OAAO,CAAC,IAAI,CAAC;kBAE9C,MAAM,UAAU,MAAM,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAG,OAAO,CAAC,IAAI,CAAC;CAGrF,CAAA"}
|
package/dist/scenario.js
CHANGED
|
@@ -125,28 +125,36 @@ export function browserTest(name, fn, options = {}) {
|
|
|
125
125
|
fn();
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
|
-
|
|
129
|
-
* A reportable step inside a scenario. Captures duration + screenshot on
|
|
130
|
-
* finish, forwards to the active reporter (no-op unless configured via env).
|
|
131
|
-
*
|
|
132
|
-
* The body may be sync or async; `step` always returns a promise, so call it
|
|
133
|
-
* with `await step('…', async () => { … })`.
|
|
134
|
-
*/
|
|
135
|
-
export async function step(name, fn) {
|
|
128
|
+
async function runStep(name, fn, fixmeReason) {
|
|
136
129
|
const reporter = getReporter();
|
|
137
130
|
// Capture order at call time, before the fire-and-forget record below.
|
|
138
131
|
const sequence = currentScenarioStepSeq++;
|
|
139
132
|
const start = Date.now();
|
|
133
|
+
const fixme = fixmeReason !== undefined;
|
|
140
134
|
let status = 'passed';
|
|
141
135
|
let error;
|
|
142
136
|
try {
|
|
143
137
|
await fn();
|
|
138
|
+
// A fixme step that *passes* is a stale marker: surface it as an
|
|
139
|
+
// 'fixmepass' warning so the author knows they can drop the marker,
|
|
140
|
+
// rather than letting it pass silently.
|
|
141
|
+
if (fixme)
|
|
142
|
+
status = 'fixmepass';
|
|
144
143
|
}
|
|
145
144
|
catch (e) {
|
|
146
|
-
status = 'failed';
|
|
147
145
|
error = e instanceof Error ? e.message : String(e);
|
|
148
|
-
|
|
149
|
-
|
|
146
|
+
if (fixme) {
|
|
147
|
+
// Known / tolerated failure. Record it as 'fixme', but DON'T count it
|
|
148
|
+
// toward scenario failures and DON'T re-throw — that's the whole point
|
|
149
|
+
// of step.fixme: the scenario (and the CI run) stay green, the failure
|
|
150
|
+
// surfaces as an amber warning on the dashboard.
|
|
151
|
+
status = 'fixme';
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
status = 'failed';
|
|
155
|
+
currentScenarioFailures++;
|
|
156
|
+
throw e;
|
|
157
|
+
}
|
|
150
158
|
}
|
|
151
159
|
finally {
|
|
152
160
|
const durationMs = Date.now() - start;
|
|
@@ -165,9 +173,28 @@ export async function step(name, fn) {
|
|
|
165
173
|
status,
|
|
166
174
|
durationMs,
|
|
167
175
|
error,
|
|
176
|
+
reason: fixmeReason,
|
|
168
177
|
screenshotPath,
|
|
169
178
|
});
|
|
170
179
|
}
|
|
171
180
|
}
|
|
172
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* A reportable step inside a scenario. Captures duration + screenshot on
|
|
184
|
+
* finish, forwards to the active reporter (no-op unless configured via env).
|
|
185
|
+
*
|
|
186
|
+
* The body may be sync or async; `step` always returns a promise, so call it
|
|
187
|
+
* with `await step('…', async () => { … })`.
|
|
188
|
+
*
|
|
189
|
+
* `step.fixme(name, reason, fn)` marks a **known, tolerated failure**: the body
|
|
190
|
+
* still runs, but a failure inside it does NOT fail the scenario or the CI run —
|
|
191
|
+
* it's reported as an amber warning instead. The `reason` is mandatory (use it
|
|
192
|
+
* to reference a ticket, e.g. 'BUG-123: tax rounding off by 1c'). If a fixme
|
|
193
|
+
* step unexpectedly *passes*, it's flagged too ('fixmepass') so a stale marker
|
|
194
|
+
* doesn't linger. Unlike Playwright's `test.fixme()`, which **skips** the test,
|
|
195
|
+
* `step.fixme` **runs** it — the mandatory reason is there to keep them apart.
|
|
196
|
+
*/
|
|
197
|
+
export const step = Object.assign((name, fn) => runStep(name, fn), {
|
|
198
|
+
fixme: (name, reason, fn) => runStep(name, fn, reason),
|
|
199
|
+
});
|
|
173
200
|
//# sourceMappingURL=scenario.js.map
|
package/dist/scenario.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario.js","sourceRoot":"","sources":["../src/scenario.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"scenario.js","sourceRoot":"","sources":["../src/scenario.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/context.ts
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { chromium, type Browser, type BrowserContext, type Page } from 'playwright'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* The live Playwright page for the running scenario.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* The live Playwright page for the running scenario.
|
|
5
|
+
*
|
|
6
|
+
* The browser process is launched **once** and reused across every scenario;
|
|
7
|
+
* each `browserTest` only opens a fresh isolated `context` + `page` in
|
|
8
|
+
* `beforeAll` and closes that context in `afterAll`. Launching (and tearing
|
|
9
|
+
* down) a whole chromium per scenario is expensive — on a constrained CI runner
|
|
10
|
+
* that per-scenario launch competes with the app/server for CPU and, when a
|
|
11
|
+
* teardown stalls, leaks a zombie browser that drags the rest of the suite
|
|
12
|
+
* down. A fresh context per scenario keeps the same isolation (separate
|
|
13
|
+
* storage/cookies) at a fraction of the cost.
|
|
14
|
+
*
|
|
15
|
+
* The DSL — `el`, `byRole`, navigation — reads the current page from here. The
|
|
16
|
+
* browser runs in-process under `bun test`; there is no shell-out and no daemon.
|
|
10
17
|
*/
|
|
11
18
|
|
|
12
19
|
let browser: Browser | null = null
|
|
@@ -34,22 +41,52 @@ export function getContext(): BrowserContext {
|
|
|
34
41
|
return context
|
|
35
42
|
}
|
|
36
43
|
|
|
37
|
-
/** Launch
|
|
44
|
+
/** Launch the shared browser once; reuse it on subsequent scenarios. */
|
|
45
|
+
async function getBrowser(): Promise<Browser> {
|
|
46
|
+
if (!browser || !browser.isConnected()) {
|
|
47
|
+
browser = await chromium.launch({ headless: !headed() })
|
|
48
|
+
}
|
|
49
|
+
return browser
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Open a fresh isolated context + page for a scenario, reusing the shared
|
|
54
|
+
* browser. Called from `beforeAll`. Any context left over from a previous
|
|
55
|
+
* scenario whose teardown didn't complete is closed first so state never
|
|
56
|
+
* bleeds across scenarios.
|
|
57
|
+
*/
|
|
38
58
|
export async function launchPage(): Promise<Page> {
|
|
39
|
-
|
|
40
|
-
|
|
59
|
+
if (context) {
|
|
60
|
+
await context.close().catch(() => {})
|
|
61
|
+
context = null
|
|
62
|
+
page = null
|
|
63
|
+
}
|
|
64
|
+
const b = await getBrowser()
|
|
65
|
+
context = await b.newContext()
|
|
41
66
|
page = await context.newPage()
|
|
42
67
|
return page
|
|
43
68
|
}
|
|
44
69
|
|
|
45
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Close the scenario's context (and page); keep the shared browser alive for
|
|
72
|
+
* the next scenario. Called from `afterAll`. The browser itself is launched
|
|
73
|
+
* once and reaped by Playwright's own process-exit handler when `bun test`
|
|
74
|
+
* exits — see the `beforeExit` hook below for the graceful path.
|
|
75
|
+
*/
|
|
46
76
|
export async function closePage(): Promise<void> {
|
|
47
77
|
try {
|
|
48
78
|
await context?.close()
|
|
49
79
|
} finally {
|
|
50
|
-
await browser?.close()
|
|
51
80
|
page = null
|
|
52
81
|
context = null
|
|
53
|
-
browser = null
|
|
54
82
|
}
|
|
55
83
|
}
|
|
84
|
+
|
|
85
|
+
// Graceful shutdown of the shared browser when the test process winds down. If
|
|
86
|
+
// this doesn't fire (hard exit/signal), Playwright's own exit handler still
|
|
87
|
+
// kills the chromium child, so the process never outlives the run.
|
|
88
|
+
process.once('beforeExit', () => {
|
|
89
|
+
const b = browser
|
|
90
|
+
browser = null
|
|
91
|
+
void b?.close().catch(() => {})
|
|
92
|
+
})
|
package/src/reporter.ts
CHANGED
|
@@ -40,9 +40,16 @@ export interface StepEvent {
|
|
|
40
40
|
/** Authoring order within the scenario, assigned at step() call time. */
|
|
41
41
|
sequence: number
|
|
42
42
|
name: string
|
|
43
|
-
|
|
43
|
+
/**
|
|
44
|
+
* 'fixme' (a step.fixme that failed, as expected) and 'fixmepass' (a
|
|
45
|
+
* step.fixme that unexpectedly passed) are tolerated warnings — neither
|
|
46
|
+
* fails the scenario.
|
|
47
|
+
*/
|
|
48
|
+
status: 'passed' | 'failed' | 'fixme' | 'fixmepass'
|
|
44
49
|
durationMs: number
|
|
45
50
|
error?: string
|
|
51
|
+
/** Mandatory note from step.fixme — why the failure is tolerated. */
|
|
52
|
+
reason?: string
|
|
46
53
|
screenshotPath?: string
|
|
47
54
|
}
|
|
48
55
|
|
|
@@ -151,6 +158,7 @@ class HttpReporter implements Reporter {
|
|
|
151
158
|
status: event.status,
|
|
152
159
|
durationMs: event.durationMs,
|
|
153
160
|
error: event.error,
|
|
161
|
+
reason: event.reason,
|
|
154
162
|
screenshot,
|
|
155
163
|
})
|
|
156
164
|
}
|
package/src/scenario.ts
CHANGED
|
@@ -140,27 +140,35 @@ export function browserTest(name: string, fn: () => void, options: BrowserTestOp
|
|
|
140
140
|
})
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
*
|
|
147
|
-
* The body may be sync or async; `step` always returns a promise, so call it
|
|
148
|
-
* with `await step('…', async () => { … })`.
|
|
149
|
-
*/
|
|
150
|
-
export async function step(name: string, fn: () => void | Promise<void>): Promise<void> {
|
|
143
|
+
type StepStatus = 'passed' | 'failed' | 'fixme' | 'fixmepass'
|
|
144
|
+
|
|
145
|
+
async function runStep(name: string, fn: () => void | Promise<void>, fixmeReason?: string): Promise<void> {
|
|
151
146
|
const reporter = getReporter()
|
|
152
147
|
// Capture order at call time, before the fire-and-forget record below.
|
|
153
148
|
const sequence = currentScenarioStepSeq++
|
|
154
149
|
const start = Date.now()
|
|
155
|
-
|
|
150
|
+
const fixme = fixmeReason !== undefined
|
|
151
|
+
let status: StepStatus = 'passed'
|
|
156
152
|
let error: string | undefined
|
|
157
153
|
try {
|
|
158
154
|
await fn()
|
|
155
|
+
// A fixme step that *passes* is a stale marker: surface it as an
|
|
156
|
+
// 'fixmepass' warning so the author knows they can drop the marker,
|
|
157
|
+
// rather than letting it pass silently.
|
|
158
|
+
if (fixme) status = 'fixmepass'
|
|
159
159
|
} catch (e) {
|
|
160
|
-
status = 'failed'
|
|
161
160
|
error = e instanceof Error ? e.message : String(e)
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
if (fixme) {
|
|
162
|
+
// Known / tolerated failure. Record it as 'fixme', but DON'T count it
|
|
163
|
+
// toward scenario failures and DON'T re-throw — that's the whole point
|
|
164
|
+
// of step.fixme: the scenario (and the CI run) stay green, the failure
|
|
165
|
+
// surfaces as an amber warning on the dashboard.
|
|
166
|
+
status = 'fixme'
|
|
167
|
+
} else {
|
|
168
|
+
status = 'failed'
|
|
169
|
+
currentScenarioFailures++
|
|
170
|
+
throw e
|
|
171
|
+
}
|
|
164
172
|
} finally {
|
|
165
173
|
const durationMs = Date.now() - start
|
|
166
174
|
let screenshotPath: string | undefined
|
|
@@ -177,8 +185,32 @@ export async function step(name: string, fn: () => void | Promise<void>): Promis
|
|
|
177
185
|
status,
|
|
178
186
|
durationMs,
|
|
179
187
|
error,
|
|
188
|
+
reason: fixmeReason,
|
|
180
189
|
screenshotPath,
|
|
181
190
|
})
|
|
182
191
|
}
|
|
183
192
|
}
|
|
184
193
|
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* A reportable step inside a scenario. Captures duration + screenshot on
|
|
197
|
+
* finish, forwards to the active reporter (no-op unless configured via env).
|
|
198
|
+
*
|
|
199
|
+
* The body may be sync or async; `step` always returns a promise, so call it
|
|
200
|
+
* with `await step('…', async () => { … })`.
|
|
201
|
+
*
|
|
202
|
+
* `step.fixme(name, reason, fn)` marks a **known, tolerated failure**: the body
|
|
203
|
+
* still runs, but a failure inside it does NOT fail the scenario or the CI run —
|
|
204
|
+
* it's reported as an amber warning instead. The `reason` is mandatory (use it
|
|
205
|
+
* to reference a ticket, e.g. 'BUG-123: tax rounding off by 1c'). If a fixme
|
|
206
|
+
* step unexpectedly *passes*, it's flagged too ('fixmepass') so a stale marker
|
|
207
|
+
* doesn't linger. Unlike Playwright's `test.fixme()`, which **skips** the test,
|
|
208
|
+
* `step.fixme` **runs** it — the mandatory reason is there to keep them apart.
|
|
209
|
+
*/
|
|
210
|
+
export const step = Object.assign(
|
|
211
|
+
(name: string, fn: () => void | Promise<void>): Promise<void> => runStep(name, fn),
|
|
212
|
+
{
|
|
213
|
+
fixme: (name: string, reason: string, fn: () => void | Promise<void>): Promise<void> =>
|
|
214
|
+
runStep(name, fn, reason),
|
|
215
|
+
},
|
|
216
|
+
)
|