@glubean/browser 0.8.1 → 0.9.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/evidence.d.ts +470 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +721 -0
- package/dist/evidence.js.map +1 -0
- package/dist/frame.d.ts +83 -0
- package/dist/frame.d.ts.map +1 -0
- package/dist/frame.js +183 -0
- package/dist/frame.js.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/locator.d.ts +73 -2
- package/dist/locator.d.ts.map +1 -1
- package/dist/locator.js +127 -2
- package/dist/locator.js.map +1 -1
- package/dist/network.d.ts +15 -5
- package/dist/network.d.ts.map +1 -1
- package/dist/network.js +16 -12
- package/dist/network.js.map +1 -1
- package/dist/page.d.ts +213 -17
- package/dist/page.d.ts.map +1 -1
- package/dist/page.js +508 -107
- package/dist/page.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared evidence CDP session — the foundation for browser evidence capture.
|
|
3
|
+
*
|
|
4
|
+
* A single self-opened `createCDPSession` hosts **all** CDP-backed capabilities
|
|
5
|
+
* at once, instead of opening one session per capability:
|
|
6
|
+
*
|
|
7
|
+
* - **Network trace** (`Network` domain) — every in-page request as a Glubean
|
|
8
|
+
* trace event (see {@link ./network.ts}).
|
|
9
|
+
* - **Request mock** (`Fetch` domain) — fulfill matching requests with a canned
|
|
10
|
+
* response; non-matching requests are continued untouched.
|
|
11
|
+
* - **Emulation** (`Emulation` domain) — timezone / geolocation / viewport / user agent.
|
|
12
|
+
* - **Storage state** — restore cookies / localStorage before the page's
|
|
13
|
+
* first script runs, and capture them back out on demand (a thin "login
|
|
14
|
+
* once, reuse the session" primitive). Cookies go through this session's
|
|
15
|
+
* `Network.setCookies` (browser-context scoped, session-agnostic in CDP).
|
|
16
|
+
* localStorage does **not** — see guardrail ③.
|
|
17
|
+
*
|
|
18
|
+
* The keystone spike disproved the "Fetch is near-exclusive" hypothesis: a
|
|
19
|
+
* self-opened session running `Fetch.enable`/`fulfillRequest` is stable **as
|
|
20
|
+
* long as the user has not enabled Puppeteer's own request interception**.
|
|
21
|
+
* Three coexistence hazards exist, each handled below:
|
|
22
|
+
*
|
|
23
|
+
* **Guardrail ① — viewport ownership.** Our `Emulation.setDeviceMetricsOverride`
|
|
24
|
+
* and Puppeteer's `page.setViewport()` both drive device metrics and clobber
|
|
25
|
+
* each other last-wins. When `emulate.viewport` is configured, Glubean is the
|
|
26
|
+
* sole owner: it applies the viewport last and blocks `page.setViewport()` with
|
|
27
|
+
* a clear error so the two never race.
|
|
28
|
+
*
|
|
29
|
+
* **Guardrail ② — Fetch double-open.** If the user turns on Puppeteer request
|
|
30
|
+
* interception (`page.setRequestInterception(true)`) while our `Fetch` mock is
|
|
31
|
+
* active, both stacks try to handle the same paused request and fulfillment
|
|
32
|
+
* conflicts. When mocks are enabled, Glubean owns `Fetch` and blocks
|
|
33
|
+
* `page.setRequestInterception(true)` with a clear error. When no mocks are
|
|
34
|
+
* configured we never enable `Fetch`, so the user's own interception is free.
|
|
35
|
+
*
|
|
36
|
+
* **Guardrail ③ — new-document scripts need Puppeteer's OWN session.**
|
|
37
|
+
* Verified empirically: sending `Page.addScriptToEvaluateOnNewDocument` on
|
|
38
|
+
* our *auxiliary* `page.createCDPSession()` session registers without error
|
|
39
|
+
* (a real `identifier` comes back) but the script never actually fires on
|
|
40
|
+
* subsequent navigations — only the session Puppeteer itself uses for the
|
|
41
|
+
* page's frame-lifecycle bookkeeping gets its new-document scripts run.
|
|
42
|
+
* `storageState.localStorage` therefore seeds via Puppeteer's own
|
|
43
|
+
* `page.evaluateOnNewDocument()`, not a raw CDP call on this session.
|
|
44
|
+
*
|
|
45
|
+
* **Downloads** (`Browser` domain, BT1-M5) — `Browser.setDownloadBehavior`
|
|
46
|
+
* with `eventsEnabled: true`, called on this same auxiliary session, both
|
|
47
|
+
* configures the save directory AND (unlike guardrail ③'s Page-domain
|
|
48
|
+
* finding) reliably delivers `Browser.downloadWillBegin` /
|
|
49
|
+
* `Browser.downloadProgress` back on THIS session — verified empirically
|
|
50
|
+
* (spike script) against puppeteer-core ^24; `Browser.*` is genuinely
|
|
51
|
+
* session-agnostic where `Page.addScriptToEvaluateOnNewDocument` was not.
|
|
52
|
+
* The deprecated `Page.setDownloadBehavior` / `Page.downloadWillBegin` also
|
|
53
|
+
* work on the same spike but `Browser.*` is the protocol's forward path, so
|
|
54
|
+
* that's what's wired here. One caveat verified in the same spike: the file
|
|
55
|
+
* on disk is saved as `suggestedFilename`, not `guid` (despite some CDP docs
|
|
56
|
+
* implying the latter) — `DownloadEntry.path` is built from that name, which
|
|
57
|
+
* is only exact when Chrome didn't have to de-duplicate a collision.
|
|
58
|
+
* Always wired when a page is created (like dialog/popup) — a download IS
|
|
59
|
+
* evidence the moment it happens, not an opt-in capability.
|
|
60
|
+
*
|
|
61
|
+
* **Guardrail ④ — download events are browser-context-global.** Unlike the
|
|
62
|
+
* page-scoped `Network`/`Fetch` domains, `Browser.setDownloadBehavior` sets a
|
|
63
|
+
* single context-wide save path (last caller wins) and its `downloadWillBegin`/
|
|
64
|
+
* `downloadProgress` events fire on *every* session that turned events on, for
|
|
65
|
+
* *every* download in the context. So two instrumented pages in one Chrome
|
|
66
|
+
* would otherwise cross-observe and cross-repoint each other's downloads. Two
|
|
67
|
+
* mitigations: (a) the page layer uses ONE browser-wide download dir (not
|
|
68
|
+
* per-test) so the last-wins path is a no-op; (b) this session enables the
|
|
69
|
+
* `Page` domain, tracks its target's frame ids (`Page.getFrameTree` +
|
|
70
|
+
* `frameAttached`/`frameDetached`), and only records downloads whose
|
|
71
|
+
* originating `frameId` it owns — so a page never resolves another page's
|
|
72
|
+
* download. Both degrade safely: an unreadable frame tree falls back to
|
|
73
|
+
* accepting all events (single-page runs are unaffected).
|
|
74
|
+
*
|
|
75
|
+
* @module evidence
|
|
76
|
+
*/
|
|
77
|
+
import type { CDPSession, Page } from "puppeteer-core";
|
|
78
|
+
import { type NetworkTracerOptions, type TraceFn } from "./network.js";
|
|
79
|
+
/**
|
|
80
|
+
* When screenshots are automatically captured into the evidence stream.
|
|
81
|
+
*
|
|
82
|
+
* - `"off"` — no automatic screenshots
|
|
83
|
+
* - `"on-failure"` — capture when a step or test fails (default)
|
|
84
|
+
* - `"every-step"` — capture after every action AND on failure
|
|
85
|
+
*/
|
|
86
|
+
export type ScreenshotMode = "off" | "on-failure" | "every-step";
|
|
87
|
+
/**
|
|
88
|
+
* What triggered a screenshot capture.
|
|
89
|
+
*
|
|
90
|
+
* - `"step"` — post-action capture in every-step mode
|
|
91
|
+
* - `"failure"` — automatic capture on action or assertion failure
|
|
92
|
+
* - `"manual"` — explicit call to `page.captureScreenshot()`
|
|
93
|
+
*/
|
|
94
|
+
export type ScreenshotTrigger = "step" | "failure" | "manual";
|
|
95
|
+
/** A screenshot captured into the evidence stream. */
|
|
96
|
+
export interface ScreenshotEntry {
|
|
97
|
+
/** Sequential number within this evidence session (1-based). */
|
|
98
|
+
seq: number;
|
|
99
|
+
/** Wall-clock ISO timestamp at capture time. */
|
|
100
|
+
ts: string;
|
|
101
|
+
/** Human-readable label (the action or assertion that triggered the capture). */
|
|
102
|
+
label: string;
|
|
103
|
+
/** What triggered this capture. */
|
|
104
|
+
trigger: ScreenshotTrigger;
|
|
105
|
+
/** Artifact ID when `ctx.saveArtifact` is available (SDK ≥ 0.13). */
|
|
106
|
+
artifactId?: string;
|
|
107
|
+
/** File path when falling back to direct file write. */
|
|
108
|
+
path?: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Screenshot capture options for the shared evidence session.
|
|
112
|
+
*
|
|
113
|
+
* The `shoot` delegate performs the actual I/O (screenshot + artifact save +
|
|
114
|
+
* `ctx.event()` emission); {@link EvidenceSession.captureShot} handles the
|
|
115
|
+
* mode / trigger policy, sequencing, and accumulation of entries.
|
|
116
|
+
*/
|
|
117
|
+
export interface EvidenceScreenshotOptions {
|
|
118
|
+
/** Policy: which triggers result in a capture. */
|
|
119
|
+
mode: ScreenshotMode;
|
|
120
|
+
/**
|
|
121
|
+
* I/O delegate — takes the screenshot, saves the artifact, and emits
|
|
122
|
+
* the `browser:screenshot` evidence event. Returns an artifact reference
|
|
123
|
+
* for {@link ScreenshotEntry}. Called only when the mode/trigger policy allows.
|
|
124
|
+
*
|
|
125
|
+
* @param filename — suggested filename: `[FAIL-]NNN-label-ts.png`
|
|
126
|
+
* @param label — human label for the action/assertion
|
|
127
|
+
* @param trigger — what triggered this capture
|
|
128
|
+
*/
|
|
129
|
+
shoot: (filename: string, label: string, trigger: ScreenshotTrigger) => Promise<{
|
|
130
|
+
artifactId?: string;
|
|
131
|
+
path?: string;
|
|
132
|
+
}>;
|
|
133
|
+
}
|
|
134
|
+
/** A single header as CDP's `Fetch.fulfillRequest` expects it. */
|
|
135
|
+
interface HeaderEntry {
|
|
136
|
+
name: string;
|
|
137
|
+
value: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* A request-mock rule. Matching requests are fulfilled with a canned response;
|
|
141
|
+
* everything else is continued untouched.
|
|
142
|
+
*/
|
|
143
|
+
export interface MockRule {
|
|
144
|
+
/**
|
|
145
|
+
* Match the request URL. A string matches by substring (`url.includes(...)`);
|
|
146
|
+
* a `RegExp` matches by `test(url)`.
|
|
147
|
+
*/
|
|
148
|
+
url: string | RegExp;
|
|
149
|
+
/** Restrict to a single HTTP method (case-insensitive). Omit to match any. */
|
|
150
|
+
method?: string;
|
|
151
|
+
/** Response status code. @default 200 */
|
|
152
|
+
status?: number;
|
|
153
|
+
/** Extra response headers. */
|
|
154
|
+
headers?: Record<string, string>;
|
|
155
|
+
/**
|
|
156
|
+
* Response body. A string is sent verbatim; any other value is
|
|
157
|
+
* `JSON.stringify`-ed. The `content-type` is inferred (JSON vs plain text)
|
|
158
|
+
* unless `contentType` is set.
|
|
159
|
+
*/
|
|
160
|
+
body?: unknown;
|
|
161
|
+
/** Explicit `content-type` header. Overrides the inferred value. */
|
|
162
|
+
contentType?: string;
|
|
163
|
+
}
|
|
164
|
+
/** Geolocation override. */
|
|
165
|
+
export interface GeolocationOverride {
|
|
166
|
+
latitude: number;
|
|
167
|
+
longitude: number;
|
|
168
|
+
/** Accuracy in meters. @default 0 (mirrors Puppeteer's `setGeolocation`). */
|
|
169
|
+
accuracy?: number;
|
|
170
|
+
}
|
|
171
|
+
/** Viewport / device-metrics override (owned solely by Glubean — see guardrail ①). */
|
|
172
|
+
export interface ViewportOverride {
|
|
173
|
+
width: number;
|
|
174
|
+
height: number;
|
|
175
|
+
/** @default 1 */
|
|
176
|
+
deviceScaleFactor?: number;
|
|
177
|
+
/** @default false */
|
|
178
|
+
mobile?: boolean;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Environment emulation applied on the shared evidence session.
|
|
182
|
+
*
|
|
183
|
+
* Timezone, geolocation, and user agent are pure overrides with no Puppeteer
|
|
184
|
+
* conflict. Viewport is special: see guardrail ① — do **not** also call
|
|
185
|
+
* `page.setViewport()`, it will race with this override.
|
|
186
|
+
*/
|
|
187
|
+
export interface EmulationOptions {
|
|
188
|
+
/** IANA timezone id, e.g. `"America/New_York"`. */
|
|
189
|
+
timezone?: string;
|
|
190
|
+
/** Geolocation override. */
|
|
191
|
+
geolocation?: GeolocationOverride;
|
|
192
|
+
/** Viewport / device metrics. Glubean becomes the sole viewport owner. */
|
|
193
|
+
viewport?: ViewportOverride;
|
|
194
|
+
/** User-agent string override (`Emulation.setUserAgentOverride`). */
|
|
195
|
+
userAgent?: string;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* A cookie as accepted by {@link EvidenceSession.attach}'s `storageState.cookies`
|
|
199
|
+
* and returned by {@link EvidenceSession.captureStorageState}. Mirrors the CDP
|
|
200
|
+
* `Network.CookieParam` / `Network.Cookie` shapes closely enough to round-trip:
|
|
201
|
+
* a captured cookie can be fed straight back in as an applied one.
|
|
202
|
+
*/
|
|
203
|
+
export interface StorageCookie {
|
|
204
|
+
name: string;
|
|
205
|
+
value: string;
|
|
206
|
+
/** Either `domain` or `url` must be resolvable for CDP to place the cookie. */
|
|
207
|
+
domain?: string;
|
|
208
|
+
path?: string;
|
|
209
|
+
url?: string;
|
|
210
|
+
/** Unix time in seconds, or `-1` for a session cookie. */
|
|
211
|
+
expires?: number;
|
|
212
|
+
httpOnly?: boolean;
|
|
213
|
+
secure?: boolean;
|
|
214
|
+
sameSite?: "Strict" | "Lax" | "None";
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Cookies + localStorage for one page — a thin "login once, reuse the
|
|
218
|
+
* session" primitive (à la Playwright's `storageState`). Cookies apply via
|
|
219
|
+
* CDP `Network.setCookies`; localStorage applies via Puppeteer's own
|
|
220
|
+
* `page.evaluateOnNewDocument()` (see guardrail ③) so it is present before
|
|
221
|
+
* the page's own scripts run on every navigation of this page.
|
|
222
|
+
*/
|
|
223
|
+
export interface StorageState {
|
|
224
|
+
cookies?: StorageCookie[];
|
|
225
|
+
/** Key/value pairs seeded into `localStorage` on every new document. */
|
|
226
|
+
localStorage?: Record<string, string>;
|
|
227
|
+
}
|
|
228
|
+
/** Lifecycle state of a browser download (mirrors CDP `Browser.downloadProgress.state`). */
|
|
229
|
+
export type DownloadState = "inProgress" | "completed" | "canceled";
|
|
230
|
+
/**
|
|
231
|
+
* A browser download captured via CDP `Browser.downloadWillBegin` /
|
|
232
|
+
* `Browser.downloadProgress`.
|
|
233
|
+
*/
|
|
234
|
+
export interface DownloadEntry {
|
|
235
|
+
/** CDP-assigned globally-unique download id. */
|
|
236
|
+
guid: string;
|
|
237
|
+
/** URL the download was initiated from (may be `data:`/`blob:`). */
|
|
238
|
+
url: string;
|
|
239
|
+
/** Filename suggested by the server/anchor at download start. */
|
|
240
|
+
suggestedFilename: string;
|
|
241
|
+
/**
|
|
242
|
+
* Best-effort on-disk path: `${dir}/${suggestedFilename}`. Exact only when
|
|
243
|
+
* Chrome didn't have to de-duplicate a filename collision in `dir` — see
|
|
244
|
+
* the module doc's Downloads note.
|
|
245
|
+
*/
|
|
246
|
+
path: string;
|
|
247
|
+
}
|
|
248
|
+
/** Options wiring the shared session's download capture. */
|
|
249
|
+
export interface DownloadOptions {
|
|
250
|
+
/** Directory downloads are saved to. Must already exist — the caller creates it. */
|
|
251
|
+
dir: string;
|
|
252
|
+
/**
|
|
253
|
+
* Called on every state transition (`inProgress` fires once per progress
|
|
254
|
+
* tick — usually more than once per download; `completed`/`canceled` fire
|
|
255
|
+
* exactly once). Mainly for evidence emission; {@link EvidenceSession.waitForDownload}
|
|
256
|
+
* is the ergonomic way to correlate a triggering action with its result.
|
|
257
|
+
*/
|
|
258
|
+
onDownload?: (entry: DownloadEntry, state: DownloadState) => void;
|
|
259
|
+
}
|
|
260
|
+
/** Options for {@link EvidenceSession.attach}. */
|
|
261
|
+
export interface EvidenceSessionOptions {
|
|
262
|
+
/**
|
|
263
|
+
* Network-trace callback (`ctx.trace`). When omitted, the `Network` domain
|
|
264
|
+
* tracer is not attached.
|
|
265
|
+
*/
|
|
266
|
+
trace?: TraceFn;
|
|
267
|
+
/** Network-trace filter configuration. Ignored when `trace` is omitted. */
|
|
268
|
+
network?: Pick<NetworkTracerOptions, "include" | "excludePaths" | "filter">;
|
|
269
|
+
/** Request-mock rules. When non-empty, the `Fetch` domain is enabled (guardrail ②). */
|
|
270
|
+
mocks?: MockRule[];
|
|
271
|
+
/** Environment emulation (timezone / geolocation / viewport / user agent). */
|
|
272
|
+
emulate?: EmulationOptions;
|
|
273
|
+
/**
|
|
274
|
+
* Cookies / localStorage to restore before the page's first script runs
|
|
275
|
+
* (`storageState.cookies` via `Network.setCookies`, `storageState.localStorage`
|
|
276
|
+
* via Puppeteer's `page.evaluateOnNewDocument()` — see guardrail ③).
|
|
277
|
+
* Capture the current state with {@link EvidenceSession.captureStorageState}.
|
|
278
|
+
*/
|
|
279
|
+
storageState?: StorageState;
|
|
280
|
+
/**
|
|
281
|
+
* Screenshot capture policy and I/O delegate.
|
|
282
|
+
*
|
|
283
|
+
* When provided, {@link EvidenceSession.captureShot} becomes active and will
|
|
284
|
+
* call `screenshots.shoot` based on the configured mode and trigger.
|
|
285
|
+
* Omit (or set `mode: "off"`) to disable all automatic screenshot capture.
|
|
286
|
+
*/
|
|
287
|
+
screenshots?: EvidenceScreenshotOptions;
|
|
288
|
+
/**
|
|
289
|
+
* Download capture (`Browser.setDownloadBehavior` + `downloadWillBegin`/
|
|
290
|
+
* `downloadProgress`). When provided, every download on this page is
|
|
291
|
+
* allowed (not blocked) and reported via `onDownload` / {@link EvidenceSession.waitForDownload}.
|
|
292
|
+
*/
|
|
293
|
+
downloads?: DownloadOptions;
|
|
294
|
+
}
|
|
295
|
+
/** A single CDP call: `{ method, params }`. Kept pure for testing. */
|
|
296
|
+
export interface CdpCall {
|
|
297
|
+
method: string;
|
|
298
|
+
params?: Record<string, unknown>;
|
|
299
|
+
}
|
|
300
|
+
/** @internal Does `rule` match the given request? */
|
|
301
|
+
export declare function matchMock(rule: MockRule, req: {
|
|
302
|
+
url: string;
|
|
303
|
+
method: string;
|
|
304
|
+
}): boolean;
|
|
305
|
+
/** @internal Find the first matching mock rule, or `undefined`. */
|
|
306
|
+
export declare function findMock(mocks: readonly MockRule[], req: {
|
|
307
|
+
url: string;
|
|
308
|
+
method: string;
|
|
309
|
+
}): MockRule | undefined;
|
|
310
|
+
/**
|
|
311
|
+
* @internal Build `Fetch.fulfillRequest` params from a rule.
|
|
312
|
+
*
|
|
313
|
+
* The body is always base64-encoded (as CDP requires). Content-type is inferred
|
|
314
|
+
* from the body kind unless `rule.contentType` is set. User headers win over the
|
|
315
|
+
* inferred content-type.
|
|
316
|
+
*/
|
|
317
|
+
export declare function buildFulfillParams(rule: MockRule, requestId: string): {
|
|
318
|
+
requestId: string;
|
|
319
|
+
responseCode: number;
|
|
320
|
+
responseHeaders: HeaderEntry[];
|
|
321
|
+
body: string;
|
|
322
|
+
};
|
|
323
|
+
/**
|
|
324
|
+
* @internal Build the ordered list of `Emulation.*` CDP calls.
|
|
325
|
+
*
|
|
326
|
+
* Timezone, geolocation, and user agent come first (order-independent among
|
|
327
|
+
* themselves); the viewport override is applied **last** (guardrail ①) so it
|
|
328
|
+
* is the final word on device metrics at setup time.
|
|
329
|
+
*/
|
|
330
|
+
export declare function buildEmulationCalls(emulate: EmulationOptions): CdpCall[];
|
|
331
|
+
/**
|
|
332
|
+
* @internal Build `Network.setCookies` params from `storageState.cookies`.
|
|
333
|
+
* Returns `undefined` when there is nothing to set (caller skips the call).
|
|
334
|
+
*/
|
|
335
|
+
export declare function buildSetCookiesParams(cookies: StorageCookie[] | undefined): {
|
|
336
|
+
cookies: StorageCookie[];
|
|
337
|
+
} | undefined;
|
|
338
|
+
/**
|
|
339
|
+
* @internal Replace `page[method]` with a guard, returning a restore function.
|
|
340
|
+
*
|
|
341
|
+
* `shouldBlock` decides, per call arguments, whether to throw the guard error.
|
|
342
|
+
* Blocked calls throw synchronously; allowed calls fall through to the original
|
|
343
|
+
* method (or resolve to `undefined` if there was none). Used to enforce
|
|
344
|
+
* guardrails ① (viewport) and ② (Fetch interception).
|
|
345
|
+
*/
|
|
346
|
+
export declare function guardPageMethod(page: any, method: string, message: string, shouldBlock: (args: unknown[]) => boolean): () => void;
|
|
347
|
+
/**
|
|
348
|
+
* A single self-opened CDP session that hosts every CDP-backed evidence
|
|
349
|
+
* capability for one page. Create with {@link EvidenceSession.attach}; release
|
|
350
|
+
* with {@link EvidenceSession.detach}.
|
|
351
|
+
*/
|
|
352
|
+
export declare class EvidenceSession {
|
|
353
|
+
private readonly _cdp;
|
|
354
|
+
private readonly _cleanups;
|
|
355
|
+
private _detached;
|
|
356
|
+
private _screenshotOpts;
|
|
357
|
+
private _screenshotSeq;
|
|
358
|
+
private _screenshotLog;
|
|
359
|
+
private _downloadsEnabled;
|
|
360
|
+
private _downloadDir;
|
|
361
|
+
private _onDownload;
|
|
362
|
+
/**
|
|
363
|
+
* Frame ids owned by THIS page's target. `Browser.setDownloadBehavior`'s
|
|
364
|
+
* events are browser-context-global — every session that turned events on
|
|
365
|
+
* receives every download in the context. We only record downloads whose
|
|
366
|
+
* originating `frameId` belongs to this page, so two instrumented pages
|
|
367
|
+
* sharing one Chrome never cross-observe each other's downloads.
|
|
368
|
+
*/
|
|
369
|
+
private _ownedFrames;
|
|
370
|
+
/**
|
|
371
|
+
* True only once the initial `Page.getFrameTree` seeded {@link _ownedFrames}.
|
|
372
|
+
* The frame filter engages ONLY when this is set — otherwise we accept all
|
|
373
|
+
* download events (fallback mode). Without this flag, a later
|
|
374
|
+
* `Page.frameAttached` would grow `_ownedFrames` from empty to non-empty and
|
|
375
|
+
* silently flip fallback mode into a PARTIAL filter that drops the page's own
|
|
376
|
+
* top-frame downloads (codex R2 P2).
|
|
377
|
+
*/
|
|
378
|
+
private _frameTreeSeeded;
|
|
379
|
+
private _pendingDownloads;
|
|
380
|
+
private _downloadWaiters;
|
|
381
|
+
private constructor();
|
|
382
|
+
/** The underlying CDP session, for advanced/raw use. */
|
|
383
|
+
get cdp(): CDPSession;
|
|
384
|
+
/**
|
|
385
|
+
* All screenshots captured into this evidence session, in order.
|
|
386
|
+
*
|
|
387
|
+
* Each entry carries `seq`, `ts`, `label`, `trigger`, and an artifact
|
|
388
|
+
* reference (`artifactId` or `path`). The list is empty when no screenshot
|
|
389
|
+
* has been captured yet or when `screenshots.mode` is `"off"`.
|
|
390
|
+
*/
|
|
391
|
+
get screenshots(): readonly ScreenshotEntry[];
|
|
392
|
+
/**
|
|
393
|
+
* Capture a screenshot into the evidence stream, subject to the configured
|
|
394
|
+
* {@link ScreenshotMode} and the `trigger` argument.
|
|
395
|
+
*
|
|
396
|
+
* | mode | "step" trigger | "failure" trigger | "manual" trigger |
|
|
397
|
+
* |---------------|----------------|-------------------|------------------|
|
|
398
|
+
* | "off" | skip | skip | skip |
|
|
399
|
+
* | "on-failure" | skip | capture | capture |
|
|
400
|
+
* | "every-step" | capture | capture | capture |
|
|
401
|
+
*
|
|
402
|
+
* Always best-effort: errors from the I/O delegate are silently swallowed
|
|
403
|
+
* so a broken page state never masks the real test error.
|
|
404
|
+
*
|
|
405
|
+
* Does nothing when no `screenshots` option was passed to {@link attach}.
|
|
406
|
+
*/
|
|
407
|
+
captureShot(label: string, trigger: ScreenshotTrigger): Promise<void>;
|
|
408
|
+
/**
|
|
409
|
+
* Open one CDP session on `page` and wire up the requested capabilities:
|
|
410
|
+
* Network trace, Fetch mock (guardrail ②), Emulation (guardrail ① for
|
|
411
|
+
* viewport), and storage state (cookies + localStorage). Capabilities are
|
|
412
|
+
* only enabled when their config is present, so a page with no mocks never
|
|
413
|
+
* enables `Fetch` and leaves the user's own request interception untouched.
|
|
414
|
+
*/
|
|
415
|
+
static attach(page: Page, options: EvidenceSessionOptions): Promise<EvidenceSession>;
|
|
416
|
+
private _installMocks;
|
|
417
|
+
private _applyStorageState;
|
|
418
|
+
/**
|
|
419
|
+
* @internal Wire `Browser.setDownloadBehavior` (`eventsEnabled: true`) plus
|
|
420
|
+
* the `downloadWillBegin` / `downloadProgress` listeners on this session.
|
|
421
|
+
* See the module doc's Downloads note for why `Browser.*` (not the
|
|
422
|
+
* deprecated `Page.*` pair) and why it works on an auxiliary session.
|
|
423
|
+
*
|
|
424
|
+
* `Browser.*` download events are browser-context-global, so we also enable
|
|
425
|
+
* the `Page` domain and track this target's frame ids, then only record
|
|
426
|
+
* downloads originating from a frame we own — two instrumented pages in one
|
|
427
|
+
* Chrome must not cross-observe each other's downloads.
|
|
428
|
+
*/
|
|
429
|
+
private _enableDownloads;
|
|
430
|
+
/** @internal Best-effort onDownload callback — never let it wedge the waiter machine. */
|
|
431
|
+
private _notifyDownload;
|
|
432
|
+
/**
|
|
433
|
+
* Wait for the NEXT download (one that completes after this call) to finish,
|
|
434
|
+
* and resolve with its metadata. Register the wait *before* triggering the
|
|
435
|
+
* action that starts the download — `GlubeanPage.waitForDownload(action)` in
|
|
436
|
+
* `page.ts` does exactly this and is the ergonomic wrapper most callers
|
|
437
|
+
* should use instead of this lower-level method.
|
|
438
|
+
*
|
|
439
|
+
* Rejects if the next download is canceled, after `timeoutMs`, if `signal`
|
|
440
|
+
* aborts (e.g. the triggering action threw), or if the session has detached.
|
|
441
|
+
* Does **not** resolve from downloads that already completed before the call —
|
|
442
|
+
* each wait is scoped to a fresh, future download.
|
|
443
|
+
*/
|
|
444
|
+
waitForDownload(timeoutMs: number, signal?: AbortSignal): Promise<DownloadEntry>;
|
|
445
|
+
/**
|
|
446
|
+
* Capture the current page's cookies + localStorage as a {@link StorageState}
|
|
447
|
+
* snapshot — the counterpart to {@link EvidenceSessionOptions.storageState}.
|
|
448
|
+
* Cookies are scoped to the page's current URL (`Network.getCookies`), not
|
|
449
|
+
* every cookie the browser holds, so unrelated tabs/origins never leak in.
|
|
450
|
+
*
|
|
451
|
+
* @example
|
|
452
|
+
* ```ts
|
|
453
|
+
* await page.goto("/login");
|
|
454
|
+
* // ... perform login ...
|
|
455
|
+
* const state = await page.getStorageState();
|
|
456
|
+
* // Reuse on a fresh page to skip the login flow:
|
|
457
|
+
* const chrome2 = browser({ launch: true, storageState: state });
|
|
458
|
+
* ```
|
|
459
|
+
*/
|
|
460
|
+
captureStorageState(page: Page): Promise<StorageState>;
|
|
461
|
+
private _guardViewport;
|
|
462
|
+
/**
|
|
463
|
+
* Remove all listeners/overrides, restore guarded page methods, and detach
|
|
464
|
+
* the CDP session. Idempotent and best-effort — safe to call after the page
|
|
465
|
+
* has closed.
|
|
466
|
+
*/
|
|
467
|
+
detach(): Promise<void>;
|
|
468
|
+
}
|
|
469
|
+
export {};
|
|
470
|
+
//# sourceMappingURL=evidence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../src/evidence.ts"],"names":[],"mappings":"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"}
|