patchright-core 1.52.4 → 1.55.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/ThirdPartyNotices.txt +65 -123
- package/bin/reinstall_chrome_beta_mac.sh +1 -1
- package/bin/reinstall_chrome_stable_mac.sh +1 -1
- package/bin/reinstall_msedge_beta_mac.sh +1 -1
- package/bin/reinstall_msedge_dev_mac.sh +1 -1
- package/bin/reinstall_msedge_stable_mac.sh +1 -1
- package/browsers.json +14 -14
- package/index.js +1 -1
- package/lib/androidServerImpl.js +4 -2
- package/lib/browserServerImpl.js +47 -12
- package/lib/cli/program.js +116 -50
- package/lib/cli/programWithTestStub.js +1 -1
- package/lib/client/android.js +30 -34
- package/lib/client/browser.js +54 -17
- package/lib/client/browserContext.js +67 -71
- package/lib/client/browserType.js +25 -34
- package/lib/client/channelOwner.js +20 -24
- package/lib/client/connection.js +6 -10
- package/lib/client/electron.js +8 -3
- package/lib/client/elementHandle.js +18 -21
- package/lib/client/fetch.js +5 -3
- package/lib/client/frame.js +57 -35
- package/lib/client/input.js +3 -1
- package/lib/client/jsHandle.js +4 -0
- package/lib/client/localUtils.js +0 -1
- package/lib/client/locator.js +32 -28
- package/lib/client/network.js +5 -12
- package/lib/client/page.js +32 -32
- package/lib/client/playwright.js +6 -16
- package/lib/client/selectors.js +18 -38
- package/lib/client/timeoutSettings.js +12 -8
- package/lib/client/tracing.js +24 -20
- package/lib/client/waiter.js +2 -2
- package/lib/client/webSocket.js +4 -22
- package/lib/generated/bindingsControllerSource.js +28 -0
- package/lib/generated/clockSource.js +1 -1
- package/lib/generated/injectedScriptSource.js +1 -1
- package/lib/generated/pollingRecorderSource.js +1 -1
- package/lib/generated/storageScriptSource.js +28 -0
- package/lib/generated/utilityScriptSource.js +1 -1
- package/lib/generated/webSocketMockSource.js +12 -50
- package/lib/inProcessFactory.js +9 -6
- package/lib/outofprocess.js +0 -2
- package/lib/protocol/validator.js +423 -346
- package/lib/protocol/validatorPrimitives.js +18 -4
- package/lib/remote/playwrightConnection.js +29 -166
- package/lib/remote/playwrightServer.js +233 -35
- package/lib/server/android/android.js +97 -83
- package/lib/server/android/backendAdb.js +0 -2
- package/lib/server/bidi/bidiBrowser.js +139 -73
- package/lib/server/bidi/bidiChromium.js +23 -22
- package/lib/server/bidi/bidiExecutionContext.js +2 -1
- package/lib/server/bidi/bidiFirefox.js +17 -14
- package/lib/server/bidi/bidiInput.js +22 -22
- package/lib/server/bidi/bidiNetworkManager.js +8 -11
- package/lib/server/bidi/bidiPage.js +42 -86
- package/lib/server/bidi/third_party/bidiProtocol.js +5 -133
- package/lib/server/bidi/third_party/bidiProtocolCore.js +179 -0
- package/lib/server/{dispatchers/selectorsDispatcher.js → bidi/third_party/bidiProtocolPermissions.js} +20 -18
- package/lib/server/browser.js +30 -21
- package/lib/server/browserContext.js +203 -165
- package/lib/server/browserType.js +109 -107
- package/lib/server/chromium/chromium.js +84 -69
- package/lib/server/chromium/chromiumSwitches.js +13 -20
- package/lib/server/chromium/crBrowser.js +74 -40
- package/lib/server/chromium/crConnection.js +8 -9
- package/lib/server/chromium/crCoverage.js +11 -8
- package/lib/server/chromium/crDragDrop.js +25 -20
- package/lib/server/chromium/crExecutionContext.js +2 -1
- package/lib/server/chromium/crInput.js +32 -29
- package/lib/server/chromium/crNetworkManager.js +45 -33
- package/lib/server/chromium/crPage.js +98 -73
- package/lib/server/chromium/crServiceWorker.js +13 -18
- package/lib/server/chromium/videoRecorder.js +10 -18
- package/lib/server/clock.js +51 -39
- package/lib/server/codegen/csharp.js +10 -5
- package/lib/server/codegen/java.js +1 -1
- package/lib/server/codegen/javascript.js +1 -1
- package/lib/server/codegen/jsonl.js +2 -1
- package/lib/server/codegen/language.js +22 -1
- package/lib/server/codegen/languages.js +4 -4
- package/lib/server/codegen/python.js +1 -1
- package/lib/server/cookieStore.js +3 -1
- package/lib/server/debugController.js +105 -71
- package/lib/server/debugger.js +6 -23
- package/lib/server/deviceDescriptorsSource.json +237 -127
- package/lib/server/dialog.js +50 -6
- package/lib/server/dispatchers/androidDispatcher.js +77 -62
- package/lib/server/dispatchers/artifactDispatcher.js +18 -18
- package/lib/server/dispatchers/browserContextDispatcher.js +141 -91
- package/lib/server/dispatchers/browserDispatcher.js +55 -88
- package/lib/server/dispatchers/browserTypeDispatcher.js +18 -9
- package/lib/server/dispatchers/cdpSessionDispatcher.js +4 -4
- package/lib/server/dispatchers/debugControllerDispatcher.js +12 -21
- package/lib/server/dispatchers/dialogDispatcher.js +4 -4
- package/lib/server/dispatchers/dispatcher.js +78 -53
- package/lib/server/dispatchers/electronDispatcher.js +19 -20
- package/lib/server/dispatchers/elementHandlerDispatcher.js +83 -93
- package/lib/server/dispatchers/frameDispatcher.js +99 -102
- package/lib/server/dispatchers/jsHandleDispatcher.js +21 -16
- package/lib/server/dispatchers/jsonPipeDispatcher.js +4 -4
- package/lib/server/dispatchers/localUtilsDispatcher.js +53 -59
- package/lib/server/dispatchers/networkDispatchers.js +41 -35
- package/lib/server/dispatchers/pageDispatcher.js +156 -107
- package/lib/server/dispatchers/playwrightDispatcher.js +37 -25
- package/lib/server/dispatchers/streamDispatcher.js +15 -8
- package/lib/server/dispatchers/tracingDispatcher.js +22 -13
- package/lib/server/dispatchers/webSocketRouteDispatcher.js +46 -35
- package/lib/server/dispatchers/writableStreamDispatcher.js +16 -10
- package/lib/server/dom.js +198 -266
- package/lib/server/download.js +3 -3
- package/lib/server/electron/electron.js +96 -103
- package/lib/server/electron/loader.js +1 -1
- package/lib/server/fetch.js +22 -41
- package/lib/server/fileUploadUtils.js +1 -1
- package/lib/server/firefox/ffBrowser.js +79 -55
- package/lib/server/firefox/ffExecutionContext.js +2 -1
- package/lib/server/firefox/ffInput.js +23 -23
- package/lib/server/firefox/ffNetworkManager.js +8 -6
- package/lib/server/firefox/ffPage.js +39 -36
- package/lib/server/firefox/firefox.js +9 -10
- package/lib/server/frameSelectors.js +65 -22
- package/lib/server/frames.js +516 -544
- package/lib/server/har/harRecorder.js +1 -1
- package/lib/server/har/harTracer.js +4 -2
- package/lib/server/helper.js +3 -7
- package/lib/server/index.js +0 -3
- package/lib/server/input.js +47 -54
- package/lib/server/instrumentation.js +8 -14
- package/lib/server/javascript.js +9 -17
- package/lib/server/launchApp.js +48 -30
- package/lib/server/localUtils.js +45 -38
- package/lib/server/network.js +44 -10
- package/lib/server/page.js +233 -178
- package/lib/server/pageBinding.js +6 -7
- package/lib/server/playwright.js +4 -14
- package/lib/server/progress.js +57 -49
- package/lib/server/recorder/recorderApp.js +298 -95
- package/lib/server/recorder/recorderRunner.js +23 -24
- package/lib/server/recorder/recorderSignalProcessor.js +83 -0
- package/lib/server/recorder/recorderUtils.js +67 -10
- package/lib/server/recorder.js +284 -146
- package/lib/server/registry/index.js +83 -48
- package/lib/server/registry/nativeDeps.js +175 -0
- package/lib/server/registry/oopDownloadBrowserMain.js +1 -1
- package/lib/server/screenshotter.js +84 -83
- package/lib/server/selectors.js +12 -12
- package/lib/server/socksClientCertificatesInterceptor.js +198 -136
- package/lib/server/trace/recorder/snapshotter.js +12 -19
- package/lib/server/trace/recorder/tracing.js +36 -27
- package/lib/server/trace/viewer/traceViewer.js +11 -20
- package/lib/server/transport.js +20 -22
- package/lib/server/utils/comparators.js +2 -2
- package/lib/server/utils/debug.js +3 -8
- package/lib/server/utils/debugLogger.js +8 -0
- package/lib/server/utils/hostPlatform.js +3 -1
- package/lib/server/utils/network.js +35 -25
- package/lib/server/utils/nodePlatform.js +1 -1
- package/lib/server/utils/processLauncher.js +4 -1
- package/lib/server/utils/wsServer.js +11 -17
- package/lib/server/webkit/webkit.js +5 -2
- package/lib/server/webkit/wkBrowser.js +51 -28
- package/lib/server/webkit/wkExecutionContext.js +2 -1
- package/lib/server/webkit/wkInput.js +25 -25
- package/lib/server/webkit/wkInterceptableRequest.js +1 -1
- package/lib/server/webkit/wkPage.js +80 -59
- package/lib/server/webkit/wkProvisionalPage.js +1 -1
- package/lib/server/webkit/wkWorkers.js +7 -7
- package/lib/utils/isomorphic/ariaSnapshot.js +13 -7
- package/lib/utils/isomorphic/cssParser.js +1 -2
- package/lib/utils/isomorphic/locatorGenerators.js +18 -0
- package/lib/utils/isomorphic/manualPromise.js +1 -2
- package/lib/utils/isomorphic/mimeType.js +1 -2
- package/lib/utils/isomorphic/multimap.js +1 -2
- package/lib/utils/isomorphic/oldUtilityScriptSerializers.js +248 -0
- package/lib/utils/isomorphic/protocolFormatter.js +78 -0
- package/lib/utils/isomorphic/protocolMetainfo.js +318 -0
- package/lib/utils/isomorphic/selectorParser.js +3 -4
- package/lib/utils/isomorphic/stringUtils.js +3 -24
- package/lib/utils/isomorphic/time.js +9 -4
- package/lib/utils/isomorphic/timeoutRunner.js +3 -4
- package/lib/utils/isomorphic/traceUtils.js +2 -3
- package/lib/utils/isomorphic/urlMatch.js +21 -7
- package/lib/utils/isomorphic/utilityScriptSerializers.js +208 -205
- package/lib/utils.js +8 -2
- package/lib/utilsBundleImpl/index.js +160 -150
- package/lib/vite/htmlReport/index.html +17 -17
- package/lib/vite/recorder/assets/{codeMirrorModule-CXVeovup.js → codeMirrorModule-DzQ0k89p.js} +1 -1
- package/lib/vite/recorder/assets/{index-eHBmevrY.css → index-CI4HQ-Zb.css} +1 -1
- package/lib/vite/recorder/assets/index-D7C7daHH.js +184 -0
- package/lib/vite/recorder/index.html +3 -3
- package/lib/vite/traceViewer/assets/{codeMirrorModule-_GLjJL-7.js → codeMirrorModule-Di48jgWx.js} +1 -1
- package/lib/vite/traceViewer/assets/defaultSettingsView-szBn8781.js +256 -0
- package/lib/vite/traceViewer/defaultSettingsView.DVJHpiGt.css +1 -0
- package/lib/vite/traceViewer/index.BFsek2M6.css +1 -0
- package/lib/vite/traceViewer/index.DQvXoPLL.js +2 -0
- package/lib/vite/traceViewer/index.html +6 -6
- package/lib/vite/traceViewer/sw.bundle.js +3 -3
- package/lib/vite/traceViewer/uiMode.dBV3oN9h.js +5 -0
- package/lib/vite/traceViewer/uiMode.html +4 -4
- package/lib/zipBundleImpl.js +4 -4
- package/package.json +1 -1
- package/types/protocol.d.ts +712 -107
- package/types/types.d.ts +148 -37
- package/lib/generated/consoleApiSource.js +0 -28
- package/lib/protocol/debug.js +0 -211
- package/lib/server/recorder/contextRecorder.js +0 -286
- package/lib/server/recorder/recorderCollection.js +0 -116
- package/lib/server/recorder/recorderFrontend.js +0 -16
- package/lib/server/storageScript.js +0 -154
- package/lib/server/timeoutSettings.js +0 -89
- package/lib/utils/isomorphic/builtins.js +0 -86
- package/lib/vite/recorder/assets/index-BsWQsSGl.js +0 -184
- package/lib/vite/traceViewer/assets/defaultSettingsView-DtCQiGHe.js +0 -265
- package/lib/vite/traceViewer/defaultSettingsView.QdHITyLI.css +0 -1
- package/lib/vite/traceViewer/index.CFOW-Ezb.css +0 -1
- package/lib/vite/traceViewer/index.cFZzK9RN.js +0 -2
- package/lib/vite/traceViewer/uiMode.XVPIqBeS.js +0 -5
package/lib/cli/program.js
CHANGED
|
@@ -50,7 +50,7 @@ import_utilsBundle.program.command("mark-docker-image [dockerImageNameTemplate]"
|
|
|
50
50
|
(0, import_server.writeDockerVersion)(dockerImageNameTemplate).catch(logErrorAndExit);
|
|
51
51
|
});
|
|
52
52
|
commandWithOpenOptions("open [url]", "open page in browser specified via -b, --browser", []).action(function(url, options) {
|
|
53
|
-
open(options, url
|
|
53
|
+
open(options, url).catch(logErrorAndExit);
|
|
54
54
|
}).addHelpText("afterAll", `
|
|
55
55
|
Examples:
|
|
56
56
|
|
|
@@ -64,8 +64,8 @@ commandWithOpenOptions(
|
|
|
64
64
|
["--target <language>", `language to generate, one of javascript, playwright-test, python, python-async, python-pytest, csharp, csharp-mstest, csharp-nunit, java, java-junit`, codegenId()],
|
|
65
65
|
["--test-id-attribute <attributeName>", "use the specified attribute to generate data test ID selectors"]
|
|
66
66
|
]
|
|
67
|
-
).action(function(url, options) {
|
|
68
|
-
codegen(options, url)
|
|
67
|
+
).action(async function(url, options) {
|
|
68
|
+
await codegen(options, url);
|
|
69
69
|
}).addHelpText("afterAll", `
|
|
70
70
|
Examples:
|
|
71
71
|
|
|
@@ -113,7 +113,59 @@ function checkBrowsersToInstall(args, options) {
|
|
|
113
113
|
throw new Error(`Invalid installation targets: ${faultyArguments.map((name) => `'${name}'`).join(", ")}. Expecting one of: ${suggestedBrowsersToInstall()}`);
|
|
114
114
|
return executables;
|
|
115
115
|
}
|
|
116
|
-
|
|
116
|
+
function printInstalledBrowsers(browsers2) {
|
|
117
|
+
const browserPaths = /* @__PURE__ */ new Set();
|
|
118
|
+
for (const browser of browsers2)
|
|
119
|
+
browserPaths.add(browser.browserPath);
|
|
120
|
+
console.log(` Browsers:`);
|
|
121
|
+
for (const browserPath of [...browserPaths].sort())
|
|
122
|
+
console.log(` ${browserPath}`);
|
|
123
|
+
console.log(` References:`);
|
|
124
|
+
const references = /* @__PURE__ */ new Set();
|
|
125
|
+
for (const browser of browsers2)
|
|
126
|
+
references.add(browser.referenceDir);
|
|
127
|
+
for (const reference of [...references].sort())
|
|
128
|
+
console.log(` ${reference}`);
|
|
129
|
+
}
|
|
130
|
+
function printGroupedByPlaywrightVersion(browsers2) {
|
|
131
|
+
const dirToVersion = /* @__PURE__ */ new Map();
|
|
132
|
+
for (const browser of browsers2) {
|
|
133
|
+
if (dirToVersion.has(browser.referenceDir))
|
|
134
|
+
continue;
|
|
135
|
+
const packageJSON2 = require(import_path.default.join(browser.referenceDir, "package.json"));
|
|
136
|
+
const version = packageJSON2.version;
|
|
137
|
+
dirToVersion.set(browser.referenceDir, version);
|
|
138
|
+
}
|
|
139
|
+
const groupedByPlaywrightMinorVersion = /* @__PURE__ */ new Map();
|
|
140
|
+
for (const browser of browsers2) {
|
|
141
|
+
const version = dirToVersion.get(browser.referenceDir);
|
|
142
|
+
let entries = groupedByPlaywrightMinorVersion.get(version);
|
|
143
|
+
if (!entries) {
|
|
144
|
+
entries = [];
|
|
145
|
+
groupedByPlaywrightMinorVersion.set(version, entries);
|
|
146
|
+
}
|
|
147
|
+
entries.push(browser);
|
|
148
|
+
}
|
|
149
|
+
const sortedVersions = [...groupedByPlaywrightMinorVersion.keys()].sort((a, b) => {
|
|
150
|
+
const aComponents = a.split(".");
|
|
151
|
+
const bComponents = b.split(".");
|
|
152
|
+
const aMajor = parseInt(aComponents[0], 10);
|
|
153
|
+
const bMajor = parseInt(bComponents[0], 10);
|
|
154
|
+
if (aMajor !== bMajor)
|
|
155
|
+
return aMajor - bMajor;
|
|
156
|
+
const aMinor = parseInt(aComponents[1], 10);
|
|
157
|
+
const bMinor = parseInt(bComponents[1], 10);
|
|
158
|
+
if (aMinor !== bMinor)
|
|
159
|
+
return aMinor - bMinor;
|
|
160
|
+
return aComponents.slice(2).join(".").localeCompare(bComponents.slice(2).join("."));
|
|
161
|
+
});
|
|
162
|
+
for (const version of sortedVersions) {
|
|
163
|
+
console.log(`
|
|
164
|
+
Playwright version: ${version}`);
|
|
165
|
+
printInstalledBrowsers(groupedByPlaywrightMinorVersion.get(version));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
import_utilsBundle.program.command("install [browser...]").description("ensure browsers necessary for this version of Playwright are installed").option("--with-deps", "install system dependencies for browsers").option("--dry-run", "do not execute installation, only print information").option("--list", "prints list of browsers from all playwright installations").option("--force", "force reinstall of stable browser channels").option("--only-shell", "only install headless shell when installing chromium").option("--no-shell", "do not install chromium headless shell").action(async function(args, options) {
|
|
117
169
|
if (options.shell === false)
|
|
118
170
|
options.noShell = true;
|
|
119
171
|
if ((0, import_utils.isLikelyNpxGlobal)()) {
|
|
@@ -141,6 +193,8 @@ import_utilsBundle.program.command("install [browser...]").description("ensure b
|
|
|
141
193
|
const executables = hasNoArguments ? defaultBrowsersToInstall(options) : checkBrowsersToInstall(args, options);
|
|
142
194
|
if (options.withDeps)
|
|
143
195
|
await import_server.registry.installDeps(executables, !!options.dryRun);
|
|
196
|
+
if (options.dryRun && options.list)
|
|
197
|
+
throw new Error(`Only one of --dry-run and --list can be specified`);
|
|
144
198
|
if (options.dryRun) {
|
|
145
199
|
for (const executable of executables) {
|
|
146
200
|
const version = executable.browserVersion ? `version ` + executable.browserVersion : "";
|
|
@@ -154,6 +208,9 @@ import_utilsBundle.program.command("install [browser...]").description("ensure b
|
|
|
154
208
|
}
|
|
155
209
|
console.log(``);
|
|
156
210
|
}
|
|
211
|
+
} else if (options.list) {
|
|
212
|
+
const browsers2 = await import_server.registry.listInstalledBrowsers();
|
|
213
|
+
printGroupedByPlaywrightVersion(browsers2);
|
|
157
214
|
} else {
|
|
158
215
|
const forceReinstall = hasNoArguments ? false : !!options.force;
|
|
159
216
|
await import_server.registry.install(executables, forceReinstall);
|
|
@@ -210,7 +267,7 @@ const browsers = [
|
|
|
210
267
|
];
|
|
211
268
|
for (const { alias, name, type } of browsers) {
|
|
212
269
|
commandWithOpenOptions(`${alias} [url]`, `open page in ${name}`, []).action(function(url, options) {
|
|
213
|
-
open({ ...options, browser: type }, url
|
|
270
|
+
open({ ...options, browser: type }, url).catch(logErrorAndExit);
|
|
214
271
|
}).addHelpText("afterAll", `
|
|
215
272
|
Examples:
|
|
216
273
|
|
|
@@ -310,30 +367,6 @@ async function launchContext(options, extraOptions) {
|
|
|
310
367
|
if (options.proxyBypass)
|
|
311
368
|
launchOptions.proxy.bypass = options.proxyBypass;
|
|
312
369
|
}
|
|
313
|
-
const browser = await browserType.launch(launchOptions);
|
|
314
|
-
if (process.env.PWTEST_CLI_IS_UNDER_TEST) {
|
|
315
|
-
process._didSetSourcesForTest = (text) => {
|
|
316
|
-
process.stdout.write("\n-------------8<-------------\n");
|
|
317
|
-
process.stdout.write(text);
|
|
318
|
-
process.stdout.write("\n-------------8<-------------\n");
|
|
319
|
-
const autoExitCondition = process.env.PWTEST_CLI_AUTO_EXIT_WHEN;
|
|
320
|
-
if (autoExitCondition && text.includes(autoExitCondition))
|
|
321
|
-
closeBrowser();
|
|
322
|
-
};
|
|
323
|
-
const logs = [];
|
|
324
|
-
require("playwright-core/lib/utilsBundle").debug.log = (...args) => {
|
|
325
|
-
const line = require("util").format(...args) + "\n";
|
|
326
|
-
logs.push(line);
|
|
327
|
-
process.stderr.write(line);
|
|
328
|
-
};
|
|
329
|
-
browser.on("disconnected", () => {
|
|
330
|
-
const hasCrashLine = logs.some((line) => line.includes("process did exit:") && !line.includes("process did exit: exitCode=0, signal=null"));
|
|
331
|
-
if (hasCrashLine) {
|
|
332
|
-
process.stderr.write("Detected browser crash.\n");
|
|
333
|
-
(0, import_utils.gracefullyProcessExitDoNotHang)(1);
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
370
|
if (options.viewportSize) {
|
|
338
371
|
try {
|
|
339
372
|
const [width, height] = options.viewportSize.split(",").map((n) => +n);
|
|
@@ -374,7 +407,15 @@ async function launchContext(options, extraOptions) {
|
|
|
374
407
|
contextOptions.recordHar.urlFilter = options.saveHarGlob;
|
|
375
408
|
contextOptions.serviceWorkers = "block";
|
|
376
409
|
}
|
|
377
|
-
|
|
410
|
+
let browser;
|
|
411
|
+
let context;
|
|
412
|
+
if (options.userDataDir) {
|
|
413
|
+
context = await browserType.launchPersistentContext(options.userDataDir, { ...launchOptions, ...contextOptions });
|
|
414
|
+
browser = context.browser();
|
|
415
|
+
} else {
|
|
416
|
+
browser = await browserType.launch(launchOptions);
|
|
417
|
+
context = await browser.newContext(contextOptions);
|
|
418
|
+
}
|
|
378
419
|
let closingBrowser = false;
|
|
379
420
|
async function closeBrowser() {
|
|
380
421
|
if (closingBrowser)
|
|
@@ -408,44 +449,35 @@ async function launchContext(options, extraOptions) {
|
|
|
408
449
|
delete launchOptions.executablePath;
|
|
409
450
|
delete launchOptions.handleSIGINT;
|
|
410
451
|
delete contextOptions.deviceScaleFactor;
|
|
411
|
-
return { browser, browserName: browserType.name(), context, contextOptions, launchOptions };
|
|
452
|
+
return { browser, browserName: browserType.name(), context, contextOptions, launchOptions, closeBrowser };
|
|
412
453
|
}
|
|
413
454
|
async function openPage(context, url) {
|
|
414
|
-
|
|
455
|
+
let page = context.pages()[0];
|
|
456
|
+
if (!page)
|
|
457
|
+
page = await context.newPage();
|
|
415
458
|
if (url) {
|
|
416
459
|
if (import_fs.default.existsSync(url))
|
|
417
460
|
url = "file://" + import_path.default.resolve(url);
|
|
418
461
|
else if (!url.startsWith("http") && !url.startsWith("file://") && !url.startsWith("about:") && !url.startsWith("data:"))
|
|
419
462
|
url = "http://" + url;
|
|
420
|
-
await page.goto(url)
|
|
421
|
-
if (process.env.PWTEST_CLI_AUTO_EXIT_WHEN) {
|
|
422
|
-
} else {
|
|
423
|
-
throw error;
|
|
424
|
-
}
|
|
425
|
-
});
|
|
463
|
+
await page.goto(url);
|
|
426
464
|
}
|
|
427
465
|
return page;
|
|
428
466
|
}
|
|
429
|
-
async function open(options, url
|
|
430
|
-
const { context
|
|
431
|
-
await context._enableRecorder({
|
|
432
|
-
language,
|
|
433
|
-
launchOptions,
|
|
434
|
-
contextOptions,
|
|
435
|
-
device: options.device,
|
|
436
|
-
saveStorage: options.saveStorage,
|
|
437
|
-
handleSIGINT: false
|
|
438
|
-
});
|
|
467
|
+
async function open(options, url) {
|
|
468
|
+
const { context } = await launchContext(options, { headless: !!process.env.PWTEST_CLI_HEADLESS, executablePath: process.env.PWTEST_CLI_EXECUTABLE_PATH });
|
|
439
469
|
await openPage(context, url);
|
|
440
470
|
}
|
|
441
471
|
async function codegen(options, url) {
|
|
442
472
|
const { target: language, output: outputFile, testIdAttribute: testIdAttributeName } = options;
|
|
443
473
|
const tracesDir = import_path.default.join(import_os.default.tmpdir(), `playwright-recorder-trace-${Date.now()}`);
|
|
444
|
-
const { context, launchOptions, contextOptions } = await launchContext(options, {
|
|
474
|
+
const { context, browser, launchOptions, contextOptions, closeBrowser } = await launchContext(options, {
|
|
445
475
|
headless: !!process.env.PWTEST_CLI_HEADLESS,
|
|
446
476
|
executablePath: process.env.PWTEST_CLI_EXECUTABLE_PATH,
|
|
447
477
|
tracesDir
|
|
448
478
|
});
|
|
479
|
+
const donePromise = new import_utils.ManualPromise();
|
|
480
|
+
maybeSetupTestHooks(browser, closeBrowser, donePromise);
|
|
449
481
|
import_utilsBundle.dotenv.config({ path: "playwright.env" });
|
|
450
482
|
await context._enableRecorder({
|
|
451
483
|
language,
|
|
@@ -459,6 +491,40 @@ async function codegen(options, url) {
|
|
|
459
491
|
handleSIGINT: false
|
|
460
492
|
});
|
|
461
493
|
await openPage(context, url);
|
|
494
|
+
donePromise.resolve();
|
|
495
|
+
}
|
|
496
|
+
async function maybeSetupTestHooks(browser, closeBrowser, donePromise) {
|
|
497
|
+
if (!process.env.PWTEST_CLI_IS_UNDER_TEST)
|
|
498
|
+
return;
|
|
499
|
+
const logs = [];
|
|
500
|
+
require("playwright-core/lib/utilsBundle").debug.log = (...args) => {
|
|
501
|
+
const line = require("util").format(...args) + "\n";
|
|
502
|
+
logs.push(line);
|
|
503
|
+
process.stderr.write(line);
|
|
504
|
+
};
|
|
505
|
+
browser.on("disconnected", () => {
|
|
506
|
+
const hasCrashLine = logs.some((line) => line.includes("process did exit:") && !line.includes("process did exit: exitCode=0, signal=null"));
|
|
507
|
+
if (hasCrashLine) {
|
|
508
|
+
process.stderr.write("Detected browser crash.\n");
|
|
509
|
+
(0, import_utils.gracefullyProcessExitDoNotHang)(1);
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
const close = async () => {
|
|
513
|
+
await donePromise;
|
|
514
|
+
await closeBrowser();
|
|
515
|
+
};
|
|
516
|
+
if (process.env.PWTEST_CLI_EXIT_AFTER_TIMEOUT) {
|
|
517
|
+
setTimeout(close, +process.env.PWTEST_CLI_EXIT_AFTER_TIMEOUT);
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
let stdin = "";
|
|
521
|
+
process.stdin.on("data", (data) => {
|
|
522
|
+
stdin += data.toString();
|
|
523
|
+
if (stdin.startsWith("exit")) {
|
|
524
|
+
process.stdin.destroy();
|
|
525
|
+
close();
|
|
526
|
+
}
|
|
527
|
+
});
|
|
462
528
|
}
|
|
463
529
|
async function waitForPage(page, captureOptions) {
|
|
464
530
|
if (captureOptions.waitForSelector) {
|
|
@@ -545,7 +611,7 @@ function commandWithOpenOptions(command, description, options) {
|
|
|
545
611
|
let result = import_utilsBundle.program.command(command).description(description);
|
|
546
612
|
for (const option of options)
|
|
547
613
|
result = result.option(option[0], ...option.slice(1));
|
|
548
|
-
return result.option("-b, --browser <browserType>", "browser to use, one of cr, chromium, ff, firefox, wk, webkit", "chromium").option("--block-service-workers", "block service workers").option("--channel <channel>", 'Chromium distribution channel, "chrome", "chrome-beta", "msedge-dev", etc').option("--color-scheme <scheme>", 'emulate preferred color scheme, "light" or "dark"').option("--device <deviceName>", 'emulate device, for example "iPhone 11"').option("--geolocation <coordinates>", 'specify geolocation coordinates, for example "37.819722,-122.478611"').option("--ignore-https-errors", "ignore https errors").option("--load-storage <filename>", "load context storage state from the file, previously saved with --save-storage").option("--lang <language>", 'specify language / locale, for example "en-GB"').option("--proxy-server <proxy>", 'specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"').option("--proxy-bypass <bypass>", 'comma-separated domains to bypass proxy, for example ".com,chromium.org,.domain.com"').option("--save-har <filename>", "save HAR file with all network activity at the end").option("--save-har-glob <glob pattern>", "filter entries in the HAR by matching url against this glob pattern").option("--save-storage <filename>", "save context storage state at the end, for later use with --load-storage").option("--timezone <time zone>", 'time zone to emulate, for example "Europe/Rome"').option("--timeout <timeout>", "timeout for Playwright actions in milliseconds, no timeout by default").option("--user-agent <ua string>", "specify user agent string").option("--viewport-size <size>", 'specify browser viewport size in pixels, for example "1280, 720"');
|
|
614
|
+
return result.option("-b, --browser <browserType>", "browser to use, one of cr, chromium, ff, firefox, wk, webkit", "chromium").option("--block-service-workers", "block service workers").option("--channel <channel>", 'Chromium distribution channel, "chrome", "chrome-beta", "msedge-dev", etc').option("--color-scheme <scheme>", 'emulate preferred color scheme, "light" or "dark"').option("--device <deviceName>", 'emulate device, for example "iPhone 11"').option("--geolocation <coordinates>", 'specify geolocation coordinates, for example "37.819722,-122.478611"').option("--ignore-https-errors", "ignore https errors").option("--load-storage <filename>", "load context storage state from the file, previously saved with --save-storage").option("--lang <language>", 'specify language / locale, for example "en-GB"').option("--proxy-server <proxy>", 'specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"').option("--proxy-bypass <bypass>", 'comma-separated domains to bypass proxy, for example ".com,chromium.org,.domain.com"').option("--save-har <filename>", "save HAR file with all network activity at the end").option("--save-har-glob <glob pattern>", "filter entries in the HAR by matching url against this glob pattern").option("--save-storage <filename>", "save context storage state at the end, for later use with --load-storage").option("--timezone <time zone>", 'time zone to emulate, for example "Europe/Rome"').option("--timeout <timeout>", "timeout for Playwright actions in milliseconds, no timeout by default").option("--user-agent <ua string>", "specify user agent string").option("--user-data-dir <directory>", "use the specified user data directory instead of a new context").option("--viewport-size <size>", 'specify browser viewport size in pixels, for example "1280, 720"');
|
|
549
615
|
}
|
|
550
616
|
function buildBasePlaywrightCLICommand(cliTargetLang) {
|
|
551
617
|
switch (cliTargetLang) {
|
|
@@ -58,7 +58,7 @@ const kExternalPlaywrightTestCommands = [
|
|
|
58
58
|
];
|
|
59
59
|
function addExternalPlaywrightTestCommands() {
|
|
60
60
|
for (const [command, description] of kExternalPlaywrightTestCommands) {
|
|
61
|
-
const playwrightTest = import_program.program.command(command).allowUnknownOption(true);
|
|
61
|
+
const playwrightTest = import_program.program.command(command).allowUnknownOption(true).allowExcessArguments(true);
|
|
62
62
|
playwrightTest.description(`${description} Available in @playwright/test package.`);
|
|
63
63
|
playwrightTest.action(async () => {
|
|
64
64
|
printPlaywrightTestError(command);
|
package/lib/client/android.js
CHANGED
|
@@ -46,10 +46,6 @@ class Android extends import_channelOwner.ChannelOwner {
|
|
|
46
46
|
}
|
|
47
47
|
setDefaultTimeout(timeout) {
|
|
48
48
|
this._timeoutSettings.setDefaultTimeout(timeout);
|
|
49
|
-
this._wrapApiCall(async () => {
|
|
50
|
-
await this._channel.setDefaultTimeoutNoReply({ timeout });
|
|
51
|
-
}, true).catch(() => {
|
|
52
|
-
});
|
|
53
49
|
}
|
|
54
50
|
async devices(options = {}) {
|
|
55
51
|
const { devices } = await this._channel.devices(options);
|
|
@@ -64,7 +60,7 @@ class Android extends import_channelOwner.ChannelOwner {
|
|
|
64
60
|
return await this._wrapApiCall(async () => {
|
|
65
61
|
const deadline = options.timeout ? (0, import_time.monotonicTime)() + options.timeout : 0;
|
|
66
62
|
const headers = { "x-playwright-browser": "android", ...options.headers };
|
|
67
|
-
const connectParams = { wsEndpoint, headers, slowMo: options.slowMo, timeout: options.timeout };
|
|
63
|
+
const connectParams = { wsEndpoint, headers, slowMo: options.slowMo, timeout: options.timeout || 0 };
|
|
68
64
|
const connection = await (0, import_webSocket.connectOverWebSocket)(this._connection, connectParams);
|
|
69
65
|
let device;
|
|
70
66
|
connection.on("close", () => {
|
|
@@ -95,6 +91,7 @@ class AndroidDevice extends import_channelOwner.ChannelOwner {
|
|
|
95
91
|
super(parent, type, guid, initializer);
|
|
96
92
|
this._webViews = /* @__PURE__ */ new Map();
|
|
97
93
|
this._shouldCloseConnectionOnClose = false;
|
|
94
|
+
this._android = parent;
|
|
98
95
|
this.input = new AndroidInput(this);
|
|
99
96
|
this._timeoutSettings = new import_timeoutSettings.TimeoutSettings(this._platform, parent._timeoutSettings);
|
|
100
97
|
this._channel.on("webViewAdded", ({ webView }) => this._onWebViewAdded(webView));
|
|
@@ -117,10 +114,6 @@ class AndroidDevice extends import_channelOwner.ChannelOwner {
|
|
|
117
114
|
}
|
|
118
115
|
setDefaultTimeout(timeout) {
|
|
119
116
|
this._timeoutSettings.setDefaultTimeout(timeout);
|
|
120
|
-
this._wrapApiCall(async () => {
|
|
121
|
-
await this._channel.setDefaultTimeoutNoReply({ timeout });
|
|
122
|
-
}, true).catch(() => {
|
|
123
|
-
});
|
|
124
117
|
}
|
|
125
118
|
serial() {
|
|
126
119
|
return this._initializer.serial;
|
|
@@ -144,42 +137,42 @@ class AndroidDevice extends import_channelOwner.ChannelOwner {
|
|
|
144
137
|
return webView;
|
|
145
138
|
return await this.waitForEvent("webview", { ...options, predicate });
|
|
146
139
|
}
|
|
147
|
-
async wait(selector, options) {
|
|
148
|
-
await this._channel.wait({
|
|
140
|
+
async wait(selector, options = {}) {
|
|
141
|
+
await this._channel.wait({ androidSelector: toSelectorChannel(selector), ...options, timeout: this._timeoutSettings.timeout(options) });
|
|
149
142
|
}
|
|
150
|
-
async fill(selector, text, options) {
|
|
151
|
-
await this._channel.fill({
|
|
143
|
+
async fill(selector, text, options = {}) {
|
|
144
|
+
await this._channel.fill({ androidSelector: toSelectorChannel(selector), text, ...options, timeout: this._timeoutSettings.timeout(options) });
|
|
152
145
|
}
|
|
153
|
-
async press(selector, key, options) {
|
|
146
|
+
async press(selector, key, options = {}) {
|
|
154
147
|
await this.tap(selector, options);
|
|
155
148
|
await this.input.press(key);
|
|
156
149
|
}
|
|
157
|
-
async tap(selector, options) {
|
|
158
|
-
await this._channel.tap({
|
|
150
|
+
async tap(selector, options = {}) {
|
|
151
|
+
await this._channel.tap({ androidSelector: toSelectorChannel(selector), ...options, timeout: this._timeoutSettings.timeout(options) });
|
|
159
152
|
}
|
|
160
|
-
async drag(selector, dest, options) {
|
|
161
|
-
await this._channel.drag({
|
|
153
|
+
async drag(selector, dest, options = {}) {
|
|
154
|
+
await this._channel.drag({ androidSelector: toSelectorChannel(selector), dest, ...options, timeout: this._timeoutSettings.timeout(options) });
|
|
162
155
|
}
|
|
163
|
-
async fling(selector, direction, options) {
|
|
164
|
-
await this._channel.fling({
|
|
156
|
+
async fling(selector, direction, options = {}) {
|
|
157
|
+
await this._channel.fling({ androidSelector: toSelectorChannel(selector), direction, ...options, timeout: this._timeoutSettings.timeout(options) });
|
|
165
158
|
}
|
|
166
|
-
async longTap(selector, options) {
|
|
167
|
-
await this._channel.longTap({
|
|
159
|
+
async longTap(selector, options = {}) {
|
|
160
|
+
await this._channel.longTap({ androidSelector: toSelectorChannel(selector), ...options, timeout: this._timeoutSettings.timeout(options) });
|
|
168
161
|
}
|
|
169
|
-
async pinchClose(selector, percent, options) {
|
|
170
|
-
await this._channel.pinchClose({
|
|
162
|
+
async pinchClose(selector, percent, options = {}) {
|
|
163
|
+
await this._channel.pinchClose({ androidSelector: toSelectorChannel(selector), percent, ...options, timeout: this._timeoutSettings.timeout(options) });
|
|
171
164
|
}
|
|
172
|
-
async pinchOpen(selector, percent, options) {
|
|
173
|
-
await this._channel.pinchOpen({
|
|
165
|
+
async pinchOpen(selector, percent, options = {}) {
|
|
166
|
+
await this._channel.pinchOpen({ androidSelector: toSelectorChannel(selector), percent, ...options, timeout: this._timeoutSettings.timeout(options) });
|
|
174
167
|
}
|
|
175
|
-
async scroll(selector, direction, percent, options) {
|
|
176
|
-
await this._channel.scroll({
|
|
168
|
+
async scroll(selector, direction, percent, options = {}) {
|
|
169
|
+
await this._channel.scroll({ androidSelector: toSelectorChannel(selector), direction, percent, ...options, timeout: this._timeoutSettings.timeout(options) });
|
|
177
170
|
}
|
|
178
|
-
async swipe(selector, direction, percent, options) {
|
|
179
|
-
await this._channel.swipe({
|
|
171
|
+
async swipe(selector, direction, percent, options = {}) {
|
|
172
|
+
await this._channel.swipe({ androidSelector: toSelectorChannel(selector), direction, percent, ...options, timeout: this._timeoutSettings.timeout(options) });
|
|
180
173
|
}
|
|
181
174
|
async info(selector) {
|
|
182
|
-
return (await this._channel.info({
|
|
175
|
+
return (await this._channel.info({ androidSelector: toSelectorChannel(selector) })).info;
|
|
183
176
|
}
|
|
184
177
|
async screenshot(options = {}) {
|
|
185
178
|
const { binary } = await this._channel.screenshot();
|
|
@@ -222,7 +215,10 @@ class AndroidDevice extends import_channelOwner.ChannelOwner {
|
|
|
222
215
|
const contextOptions = await (0, import_browserContext.prepareBrowserContextParams)(this._platform, options);
|
|
223
216
|
const result = await this._channel.launchBrowser(contextOptions);
|
|
224
217
|
const context = import_browserContext.BrowserContext.from(result.context);
|
|
225
|
-
|
|
218
|
+
const selectors = this._android._playwright.selectors;
|
|
219
|
+
selectors._contextsForSelectors.add(context);
|
|
220
|
+
context.once(import_events.Events.BrowserContext.Close, () => selectors._contextsForSelectors.delete(context));
|
|
221
|
+
await context._initializeHarFromOptions(options.recordHar);
|
|
226
222
|
return context;
|
|
227
223
|
}
|
|
228
224
|
async waitForEvent(event, optionsOrPredicate = {}) {
|
|
@@ -323,8 +319,8 @@ function toSelectorChannel(selector) {
|
|
|
323
319
|
enabled,
|
|
324
320
|
focusable,
|
|
325
321
|
focused,
|
|
326
|
-
hasChild: hasChild ? {
|
|
327
|
-
hasDescendant: hasDescendant ? {
|
|
322
|
+
hasChild: hasChild ? { androidSelector: toSelectorChannel(hasChild.selector) } : void 0,
|
|
323
|
+
hasDescendant: hasDescendant ? { androidSelector: toSelectorChannel(hasDescendant.selector), maxDepth: hasDescendant.maxDepth } : void 0,
|
|
328
324
|
longClickable,
|
|
329
325
|
scrollable,
|
|
330
326
|
selected
|
package/lib/client/browser.js
CHANGED
|
@@ -36,6 +36,7 @@ class Browser extends import_channelOwner.ChannelOwner {
|
|
|
36
36
|
this._shouldCloseConnectionOnClose = false;
|
|
37
37
|
this._options = {};
|
|
38
38
|
this._name = initializer.name;
|
|
39
|
+
this._channel.on("context", ({ context }) => this._didCreateContext(import_browserContext.BrowserContext.from(context)));
|
|
39
40
|
this._channel.on("close", () => this._didClose());
|
|
40
41
|
this._closedPromise = new Promise((f) => this.once(import_events.Events.Browser.Disconnected, f));
|
|
41
42
|
}
|
|
@@ -49,29 +50,55 @@ class Browser extends import_channelOwner.ChannelOwner {
|
|
|
49
50
|
return await this._innerNewContext(options, false);
|
|
50
51
|
}
|
|
51
52
|
async _newContextForReuse(options = {}) {
|
|
52
|
-
return await this.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return await this._wrapApiCall(async () => {
|
|
64
|
-
await this._channel.stopPendingOperations({ reason });
|
|
65
|
-
}, true);
|
|
53
|
+
return await this._innerNewContext(options, true);
|
|
54
|
+
}
|
|
55
|
+
async _disconnectFromReusedContext(reason) {
|
|
56
|
+
const context = [...this._contexts].find((context2) => context2._forReuse);
|
|
57
|
+
if (!context)
|
|
58
|
+
return;
|
|
59
|
+
await this._instrumentation.runBeforeCloseBrowserContext(context);
|
|
60
|
+
for (const page of context.pages())
|
|
61
|
+
page._onClose();
|
|
62
|
+
context._onClose();
|
|
63
|
+
await this._channel.disconnectFromReusedContext({ reason });
|
|
66
64
|
}
|
|
67
65
|
async _innerNewContext(options = {}, forReuse) {
|
|
68
|
-
options =
|
|
66
|
+
options = this._browserType._playwright.selectors._withSelectorOptions({
|
|
67
|
+
...this._browserType._playwright._defaultContextOptions,
|
|
68
|
+
...options
|
|
69
|
+
});
|
|
69
70
|
const contextOptions = await (0, import_browserContext.prepareBrowserContextParams)(this._platform, options);
|
|
70
71
|
const response = forReuse ? await this._channel.newContextForReuse(contextOptions) : await this._channel.newContext(contextOptions);
|
|
71
72
|
const context = import_browserContext.BrowserContext.from(response.context);
|
|
72
|
-
|
|
73
|
+
if (forReuse)
|
|
74
|
+
context._forReuse = true;
|
|
75
|
+
if (options.logger)
|
|
76
|
+
context._logger = options.logger;
|
|
77
|
+
await context._initializeHarFromOptions(options.recordHar);
|
|
78
|
+
await this._instrumentation.runAfterCreateBrowserContext(context);
|
|
73
79
|
return context;
|
|
74
80
|
}
|
|
81
|
+
_connectToBrowserType(browserType, browserOptions, logger) {
|
|
82
|
+
this._browserType = browserType;
|
|
83
|
+
this._options = browserOptions;
|
|
84
|
+
this._logger = logger;
|
|
85
|
+
for (const context of this._contexts)
|
|
86
|
+
this._setupBrowserContext(context);
|
|
87
|
+
}
|
|
88
|
+
_didCreateContext(context) {
|
|
89
|
+
context._browser = this;
|
|
90
|
+
this._contexts.add(context);
|
|
91
|
+
if (this._browserType)
|
|
92
|
+
this._setupBrowserContext(context);
|
|
93
|
+
}
|
|
94
|
+
_setupBrowserContext(context) {
|
|
95
|
+
context._logger = this._logger;
|
|
96
|
+
context.tracing._tracesDir = this._options.tracesDir;
|
|
97
|
+
this._browserType._contexts.add(context);
|
|
98
|
+
this._browserType._playwright.selectors._contextsForSelectors.add(context);
|
|
99
|
+
context.setDefaultTimeout(this._browserType._playwright._defaultContextTimeout);
|
|
100
|
+
context.setDefaultNavigationTimeout(this._browserType._playwright._defaultContextNavigationTimeout);
|
|
101
|
+
}
|
|
75
102
|
contexts() {
|
|
76
103
|
return [...this._contexts];
|
|
77
104
|
}
|
|
@@ -85,7 +112,7 @@ class Browser extends import_channelOwner.ChannelOwner {
|
|
|
85
112
|
page._ownedContext = context;
|
|
86
113
|
context._ownerPage = page;
|
|
87
114
|
return page;
|
|
88
|
-
});
|
|
115
|
+
}, { title: "Create page" });
|
|
89
116
|
}
|
|
90
117
|
isConnected() {
|
|
91
118
|
return this._isConnected;
|
|
@@ -93,6 +120,16 @@ class Browser extends import_channelOwner.ChannelOwner {
|
|
|
93
120
|
async newBrowserCDPSession() {
|
|
94
121
|
return import_cdpSession.CDPSession.from((await this._channel.newBrowserCDPSession()).session);
|
|
95
122
|
}
|
|
123
|
+
async _launchServer(options = {}) {
|
|
124
|
+
const serverLauncher = this._browserType._serverLauncher;
|
|
125
|
+
const browserImpl = this._connection.toImpl?.(this);
|
|
126
|
+
if (!serverLauncher || !browserImpl)
|
|
127
|
+
throw new Error("Launching server is not supported");
|
|
128
|
+
return await serverLauncher.launchServerOnExistingBrowser(browserImpl, {
|
|
129
|
+
_sharedBrowser: true,
|
|
130
|
+
...options
|
|
131
|
+
});
|
|
132
|
+
}
|
|
96
133
|
async startTracing(page, options = {}) {
|
|
97
134
|
this._path = options.path;
|
|
98
135
|
await this._channel.startTracing({ ...options, page: page ? page._channel : void 0 });
|