playwright-core 1.58.0-alpha-2025-12-08 → 1.58.0-alpha-2025-12-09
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/browsers.json +3 -3
- package/lib/client/browserContext.js +7 -0
- package/lib/protocol/validator.js +10 -5
- package/lib/server/agent/actionRunner.js +16 -6
- package/lib/server/agent/agent.js +5 -6
- package/lib/server/agent/context.js +34 -10
- package/lib/server/agent/tools.js +51 -9
- package/lib/server/bidi/bidiNetworkManager.js +1 -1
- package/lib/server/bidi/bidiPage.js +3 -1
- package/lib/server/browserContext.js +1 -1
- package/lib/server/chromium/chromiumSwitches.js +0 -2
- package/lib/server/chromium/crBrowser.js +1 -1
- package/lib/server/chromium/crNetworkManager.js +39 -2
- package/lib/server/chromium/crPage.js +14 -81
- package/lib/server/deviceDescriptorsSource.json +2 -2
- package/lib/server/firefox/ffNetworkManager.js +2 -2
- package/lib/server/firefox/ffPage.js +9 -8
- package/lib/server/frames.js +2 -2
- package/lib/server/network.js +3 -0
- package/lib/server/page.js +4 -64
- package/lib/server/progress.js +3 -2
- package/lib/server/registry/index.js +1 -1
- package/lib/server/screencast.js +191 -0
- package/lib/server/trace/recorder/tracing.js +5 -5
- package/lib/server/{chromium/videoRecorder.js → videoRecorder.js} +3 -3
- package/lib/server/webkit/wkBrowser.js +1 -1
- package/lib/server/webkit/wkInterceptableRequest.js +29 -1
- package/lib/server/webkit/wkPage.js +20 -40
- package/package.json +1 -1
- package/types/types.d.ts +8 -3
package/browsers.json
CHANGED
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"name": "firefox",
|
|
34
|
-
"revision": "
|
|
34
|
+
"revision": "1504",
|
|
35
35
|
"installByDefault": true,
|
|
36
|
-
"browserVersion": "145.0.
|
|
36
|
+
"browserVersion": "145.0.2",
|
|
37
37
|
"title": "Firefox"
|
|
38
38
|
},
|
|
39
39
|
{
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"name": "webkit",
|
|
48
|
-
"revision": "
|
|
48
|
+
"revision": "2237",
|
|
49
49
|
"installByDefault": true,
|
|
50
50
|
"revisionOverrides": {
|
|
51
51
|
"debian11-x64": "2105",
|
|
@@ -493,6 +493,7 @@ async function prepareBrowserContextParams(platform, options) {
|
|
|
493
493
|
network.validateHeaders(options.extraHTTPHeaders);
|
|
494
494
|
const contextParams = {
|
|
495
495
|
...options,
|
|
496
|
+
agent: toAgentProtocol(options.agent),
|
|
496
497
|
viewport: options.viewport === null ? void 0 : options.viewport,
|
|
497
498
|
noDefaultViewport: options.viewport === null,
|
|
498
499
|
extraHTTPHeaders: options.extraHTTPHeaders ? (0, import_headers.headersObjectToArray)(options.extraHTTPHeaders) : void 0,
|
|
@@ -515,6 +516,12 @@ async function prepareBrowserContextParams(platform, options) {
|
|
|
515
516
|
contextParams.recordVideo.dir = platform.path().resolve(contextParams.recordVideo.dir);
|
|
516
517
|
return contextParams;
|
|
517
518
|
}
|
|
519
|
+
function toAgentProtocol(agent) {
|
|
520
|
+
if (!agent)
|
|
521
|
+
return void 0;
|
|
522
|
+
const secrets = agent.secrets ? Object.entries(agent.secrets).map(([name, value]) => ({ name, value })) : void 0;
|
|
523
|
+
return { ...agent, secrets };
|
|
524
|
+
}
|
|
518
525
|
function toAcceptDownloadsProtocol(acceptDownloads) {
|
|
519
526
|
if (acceptDownloads === void 0)
|
|
520
527
|
return void 0;
|
|
@@ -612,7 +612,8 @@ import_validatorPrimitives.scheme.BrowserTypeLaunchPersistentContextParams = (0,
|
|
|
612
612
|
provider: import_validatorPrimitives.tString,
|
|
613
613
|
model: import_validatorPrimitives.tString,
|
|
614
614
|
cacheFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
|
|
615
|
-
cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "auto"]))
|
|
615
|
+
cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "auto"])),
|
|
616
|
+
secrets: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("NameValue")))
|
|
616
617
|
})),
|
|
617
618
|
userDataDir: import_validatorPrimitives.tString,
|
|
618
619
|
slowMo: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tFloat)
|
|
@@ -710,7 +711,8 @@ import_validatorPrimitives.scheme.BrowserNewContextParams = (0, import_validator
|
|
|
710
711
|
provider: import_validatorPrimitives.tString,
|
|
711
712
|
model: import_validatorPrimitives.tString,
|
|
712
713
|
cacheFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
|
|
713
|
-
cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "auto"]))
|
|
714
|
+
cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "auto"])),
|
|
715
|
+
secrets: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("NameValue")))
|
|
714
716
|
})),
|
|
715
717
|
proxy: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tObject)({
|
|
716
718
|
server: import_validatorPrimitives.tString,
|
|
@@ -787,7 +789,8 @@ import_validatorPrimitives.scheme.BrowserNewContextForReuseParams = (0, import_v
|
|
|
787
789
|
provider: import_validatorPrimitives.tString,
|
|
788
790
|
model: import_validatorPrimitives.tString,
|
|
789
791
|
cacheFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
|
|
790
|
-
cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "auto"]))
|
|
792
|
+
cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "auto"])),
|
|
793
|
+
secrets: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("NameValue")))
|
|
791
794
|
})),
|
|
792
795
|
proxy: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tObject)({
|
|
793
796
|
server: import_validatorPrimitives.tString,
|
|
@@ -909,7 +912,8 @@ import_validatorPrimitives.scheme.BrowserContextInitializer = (0, import_validat
|
|
|
909
912
|
provider: import_validatorPrimitives.tString,
|
|
910
913
|
model: import_validatorPrimitives.tString,
|
|
911
914
|
cacheFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
|
|
912
|
-
cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "auto"]))
|
|
915
|
+
cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "auto"])),
|
|
916
|
+
secrets: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("NameValue")))
|
|
913
917
|
}))
|
|
914
918
|
})
|
|
915
919
|
});
|
|
@@ -2818,7 +2822,8 @@ import_validatorPrimitives.scheme.AndroidDeviceLaunchBrowserParams = (0, import_
|
|
|
2818
2822
|
provider: import_validatorPrimitives.tString,
|
|
2819
2823
|
model: import_validatorPrimitives.tString,
|
|
2820
2824
|
cacheFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
|
|
2821
|
-
cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "auto"]))
|
|
2825
|
+
cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "auto"])),
|
|
2826
|
+
secrets: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("NameValue")))
|
|
2822
2827
|
})),
|
|
2823
2828
|
pkg: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
|
|
2824
2829
|
args: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)(import_validatorPrimitives.tString)),
|
|
@@ -21,7 +21,7 @@ __export(actionRunner_exports, {
|
|
|
21
21
|
runAction: () => runAction
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(actionRunner_exports);
|
|
24
|
-
async function runAction(progress, page, action) {
|
|
24
|
+
async function runAction(progress, page, action, secrets) {
|
|
25
25
|
const frame = page.mainFrame();
|
|
26
26
|
switch (action.method) {
|
|
27
27
|
case "click":
|
|
@@ -34,21 +34,31 @@ async function runAction(progress, page, action) {
|
|
|
34
34
|
await frame.hover(progress, action.selector, { ...action.options, ...strictTrue });
|
|
35
35
|
break;
|
|
36
36
|
case "selectOption":
|
|
37
|
-
await frame.selectOption(progress, action.selector, [], action.
|
|
37
|
+
await frame.selectOption(progress, action.selector, [], action.labels.map((a) => ({ label: a })), { ...strictTrue });
|
|
38
38
|
break;
|
|
39
39
|
case "pressKey":
|
|
40
40
|
await page.keyboard.press(progress, action.key);
|
|
41
41
|
break;
|
|
42
|
-
case "pressSequentially":
|
|
43
|
-
|
|
42
|
+
case "pressSequentially": {
|
|
43
|
+
const secret = secrets?.find((s) => s.name === action.text)?.value ?? action.text;
|
|
44
|
+
await frame.type(progress, action.selector, secret, { ...strictTrue });
|
|
44
45
|
if (action.submit)
|
|
45
46
|
await page.keyboard.press(progress, "Enter");
|
|
46
47
|
break;
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
}
|
|
49
|
+
case "fill": {
|
|
50
|
+
const secret = secrets?.find((s) => s.name === action.text)?.value ?? action.text;
|
|
51
|
+
await frame.fill(progress, action.selector, secret, { ...strictTrue });
|
|
49
52
|
if (action.submit)
|
|
50
53
|
await page.keyboard.press(progress, "Enter");
|
|
51
54
|
break;
|
|
55
|
+
}
|
|
56
|
+
case "setChecked":
|
|
57
|
+
if (action.checked)
|
|
58
|
+
await frame.check(progress, action.selector, { ...strictTrue });
|
|
59
|
+
else
|
|
60
|
+
await frame.uncheck(progress, action.selector, { ...strictTrue });
|
|
61
|
+
break;
|
|
52
62
|
}
|
|
53
63
|
}
|
|
54
64
|
const strictTrue = { strict: true };
|
|
@@ -83,23 +83,22 @@ ${full}
|
|
|
83
83
|
}
|
|
84
84
|
const allCaches = /* @__PURE__ */ new Map();
|
|
85
85
|
async function cachedPerform(context, options) {
|
|
86
|
-
|
|
87
|
-
if (!agentSettings?.cacheFile || agentSettings.cacheMode === "ignore")
|
|
86
|
+
if (!context.options?.cacheFile || context.options.cacheMode === "ignore")
|
|
88
87
|
return false;
|
|
89
|
-
const cache = await cachedActions(
|
|
88
|
+
const cache = await cachedActions(context.options.cacheFile);
|
|
90
89
|
const cacheKey = options.key ?? options.task;
|
|
91
90
|
const actions = cache[cacheKey];
|
|
92
91
|
if (!actions) {
|
|
93
|
-
if (
|
|
92
|
+
if (context.options.cacheMode === "force")
|
|
94
93
|
throw new Error(`No cached actions for key "${cacheKey}", but cache mode is set to "force"`);
|
|
95
94
|
return false;
|
|
96
95
|
}
|
|
97
96
|
for (const action of actions)
|
|
98
|
-
await (0, import_actionRunner.runAction)(context.progress, context.page, action);
|
|
97
|
+
await (0, import_actionRunner.runAction)(context.progress, context.page, action, context.options.secrets ?? []);
|
|
99
98
|
return true;
|
|
100
99
|
}
|
|
101
100
|
async function updateCache(context, options) {
|
|
102
|
-
const cacheFile = context.
|
|
101
|
+
const cacheFile = context.options?.cacheFile;
|
|
103
102
|
if (!cacheFile)
|
|
104
103
|
return;
|
|
105
104
|
const cache = await cachedActions(cacheFile);
|
|
@@ -28,10 +28,18 @@ class Context {
|
|
|
28
28
|
this.actions = [];
|
|
29
29
|
this.progress = progress;
|
|
30
30
|
this.page = page;
|
|
31
|
+
this.options = page.browserContext._options.agent;
|
|
31
32
|
}
|
|
32
|
-
async
|
|
33
|
-
await this.
|
|
34
|
-
|
|
33
|
+
async runActionAndWait(action) {
|
|
34
|
+
return await this.runActionsAndWait([action]);
|
|
35
|
+
}
|
|
36
|
+
async runActionsAndWait(action) {
|
|
37
|
+
await this.waitForCompletion(async () => {
|
|
38
|
+
for (const a of action) {
|
|
39
|
+
await (0, import_actionRunner.runAction)(this.progress, this.page, a, this.options?.secrets ?? []);
|
|
40
|
+
this.actions.push(a);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
35
43
|
return await this.snapshotResult();
|
|
36
44
|
}
|
|
37
45
|
async waitForCompletion(callback) {
|
|
@@ -40,6 +48,7 @@ class Context {
|
|
|
40
48
|
const disposeListeners = () => {
|
|
41
49
|
this.page.browserContext.off(import_browserContext.BrowserContext.Events.Request, requestListener);
|
|
42
50
|
};
|
|
51
|
+
this.page.browserContext.on(import_browserContext.BrowserContext.Events.Request, requestListener);
|
|
43
52
|
let result;
|
|
44
53
|
try {
|
|
45
54
|
result = await callback();
|
|
@@ -49,20 +58,24 @@ class Context {
|
|
|
49
58
|
}
|
|
50
59
|
const requestedNavigation = requests.some((request) => request.isNavigationRequest());
|
|
51
60
|
if (requestedNavigation) {
|
|
52
|
-
await this.page.
|
|
61
|
+
await this.page.mainFrame().waitForLoadState(this.progress, "load");
|
|
53
62
|
return result;
|
|
54
63
|
}
|
|
55
|
-
const
|
|
64
|
+
const promises = [];
|
|
56
65
|
for (const request of requests) {
|
|
57
|
-
if (request.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
if (["document", "stylesheet", "script", "xhr", "fetch"].includes(request.resourceType()))
|
|
67
|
+
promises.push(request.response().then((r) => r?.finished()));
|
|
68
|
+
else
|
|
69
|
+
promises.push(request.response());
|
|
61
70
|
}
|
|
71
|
+
await this.progress.race(promises, { timeout: 5e3 });
|
|
72
|
+
if (requests.length)
|
|
73
|
+
await this.progress.wait(500);
|
|
62
74
|
return result;
|
|
63
75
|
}
|
|
64
76
|
async snapshotResult() {
|
|
65
|
-
|
|
77
|
+
let { full } = await this.page.snapshotForAI(this.progress);
|
|
78
|
+
full = this._redactText(full);
|
|
66
79
|
const text = [`# Page snapshot
|
|
67
80
|
${full}`];
|
|
68
81
|
return {
|
|
@@ -84,6 +97,17 @@ ${full}`];
|
|
|
84
97
|
}
|
|
85
98
|
}));
|
|
86
99
|
}
|
|
100
|
+
_redactText(text) {
|
|
101
|
+
const secrets = this.options?.secrets;
|
|
102
|
+
if (!secrets)
|
|
103
|
+
return text;
|
|
104
|
+
const redactText = (text2) => {
|
|
105
|
+
for (const { name, value } of secrets)
|
|
106
|
+
text2 = text2.replaceAll(value, `<secret>${name}</secret>`);
|
|
107
|
+
return text2;
|
|
108
|
+
};
|
|
109
|
+
return redactText(text);
|
|
110
|
+
}
|
|
87
111
|
}
|
|
88
112
|
// Annotate the CommonJS export names for ESM import in node:
|
|
89
113
|
0 && (module.exports = {
|
|
@@ -54,7 +54,7 @@ const click = defineTool({
|
|
|
54
54
|
},
|
|
55
55
|
handle: async (context, params) => {
|
|
56
56
|
const [selector] = await context.refSelectors([params]);
|
|
57
|
-
return await context.
|
|
57
|
+
return await context.runActionAndWait({
|
|
58
58
|
method: "click",
|
|
59
59
|
selector,
|
|
60
60
|
options: {
|
|
@@ -82,7 +82,7 @@ const drag = defineTool({
|
|
|
82
82
|
{ ref: params.startRef, element: params.startElement },
|
|
83
83
|
{ ref: params.endRef, element: params.endElement }
|
|
84
84
|
]);
|
|
85
|
-
return await context.
|
|
85
|
+
return await context.runActionAndWait({
|
|
86
86
|
method: "drag",
|
|
87
87
|
sourceSelector,
|
|
88
88
|
targetSelector
|
|
@@ -101,7 +101,7 @@ const hover = defineTool({
|
|
|
101
101
|
},
|
|
102
102
|
handle: async (context, params) => {
|
|
103
103
|
const [selector] = await context.refSelectors([params]);
|
|
104
|
-
return await context.
|
|
104
|
+
return await context.runActionAndWait({
|
|
105
105
|
method: "hover",
|
|
106
106
|
selector,
|
|
107
107
|
options: {
|
|
@@ -122,10 +122,10 @@ const selectOption = defineTool({
|
|
|
122
122
|
},
|
|
123
123
|
handle: async (context, params) => {
|
|
124
124
|
const [selector] = await context.refSelectors([params]);
|
|
125
|
-
return await context.
|
|
125
|
+
return await context.runActionAndWait({
|
|
126
126
|
method: "selectOption",
|
|
127
127
|
selector,
|
|
128
|
-
|
|
128
|
+
labels: params.values
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
131
|
});
|
|
@@ -139,7 +139,7 @@ const pressKey = defineTool({
|
|
|
139
139
|
})
|
|
140
140
|
},
|
|
141
141
|
handle: async (context, params) => {
|
|
142
|
-
return await context.
|
|
142
|
+
return await context.runActionAndWait({
|
|
143
143
|
method: "pressKey",
|
|
144
144
|
key: params.key
|
|
145
145
|
});
|
|
@@ -160,14 +160,14 @@ const type = defineTool({
|
|
|
160
160
|
handle: async (context, params) => {
|
|
161
161
|
const [selector] = await context.refSelectors([params]);
|
|
162
162
|
if (params.slowly) {
|
|
163
|
-
return await context.
|
|
163
|
+
return await context.runActionAndWait({
|
|
164
164
|
method: "pressSequentially",
|
|
165
165
|
selector,
|
|
166
166
|
text: params.text,
|
|
167
167
|
submit: params.submit
|
|
168
168
|
});
|
|
169
169
|
} else {
|
|
170
|
-
return await context.
|
|
170
|
+
return await context.runActionAndWait({
|
|
171
171
|
method: "fill",
|
|
172
172
|
selector,
|
|
173
173
|
text: params.text,
|
|
@@ -176,6 +176,47 @@ const type = defineTool({
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
});
|
|
179
|
+
const fillForm = defineTool({
|
|
180
|
+
schema: {
|
|
181
|
+
name: "browser_fill_form",
|
|
182
|
+
title: "Fill form",
|
|
183
|
+
description: "Fill multiple form fields",
|
|
184
|
+
inputSchema: import_mcpBundle.z.object({
|
|
185
|
+
fields: import_mcpBundle.z.array(import_mcpBundle.z.object({
|
|
186
|
+
name: import_mcpBundle.z.string().describe("Human-readable field name"),
|
|
187
|
+
type: import_mcpBundle.z.enum(["textbox", "checkbox", "radio", "combobox", "slider"]).describe("Type of the field"),
|
|
188
|
+
ref: import_mcpBundle.z.string().describe("Exact target field reference from the page snapshot"),
|
|
189
|
+
value: import_mcpBundle.z.string().describe("Value to fill in the field. If the field is a checkbox, the value should be `true` or `false`. If the field is a combobox, the value should be the text of the option.")
|
|
190
|
+
})).describe("Fields to fill in")
|
|
191
|
+
})
|
|
192
|
+
},
|
|
193
|
+
handle: async (context, params) => {
|
|
194
|
+
const actions = [];
|
|
195
|
+
for (const field of params.fields) {
|
|
196
|
+
const [selector] = await context.refSelectors([{ ref: field.ref, element: field.name }]);
|
|
197
|
+
if (field.type === "textbox" || field.type === "slider") {
|
|
198
|
+
actions.push({
|
|
199
|
+
method: "fill",
|
|
200
|
+
selector,
|
|
201
|
+
text: field.value
|
|
202
|
+
});
|
|
203
|
+
} else if (field.type === "checkbox" || field.type === "radio") {
|
|
204
|
+
actions.push({
|
|
205
|
+
method: "setChecked",
|
|
206
|
+
selector,
|
|
207
|
+
checked: field.value === "true"
|
|
208
|
+
});
|
|
209
|
+
} else if (field.type === "combobox") {
|
|
210
|
+
actions.push({
|
|
211
|
+
method: "selectOption",
|
|
212
|
+
selector,
|
|
213
|
+
labels: [field.value]
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return await context.runActionsAndWait(actions);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
179
220
|
var tools_default = [
|
|
180
221
|
snapshot,
|
|
181
222
|
click,
|
|
@@ -183,5 +224,6 @@ var tools_default = [
|
|
|
183
224
|
hover,
|
|
184
225
|
selectOption,
|
|
185
226
|
pressKey,
|
|
186
|
-
type
|
|
227
|
+
type,
|
|
228
|
+
fillForm
|
|
187
229
|
];
|
|
@@ -322,7 +322,7 @@ if (navigator.serviceWorker) navigator.serviceWorker.register = async () => { co
|
|
|
322
322
|
const pageOrError = await progress.race(page.waitForInitializedOrError());
|
|
323
323
|
if (pageOrError instanceof Error)
|
|
324
324
|
throw pageOrError;
|
|
325
|
-
await page.mainFrame().
|
|
325
|
+
await page.mainFrame().waitForLoadState(progress, "load");
|
|
326
326
|
return page;
|
|
327
327
|
}
|
|
328
328
|
async _loadDefaultContext(progress) {
|
|
@@ -22,8 +22,6 @@ __export(chromiumSwitches_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(chromiumSwitches_exports);
|
|
24
24
|
const disabledFeatures = (assistantMode) => [
|
|
25
|
-
// See https://github.com/microsoft/playwright/pull/10380
|
|
26
|
-
"AcceptCHFrame",
|
|
27
25
|
// See https://github.com/microsoft/playwright/issues/14047
|
|
28
26
|
"AvoidUnnecessaryBeforeUnloadCheckSync",
|
|
29
27
|
"DestroyProfileOnBrowserClose",
|
|
@@ -470,7 +470,7 @@ class CRBrowserContext extends import_browserContext.BrowserContext {
|
|
|
470
470
|
}
|
|
471
471
|
}
|
|
472
472
|
async stopVideoRecording() {
|
|
473
|
-
await Promise.all(this._crPages().map((crPage) => crPage.
|
|
473
|
+
await Promise.all(this._crPages().map((crPage) => crPage._page.screencast.stopVideoRecording()));
|
|
474
474
|
}
|
|
475
475
|
onClosePersistent() {
|
|
476
476
|
}
|
|
@@ -482,12 +482,11 @@ class InterceptableRequest {
|
|
|
482
482
|
url,
|
|
483
483
|
postDataEntries = null
|
|
484
484
|
} = requestPausedEvent ? requestPausedEvent.request : requestWillBeSentEvent.request;
|
|
485
|
-
const type = (requestWillBeSentEvent.type || "").toLowerCase();
|
|
486
485
|
let postDataBuffer = null;
|
|
487
486
|
const entries = postDataEntries?.filter((entry) => entry.bytes);
|
|
488
487
|
if (entries && entries.length)
|
|
489
488
|
postDataBuffer = Buffer.concat(entries.map((entry) => Buffer.from(entry.bytes, "base64")));
|
|
490
|
-
this.request = new network.Request(context, frame, serviceWorker, redirectedFrom?.request || null, documentId, url, type, method, postDataBuffer, headersOverride || (0, import_utils.headersObjectToArray)(headers));
|
|
489
|
+
this.request = new network.Request(context, frame, serviceWorker, redirectedFrom?.request || null, documentId, url, toResourceType(requestWillBeSentEvent.type || "Other"), method, postDataBuffer, headersOverride || (0, import_utils.headersObjectToArray)(headers));
|
|
491
490
|
}
|
|
492
491
|
}
|
|
493
492
|
class RouteImpl {
|
|
@@ -660,6 +659,44 @@ class ResponseExtraInfoTracker {
|
|
|
660
659
|
this._requests.delete(requestId);
|
|
661
660
|
}
|
|
662
661
|
}
|
|
662
|
+
function toResourceType(type) {
|
|
663
|
+
switch (type) {
|
|
664
|
+
case "Document":
|
|
665
|
+
return "document";
|
|
666
|
+
case "Stylesheet":
|
|
667
|
+
return "stylesheet";
|
|
668
|
+
case "Image":
|
|
669
|
+
return "image";
|
|
670
|
+
case "Media":
|
|
671
|
+
return "media";
|
|
672
|
+
case "Font":
|
|
673
|
+
return "font";
|
|
674
|
+
case "Script":
|
|
675
|
+
return "script";
|
|
676
|
+
case "TextTrack":
|
|
677
|
+
return "texttrack";
|
|
678
|
+
case "XHR":
|
|
679
|
+
return "xhr";
|
|
680
|
+
case "Fetch":
|
|
681
|
+
return "fetch";
|
|
682
|
+
case "EventSource":
|
|
683
|
+
return "eventsource";
|
|
684
|
+
case "WebSocket":
|
|
685
|
+
return "websocket";
|
|
686
|
+
case "Manifest":
|
|
687
|
+
return "manifest";
|
|
688
|
+
case "Ping":
|
|
689
|
+
return "ping";
|
|
690
|
+
case "CSPViolationReport":
|
|
691
|
+
return "cspreport";
|
|
692
|
+
case "Prefetch":
|
|
693
|
+
case "SignedExchange":
|
|
694
|
+
case "Preflight":
|
|
695
|
+
case "FedCM":
|
|
696
|
+
default:
|
|
697
|
+
return "other";
|
|
698
|
+
}
|
|
699
|
+
}
|
|
663
700
|
// Annotate the CommonJS export names for ESM import in node:
|
|
664
701
|
0 && (module.exports = {
|
|
665
702
|
CRNetworkManager
|
|
@@ -31,9 +31,7 @@ __export(crPage_exports, {
|
|
|
31
31
|
CRPage: () => CRPage
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(crPage_exports);
|
|
34
|
-
var import_path = __toESM(require("path"));
|
|
35
34
|
var import_assert = require("../../utils/isomorphic/assert");
|
|
36
|
-
var import_crypto = require("../utils/crypto");
|
|
37
35
|
var import_eventsHelper = require("../utils/eventsHelper");
|
|
38
36
|
var import_stackTrace = require("../../utils/isomorphic/stackTrace");
|
|
39
37
|
var dialog = __toESM(require("../dialog"));
|
|
@@ -42,7 +40,6 @@ var frames = __toESM(require("../frames"));
|
|
|
42
40
|
var import_helper = require("../helper");
|
|
43
41
|
var network = __toESM(require("../network"));
|
|
44
42
|
var import_page = require("../page");
|
|
45
|
-
var import_registry = require("../registry");
|
|
46
43
|
var import_crCoverage = require("./crCoverage");
|
|
47
44
|
var import_crDragDrop = require("./crDragDrop");
|
|
48
45
|
var import_crExecutionContext = require("./crExecutionContext");
|
|
@@ -51,7 +48,6 @@ var import_crNetworkManager = require("./crNetworkManager");
|
|
|
51
48
|
var import_crPdf = require("./crPdf");
|
|
52
49
|
var import_crProtocolHelper = require("./crProtocolHelper");
|
|
53
50
|
var import_defaultFontFamilies = require("./defaultFontFamilies");
|
|
54
|
-
var import_videoRecorder = require("./videoRecorder");
|
|
55
51
|
var import_errors = require("../errors");
|
|
56
52
|
var import_protocolError = require("../protocolError");
|
|
57
53
|
class CRPage {
|
|
@@ -236,17 +232,16 @@ class CRPage {
|
|
|
236
232
|
async scrollRectIntoViewIfNeeded(handle, rect) {
|
|
237
233
|
return this._sessionForHandle(handle)._scrollRectIntoViewIfNeeded(handle, rect);
|
|
238
234
|
}
|
|
239
|
-
async
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
235
|
+
async startScreencast(options) {
|
|
236
|
+
await this._mainFrameSession._client.send("Page.startScreencast", {
|
|
237
|
+
format: "jpeg",
|
|
238
|
+
quality: options.quality,
|
|
239
|
+
maxWidth: options.width,
|
|
240
|
+
maxHeight: options.height
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
async stopScreencast() {
|
|
244
|
+
await this._mainFrameSession._client._sendMayFail("Page.stopScreencast");
|
|
250
245
|
}
|
|
251
246
|
rafCountForStablePosition() {
|
|
252
247
|
return 1;
|
|
@@ -311,9 +306,6 @@ class FrameSession {
|
|
|
311
306
|
// Marks the oopif session that remote -> local transition has happened in the parent.
|
|
312
307
|
// See Target.detachedFromTarget handler for details.
|
|
313
308
|
this._swappedIn = false;
|
|
314
|
-
this._videoRecorder = null;
|
|
315
|
-
this._screencastId = null;
|
|
316
|
-
this._screencastClients = /* @__PURE__ */ new Set();
|
|
317
309
|
this._workerSessions = /* @__PURE__ */ new Map();
|
|
318
310
|
this._initScriptIds = /* @__PURE__ */ new Map();
|
|
319
311
|
this._client = client;
|
|
@@ -366,22 +358,8 @@ class FrameSession {
|
|
|
366
358
|
this._windowId = windowId;
|
|
367
359
|
}
|
|
368
360
|
let screencastOptions;
|
|
369
|
-
if (!this._page.isStorageStatePage && this._isMainFrame() &&
|
|
370
|
-
|
|
371
|
-
const outputFile = import_path.default.join(this._crPage._browserContext._options.recordVideo.dir, screencastId + ".webm");
|
|
372
|
-
screencastOptions = {
|
|
373
|
-
// validateBrowserContextOptions ensures correct video size.
|
|
374
|
-
...this._crPage._browserContext._options.recordVideo.size,
|
|
375
|
-
outputFile
|
|
376
|
-
};
|
|
377
|
-
await this._crPage._browserContext._ensureVideosPath();
|
|
378
|
-
await this._createVideoRecorder(screencastId, screencastOptions);
|
|
379
|
-
this._crPage._page.waitForInitializedOrError().then((p) => {
|
|
380
|
-
if (p instanceof Error)
|
|
381
|
-
this._stopVideoRecording().catch(() => {
|
|
382
|
-
});
|
|
383
|
-
});
|
|
384
|
-
}
|
|
361
|
+
if (!this._page.isStorageStatePage && this._isMainFrame() && hasUIWindow)
|
|
362
|
+
screencastOptions = await this._crPage._page.screencast.initializeVideoRecorder();
|
|
385
363
|
let lifecycleEventsEnabled;
|
|
386
364
|
if (!this._isMainFrame())
|
|
387
365
|
this._addRendererListeners();
|
|
@@ -462,7 +440,7 @@ class FrameSession {
|
|
|
462
440
|
/* runImmediately */
|
|
463
441
|
));
|
|
464
442
|
if (screencastOptions)
|
|
465
|
-
promises.push(this.
|
|
443
|
+
promises.push(this._crPage._page.screencast.startVideoRecording(screencastOptions));
|
|
466
444
|
}
|
|
467
445
|
promises.push(this._client.send("Runtime.runIfWaitingForDebugger"));
|
|
468
446
|
promises.push(this._firstNonInitialNavigationCommittedPromise);
|
|
@@ -730,7 +708,7 @@ class FrameSession {
|
|
|
730
708
|
}
|
|
731
709
|
}
|
|
732
710
|
_onScreencastFrame(payload) {
|
|
733
|
-
this._page.
|
|
711
|
+
this._page.screencast.throttleFrameAck(() => {
|
|
734
712
|
this._client.send("Page.screencastFrameAck", { sessionId: payload.sessionId }).catch(() => {
|
|
735
713
|
});
|
|
736
714
|
});
|
|
@@ -742,51 +720,6 @@ class FrameSession {
|
|
|
742
720
|
height: payload.metadata.deviceHeight
|
|
743
721
|
});
|
|
744
722
|
}
|
|
745
|
-
async _createVideoRecorder(screencastId, options) {
|
|
746
|
-
(0, import_assert.assert)(!this._screencastId);
|
|
747
|
-
const ffmpegPath = import_registry.registry.findExecutable("ffmpeg").executablePathOrDie(this._page.browserContext._browser.sdkLanguage());
|
|
748
|
-
this._videoRecorder = await import_videoRecorder.VideoRecorder.launch(this._crPage._page, ffmpegPath, options);
|
|
749
|
-
this._screencastId = screencastId;
|
|
750
|
-
}
|
|
751
|
-
async _startVideoRecording(options) {
|
|
752
|
-
const screencastId = this._screencastId;
|
|
753
|
-
(0, import_assert.assert)(screencastId);
|
|
754
|
-
this._page.once(import_page.Page.Events.Close, () => this._stopVideoRecording().catch(() => {
|
|
755
|
-
}));
|
|
756
|
-
const gotFirstFrame = new Promise((f) => this._client.once("Page.screencastFrame", f));
|
|
757
|
-
await this._startScreencast(this._videoRecorder, {
|
|
758
|
-
format: "jpeg",
|
|
759
|
-
quality: 90,
|
|
760
|
-
maxWidth: options.width,
|
|
761
|
-
maxHeight: options.height
|
|
762
|
-
});
|
|
763
|
-
gotFirstFrame.then(() => {
|
|
764
|
-
this._crPage._browserContext._browser._videoStarted(this._crPage._browserContext, screencastId, options.outputFile, this._crPage._page.waitForInitializedOrError());
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
async _stopVideoRecording() {
|
|
768
|
-
if (!this._screencastId)
|
|
769
|
-
return;
|
|
770
|
-
const screencastId = this._screencastId;
|
|
771
|
-
this._screencastId = null;
|
|
772
|
-
const recorder = this._videoRecorder;
|
|
773
|
-
this._videoRecorder = null;
|
|
774
|
-
await this._stopScreencast(recorder);
|
|
775
|
-
await recorder.stop().catch(() => {
|
|
776
|
-
});
|
|
777
|
-
const video = this._crPage._browserContext._browser._takeVideo(screencastId);
|
|
778
|
-
video?.reportFinished();
|
|
779
|
-
}
|
|
780
|
-
async _startScreencast(client, options = {}) {
|
|
781
|
-
this._screencastClients.add(client);
|
|
782
|
-
if (this._screencastClients.size === 1)
|
|
783
|
-
await this._client.send("Page.startScreencast", options);
|
|
784
|
-
}
|
|
785
|
-
async _stopScreencast(client) {
|
|
786
|
-
this._screencastClients.delete(client);
|
|
787
|
-
if (!this._screencastClients.size)
|
|
788
|
-
await this._client._sendMayFail("Page.stopScreencast");
|
|
789
|
-
}
|
|
790
723
|
async _updateGeolocation(initial) {
|
|
791
724
|
const geolocation = this._crPage._browserContext._options.geolocation;
|
|
792
725
|
if (!initial || geolocation)
|
|
@@ -1702,7 +1702,7 @@
|
|
|
1702
1702
|
"defaultBrowserType": "chromium"
|
|
1703
1703
|
},
|
|
1704
1704
|
"Desktop Firefox HiDPI": {
|
|
1705
|
-
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0.
|
|
1705
|
+
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0.2) Gecko/20100101 Firefox/145.0.2",
|
|
1706
1706
|
"screen": {
|
|
1707
1707
|
"width": 1792,
|
|
1708
1708
|
"height": 1120
|
|
@@ -1762,7 +1762,7 @@
|
|
|
1762
1762
|
"defaultBrowserType": "chromium"
|
|
1763
1763
|
},
|
|
1764
1764
|
"Desktop Firefox": {
|
|
1765
|
-
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0.
|
|
1765
|
+
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0.2) Gecko/20100101 Firefox/145.0.2",
|
|
1766
1766
|
"screen": {
|
|
1767
1767
|
"width": 1920,
|
|
1768
1768
|
"height": 1080
|