@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/dist/index.js CHANGED
@@ -1,154 +1,114 @@
1
1
  /**
2
- * Shared Playwright `test` + `expect` with auto-attached browser
3
- * console-error / pageerror guard.
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
- * Every fleet app's e2e specs import `test` and `expect` from this
6
- * module (re-exported through their per-app `_helpers.ts`) instead of
7
- * `@playwright/test` directly. The custom `test` includes a
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
- * This catches the failure mode where React (or any other client-side
14
- * module) throws on mount but the spec only asserts against
15
- * `page.request.get/post`, leaving the test green while the rendered
16
- * page is blank. A single quill-delta ESM/CJS interop error sat for
17
- * four days like this before we noticed — the replay videos were
18
- * 17 KB of nothing and the JSON reported PASS.
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
- * To intentionally let a known error through (rare almost always a
21
- * smell that should be fixed in the app), use
22
- * `test.info().annotations.push({ type: 'allow-console-error', description: 'why' })`
23
- * inside the test body BEFORE the error fires. The `description` is
24
- * matched against the error text as a regular expression; if it is not
25
- * a valid regex it is matched as a plain substring instead (so literal
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
- * A small, fixed set of browser-noise patterns are ALWAYS ignored regardless
30
- * of `allow-console-error` (Vite HMR reconnect chatter, service-worker 404s
31
- * in headless Chrome, and a real Chrome DevTools "failed to load SourceMap"
32
- * message for any `https://`-hosted bundle — e.g. Stripe/Google Maps CDN
33
- * scripts shipped without source maps). That last pattern is verified
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
- * // In fleet apps, the per-app `./_helpers.ts` re-exports these:
41
- * import { test, expect } from '@molecule/app-e2e-fixtures-default'
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
- * test('login lands on dashboard', async ({ page }) => {
44
- * await page.goto('/login')
45
- * await page.getByLabel(/email/i).fill('user@example.com')
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
- import { expect, test as base } from '@playwright/test';
53
- /** Substrings that are always ignored — browser noise that doesn't reflect app bugs. */
54
- const ALWAYS_IGNORE = [
55
- // Vite HMR dev-only websocket reconnect warnings — happen on the
56
- // test runner's first poll before vite is fully booted; harmless.
57
- /\[vite\].*connecting/i,
58
- /\[vite\].*server connection lost/i,
59
- // Service worker registration failures in headless Chrome — VitePWA
60
- // tries to register at /sw.js but our smoke build emits to /workbox-*
61
- // and Playwright fixtures the user-agent. Cosmetic.
62
- /service worker.*404/i,
63
- // Chrome DevTools' own probe for source maps on third-party CDN bundles
64
- // we don't ship maps for (Stripe, Google Maps, etc). Two bugs fixed here,
65
- // both verified against a headless Chromium probe + the real reported
66
- // message text (not guessed): (1) the verb was wrong — real Chrome output
67
- // is "DevTools failed to load SourceMap: Could not load content for
68
- // <url>: ...", not "failed to fetch source map", so the old pattern never
69
- // matched real Chrome text at all; (2) the host check (`.cdn.`) doesn't
70
- // match real vendor hosts (js.stripe.com, maps.googleapis.com contain no
71
- // '.cdn.' substring). Now matches any `https://`-hosted source map
72
- // (third-party CDN bundles are always TLS; the app's own dev/preview
73
- // server is plain `http://localhost`, so same-origin source-map issues
74
- // are never accidentally silenced by this pattern).
75
- // NOTE (verified, not assumed): a probe with a broken `sourceMappingURL`
76
- // produced ZERO console messages via `page.on('console')` under plain
77
- // Playwright automation (with and without tracing) — Chrome only fetches
78
- // source maps when a DevTools Sources panel is actually attached, which a
79
- // headless Playwright run never does. So this entry currently matches
80
- // nothing observed in practice; it is defense-in-depth against a future
81
- // Chrome/Playwright behavior change, not an active filter today.
82
- /devtools failed to load source ?map.*https:\/\//i,
83
- ];
84
- /**
85
- * Custom Playwright `test` with an auto-attached browser console-error
86
- * guard. Drop-in replacement for `import { test } from '@playwright/test'`.
87
- */
88
- export const test = base.extend({
89
- consoleGuard: [
90
- async ({ page }, use, testInfo) => {
91
- const buffer = [];
92
- // Each allow-console-error description is tried as a regex; an invalid
93
- // pattern (e.g. verbatim error text containing `[` or `(`) falls back to
94
- // plain substring matching instead of throwing from inside the guard.
95
- const matchesAllowed = (text, description) => {
96
- if (description === undefined)
97
- return true; // no description = allow everything
98
- try {
99
- return new RegExp(description).test(text);
100
- }
101
- catch (_error) {
102
- // Invalid regex — treat the description as a literal substring.
103
- return text.includes(description);
104
- }
105
- };
106
- const shouldIgnore = (text) => {
107
- if (ALWAYS_IGNORE.some((re) => re.test(text)))
108
- return true;
109
- return testInfo.annotations
110
- .filter((a) => a.type === 'allow-console-error')
111
- .some((a) => matchesAllowed(text, a.description));
112
- };
113
- const onPageError = (err) => {
114
- const text = err.message || String(err);
115
- if (shouldIgnore(text))
116
- return;
117
- buffer.push({ type: 'pageerror', text });
118
- };
119
- const onConsole = (msg) => {
120
- if (msg.type() !== 'error')
121
- return;
122
- const text = msg.text();
123
- if (shouldIgnore(text))
124
- return;
125
- const loc = msg.location();
126
- buffer.push({
127
- type: 'console.error',
128
- text,
129
- location: loc?.url ? `${loc.url}:${loc.lineNumber}` : undefined,
130
- });
131
- };
132
- page.on('pageerror', onPageError);
133
- page.on('console', onConsole);
134
- try {
135
- await use();
136
- }
137
- finally {
138
- page.off('pageerror', onPageError);
139
- page.off('console', onConsole);
140
- }
141
- if (buffer.length > 0) {
142
- const lines = buffer
143
- .map((e) => ` - [${e.type}] ${e.text}${e.location ? ` (${e.location})` : ''}`)
144
- .join('\n');
145
- throw new Error(`Browser console error(s) during test (${buffer.length}):\n${lines}\n\n` +
146
- `If this error is genuinely expected, add\n` +
147
- ` test.info().annotations.push({ type: 'allow-console-error', description: '<regex>' })\n` +
148
- `to the test body BEFORE the error fires.`);
149
- }
150
- },
151
- { auto: true },
152
- ],
153
- });
154
- export { expect };
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';
114
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","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"}
package/dist/page.d.ts ADDED
@@ -0,0 +1,370 @@
1
+ /**
2
+ * A Playwright-shaped `Page` built on an {@link E2ETransport} — the driver
3
+ * half of the runtime in `runtime.ts`. Bonds that can only run code inside a
4
+ * page (the live preview) get the whole documented subset from this file.
5
+ *
6
+ * @module
7
+ */
8
+ import type { BrowserContext, Frame, Page } from '@playwright/test';
9
+ import type { E2EPageOptions, E2ETransport, E2EViewport } from '@molecule/app-e2e';
10
+ import { type LocatorStep, type TextMatch } from './runtime.js';
11
+ /** Brand on locators created here (the `expect` wrapper routes on it). */
12
+ export declare const E2E_LOCATOR: unique symbol;
13
+ /** Brand on pages created here. */
14
+ export declare const E2E_PAGE: unique symbol;
15
+ type Dict = Record<string, unknown>;
16
+ type Listener = (payload: unknown) => void;
17
+ declare const toMatch: (value: string | RegExp, opts?: {
18
+ exact?: boolean;
19
+ ignoreCase?: boolean;
20
+ }) => TextMatch;
21
+ /** Full-text match (expect's toHaveText): a string must equal the whole text; a RegExp tests it. */
22
+ declare const toFull: (value: string | RegExp, opts?: {
23
+ ignoreCase?: boolean;
24
+ }) => TextMatch;
25
+ /** A Playwright-shaped Locator: a lazy chain of steps resolved inside the page on every action. */
26
+ declare class LocatorImpl {
27
+ private readonly owner;
28
+ readonly steps: LocatorStep[];
29
+ readonly [E2E_LOCATOR] = true;
30
+ constructor(owner: PageImpl, steps: LocatorStep[]);
31
+ /** A new locator with more steps (locators are immutable). */
32
+ private extend;
33
+ /** Steps for a selector string (parsed in the page) or another locator. */
34
+ private stepsOf;
35
+ /** The filter steps a `filter()` / `locator()` options object adds. */
36
+ private filterStep;
37
+ /** Playwright's `locator()`: narrow to descendants matching a selector, with optional `hasText` / `has` filters. */
38
+ locator(sel: string | LocatorImpl, opts?: {
39
+ hasText?: string | RegExp;
40
+ hasNotText?: string | RegExp;
41
+ has?: LocatorImpl;
42
+ hasNot?: LocatorImpl;
43
+ }): LocatorImpl;
44
+ /** Playwright's `getByRole()`: by ARIA role, with accessible-name, heading-level and state options. */
45
+ getByRole(role: string, opts?: Dict): LocatorImpl;
46
+ /** Playwright's `getByText()`: the smallest elements whose text matches. */
47
+ getByText(text: string | RegExp, opts?: {
48
+ exact?: boolean;
49
+ }): LocatorImpl;
50
+ /** Playwright's `getByLabel()`: form controls by their label text (also `aria-label`). */
51
+ getByLabel(text: string | RegExp, opts?: {
52
+ exact?: boolean;
53
+ }): LocatorImpl;
54
+ /** Playwright's `getByPlaceholder()`. */
55
+ getByPlaceholder(text: string | RegExp, opts?: {
56
+ exact?: boolean;
57
+ }): LocatorImpl;
58
+ /** Playwright's `getByTitle()`. */
59
+ getByTitle(text: string | RegExp, opts?: {
60
+ exact?: boolean;
61
+ }): LocatorImpl;
62
+ /** Playwright's `getByAltText()`. */
63
+ getByAltText(text: string | RegExp, opts?: {
64
+ exact?: boolean;
65
+ }): LocatorImpl;
66
+ /** Playwright's `getByTestId()` on the configured test-id attribute (default `data-testid`). */
67
+ getByTestId(id: string | RegExp): LocatorImpl;
68
+ /** Playwright's `locator.filter()`: keep matches by text, by a descendant locator, or by visibility. */
69
+ filter(opts?: {
70
+ hasText?: string | RegExp;
71
+ hasNotText?: string | RegExp;
72
+ has?: LocatorImpl;
73
+ hasNot?: LocatorImpl;
74
+ visible?: boolean;
75
+ }): LocatorImpl;
76
+ /** The first match. */
77
+ first(): LocatorImpl;
78
+ /** The last match. */
79
+ last(): LocatorImpl;
80
+ /** The i-th match (a negative index counts from the end). */
81
+ nth(i: number): LocatorImpl;
82
+ /** The page this belongs to (null for a console message over the preview). */
83
+ page(): Page;
84
+ /** The locator chain, Playwright-style, for error messages. */
85
+ toString(): string;
86
+ /** The locator chain as text. */
87
+ describe(): string;
88
+ /** Run one runtime call for this locator. */
89
+ private call;
90
+ /** Turn a runtime reply into a value, throwing strict-mode, timeout or plain errors. */
91
+ private unwrap;
92
+ /** Run a single-target action with auto-wait and actionability checks. */
93
+ private act;
94
+ /** Read one value from the single strict target. */
95
+ private read;
96
+ /** Playwright's `click()`: waits until the element is visible, enabled and not covered, then clicks its centre (or `position`). */
97
+ click(opts?: Dict): Promise<void>;
98
+ /** Playwright's `dblclick()`. */
99
+ dblclick(opts?: Dict): Promise<void>;
100
+ /** Playwright's `hover()`: moves the pointer over the element. */
101
+ hover(opts?: Dict): Promise<void>;
102
+ /** Playwright's `tap()`: touch events followed by a click. */
103
+ tap(opts?: Dict): Promise<void>;
104
+ /** Playwright's `fill()`: focuses, replaces the value through the native setter and fires `input` / `change`. */
105
+ fill(value: string, opts?: Dict): Promise<void>;
106
+ /** Playwright's `clear()`: fills with an empty string. */
107
+ clear(opts?: Dict): Promise<void>;
108
+ /** Playwright's `type()`: presses each character in turn (or, on a console message, its level). */
109
+ type(text: string, opts?: Dict): Promise<void>;
110
+ /** Playwright's `pressSequentially()`: presses each character in turn. */
111
+ pressSequentially(text: string, opts?: Dict): Promise<void>;
112
+ /** Playwright's `press()`: a key or chord (`Enter`, `Control+a`); Enter submits a form. */
113
+ press(key: string, opts?: Dict): Promise<void>;
114
+ /** Playwright's `check()`: clicks until checked (or, on the page, throws on a failed runtime reply). */
115
+ check(opts?: Dict): Promise<void>;
116
+ /** Playwright's `uncheck()`: clicks until unchecked. */
117
+ uncheck(opts?: Dict): Promise<void>;
118
+ /** Playwright's `setChecked()`. */
119
+ setChecked(checked: boolean, opts?: Dict): Promise<void>;
120
+ /** Playwright's `selectOption()`: by value, label or index; returns the selected values. */
121
+ selectOption(values: unknown, opts?: Dict): Promise<string[]>;
122
+ /** Playwright's `focus()`. */
123
+ focus(opts?: Dict): Promise<void>;
124
+ /** Playwright's `blur()`. */
125
+ blur(opts?: Dict): Promise<void>;
126
+ /** Playwright's `dispatchEvent()`: a synthetic event of the given type. */
127
+ dispatchEvent(type: string, init?: Dict, opts?: Dict): Promise<void>;
128
+ /** Playwright's `scrollIntoViewIfNeeded()`. */
129
+ scrollIntoViewIfNeeded(opts?: Dict): Promise<void>;
130
+ /** No-op over the preview: nothing to paint. */
131
+ highlight(): Promise<void>;
132
+ /** Playwright's `count()`: how many elements match right now. */
133
+ count(): Promise<number>;
134
+ /** Playwright's `all()`: one locator per current match. */
135
+ all(): Promise<LocatorImpl[]>;
136
+ /** Playwright's `allTextContents()`. */
137
+ allTextContents(): Promise<string[]>;
138
+ /** Playwright's `allInnerTexts()`. */
139
+ allInnerTexts(): Promise<string[]>;
140
+ /** Playwright's `textContent()` (strict: exactly one match). */
141
+ textContent(opts?: Dict): Promise<string | null>;
142
+ /** Playwright's `innerText()`. */
143
+ innerText(opts?: Dict): Promise<string>;
144
+ /** Playwright's `innerHTML()`. */
145
+ innerHTML(opts?: Dict): Promise<string>;
146
+ /** Playwright's `inputValue()` for inputs, textareas and selects. */
147
+ inputValue(opts?: Dict): Promise<string>;
148
+ /** Playwright's `getAttribute()`. */
149
+ getAttribute(name: string, opts?: Dict): Promise<string | null>;
150
+ /** Playwright's `isVisible()`: false when nothing matches; no waiting. */
151
+ isVisible(): Promise<boolean>;
152
+ /** Playwright's `isHidden()`: true when nothing matches; no waiting. */
153
+ isHidden(): Promise<boolean>;
154
+ /** Playwright's `isEnabled()`. */
155
+ isEnabled(opts?: Dict): Promise<boolean>;
156
+ /** Playwright's `isDisabled()`. */
157
+ isDisabled(opts?: Dict): Promise<boolean>;
158
+ /** Playwright's `isEditable()`. */
159
+ isEditable(opts?: Dict): Promise<boolean>;
160
+ /** Playwright's `isChecked()` for checkboxes, radios and switches. */
161
+ isChecked(opts?: Dict): Promise<boolean>;
162
+ /** Playwright's `boundingBox()`: the element's rect, or null when it is not visible. */
163
+ boundingBox(opts?: Dict): Promise<{
164
+ x: number;
165
+ y: number;
166
+ width: number;
167
+ height: number;
168
+ } | null>;
169
+ /** Playwright's `evaluate()`: runs the function inside the page and returns JSON. */
170
+ evaluate(fn: unknown, arg?: unknown, opts?: Dict): Promise<unknown>;
171
+ /** Playwright's `locator.evaluateAll()`: runs `fn(elements, arg)` inside the page. */
172
+ evaluateAll(fn: unknown, arg?: unknown): Promise<unknown>;
173
+ /** Playwright's `waitFor()`: until attached, detached, visible or hidden. */
174
+ waitFor(opts?: {
175
+ state?: 'attached' | 'detached' | 'visible' | 'hidden';
176
+ timeout?: number;
177
+ }): Promise<void>;
178
+ /** One probe for the expect matchers; the wrapper polls it. */
179
+ probe(matcher: string, args: Dict): Promise<Dict>;
180
+ }
181
+ interface DialogImpl {
182
+ type(): string;
183
+ message(): string;
184
+ defaultValue(): string;
185
+ accept(text?: string): Promise<void>;
186
+ dismiss(): Promise<void>;
187
+ }
188
+ /** A Playwright-shaped Page over an `E2ETransport`; `createEvaluatePage` wraps it in a Proxy. */
189
+ declare class PageImpl {
190
+ private readonly transport;
191
+ private readonly options;
192
+ readonly [E2E_PAGE] = true;
193
+ defaultTimeout: number;
194
+ navigationTimeout: number;
195
+ readonly testIdAttribute: string;
196
+ private viewport;
197
+ private closed;
198
+ private proxy;
199
+ private readonly listeners;
200
+ private readonly warned;
201
+ private readonly unsubscribe;
202
+ readonly mouse: Dict;
203
+ readonly keyboard: Dict;
204
+ readonly touchscreen: Dict;
205
+ readonly request: Dict;
206
+ constructor(transport: E2ETransport, options: E2EPageOptions);
207
+ /** The bond's name, for error messages. */
208
+ get bondName(): string;
209
+ /** The branded Page proxy. */
210
+ asPage(): Page;
211
+ /** Called once by `createEvaluatePage` with the proxy that wraps this instance. */
212
+ attachProxy(proxy: Page): void;
213
+ /** Fire the listeners of one event. */
214
+ private emit;
215
+ /** Playwright's `check()`: clicks until checked (or, on the page, throws on a failed runtime reply). */
216
+ private check;
217
+ /** Run a runtime call inside the page, installing the runtime on a fresh document. */
218
+ rt(fn: string, args: unknown[], timeout?: number): Promise<Dict>;
219
+ /** Resolve a spec URL against `baseURL` when it is relative. */
220
+ private resolveUrl;
221
+ /** Playwright's `page.goto()`: navigate and wait for the new document to load. */
222
+ goto(url: string, opts?: {
223
+ timeout?: number;
224
+ }): Promise<null>;
225
+ /** Playwright's `page.reload()`. */
226
+ reload(opts?: {
227
+ timeout?: number;
228
+ }): Promise<null>;
229
+ /** Playwright's `page.goBack()`. */
230
+ goBack(opts?: {
231
+ timeout?: number;
232
+ }): Promise<null>;
233
+ /** Playwright's `page.goForward()`. */
234
+ goForward(opts?: {
235
+ timeout?: number;
236
+ }): Promise<null>;
237
+ /** Playwright's `url()`: the last known URL (or, on a response, its final URL). */
238
+ url(): string;
239
+ /** Playwright's `page.title()`. */
240
+ title(): Promise<string>;
241
+ /** Playwright's `page.content()`: the document's HTML. */
242
+ content(): Promise<string>;
243
+ /** Playwright's `waitForLoadState()`: until the document is complete (plus a quiet moment for `networkidle`). */
244
+ waitForLoadState(state?: string, opts?: {
245
+ timeout?: number;
246
+ }): Promise<void>;
247
+ /** Playwright's `waitForURL()`: a string (full URL or path), RegExp or predicate. */
248
+ waitForURL(url: string | RegExp | ((u: URL) => boolean), opts?: {
249
+ timeout?: number;
250
+ }): Promise<void>;
251
+ /** Playwright's `waitForTimeout()`. */
252
+ waitForTimeout(ms: number): Promise<void>;
253
+ /** Playwright's `waitForFunction()`: polls the function inside the page until it returns a truthy value. */
254
+ waitForFunction(fn: unknown, arg?: unknown, opts?: {
255
+ timeout?: number;
256
+ polling?: number | 'raf';
257
+ }): Promise<unknown>;
258
+ /** Playwright's `waitForSelector()`; returns the locator (element handles are not available). */
259
+ waitForSelector(selector: string, opts?: {
260
+ state?: 'attached' | 'detached' | 'visible' | 'hidden';
261
+ timeout?: number;
262
+ }): Promise<LocatorImpl | null>;
263
+ /** Playwright's `evaluate()`: runs the function inside the page and returns JSON. */
264
+ evaluate(fn: unknown, arg?: unknown): Promise<unknown>;
265
+ /** Playwright's `$eval()`. */
266
+ $eval(selector: string, fn: unknown, arg?: unknown): Promise<unknown>;
267
+ /** Playwright's `$$eval()`. */
268
+ $$eval(selector: string, fn: unknown, arg?: unknown): Promise<unknown>;
269
+ /** Playwright's `addStyleTag()` (inline content). */
270
+ addStyleTag(opts: {
271
+ content?: string;
272
+ url?: string;
273
+ }): Promise<null>;
274
+ /** Playwright's `addScriptTag()`. */
275
+ addScriptTag(opts: {
276
+ content?: string;
277
+ url?: string;
278
+ type?: string;
279
+ }): Promise<null>;
280
+ /** Playwright's `locator()`: narrow to descendants matching a selector, with optional `hasText` / `has` filters. */
281
+ locator(sel: string | LocatorImpl, opts?: {
282
+ hasText?: string | RegExp;
283
+ hasNotText?: string | RegExp;
284
+ has?: LocatorImpl;
285
+ hasNot?: LocatorImpl;
286
+ }): LocatorImpl;
287
+ /** Playwright's `getByRole()`: by ARIA role, with accessible-name, heading-level and state options. */
288
+ getByRole(role: string, opts?: Dict): LocatorImpl;
289
+ /** Playwright's `getByText()`: the smallest elements whose text matches. */
290
+ getByText(text: string | RegExp, opts?: {
291
+ exact?: boolean;
292
+ }): LocatorImpl;
293
+ /** Playwright's `getByLabel()`: form controls by their label text (also `aria-label`). */
294
+ getByLabel(text: string | RegExp, opts?: {
295
+ exact?: boolean;
296
+ }): LocatorImpl;
297
+ /** Playwright's `getByPlaceholder()`. */
298
+ getByPlaceholder(text: string | RegExp, opts?: {
299
+ exact?: boolean;
300
+ }): LocatorImpl;
301
+ /** Playwright's `getByTitle()`. */
302
+ getByTitle(text: string | RegExp, opts?: {
303
+ exact?: boolean;
304
+ }): LocatorImpl;
305
+ /** Playwright's `getByAltText()`. */
306
+ getByAltText(text: string | RegExp, opts?: {
307
+ exact?: boolean;
308
+ }): LocatorImpl;
309
+ /** Playwright's `getByTestId()` on the configured test-id attribute (default `data-testid`). */
310
+ getByTestId(id: string | RegExp): LocatorImpl;
311
+ /** Playwright's `setViewportSize()`: asks the host to resize the frame; throws when it did not. */
312
+ setViewportSize(size: E2EViewport): Promise<void>;
313
+ /** Apply the configured viewport without failing the test when the host cannot resize (used once at connect). */
314
+ applyInitialViewport(): Promise<void>;
315
+ /** Playwright's `viewportSize()`. */
316
+ viewportSize(): E2EViewport | null;
317
+ /** Log a warning once per key. */
318
+ private warnOnce;
319
+ /** Playwright's `page.on()`: console, pageerror, dialog, close and load fire over the preview; network events never do (warned once). */
320
+ on(event: string, fn: Listener): Page;
321
+ /** Alias of `on()`. */
322
+ addListener(event: string, fn: Listener): Page;
323
+ /** Playwright's `page.once()`. */
324
+ once(event: string, fn: Listener): Page;
325
+ /** Playwright's `page.off()`. */
326
+ off(event: string, fn: Listener): Page;
327
+ /** Alias of `off()`. */
328
+ removeListener(event: string, fn: Listener): Page;
329
+ /** Playwright's `removeAllListeners()`. */
330
+ removeAllListeners(event?: string): Page;
331
+ /** Called by a transport that forwards dialogs (the preview client auto-accepts them). */
332
+ emitDialog(dialog: DialogImpl): void;
333
+ /** Playwright's `page.close()`: releases the transport. */
334
+ close(): Promise<void>;
335
+ /** Playwright's `isClosed()`. */
336
+ isClosed(): boolean;
337
+ /** No-op over the preview: the page is already in front. */
338
+ bringToFront(): Promise<void>;
339
+ /** Playwright's `setDefaultTimeout()`. */
340
+ setDefaultTimeout(ms: number): void;
341
+ /** Playwright's `setDefaultNavigationTimeout()`. */
342
+ setDefaultNavigationTimeout(ms: number): void;
343
+ /** No-op: there is no inspector to pause in. */
344
+ pause(): Promise<void>;
345
+ /** The page itself, standing in for the main frame. */
346
+ mainFrame(): Frame;
347
+ /** The main frame only. */
348
+ frames(): Frame[];
349
+ /** Always empty over the preview. */
350
+ workers(): unknown[];
351
+ /** Always null over the preview. */
352
+ opener(): null;
353
+ /** Always null: no recording over the preview. */
354
+ video(): null;
355
+ /** A minimal BrowserContext: pages, timeouts and no-op tracing; the rest throws naming the alternative. */
356
+ context(): BrowserContext;
357
+ }
358
+ /**
359
+ * Build a Playwright-shaped `Page` over a transport. Bonds call this from
360
+ * `connect()`; the returned object carries the documented subset and throws an
361
+ * {@link E2EUnsupportedError} naming the alternative for the rest.
362
+ */
363
+ export declare const createEvaluatePage: (transport: E2ETransport, options?: E2EPageOptions) => Promise<Page>;
364
+ /** Whether a value is a locator built by {@link createEvaluatePage}. */
365
+ export declare const isE2ELocator: (value: unknown) => value is LocatorImpl;
366
+ /** Whether a value is a page built by {@link createEvaluatePage}. */
367
+ export declare const isE2EPage: (value: unknown) => value is PageImpl;
368
+ export type { LocatorImpl as E2ELocatorImpl, PageImpl as E2EPageImpl };
369
+ export { toMatch as textMatch, toFull as textMatchFull };
370
+ //# sourceMappingURL=page.d.ts.map