@glubean/browser 0.1.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/chrome.d.ts +44 -0
- package/dist/chrome.d.ts.map +1 -0
- package/dist/chrome.js +134 -0
- package/dist/chrome.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/locator.d.ts +39 -0
- package/dist/locator.d.ts.map +1 -0
- package/dist/locator.js +116 -0
- package/dist/locator.js.map +1 -0
- package/dist/metrics.d.ts +23 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +54 -0
- package/dist/metrics.js.map +1 -0
- package/dist/network.d.ts +55 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/network.js +176 -0
- package/dist/network.js.map +1 -0
- package/dist/page.d.ts +543 -0
- package/dist/page.d.ts.map +1 -0
- package/dist/page.js +1259 -0
- package/dist/page.js.map +1 -0
- package/dist/plugin.d.ts +21 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +120 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +33 -0
package/dist/chrome.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome browser resolution: launch, connect, and auto-discover.
|
|
3
|
+
*
|
|
4
|
+
* Supports three modes:
|
|
5
|
+
* 1. `launch: true` — find and launch a local Chrome/Chromium in headless mode
|
|
6
|
+
* 2. `endpoint: "ws://..."` — connect directly to a WebSocket debugger URL
|
|
7
|
+
* 3. `endpoint: "http://..."` — auto-discover WS URL via /json/version
|
|
8
|
+
*
|
|
9
|
+
* @module chrome
|
|
10
|
+
*/
|
|
11
|
+
import { type Browser } from "puppeteer-core";
|
|
12
|
+
import type { PuppeteerLike } from "./page.js";
|
|
13
|
+
/**
|
|
14
|
+
* Detect the path of a locally installed Chrome or Chromium.
|
|
15
|
+
* Checks well-known paths for the current OS, plus the CHROME_PATH env var.
|
|
16
|
+
*
|
|
17
|
+
* @internal Exported for testing.
|
|
18
|
+
* @returns The path to the Chrome executable, or null if not found.
|
|
19
|
+
*/
|
|
20
|
+
export declare function detectChromePath(): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Launch a local Chrome instance.
|
|
23
|
+
*
|
|
24
|
+
* @param executablePath Explicit path to Chrome. If omitted, auto-detects.
|
|
25
|
+
* @param puppeteerInstance Custom puppeteer-compatible instance (e.g. puppeteer-extra).
|
|
26
|
+
* @param launchOptions Extra options forwarded to `puppeteer.launch()`. Merged with defaults; user values win.
|
|
27
|
+
* @returns A connected Browser instance. The caller is responsible for closing it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function launchChrome(executablePath?: string, puppeteerInstance?: PuppeteerLike, launchOptions?: Record<string, unknown>): Promise<Browser>;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve an endpoint string to a WebSocket debugger URL.
|
|
32
|
+
*
|
|
33
|
+
* - `ws://` or `wss://` → returned as-is
|
|
34
|
+
* - `http://` or `https://` → fetches /json/version to discover the WS URL
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveEndpoint(endpoint: string): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Connect to a Chrome instance via WebSocket endpoint (with auto-discovery).
|
|
39
|
+
*
|
|
40
|
+
* @param endpoint WebSocket or HTTP endpoint URL.
|
|
41
|
+
* @param puppeteerInstance Custom puppeteer-compatible instance (e.g. puppeteer-extra).
|
|
42
|
+
*/
|
|
43
|
+
export declare function connectChrome(endpoint: string, puppeteerInstance?: PuppeteerLike): Promise<Browser>;
|
|
44
|
+
//# sourceMappingURL=chrome.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../src/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAyB,EAAE,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAqB/C;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAiBhD;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,cAAc,CAAC,EAAE,MAAM,EACvB,iBAAiB,CAAC,EAAE,aAAa,EACjC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACtC,OAAO,CAAC,OAAO,CAAC,CA0BlB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyCvE;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,CAAC,EAAE,aAAa,GAChC,OAAO,CAAC,OAAO,CAAC,CAIlB"}
|
package/dist/chrome.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome browser resolution: launch, connect, and auto-discover.
|
|
3
|
+
*
|
|
4
|
+
* Supports three modes:
|
|
5
|
+
* 1. `launch: true` — find and launch a local Chrome/Chromium in headless mode
|
|
6
|
+
* 2. `endpoint: "ws://..."` — connect directly to a WebSocket debugger URL
|
|
7
|
+
* 3. `endpoint: "http://..."` — auto-discover WS URL via /json/version
|
|
8
|
+
*
|
|
9
|
+
* @module chrome
|
|
10
|
+
*/
|
|
11
|
+
import { statSync } from "node:fs";
|
|
12
|
+
import puppeteerDefault from "puppeteer-core";
|
|
13
|
+
const WELL_KNOWN_PATHS = {
|
|
14
|
+
darwin: [
|
|
15
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
16
|
+
"/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
|
|
17
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
18
|
+
],
|
|
19
|
+
linux: [
|
|
20
|
+
"/usr/bin/google-chrome",
|
|
21
|
+
"/usr/bin/google-chrome-stable",
|
|
22
|
+
"/usr/bin/chromium",
|
|
23
|
+
"/usr/bin/chromium-browser",
|
|
24
|
+
"/snap/bin/chromium",
|
|
25
|
+
],
|
|
26
|
+
win32: [
|
|
27
|
+
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
28
|
+
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Detect the path of a locally installed Chrome or Chromium.
|
|
33
|
+
* Checks well-known paths for the current OS, plus the CHROME_PATH env var.
|
|
34
|
+
*
|
|
35
|
+
* @internal Exported for testing.
|
|
36
|
+
* @returns The path to the Chrome executable, or null if not found.
|
|
37
|
+
*/
|
|
38
|
+
export function detectChromePath() {
|
|
39
|
+
// Explicit env override takes priority
|
|
40
|
+
const envPath = process.env.CHROME_PATH;
|
|
41
|
+
if (envPath)
|
|
42
|
+
return envPath;
|
|
43
|
+
const os = process.platform;
|
|
44
|
+
const candidates = WELL_KNOWN_PATHS[os] ?? [];
|
|
45
|
+
for (const candidate of candidates) {
|
|
46
|
+
try {
|
|
47
|
+
statSync(candidate);
|
|
48
|
+
return candidate;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// not found, try next
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Launch a local Chrome instance.
|
|
58
|
+
*
|
|
59
|
+
* @param executablePath Explicit path to Chrome. If omitted, auto-detects.
|
|
60
|
+
* @param puppeteerInstance Custom puppeteer-compatible instance (e.g. puppeteer-extra).
|
|
61
|
+
* @param launchOptions Extra options forwarded to `puppeteer.launch()`. Merged with defaults; user values win.
|
|
62
|
+
* @returns A connected Browser instance. The caller is responsible for closing it.
|
|
63
|
+
*/
|
|
64
|
+
export async function launchChrome(executablePath, puppeteerInstance, launchOptions) {
|
|
65
|
+
const chromePath = executablePath ?? detectChromePath();
|
|
66
|
+
if (!chromePath) {
|
|
67
|
+
throw new Error("Could not find Chrome or Chromium on this machine.\n" +
|
|
68
|
+
"Install Chrome, or set the CHROME_PATH environment variable, " +
|
|
69
|
+
"or pass executablePath in browser options.\n\n" +
|
|
70
|
+
"Checked paths:\n" +
|
|
71
|
+
(WELL_KNOWN_PATHS[process.platform] ?? [])
|
|
72
|
+
.map((p) => ` - ${p}`)
|
|
73
|
+
.join("\n"));
|
|
74
|
+
}
|
|
75
|
+
const pptr = puppeteerInstance ?? puppeteerDefault;
|
|
76
|
+
return await pptr.launch({
|
|
77
|
+
headless: true,
|
|
78
|
+
args: [
|
|
79
|
+
"--no-sandbox",
|
|
80
|
+
"--disable-setuid-sandbox",
|
|
81
|
+
"--disable-dev-shm-usage",
|
|
82
|
+
"--disable-gpu",
|
|
83
|
+
],
|
|
84
|
+
...launchOptions,
|
|
85
|
+
executablePath: chromePath,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Resolve an endpoint string to a WebSocket debugger URL.
|
|
90
|
+
*
|
|
91
|
+
* - `ws://` or `wss://` → returned as-is
|
|
92
|
+
* - `http://` or `https://` → fetches /json/version to discover the WS URL
|
|
93
|
+
*/
|
|
94
|
+
export async function resolveEndpoint(endpoint) {
|
|
95
|
+
if (endpoint.startsWith("ws://") || endpoint.startsWith("wss://")) {
|
|
96
|
+
return endpoint;
|
|
97
|
+
}
|
|
98
|
+
if (endpoint.startsWith("http://") || endpoint.startsWith("https://")) {
|
|
99
|
+
const base = endpoint.endsWith("/") ? endpoint.slice(0, -1) : endpoint;
|
|
100
|
+
const url = `${base}/json/version`;
|
|
101
|
+
let response;
|
|
102
|
+
try {
|
|
103
|
+
response = await fetch(url);
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
throw new Error(`Failed to connect to Chrome at ${url}.\n` +
|
|
107
|
+
`Is Chrome running with --remote-debugging-port?\n` +
|
|
108
|
+
`Original error: ${err instanceof Error ? err.message : err}`);
|
|
109
|
+
}
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
throw new Error(`Chrome endpoint returned HTTP ${response.status} for ${url}.`);
|
|
112
|
+
}
|
|
113
|
+
const data = await response.json();
|
|
114
|
+
if (!data.webSocketDebuggerUrl) {
|
|
115
|
+
throw new Error(`Chrome endpoint at ${url} did not return a webSocketDebuggerUrl.\n` +
|
|
116
|
+
`Response: ${JSON.stringify(data)}`);
|
|
117
|
+
}
|
|
118
|
+
return data.webSocketDebuggerUrl;
|
|
119
|
+
}
|
|
120
|
+
throw new Error(`Invalid Chrome endpoint: "${endpoint}".\n` +
|
|
121
|
+
`Expected ws://, wss://, http://, or https:// URL.`);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Connect to a Chrome instance via WebSocket endpoint (with auto-discovery).
|
|
125
|
+
*
|
|
126
|
+
* @param endpoint WebSocket or HTTP endpoint URL.
|
|
127
|
+
* @param puppeteerInstance Custom puppeteer-compatible instance (e.g. puppeteer-extra).
|
|
128
|
+
*/
|
|
129
|
+
export async function connectChrome(endpoint, puppeteerInstance) {
|
|
130
|
+
const wsEndpoint = await resolveEndpoint(endpoint);
|
|
131
|
+
const pptr = puppeteerInstance ?? puppeteerDefault;
|
|
132
|
+
return await pptr.connect({ browserWSEndpoint: wsEndpoint });
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=chrome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chrome.js","sourceRoot":"","sources":["../src/chrome.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @glubean/browser — Browser automation plugin for Glubean.
|
|
3
|
+
*
|
|
4
|
+
* Connects to or launches a Chrome instance via puppeteer-core and provides
|
|
5
|
+
* auto-instrumentation: navigation tracing, network request tracing,
|
|
6
|
+
* performance metrics, and console log forwarding — all wired into
|
|
7
|
+
* the Glubean test context.
|
|
8
|
+
*
|
|
9
|
+
* @example Launch mode (zero config)
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { configure, test } from "@glubean/sdk";
|
|
12
|
+
* import { browser } from "@glubean/browser";
|
|
13
|
+
*
|
|
14
|
+
* const { chrome } = configure({
|
|
15
|
+
* plugins: {
|
|
16
|
+
* chrome: browser({ launch: true }),
|
|
17
|
+
* },
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* const myTest = test.extend({
|
|
21
|
+
* page: async (ctx, use) => {
|
|
22
|
+
* const pg = await chrome.newPage(ctx);
|
|
23
|
+
* try {
|
|
24
|
+
* await use(pg);
|
|
25
|
+
* } finally {
|
|
26
|
+
* await pg.close();
|
|
27
|
+
* }
|
|
28
|
+
* },
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* export const homepage = myTest("homepage-loads", async (ctx) => {
|
|
32
|
+
* await ctx.page.goto("/");
|
|
33
|
+
* ctx.expect(await ctx.page.title()).toBe("My App");
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @module
|
|
38
|
+
*/
|
|
39
|
+
export { browser } from "./plugin.js";
|
|
40
|
+
export { GlubeanBrowser, GlubeanPage } from "./page.js";
|
|
41
|
+
export type { ActionOptions, BrowserAction, BrowserEvent, BrowserOptions, BrowserTestContext, InstrumentedPage, PuppeteerLike, NetworkTraceOptions, ResponseChecks, ScreenshotMode, } from "./page.js";
|
|
42
|
+
export type { WrappedLocator } from "./locator.js";
|
|
43
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxD,YAAY,EACV,aAAa,EACb,aAAa,EACb,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @glubean/browser — Browser automation plugin for Glubean.
|
|
3
|
+
*
|
|
4
|
+
* Connects to or launches a Chrome instance via puppeteer-core and provides
|
|
5
|
+
* auto-instrumentation: navigation tracing, network request tracing,
|
|
6
|
+
* performance metrics, and console log forwarding — all wired into
|
|
7
|
+
* the Glubean test context.
|
|
8
|
+
*
|
|
9
|
+
* @example Launch mode (zero config)
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { configure, test } from "@glubean/sdk";
|
|
12
|
+
* import { browser } from "@glubean/browser";
|
|
13
|
+
*
|
|
14
|
+
* const { chrome } = configure({
|
|
15
|
+
* plugins: {
|
|
16
|
+
* chrome: browser({ launch: true }),
|
|
17
|
+
* },
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* const myTest = test.extend({
|
|
21
|
+
* page: async (ctx, use) => {
|
|
22
|
+
* const pg = await chrome.newPage(ctx);
|
|
23
|
+
* try {
|
|
24
|
+
* await use(pg);
|
|
25
|
+
* } finally {
|
|
26
|
+
* await pg.close();
|
|
27
|
+
* }
|
|
28
|
+
* },
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* export const homepage = myTest("homepage-loads", async (ctx) => {
|
|
32
|
+
* await ctx.page.goto("/");
|
|
33
|
+
* ctx.expect(await ctx.page.title()).toBe("My App");
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @module
|
|
38
|
+
*/
|
|
39
|
+
export { browser } from "./plugin.js";
|
|
40
|
+
export { GlubeanBrowser, GlubeanPage } from "./page.js";
|
|
41
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WrappedLocator — Proxy-based wrapper around Puppeteer's Locator that
|
|
3
|
+
* auto-injects trace events and screenshot capture for action methods.
|
|
4
|
+
*
|
|
5
|
+
* @module locator
|
|
6
|
+
*/
|
|
7
|
+
import type { Locator } from "puppeteer-core";
|
|
8
|
+
/** Context required by the WrappedLocator for trace/screenshot injection. */
|
|
9
|
+
export interface LocatorContext {
|
|
10
|
+
action(event: {
|
|
11
|
+
category: string;
|
|
12
|
+
target: string;
|
|
13
|
+
duration: number;
|
|
14
|
+
status: "ok" | "error" | "timeout";
|
|
15
|
+
detail?: Record<string, unknown>;
|
|
16
|
+
}): void;
|
|
17
|
+
captureStep(label: string): Promise<void>;
|
|
18
|
+
captureFailure(label: string): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/** A Puppeteer Locator enhanced with auto-tracing and screenshot capture. */
|
|
21
|
+
export type WrappedLocator = Locator<any> & {
|
|
22
|
+
/**
|
|
23
|
+
* Type text into the located element (appends — does not clear).
|
|
24
|
+
*
|
|
25
|
+
* Puppeteer's Locator has no `type()` method, so this is an extension
|
|
26
|
+
* that calls `waitHandle()` + `handle.type()` under the hood.
|
|
27
|
+
*/
|
|
28
|
+
type(text: string): Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Create a WrappedLocator that proxies a Puppeteer Locator with auto-tracing.
|
|
32
|
+
*
|
|
33
|
+
* - **Chain methods** (setTimeout, setVisibility, etc.) return a new WrappedLocator.
|
|
34
|
+
* - **Action methods** (click, fill, hover, scroll) inject trace + screenshot.
|
|
35
|
+
* - **type()** is a custom extension (Locator has no type method).
|
|
36
|
+
* - Everything else is transparently forwarded.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createWrappedLocator(inner: Locator<unknown>, ctx: LocatorContext, selector: string): WrappedLocator;
|
|
39
|
+
//# sourceMappingURL=locator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locator.d.ts","sourceRoot":"","sources":["../src/locator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAiB,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE7D,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,KAAK,EAAE;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC;QACnC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAClC,GAAG,IAAI,CAAC;IACT,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;AAED,6EAA6E;AAE7E,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG;IAC1C;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC,CAAC;AAsBF;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,EACvB,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,MAAM,GACf,cAAc,CAoFhB"}
|
package/dist/locator.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WrappedLocator — Proxy-based wrapper around Puppeteer's Locator that
|
|
3
|
+
* auto-injects trace events and screenshot capture for action methods.
|
|
4
|
+
*
|
|
5
|
+
* @module locator
|
|
6
|
+
*/
|
|
7
|
+
/** Methods that return a new Locator — we re-wrap the result. */
|
|
8
|
+
const CHAIN_METHODS = new Set([
|
|
9
|
+
"setTimeout",
|
|
10
|
+
"setVisibility",
|
|
11
|
+
"setEnsureElementIsInTheViewport",
|
|
12
|
+
"setWaitForEnabled",
|
|
13
|
+
"setWaitForStableBoundingBox",
|
|
14
|
+
"clone",
|
|
15
|
+
"filter",
|
|
16
|
+
"map",
|
|
17
|
+
]);
|
|
18
|
+
/** Action methods that get trace/screenshot injection. */
|
|
19
|
+
const ACTION_METHODS = new Set([
|
|
20
|
+
"click",
|
|
21
|
+
"fill",
|
|
22
|
+
"hover",
|
|
23
|
+
"scroll",
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* Create a WrappedLocator that proxies a Puppeteer Locator with auto-tracing.
|
|
27
|
+
*
|
|
28
|
+
* - **Chain methods** (setTimeout, setVisibility, etc.) return a new WrappedLocator.
|
|
29
|
+
* - **Action methods** (click, fill, hover, scroll) inject trace + screenshot.
|
|
30
|
+
* - **type()** is a custom extension (Locator has no type method).
|
|
31
|
+
* - Everything else is transparently forwarded.
|
|
32
|
+
*/
|
|
33
|
+
export function createWrappedLocator(inner, ctx, selector) {
|
|
34
|
+
const proxy = new Proxy(inner, {
|
|
35
|
+
get(target, prop, receiver) {
|
|
36
|
+
if (prop === "type") {
|
|
37
|
+
return async (text) => {
|
|
38
|
+
const start = Date.now();
|
|
39
|
+
try {
|
|
40
|
+
const handle = await target.waitHandle();
|
|
41
|
+
await handle.type(text);
|
|
42
|
+
await handle.dispose();
|
|
43
|
+
const duration = Date.now() - start;
|
|
44
|
+
ctx.action({
|
|
45
|
+
category: "browser:type",
|
|
46
|
+
target: selector,
|
|
47
|
+
duration,
|
|
48
|
+
status: "ok",
|
|
49
|
+
detail: { textLength: text.length },
|
|
50
|
+
});
|
|
51
|
+
await ctx.captureStep(`type-${selector}`);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
const duration = Date.now() - start;
|
|
55
|
+
ctx.action({
|
|
56
|
+
category: "browser:type",
|
|
57
|
+
target: selector,
|
|
58
|
+
duration,
|
|
59
|
+
status: "timeout",
|
|
60
|
+
detail: { textLength: text.length, error: String(err) },
|
|
61
|
+
});
|
|
62
|
+
await ctx.captureFailure(`type-${selector}`);
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (typeof prop === "string" && CHAIN_METHODS.has(prop)) {
|
|
68
|
+
const origFn = Reflect.get(target, prop, receiver);
|
|
69
|
+
if (typeof origFn === "function") {
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
|
+
return (...args) => {
|
|
72
|
+
const newLocator = origFn.apply(target, args);
|
|
73
|
+
return createWrappedLocator(newLocator, ctx, selector);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (typeof prop === "string" && ACTION_METHODS.has(prop)) {
|
|
78
|
+
const origFn = Reflect.get(target, prop, receiver);
|
|
79
|
+
if (typeof origFn === "function") {
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
81
|
+
return async (...args) => {
|
|
82
|
+
const start = Date.now();
|
|
83
|
+
try {
|
|
84
|
+
const result = await origFn.apply(target, args);
|
|
85
|
+
const duration = Date.now() - start;
|
|
86
|
+
ctx.action({
|
|
87
|
+
category: `browser:${prop}`,
|
|
88
|
+
target: selector,
|
|
89
|
+
duration,
|
|
90
|
+
status: "ok",
|
|
91
|
+
});
|
|
92
|
+
await ctx.captureStep(`${prop}-${selector}`);
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
const duration = Date.now() - start;
|
|
97
|
+
ctx.action({
|
|
98
|
+
category: `browser:${prop}`,
|
|
99
|
+
target: selector,
|
|
100
|
+
duration,
|
|
101
|
+
status: "timeout",
|
|
102
|
+
detail: { error: String(err) },
|
|
103
|
+
});
|
|
104
|
+
await ctx.captureFailure(`${prop}-${selector}`);
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Everything else — transparent passthrough
|
|
111
|
+
return Reflect.get(target, prop, receiver);
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
return proxy;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=locator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locator.js","sourceRoot":"","sources":["../src/locator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance timing collection for browser pages.
|
|
3
|
+
*
|
|
4
|
+
* Collects Navigation Timing API metrics after page loads and emits them
|
|
5
|
+
* via the Glubean metric callback so they appear in dashboards and trend
|
|
6
|
+
* analysis alongside API latency data.
|
|
7
|
+
*
|
|
8
|
+
* @module metrics
|
|
9
|
+
*/
|
|
10
|
+
import type { Page } from "puppeteer-core";
|
|
11
|
+
/** Callback shape matching `ctx.metric()`. */
|
|
12
|
+
export type MetricFn = (name: string, value: number, options?: {
|
|
13
|
+
unit?: string;
|
|
14
|
+
tags?: Record<string, string>;
|
|
15
|
+
}) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Collect Navigation Timing metrics from the page and emit them.
|
|
18
|
+
* Should be called after a successful `page.goto()` navigation.
|
|
19
|
+
*
|
|
20
|
+
* Silently skips if timing data is unavailable (e.g., page not fully loaded).
|
|
21
|
+
*/
|
|
22
|
+
export declare function collectNavigationMetrics(page: Page, metric: MetricFn, url: string): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAE3C,8CAA8C;AAC9C,MAAM,MAAM,QAAQ,GAAG,CACrB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,KACvD,IAAI,CAAC;AAQV;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,QAAQ,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAkCf"}
|
package/dist/metrics.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance timing collection for browser pages.
|
|
3
|
+
*
|
|
4
|
+
* Collects Navigation Timing API metrics after page loads and emits them
|
|
5
|
+
* via the Glubean metric callback so they appear in dashboards and trend
|
|
6
|
+
* analysis alongside API latency data.
|
|
7
|
+
*
|
|
8
|
+
* @module metrics
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Collect Navigation Timing metrics from the page and emit them.
|
|
12
|
+
* Should be called after a successful `page.goto()` navigation.
|
|
13
|
+
*
|
|
14
|
+
* Silently skips if timing data is unavailable (e.g., page not fully loaded).
|
|
15
|
+
*/
|
|
16
|
+
export async function collectNavigationMetrics(page, metric, url) {
|
|
17
|
+
try {
|
|
18
|
+
const timing = await page.evaluate(() => {
|
|
19
|
+
// performance.timing is deprecated but universally supported and
|
|
20
|
+
// available in all Chrome versions. The newer PerformanceNavigationTiming
|
|
21
|
+
// API doesn't provide the same absolute timestamps needed here.
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
const t = performance.timing;
|
|
24
|
+
return {
|
|
25
|
+
navigationStart: t.navigationStart,
|
|
26
|
+
domContentLoadedEventEnd: t.domContentLoadedEventEnd,
|
|
27
|
+
loadEventEnd: t.loadEventEnd,
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
const tags = { url: shortenUrl(url) };
|
|
31
|
+
if (timing.loadEventEnd > 0 && timing.navigationStart > 0) {
|
|
32
|
+
metric("page_load_ms", timing.loadEventEnd - timing.navigationStart, {
|
|
33
|
+
unit: "ms",
|
|
34
|
+
tags,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
if (timing.domContentLoadedEventEnd > 0 && timing.navigationStart > 0) {
|
|
38
|
+
metric("dom_content_loaded_ms", timing.domContentLoadedEventEnd - timing.navigationStart, { unit: "ms", tags });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Page context may be destroyed or navigation incomplete — skip silently
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function shortenUrl(url) {
|
|
46
|
+
try {
|
|
47
|
+
const u = new URL(url);
|
|
48
|
+
return u.pathname + u.search;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return url;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiBH;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,IAAU,EACV,MAAgB,EAChB,GAAW;IAEX,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;YACtC,iEAAiE;YACjE,0EAA0E;YAC1E,gEAAgE;YAChE,8DAA8D;YAC9D,MAAM,CAAC,GAAI,WAAmB,CAAC,MAAM,CAAC;YACtC,OAAO;gBACL,eAAe,EAAE,CAAC,CAAC,eAAyB;gBAC5C,wBAAwB,EAAE,CAAC,CAAC,wBAAkC;gBAC9D,YAAY,EAAE,CAAC,CAAC,YAAsB;aACvC,CAAC;QACJ,CAAC,CAAqB,CAAC;QAEvB,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAEtC,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,IAAI,MAAM,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;YAC1D,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,eAAe,EAAE;gBACnE,IAAI,EAAE,IAAI;gBACV,IAAI;aACL,CAAC,CAAC;QACL,CAAC;QAED,IAAI,MAAM,CAAC,wBAAwB,GAAG,CAAC,IAAI,MAAM,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;YACtE,MAAM,CACJ,uBAAuB,EACvB,MAAM,CAAC,wBAAwB,GAAG,MAAM,CAAC,eAAe,EACxD,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CACrB,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;IAC3E,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDP Network domain listener for auto-tracing in-page requests.
|
|
3
|
+
*
|
|
4
|
+
* Intercepts XHR, fetch, and document requests inside the browser page and
|
|
5
|
+
* emits them as Glubean trace events so they appear in the same timeline as
|
|
6
|
+
* `ctx.http` calls.
|
|
7
|
+
*
|
|
8
|
+
* @module network
|
|
9
|
+
*/
|
|
10
|
+
import type { Page } from "puppeteer-core";
|
|
11
|
+
/** Callback shape matching `ctx.trace()`. */
|
|
12
|
+
export type TraceFn = (trace: {
|
|
13
|
+
name?: string;
|
|
14
|
+
method: string;
|
|
15
|
+
url: string;
|
|
16
|
+
status: number;
|
|
17
|
+
duration: number;
|
|
18
|
+
requestBody?: unknown;
|
|
19
|
+
responseBody?: unknown;
|
|
20
|
+
}) => void;
|
|
21
|
+
/** @internal Exported for testing. */
|
|
22
|
+
export declare function shouldSkipProtocol(url: string): boolean;
|
|
23
|
+
/** @internal Exported for testing. */
|
|
24
|
+
export declare function shouldSkipPath(url: string, excludePaths: string[]): boolean;
|
|
25
|
+
/** @internal Exported for testing. */
|
|
26
|
+
export declare function shouldInclude(contentType: string, include: string[]): boolean;
|
|
27
|
+
/** Filter predicate for network requests. */
|
|
28
|
+
export type NetworkFilter = (req: {
|
|
29
|
+
url: string;
|
|
30
|
+
contentType: string;
|
|
31
|
+
status: number;
|
|
32
|
+
}) => boolean;
|
|
33
|
+
export interface NetworkTracerOptions {
|
|
34
|
+
trace: TraceFn;
|
|
35
|
+
/**
|
|
36
|
+
* Content-type prefixes to include. Ignored when `filter` is provided.
|
|
37
|
+
* @default ["application/json", "text/html"]
|
|
38
|
+
*/
|
|
39
|
+
include?: string[];
|
|
40
|
+
/**
|
|
41
|
+
* URL paths to skip. Pass `[]` to disable default exclusions.
|
|
42
|
+
* @default ["/favicon.ico", "/favicon.png", "/apple-touch-icon.png", "/apple-touch-icon-precomposed.png"]
|
|
43
|
+
*/
|
|
44
|
+
excludePaths?: string[];
|
|
45
|
+
/** Custom predicate. Overrides `include` and `excludePaths` when provided. */
|
|
46
|
+
filter?: NetworkFilter;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Attach a CDP Network listener to the page that emits Glubean trace events
|
|
50
|
+
* for every in-page network request.
|
|
51
|
+
*
|
|
52
|
+
* Returns a cleanup function that detaches the listener.
|
|
53
|
+
*/
|
|
54
|
+
export declare function attachNetworkTracer(page: Page, options: NetworkTracerOptions): Promise<() => Promise<void>>;
|
|
55
|
+
//# sourceMappingURL=network.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAc,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEvD,6CAA6C;AAC7C,MAAM,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,KAAK,IAAI,CAAC;AAkBX,sCAAsC;AACtC,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAKvD;AAED,sCAAsC;AACtC,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAU3E;AAED,sCAAsC;AACtC,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAMT;AAED,6CAA6C;AAC7C,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,KAAK,OAAO,CAAC;AAEd,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAcD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CA6H9B"}
|