@molecule/app-e2e-fixtures-default 1.0.0 → 1.0.2
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 +28556 -0
- package/dist/console-guard.d.ts +39 -0
- package/dist/console-guard.d.ts.map +1 -0
- package/dist/console-guard.js +117 -0
- package/dist/console-guard.js.map +1 -0
- package/dist/expect.d.ts +18 -0
- package/dist/expect.d.ts.map +1 -0
- package/dist/expect.js +233 -0
- package/dist/expect.js.map +1 -0
- package/dist/index.d.ts +99 -52
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +100 -140
- package/dist/index.js.map +1 -0
- package/dist/page.d.ts +370 -0
- package/dist/page.d.ts.map +1 -0
- package/dist/page.js +1052 -0
- package/dist/page.js.map +1 -0
- package/dist/playwright.d.ts +10 -0
- package/dist/playwright.d.ts.map +1 -0
- package/dist/playwright.js +9 -0
- package/dist/playwright.js.map +1 -0
- package/dist/runtime.d.ts +94 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1501 -0
- package/dist/runtime.js.map +1 -0
- package/dist/test.d.ts +23 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +69 -0
- package/dist/test.js.map +1 -0
- package/package.json +9 -3
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The console-error guard fixture: every test subscribes to the page's
|
|
3
|
+
* `pageerror` and `console.error` events and fails at teardown if any were
|
|
4
|
+
* seen. It works over both bonds — the preview client forwards console output
|
|
5
|
+
* and errors, so the guard sees the same events a real browser emits.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import type { PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestType } from '@playwright/test';
|
|
10
|
+
type BaseTest = TestType<PlaywrightTestArgs & PlaywrightTestOptions, PlaywrightWorkerArgs & PlaywrightWorkerOptions>;
|
|
11
|
+
/** One captured browser error. */
|
|
12
|
+
export interface ConsoleErrorEntry {
|
|
13
|
+
type: 'pageerror' | 'console.error';
|
|
14
|
+
text: string;
|
|
15
|
+
location?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Substrings that are always ignored — browser noise that doesn't reflect app
|
|
19
|
+
* bugs.
|
|
20
|
+
*/
|
|
21
|
+
export declare const ALWAYS_IGNORE: readonly RegExp[];
|
|
22
|
+
/** The fixture object `withConsoleGuard` adds to a test. */
|
|
23
|
+
export interface ConsoleGuardFixtures {
|
|
24
|
+
consoleGuard: void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extend a Playwright `test` with the auto-attached console-error guard.
|
|
28
|
+
*
|
|
29
|
+
* To intentionally let a known error through (rare — almost always a smell
|
|
30
|
+
* that should be fixed in the app), use
|
|
31
|
+
* `test.info().annotations.push({ type: 'allow-console-error', description: 'why' })`
|
|
32
|
+
* inside the test body BEFORE the error fires. The `description` is matched
|
|
33
|
+
* against the error text as a regular expression; if it is not a valid regex
|
|
34
|
+
* it is matched as a plain substring instead. An annotation with no
|
|
35
|
+
* description allows every error — always provide one.
|
|
36
|
+
*/
|
|
37
|
+
export declare const withConsoleGuard: (base: BaseTest) => TestType<PlaywrightTestArgs & PlaywrightTestOptions & ConsoleGuardFixtures, PlaywrightWorkerArgs & PlaywrightWorkerOptions>;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=console-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console-guard.d.ts","sourceRoot":"","sources":["../src/console-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAEV,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,QAAQ,EACT,MAAM,kBAAkB,CAAA;AAEzB,KAAK,QAAQ,GAAG,QAAQ,CACtB,kBAAkB,GAAG,qBAAqB,EAC1C,oBAAoB,GAAG,uBAAuB,CAC/C,CAAA;AAED,kCAAkC;AAClC,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,GAAG,eAAe,CAAA;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EA6B1C,CAAA;AAED,4DAA4D;AAC5D,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,IAAI,CAAA;CACnB;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,QAAQ,KACb,QAAQ,CACT,kBAAkB,GAAG,qBAAqB,GAAG,oBAAoB,EACjE,oBAAoB,GAAG,uBAAuB,CAiE5C,CAAA"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The console-error guard fixture: every test subscribes to the page's
|
|
3
|
+
* `pageerror` and `console.error` events and fails at teardown if any were
|
|
4
|
+
* seen. It works over both bonds — the preview client forwards console output
|
|
5
|
+
* and errors, so the guard sees the same events a real browser emits.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Substrings that are always ignored — browser noise that doesn't reflect app
|
|
11
|
+
* bugs.
|
|
12
|
+
*/
|
|
13
|
+
export const ALWAYS_IGNORE = [
|
|
14
|
+
// Vite HMR dev-only websocket reconnect warnings — happen on the
|
|
15
|
+
// test runner's first poll before vite is fully booted; harmless.
|
|
16
|
+
/\[vite\].*connecting/i,
|
|
17
|
+
/\[vite\].*server connection lost/i,
|
|
18
|
+
// Service worker registration failures in headless Chrome — VitePWA
|
|
19
|
+
// tries to register at /sw.js but our smoke build emits to /workbox-*
|
|
20
|
+
// and Playwright fixtures the user-agent. Cosmetic.
|
|
21
|
+
/service worker.*404/i,
|
|
22
|
+
// Chrome DevTools' own probe for source maps on third-party CDN bundles
|
|
23
|
+
// we don't ship maps for (Stripe, Google Maps, etc). Two bugs fixed here,
|
|
24
|
+
// both verified against a headless Chromium probe + the real reported
|
|
25
|
+
// message text (not guessed): (1) the verb was wrong — real Chrome output
|
|
26
|
+
// is "DevTools failed to load SourceMap: Could not load content for
|
|
27
|
+
// <url>: ...", not "failed to fetch source map", so the old pattern never
|
|
28
|
+
// matched real Chrome text at all; (2) the host check (`.cdn.`) doesn't
|
|
29
|
+
// match real vendor hosts (js.stripe.com, maps.googleapis.com contain no
|
|
30
|
+
// '.cdn.' substring). Now matches any `https://`-hosted source map
|
|
31
|
+
// (third-party CDN bundles are always TLS; the app's own dev/preview
|
|
32
|
+
// server is plain `http://localhost`, so same-origin source-map issues
|
|
33
|
+
// are never accidentally silenced by this pattern).
|
|
34
|
+
// NOTE (verified, not assumed): a probe with a broken `sourceMappingURL`
|
|
35
|
+
// produced ZERO console messages via `page.on('console')` under plain
|
|
36
|
+
// Playwright automation (with and without tracing) — Chrome only fetches
|
|
37
|
+
// source maps when a DevTools Sources panel is actually attached, which a
|
|
38
|
+
// headless Playwright run never does. So this entry currently matches
|
|
39
|
+
// nothing observed in practice; it is defense-in-depth against a future
|
|
40
|
+
// Chrome/Playwright behavior change, not an active filter today.
|
|
41
|
+
/devtools failed to load source ?map.*https:\/\//i,
|
|
42
|
+
];
|
|
43
|
+
/**
|
|
44
|
+
* Extend a Playwright `test` with the auto-attached console-error guard.
|
|
45
|
+
*
|
|
46
|
+
* To intentionally let a known error through (rare — almost always a smell
|
|
47
|
+
* that should be fixed in the app), use
|
|
48
|
+
* `test.info().annotations.push({ type: 'allow-console-error', description: 'why' })`
|
|
49
|
+
* inside the test body BEFORE the error fires. The `description` is matched
|
|
50
|
+
* against the error text as a regular expression; if it is not a valid regex
|
|
51
|
+
* it is matched as a plain substring instead. An annotation with no
|
|
52
|
+
* description allows every error — always provide one.
|
|
53
|
+
*/
|
|
54
|
+
export const withConsoleGuard = (base) => base.extend({
|
|
55
|
+
consoleGuard: [
|
|
56
|
+
async ({ page }, use, testInfo) => {
|
|
57
|
+
const buffer = [];
|
|
58
|
+
const matchesAllowed = (text, description) => {
|
|
59
|
+
if (description === undefined)
|
|
60
|
+
return true; // no description = allow everything
|
|
61
|
+
try {
|
|
62
|
+
return new RegExp(description).test(text);
|
|
63
|
+
}
|
|
64
|
+
catch (_error) {
|
|
65
|
+
// Not a valid regex: the annotation holds literal error text — match it as a substring.
|
|
66
|
+
return text.includes(description);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const shouldIgnore = (text) => {
|
|
70
|
+
if (ALWAYS_IGNORE.some((re) => re.test(text)))
|
|
71
|
+
return true;
|
|
72
|
+
return testInfo.annotations
|
|
73
|
+
.filter((a) => a.type === 'allow-console-error')
|
|
74
|
+
.some((a) => matchesAllowed(text, a.description));
|
|
75
|
+
};
|
|
76
|
+
const onPageError = (err) => {
|
|
77
|
+
const text = err.message || String(err);
|
|
78
|
+
if (shouldIgnore(text))
|
|
79
|
+
return;
|
|
80
|
+
buffer.push({ type: 'pageerror', text });
|
|
81
|
+
};
|
|
82
|
+
const onConsole = (msg) => {
|
|
83
|
+
if (msg.type() !== 'error')
|
|
84
|
+
return;
|
|
85
|
+
const text = msg.text();
|
|
86
|
+
if (shouldIgnore(text))
|
|
87
|
+
return;
|
|
88
|
+
const loc = msg.location();
|
|
89
|
+
buffer.push({
|
|
90
|
+
type: 'console.error',
|
|
91
|
+
text,
|
|
92
|
+
location: loc?.url ? `${loc.url}:${loc.lineNumber}` : undefined,
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
page.on('pageerror', onPageError);
|
|
96
|
+
page.on('console', onConsole);
|
|
97
|
+
try {
|
|
98
|
+
await use();
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
page.off('pageerror', onPageError);
|
|
102
|
+
page.off('console', onConsole);
|
|
103
|
+
}
|
|
104
|
+
if (buffer.length > 0) {
|
|
105
|
+
const lines = buffer
|
|
106
|
+
.map((e) => ` - [${e.type}] ${e.text}${e.location ? ` (${e.location})` : ''}`)
|
|
107
|
+
.join('\n');
|
|
108
|
+
throw new Error(`Browser console error(s) during test (${buffer.length}):\n${lines}\n\n` +
|
|
109
|
+
`If this error is genuinely expected, add\n` +
|
|
110
|
+
` test.info().annotations.push({ type: 'allow-console-error', description: '<regex>' })\n` +
|
|
111
|
+
`to the test body BEFORE the error fires.`);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{ auto: true },
|
|
115
|
+
],
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=console-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console-guard.js","sourceRoot":"","sources":["../src/console-guard.ts"],"names":[],"mappings":"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"}
|
package/dist/expect.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `expect` that routes locators and pages built by {@link createEvaluatePage}
|
|
3
|
+
* to polling matchers of their own, and everything else — values, real
|
|
4
|
+
* Playwright locators — to Playwright's `expect` untouched.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { expect as playwrightExpect } from '@playwright/test';
|
|
9
|
+
type AnyExpect = typeof playwrightExpect;
|
|
10
|
+
/**
|
|
11
|
+
* Playwright's `expect`, plus polling matchers for pages and locators built
|
|
12
|
+
* over the preview. `expect(value)`, `expect.soft`, `expect.poll`,
|
|
13
|
+
* `expect.configure` and the asymmetric matchers behave exactly as in
|
|
14
|
+
* Playwright.
|
|
15
|
+
*/
|
|
16
|
+
export declare const expect: AnyExpect;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=expect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../src/expect.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAA0B,MAAM,kBAAkB,CAAA;AAqWrF,KAAK,SAAS,GAAG,OAAO,gBAAgB,CAAA;AAuCxC;;;;;GAKG;AACH,eAAO,MAAM,MAAM,EAAE,SAAsC,CAAA"}
|
package/dist/expect.js
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `expect` that routes locators and pages built by {@link createEvaluatePage}
|
|
3
|
+
* to polling matchers of their own, and everything else — values, real
|
|
4
|
+
* Playwright locators — to Playwright's `expect` untouched.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { expect as playwrightExpect, test as playwrightTest } from '@playwright/test';
|
|
9
|
+
import { E2EStrictModeError } from '@molecule/app-e2e';
|
|
10
|
+
import { isE2ELocator, isE2EPage, textMatch, textMatchFull, } from './page.js';
|
|
11
|
+
const DEFAULT_TIMEOUT = 5_000;
|
|
12
|
+
const pretty = (value) => typeof value === 'string' ? JSON.stringify(value) : (JSON.stringify(value) ?? String(value));
|
|
13
|
+
const expectationText = (expected) => {
|
|
14
|
+
if (expected instanceof RegExp)
|
|
15
|
+
return String(expected);
|
|
16
|
+
if (Array.isArray(expected))
|
|
17
|
+
return JSON.stringify(expected.map((e) => (e instanceof RegExp ? String(e) : e)));
|
|
18
|
+
return pretty(expected);
|
|
19
|
+
};
|
|
20
|
+
const failure = (subject, matcher, describeSubject, expected, received, timeout, negate, message) => {
|
|
21
|
+
const lines = [
|
|
22
|
+
`${message ?? `expect(${subject}).${negate ? 'not.' : ''}${matcher}() failed`}`,
|
|
23
|
+
'',
|
|
24
|
+
`${subject === 'page' ? 'Page' : 'Locator'}: ${describeSubject}`,
|
|
25
|
+
`Expected: ${negate ? 'not ' : ''}${expected}`,
|
|
26
|
+
`Received: ${pretty(received)}`,
|
|
27
|
+
`Timeout: ${timeout}ms`,
|
|
28
|
+
];
|
|
29
|
+
const err = new Error(lines.join('\n'));
|
|
30
|
+
err.name = 'Error';
|
|
31
|
+
return err;
|
|
32
|
+
};
|
|
33
|
+
const record = (soft, err) => {
|
|
34
|
+
if (!soft)
|
|
35
|
+
throw err;
|
|
36
|
+
let info;
|
|
37
|
+
try {
|
|
38
|
+
info = playwrightTest.info();
|
|
39
|
+
}
|
|
40
|
+
catch (_error) {
|
|
41
|
+
info = null;
|
|
42
|
+
}
|
|
43
|
+
if (info && typeof info._failWithError === 'function')
|
|
44
|
+
info._failWithError(err);
|
|
45
|
+
else
|
|
46
|
+
throw err;
|
|
47
|
+
};
|
|
48
|
+
const toMatchArg = (expected, full, opts) => Array.isArray(expected)
|
|
49
|
+
? expected.map((e) => (full ? textMatchFull(e, opts) : textMatch(e, opts)))
|
|
50
|
+
: full
|
|
51
|
+
? textMatchFull(expected, opts)
|
|
52
|
+
: textMatch(expected, opts);
|
|
53
|
+
const locatorMatchers = (locator, defaults, negate = false) => {
|
|
54
|
+
const run = async (matcher, args, expected, opts) => {
|
|
55
|
+
const timeout = opts?.timeout ?? defaults.timeout ?? DEFAULT_TIMEOUT;
|
|
56
|
+
const deadline = Date.now() + timeout;
|
|
57
|
+
let last;
|
|
58
|
+
let delay = 100;
|
|
59
|
+
for (;;) {
|
|
60
|
+
const res = await locator.probe(matcher, args);
|
|
61
|
+
if (res.strict) {
|
|
62
|
+
record(!!defaults.soft, new E2EStrictModeError(locator.describe(), Number(res.count)));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (res.error) {
|
|
66
|
+
record(!!defaults.soft, new Error(`expect(locator).${matcher}(): ${String(res.error)}`));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
last = res.received;
|
|
70
|
+
if (Boolean(res.pass) !== negate)
|
|
71
|
+
return;
|
|
72
|
+
if (Date.now() > deadline) {
|
|
73
|
+
record(!!defaults.soft, failure('locator', matcher, locator.describe(), expected, last, timeout, negate, defaults.message));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
77
|
+
delay = Math.min(delay * 2, 500);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const timeoutOf = (opts) => opts && typeof opts.timeout === 'number' ? { timeout: opts.timeout } : undefined;
|
|
81
|
+
const matchers = {
|
|
82
|
+
toBeVisible: (opts) => run('toBeVisible', {}, 'visible', timeoutOf(opts)),
|
|
83
|
+
toBeHidden: (opts) => run('toBeHidden', {}, 'hidden', timeoutOf(opts)),
|
|
84
|
+
toBeAttached: (opts) => run('toBeAttached', {}, 'attached', timeoutOf(opts)),
|
|
85
|
+
toHaveCount: (n, opts) => run('toHaveCount', { n }, String(n), timeoutOf(opts)),
|
|
86
|
+
toHaveText: (expected, opts) => run('toHaveText', {
|
|
87
|
+
expected: toMatchArg(expected, true, {
|
|
88
|
+
ignoreCase: opts?.ignoreCase,
|
|
89
|
+
}),
|
|
90
|
+
useInnerText: opts?.useInnerText,
|
|
91
|
+
}, expectationText(expected), timeoutOf(opts)),
|
|
92
|
+
toContainText: (expected, opts) => run('toContainText', {
|
|
93
|
+
expected: toMatchArg(expected, false, {
|
|
94
|
+
ignoreCase: opts?.ignoreCase,
|
|
95
|
+
}),
|
|
96
|
+
useInnerText: opts?.useInnerText,
|
|
97
|
+
}, `containing ${expectationText(expected)}`, timeoutOf(opts)),
|
|
98
|
+
toHaveAttribute: (name, expected, opts) => {
|
|
99
|
+
const valueGiven = expected !== undefined && !(typeof expected === 'object' && !(expected instanceof RegExp));
|
|
100
|
+
const options = (valueGiven ? opts : expected) ?? {};
|
|
101
|
+
return run('toHaveAttribute', {
|
|
102
|
+
name,
|
|
103
|
+
expected: valueGiven
|
|
104
|
+
? textMatchFull(expected, {
|
|
105
|
+
ignoreCase: options.ignoreCase,
|
|
106
|
+
})
|
|
107
|
+
: undefined,
|
|
108
|
+
}, valueGiven ? `${name}=${expectationText(expected)}` : `attribute ${name}`, timeoutOf(options));
|
|
109
|
+
},
|
|
110
|
+
toHaveClass: (expected, opts) => run('toHaveClass', { expected: toMatchArg(expected, true) }, `class ${expectationText(expected)}`, timeoutOf(opts)),
|
|
111
|
+
toContainClass: (expected, opts) => run('toContainClass', { expected }, `classes ${expectationText(expected)}`, timeoutOf(opts)),
|
|
112
|
+
toHaveCSS: (name, expected, opts) => run('toHaveCSS', { name, expected: textMatchFull(expected) }, `${name}: ${expectationText(expected)}`, timeoutOf(opts)),
|
|
113
|
+
toHaveValue: (expected, opts) => run('toHaveValue', { expected: textMatchFull(expected) }, `value ${expectationText(expected)}`, timeoutOf(opts)),
|
|
114
|
+
toHaveValues: (expected, opts) => run('toHaveValues', { expected: toMatchArg(expected, true) }, `values ${expectationText(expected)}`, timeoutOf(opts)),
|
|
115
|
+
toHaveId: (expected, opts) => run('toHaveId', { expected: textMatchFull(expected) }, `id ${expectationText(expected)}`, timeoutOf(opts)),
|
|
116
|
+
toHaveJSProperty: (name, expected, opts) => run('toHaveJSProperty', { name, expected }, `${name} = ${expectationText(expected)}`, timeoutOf(opts)),
|
|
117
|
+
toBeChecked: (opts) => run('toBeChecked', { checked: opts?.checked }, opts?.checked === false ? 'unchecked' : 'checked', timeoutOf(opts)),
|
|
118
|
+
toBeEnabled: (opts) => run('toBeEnabled', {}, 'enabled', timeoutOf(opts)),
|
|
119
|
+
toBeDisabled: (opts) => run('toBeDisabled', {}, 'disabled', timeoutOf(opts)),
|
|
120
|
+
toBeEditable: (opts) => run('toBeEditable', {}, 'editable', timeoutOf(opts)),
|
|
121
|
+
toBeEmpty: (opts) => run('toBeEmpty', {}, 'empty', timeoutOf(opts)),
|
|
122
|
+
toBeFocused: (opts) => run('toBeFocused', {}, 'focused', timeoutOf(opts)),
|
|
123
|
+
toBeInViewport: (opts) => run('toBeInViewport', { ratio: opts?.ratio }, 'in viewport', timeoutOf(opts)),
|
|
124
|
+
toHaveAccessibleName: (expected, opts) => run('toHaveAccessibleName', {
|
|
125
|
+
expected: textMatchFull(expected, {
|
|
126
|
+
ignoreCase: opts?.ignoreCase,
|
|
127
|
+
}),
|
|
128
|
+
}, `accessible name ${expectationText(expected)}`, timeoutOf(opts)),
|
|
129
|
+
toHaveRole: (expected, opts) => run('toHaveRole', { expected }, `role ${expectationText(expected)}`, timeoutOf(opts)),
|
|
130
|
+
};
|
|
131
|
+
if (!negate)
|
|
132
|
+
matchers.not = locatorMatchers(locator, defaults, true);
|
|
133
|
+
return new Proxy(matchers, {
|
|
134
|
+
get(target, prop) {
|
|
135
|
+
if (typeof prop === 'symbol' || prop in target)
|
|
136
|
+
return target[prop];
|
|
137
|
+
if (prop === 'then')
|
|
138
|
+
return undefined;
|
|
139
|
+
return () => {
|
|
140
|
+
throw new Error(`expect(locator).${String(prop)}() is not supported by the e2e core over the preview. Supported: ${Object.keys(matchers)
|
|
141
|
+
.filter((k) => k !== 'not')
|
|
142
|
+
.join(', ')}. For anything else read the value (textContent, boundingBox, evaluate) and assert on it.`);
|
|
143
|
+
};
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
const pageMatchers = (page, defaults, negate = false) => {
|
|
148
|
+
const poll = async (matcher, expected, describe, read, test, opts) => {
|
|
149
|
+
const timeout = opts?.timeout ?? defaults.timeout ?? DEFAULT_TIMEOUT;
|
|
150
|
+
const deadline = Date.now() + timeout;
|
|
151
|
+
let last;
|
|
152
|
+
for (;;) {
|
|
153
|
+
last = await read();
|
|
154
|
+
if (test(last) !== negate)
|
|
155
|
+
return;
|
|
156
|
+
if (Date.now() > deadline) {
|
|
157
|
+
record(!!defaults.soft, failure('page', matcher, describe, expectationText(expected), last, timeout, negate, defaults.message));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const matchers = {
|
|
164
|
+
toHaveTitle: (expected, opts) => poll('toHaveTitle', expected, page.url(), () => page.title(), (t) => expected instanceof RegExp
|
|
165
|
+
? expected.test(t)
|
|
166
|
+
: t.replace(/\s+/g, ' ').trim() === expected.replace(/\s+/g, ' ').trim(), opts),
|
|
167
|
+
toHaveURL: (expected, opts) => poll('toHaveURL', expected, page.url(), async () => String((await page.rt('info', [])).url ?? page.url()), (current) => {
|
|
168
|
+
if (expected instanceof RegExp)
|
|
169
|
+
return expected.test(current);
|
|
170
|
+
if (/^[a-z]+:/i.test(expected))
|
|
171
|
+
return (current === expected || current.replace(/\/$/, '') === expected.replace(/\/$/, ''));
|
|
172
|
+
const u = new URL(current);
|
|
173
|
+
const path = u.pathname + u.search + u.hash;
|
|
174
|
+
return (path === expected ||
|
|
175
|
+
u.pathname === expected ||
|
|
176
|
+
u.pathname.replace(/\/$/, '') === expected.replace(/\/$/, ''));
|
|
177
|
+
}, opts),
|
|
178
|
+
};
|
|
179
|
+
if (!negate)
|
|
180
|
+
matchers.not = pageMatchers(page, defaults, true);
|
|
181
|
+
return new Proxy(matchers, {
|
|
182
|
+
get(target, prop) {
|
|
183
|
+
if (typeof prop === 'symbol' || prop in target)
|
|
184
|
+
return target[prop];
|
|
185
|
+
if (prop === 'then')
|
|
186
|
+
return undefined;
|
|
187
|
+
return () => {
|
|
188
|
+
throw new Error(`expect(page).${String(prop)}() is not supported over the preview. Supported: toHaveTitle, toHaveURL. Screenshots need a real browser; assert layout with locator.boundingBox() and page.evaluate().`);
|
|
189
|
+
};
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
const wrap = (base, defaults) => new Proxy(base, {
|
|
194
|
+
apply(target, thisArg, args) {
|
|
195
|
+
const [actual, messageOrOptions] = args;
|
|
196
|
+
const message = typeof messageOrOptions === 'string'
|
|
197
|
+
? messageOrOptions
|
|
198
|
+
: messageOrOptions?.message;
|
|
199
|
+
if (isE2ELocator(actual))
|
|
200
|
+
return locatorMatchers(actual, { ...defaults, message: message ?? defaults.message });
|
|
201
|
+
if (isE2EPage(actual))
|
|
202
|
+
return pageMatchers(actual, { ...defaults, message: message ?? defaults.message });
|
|
203
|
+
return Reflect.apply(target, thisArg, args);
|
|
204
|
+
},
|
|
205
|
+
get(target, prop, receiver) {
|
|
206
|
+
if (prop === 'soft') {
|
|
207
|
+
const soft = Reflect.get(target, prop, receiver);
|
|
208
|
+
return (actual, messageOrOptions) => {
|
|
209
|
+
const message = typeof messageOrOptions === 'string'
|
|
210
|
+
? messageOrOptions
|
|
211
|
+
: messageOrOptions?.message;
|
|
212
|
+
if (isE2ELocator(actual))
|
|
213
|
+
return locatorMatchers(actual, { ...defaults, soft: true, message });
|
|
214
|
+
if (isE2EPage(actual))
|
|
215
|
+
return pageMatchers(actual, { ...defaults, soft: true, message });
|
|
216
|
+
return soft(actual, messageOrOptions);
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
if (prop === 'configure') {
|
|
220
|
+
const configure = Reflect.get(target, prop, receiver);
|
|
221
|
+
return (opts) => wrap(configure(opts), { ...defaults, ...opts });
|
|
222
|
+
}
|
|
223
|
+
return Reflect.get(target, prop, receiver);
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
/**
|
|
227
|
+
* Playwright's `expect`, plus polling matchers for pages and locators built
|
|
228
|
+
* over the preview. `expect(value)`, `expect.soft`, `expect.poll`,
|
|
229
|
+
* `expect.configure` and the asymmetric matchers behave exactly as in
|
|
230
|
+
* Playwright.
|
|
231
|
+
*/
|
|
232
|
+
export const expect = wrap(playwrightExpect, {});
|
|
233
|
+
//# sourceMappingURL=expect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expect.js","sourceRoot":"","sources":["../src/expect.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,67 +1,114 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* The `@playwright/test` drop-in for molecule apps: Playwright's `test`,
|
|
3
|
+
* `expect` and `page`, with the browser supplied by the bonded e2e provider
|
|
4
|
+
* and a console-error guard on every test.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `@
|
|
8
|
-
* `consoleGuard` fixture with `{ auto: true }`, so every test
|
|
9
|
-
* automatically subscribes to the browser's `pageerror` event and
|
|
10
|
-
* `console.error` messages, then asserts the buffer is empty at test
|
|
11
|
-
* teardown.
|
|
6
|
+
* Import `test` and `expect` from here instead of `@playwright/test` and
|
|
7
|
+
* write ordinary Playwright specs. Which browser runs them is the e2e bond
|
|
8
|
+
* (`@molecule/app-e2e`):
|
|
12
9
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
10
|
+
* - **`@molecule/app-e2e-preview`** drives the LIVE PREVIEW the molecule.dev
|
|
11
|
+
* IDE is already showing — the page the person is looking at, in their own
|
|
12
|
+
* browser — over a WebSocket through the dev server. No browser binary in
|
|
13
|
+
* the sandbox, nothing to download. This is what a molecule sandbox uses.
|
|
14
|
+
* - **`@molecule/app-e2e-playwright`** launches real Playwright browsers. This
|
|
15
|
+
* is what your own machine and CI use.
|
|
19
16
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* error text with `[`/`(` can be pasted verbatim). An annotation with
|
|
27
|
-
* no description allows every error — always provide one.
|
|
17
|
+
* The same spec file runs unchanged in both. The provider is picked by
|
|
18
|
+
* `resolveE2EProviderName()`: `MOL_E2E_PROVIDER` when set, otherwise `preview`
|
|
19
|
+
* inside a molecule sandbox (the `/etc/mol/app-root` marker exists) and
|
|
20
|
+
* `playwright` everywhere else. The scaffolded `e2e/bonds.ts` bonds the
|
|
21
|
+
* matching provider (and `test` bonds it by name as a fallback); `test` reads
|
|
22
|
+
* the same answer to decide whether to launch a browser.
|
|
28
23
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* against the actual Chrome message text and constrained to `https://` so it
|
|
35
|
-
* can never silence a genuinely broken source map in the app's OWN bundle
|
|
36
|
-
* (served over plain `http://localhost` in dev/preview).
|
|
24
|
+
* Every test also carries the console-error guard: the page's `pageerror`
|
|
25
|
+
* and `console.error` events fail the test at teardown, so a spec that only
|
|
26
|
+
* asserts on `page.request` cannot stay green while the rendered page is
|
|
27
|
+
* blank. Allow a known error with
|
|
28
|
+
* `test.info().annotations.push({ type: 'allow-console-error', description: '<regex>' })`.
|
|
37
29
|
*
|
|
38
30
|
* @example
|
|
39
31
|
* ```ts
|
|
40
|
-
* //
|
|
41
|
-
* import {
|
|
32
|
+
* // e2e/bonds.ts — scaffolded; wires the provider for THIS environment
|
|
33
|
+
* import { resolveE2EProviderName, setProvider } from '@molecule/app-e2e'
|
|
34
|
+
* import { provider as playwright } from '@molecule/app-e2e-playwright'
|
|
35
|
+
* import { provider as preview } from '@molecule/app-e2e-preview'
|
|
42
36
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
37
|
+
* setProvider(resolveE2EProviderName() === 'preview' ? preview : playwright)
|
|
38
|
+
*
|
|
39
|
+
* // e2e/post.spec.ts — an ordinary Playwright spec
|
|
40
|
+
* import { expect, test } from '@molecule/app-e2e-fixtures-default'
|
|
41
|
+
*
|
|
42
|
+
* import './bonds.js'
|
|
43
|
+
*
|
|
44
|
+
* test('the phone layout keeps the prose large', async ({ page }) => {
|
|
45
|
+
* await page.setViewportSize({ width: 390, height: 844 })
|
|
46
|
+
* await page.goto('/blog/hello/')
|
|
47
|
+
* const prose = page.locator('article p').first()
|
|
48
|
+
* const size = await prose.evaluate((el) => parseFloat(getComputedStyle(el).fontSize))
|
|
49
|
+
* expect(size).toBeGreaterThanOrEqual(18)
|
|
50
|
+
* await expect(page.getByRole('switch', { name: /summar/i })).toBeVisible()
|
|
47
51
|
* })
|
|
48
52
|
* ```
|
|
49
53
|
*
|
|
54
|
+
* @remarks
|
|
55
|
+
* - **What works over the preview** (the `@molecule/app-e2e-preview` bond):
|
|
56
|
+
* `page.goto/reload/goBack/goForward/url/title/content`,
|
|
57
|
+
* `page.evaluate/$eval/$$eval`, `page.locator` and every `getBy*` (role
|
|
58
|
+
* with name/level/checked/pressed/expanded/selected, text, label,
|
|
59
|
+
* placeholder, title, alt text, test id), `first/last/nth/filter/count/all`,
|
|
60
|
+
* `click/dblclick/hover/tap/fill/clear/type/press/check/uncheck/setChecked/
|
|
61
|
+
* selectOption/focus/blur/dispatchEvent/scrollIntoViewIfNeeded`,
|
|
62
|
+
* `textContent/innerText/innerHTML/inputValue/getAttribute/isVisible/isHidden/
|
|
63
|
+
* isEnabled/isDisabled/isEditable/isChecked/boundingBox/evaluate/evaluateAll/
|
|
64
|
+
* waitFor`, `page.setViewportSize/viewportSize`, `page.mouse.*`,
|
|
65
|
+
* `page.keyboard.*`, `page.request.get/post/put/patch/delete/fetch` (runs
|
|
66
|
+
* `fetch` inside the page, cookies included), `waitForSelector/waitForURL/
|
|
67
|
+
* waitForFunction/waitForLoadState/waitForTimeout`, `page.on('console' |
|
|
68
|
+
* 'pageerror' | 'dialog' | 'close')`, and `expect(locator)` with
|
|
69
|
+
* `toBeVisible/toBeHidden/toBeAttached/toHaveCount/toHaveText/toContainText/
|
|
70
|
+
* toHaveAttribute/toHaveClass/toContainClass/toHaveCSS/toHaveValue/toHaveId/
|
|
71
|
+
* toBeChecked/toBeEnabled/toBeDisabled/toBeEditable/toBeEmpty/toBeFocused/
|
|
72
|
+
* toBeInViewport/toHaveAccessibleName/toHaveRole` (+ `.not`, `expect.soft`,
|
|
73
|
+
* `expect.configure`), `expect(page).toHaveTitle/toHaveURL`.
|
|
74
|
+
* - **The escape hatch is `page.evaluate()`.** Anything the list above does
|
|
75
|
+
* not cover — a computed style, a scroll position, `matchMedia`, a
|
|
76
|
+
* `fetch` — is one `evaluate` away; the function runs inside the real page
|
|
77
|
+
* and returns JSON.
|
|
78
|
+
* - **Not available over the preview**, and the method THROWS naming the
|
|
79
|
+
* alternative: screenshots and `toHaveScreenshot` (assert layout with
|
|
80
|
+
* `boundingBox()` and computed styles instead), `page.route/waitForResponse/
|
|
81
|
+
* waitForRequest` (read the response with `page.request` or `fetch` in
|
|
82
|
+
* `evaluate`), element handles (`$`, `$$`, `elementHandle` — use locators),
|
|
83
|
+
* `setInputFiles`, `dragTo`, iframes inside the preview, `emulateMedia`,
|
|
84
|
+
* `addInitScript/exposeFunction`, `context.cookies/storageState` (read
|
|
85
|
+
* `document.cookie`/`localStorage` in `evaluate`). The playwright bond
|
|
86
|
+
* supports all of them.
|
|
87
|
+
* - **Viewport.** `page.setViewportSize` asks the IDE to resize the preview
|
|
88
|
+
* frame and throws if the host did not (a preview opened in a plain tab
|
|
89
|
+
* keeps the tab's width). Test phone layouts at 390×844 this way.
|
|
90
|
+
* - **Events.** `page.on('response')`/`'request'` never fire over the preview
|
|
91
|
+
* (a one-time warning says so); `'console'` and `'pageerror'` do, so the
|
|
92
|
+
* console-error guard works there too.
|
|
93
|
+
* - **The person's browser is the renderer.** If every tab showing the
|
|
94
|
+
* preview is closed or asleep, actions wait for a page to reconnect and
|
|
95
|
+
* then time out with a message saying so. Keep the IDE tab open (the IDE
|
|
96
|
+
* holds a screen wake lock while a build runs) or open the preview URL in
|
|
97
|
+
* any other tab — any connected viewer will do.
|
|
98
|
+
* - `createEvaluatePage()` is how a bond that can only run code inside a page
|
|
99
|
+
* (an `E2ETransport`) gets the whole Playwright-shaped page; the preview
|
|
100
|
+
* bond uses it, and so can any future one.
|
|
101
|
+
* - `@playwright/test` is a peer dependency: it supplies the runner
|
|
102
|
+
* (`npx playwright test`), `expect` for plain values, and the `Page` types.
|
|
103
|
+
* It never downloads browsers on install; only the playwright bond needs
|
|
104
|
+
* `npx playwright install`.
|
|
105
|
+
*
|
|
50
106
|
* @module
|
|
51
107
|
*/
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Custom Playwright `test` with an auto-attached browser console-error
|
|
60
|
-
* guard. Drop-in replacement for `import { test } from '@playwright/test'`.
|
|
61
|
-
*/
|
|
62
|
-
export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & {
|
|
63
|
-
consoleGuard: void;
|
|
64
|
-
}, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
65
|
-
export { expect };
|
|
66
|
-
export type { ConsoleErrorEntry };
|
|
108
|
+
export * from './console-guard.js';
|
|
109
|
+
export * from './expect.js';
|
|
110
|
+
export * from './page.js';
|
|
111
|
+
export * from './playwright.js';
|
|
112
|
+
export * from './runtime.js';
|
|
113
|
+
export * from './test.js';
|
|
67
114
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0GG;AAEH,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA"}
|