brave-real-playwright-core 1.56.1 → 1.57.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.
Files changed (96) hide show
  1. package/README.md +5 -5
  2. package/advanced-stealth.js +1 -1
  3. package/lib/cli/program.js +14 -57
  4. package/lib/client/api.js +0 -3
  5. package/lib/client/browserContext.js +22 -4
  6. package/lib/client/consoleMessage.js +5 -1
  7. package/lib/client/electron.js +1 -1
  8. package/lib/client/events.js +2 -1
  9. package/lib/client/locator.js +4 -1
  10. package/lib/client/page.js +2 -5
  11. package/lib/client/playwright.js +1 -5
  12. package/lib/client/tracing.js +6 -4
  13. package/lib/client/worker.js +22 -0
  14. package/lib/generated/clockSource.js +1 -1
  15. package/lib/generated/injectedScriptSource.js +1 -1
  16. package/lib/generated/pollingRecorderSource.js +1 -1
  17. package/lib/inProcessFactory.js +0 -2
  18. package/lib/protocol/validator.js +24 -46
  19. package/lib/server/android/android.js +1 -1
  20. package/lib/server/bidi/bidiBrowser.js +26 -11
  21. package/lib/server/bidi/bidiChromium.js +1 -1
  22. package/lib/server/bidi/bidiFirefox.js +1 -1
  23. package/lib/server/bidi/bidiPage.js +25 -5
  24. package/lib/server/browserContext.js +9 -10
  25. package/lib/server/chromium/chromium.js +12 -1
  26. package/lib/server/chromium/chromiumSwitches.js +11 -2
  27. package/lib/server/chromium/crBrowser.js +8 -0
  28. package/lib/server/chromium/crPage.js +7 -7
  29. package/lib/server/chromium/crServiceWorker.js +16 -5
  30. package/lib/server/chromium/videoRecorder.js +14 -12
  31. package/lib/server/console.js +5 -1
  32. package/lib/server/deviceDescriptorsSource.json +56 -56
  33. package/lib/server/dispatchers/browserContextDispatcher.js +23 -6
  34. package/lib/server/dispatchers/pageDispatcher.js +10 -22
  35. package/lib/server/dispatchers/playwrightDispatcher.js +0 -4
  36. package/lib/server/electron/electron.js +1 -1
  37. package/lib/server/firefox/ffPage.js +3 -6
  38. package/lib/server/firefox/firefox.js +12 -1
  39. package/lib/server/frameSelectors.js +2 -4
  40. package/lib/server/frames.js +10 -3
  41. package/lib/server/input.js +7 -3
  42. package/lib/server/localUtils.js +4 -8
  43. package/lib/server/page.js +54 -40
  44. package/lib/server/playwright.js +2 -4
  45. package/lib/server/recorder/recorderApp.js +1 -1
  46. package/lib/server/recorder.js +3 -2
  47. package/lib/server/registry/index.js +113 -47
  48. package/lib/server/registry/oopDownloadBrowserMain.js +6 -2
  49. package/lib/server/socksClientCertificatesInterceptor.js +1 -1
  50. package/lib/server/trace/recorder/tracing.js +2 -0
  51. package/lib/server/trace/viewer/traceViewer.js +37 -36
  52. package/lib/server/utils/comparators.js +3 -25
  53. package/lib/server/utils/hostPlatform.js +15 -3
  54. package/lib/server/utils/imageUtils.js +141 -0
  55. package/lib/server/utils/network.js +22 -16
  56. package/lib/server/webkit/webkit.js +1 -10
  57. package/lib/server/webkit/wkPage.js +1 -5
  58. package/lib/server/webkit/wkWorkers.js +2 -1
  59. package/lib/utils/isomorphic/ariaSnapshot.js +5 -0
  60. package/lib/utils/isomorphic/locatorGenerators.js +24 -8
  61. package/lib/utils/isomorphic/mimeType.js +1 -1
  62. package/lib/utils/isomorphic/protocolFormatter.js +3 -0
  63. package/lib/utils/isomorphic/protocolMetainfo.js +2 -1
  64. package/lib/utils/isomorphic/urlMatch.js +19 -5
  65. package/lib/utils.js +2 -0
  66. package/lib/utilsBundle.js +6 -3
  67. package/lib/utilsBundleImpl/index.js +171 -171
  68. package/lib/vite/htmlReport/index.html +18 -18
  69. package/lib/vite/recorder/assets/codeMirrorModule-BoWUGj0J.js +25 -0
  70. package/lib/vite/recorder/assets/{index-Y-X2TGJv.js → index-DJqDAOZp.js} +32 -32
  71. package/lib/vite/recorder/index.html +1 -1
  72. package/lib/vite/traceViewer/assets/codeMirrorModule-Bucv2d7q.js +25 -0
  73. package/lib/vite/traceViewer/assets/defaultSettingsView-BEpdCv1S.js +266 -0
  74. package/lib/vite/traceViewer/defaultSettingsView.ConWv5KN.css +1 -0
  75. package/lib/vite/traceViewer/index.BxQ34UMZ.js +2 -0
  76. package/lib/vite/traceViewer/index.C4Y3Aw8n.css +1 -0
  77. package/lib/vite/traceViewer/index.html +6 -6
  78. package/lib/vite/traceViewer/manifest.webmanifest +16 -0
  79. package/lib/vite/traceViewer/snapshot.html +3 -3
  80. package/lib/vite/traceViewer/sw.bundle.js +3 -3
  81. package/lib/vite/traceViewer/{uiMode.DRQ310U5.js → uiMode.BWTwXl41.js} +3 -3
  82. package/lib/vite/traceViewer/uiMode.html +3 -3
  83. package/package.json +9 -9
  84. package/lib/client/accessibility.js +0 -49
  85. package/lib/server/accessibility.js +0 -69
  86. package/lib/server/chromium/crAccessibility.js +0 -263
  87. package/lib/server/firefox/ffAccessibility.js +0 -238
  88. package/lib/server/webkit/wkAccessibility.js +0 -237
  89. package/lib/server/webkit/wsl/webkit-wsl-transport-client.js +0 -74
  90. package/lib/server/webkit/wsl/webkit-wsl-transport-server.js +0 -113
  91. package/lib/vite/recorder/assets/codeMirrorModule-RJCXzfmE.js +0 -24
  92. package/lib/vite/traceViewer/assets/codeMirrorModule-eyVcHN77.js +0 -24
  93. package/lib/vite/traceViewer/assets/defaultSettingsView-w0zYjHsW.js +0 -265
  94. package/lib/vite/traceViewer/defaultSettingsView.TQ8_7ybu.css +0 -1
  95. package/lib/vite/traceViewer/index.Bx16ehp1.js +0 -2
  96. package/lib/vite/traceViewer/index.I8N9v4jT.css +0 -1
@@ -77,34 +77,72 @@ if (process.env.PW_TEST_CDN_THAT_SHOULD_WORK) {
77
77
  }
78
78
  const EXECUTABLE_PATHS = {
79
79
  "chromium": {
80
- "linux": ["chrome-linux", "chrome"],
81
- "mac": ["chrome-mac", "Chromium.app", "Contents", "MacOS", "Chromium"],
82
- "win": ["chrome-win", "chrome.exe"]
80
+ "<unknown>": void 0,
81
+ "linux-x64": ["chrome-linux64", "chrome"],
82
+ "linux-arm64": ["chrome-linux", "chrome"],
83
+ // non-cft build
84
+ "mac-x64": ["chrome-mac-x64", "Google Chrome for Testing.app", "Contents", "MacOS", "Google Chrome for Testing"],
85
+ "mac-arm64": ["chrome-mac-arm64", "Google Chrome for Testing.app", "Contents", "MacOS", "Google Chrome for Testing"],
86
+ "win-x64": ["chrome-win64", "chrome.exe"]
83
87
  },
84
88
  "chromium-headless-shell": {
85
- "linux": ["chrome-linux", "headless_shell"],
86
- "mac": ["chrome-mac", "headless_shell"],
87
- "win": ["chrome-win", "headless_shell.exe"]
89
+ "<unknown>": void 0,
90
+ "linux-x64": ["chrome-headless-shell-linux64", "chrome-headless-shell"],
91
+ "linux-arm64": ["chrome-linux", "headless_shell"],
92
+ // non-cft build
93
+ "mac-x64": ["chrome-headless-shell-mac-x64", "chrome-headless-shell"],
94
+ "mac-arm64": ["chrome-headless-shell-mac-arm64", "chrome-headless-shell"],
95
+ "win-x64": ["chrome-headless-shell-win64", "chrome-headless-shell.exe"]
96
+ },
97
+ "chromium-tip-of-tree": {
98
+ "<unknown>": void 0,
99
+ "linux-x64": ["chrome-linux64", "chrome"],
100
+ "linux-arm64": ["chrome-linux", "chrome"],
101
+ // non-cft build
102
+ "mac-x64": ["chrome-mac-x64", "Google Chrome for Testing.app", "Contents", "MacOS", "Google Chrome for Testing"],
103
+ "mac-arm64": ["chrome-mac-arm64", "Google Chrome for Testing.app", "Contents", "MacOS", "Google Chrome for Testing"],
104
+ "win-x64": ["chrome-win64", "chrome.exe"]
105
+ },
106
+ "chromium-tip-of-tree-headless-shell": {
107
+ "<unknown>": void 0,
108
+ "linux-x64": ["chrome-headless-shell-linux64", "chrome-headless-shell"],
109
+ "linux-arm64": ["chrome-linux", "headless_shell"],
110
+ // non-cft build
111
+ "mac-x64": ["chrome-headless-shell-mac-x64", "chrome-headless-shell"],
112
+ "mac-arm64": ["chrome-headless-shell-mac-arm64", "chrome-headless-shell"],
113
+ "win-x64": ["chrome-headless-shell-win64", "chrome-headless-shell.exe"]
88
114
  },
89
115
  "firefox": {
90
- "linux": ["firefox", "firefox"],
91
- "mac": ["firefox", "Nightly.app", "Contents", "MacOS", "firefox"],
92
- "win": ["firefox", "firefox.exe"]
116
+ "<unknown>": void 0,
117
+ "linux-x64": ["firefox", "firefox"],
118
+ "linux-arm64": ["firefox", "firefox"],
119
+ "mac-x64": ["firefox", "Nightly.app", "Contents", "MacOS", "firefox"],
120
+ "mac-arm64": ["firefox", "Nightly.app", "Contents", "MacOS", "firefox"],
121
+ "win-x64": ["firefox", "firefox.exe"]
93
122
  },
94
123
  "webkit": {
95
- "linux": ["pw_run.sh"],
96
- "mac": ["pw_run.sh"],
97
- "win": ["Playwright.exe"]
124
+ "<unknown>": void 0,
125
+ "linux-x64": ["pw_run.sh"],
126
+ "linux-arm64": ["pw_run.sh"],
127
+ "mac-x64": ["pw_run.sh"],
128
+ "mac-arm64": ["pw_run.sh"],
129
+ "win-x64": ["Playwright.exe"]
98
130
  },
99
131
  "ffmpeg": {
100
- "linux": ["ffmpeg-linux"],
101
- "mac": ["ffmpeg-mac"],
102
- "win": ["ffmpeg-win64.exe"]
132
+ "<unknown>": void 0,
133
+ "linux-x64": ["ffmpeg-linux"],
134
+ "linux-arm64": ["ffmpeg-linux"],
135
+ "mac-x64": ["ffmpeg-mac"],
136
+ "mac-arm64": ["ffmpeg-mac"],
137
+ "win-x64": ["ffmpeg-win64.exe"]
103
138
  },
104
139
  "winldd": {
105
- "linux": void 0,
106
- "mac": void 0,
107
- "win": ["PrintDeps.exe"]
140
+ "<unknown>": void 0,
141
+ "linux-x64": void 0,
142
+ "linux-arm64": void 0,
143
+ "mac-x64": void 0,
144
+ "mac-arm64": void 0,
145
+ "win-x64": ["PrintDeps.exe"]
108
146
  }
109
147
  };
110
148
  const DOWNLOAD_PATHS = {
@@ -417,10 +455,7 @@ const DOWNLOAD_PATHS = {
417
455
  "mac15": "builds/android/%s/android.zip",
418
456
  "mac15-arm64": "builds/android/%s/android.zip",
419
457
  "win64": "builds/android/%s/android.zip"
420
- },
421
- // TODO(bidi): implement downloads.
422
- "_bidiFirefox": {},
423
- "_bidiChromium": {}
458
+ }
424
459
  };
425
460
  const registryDirectory = (() => {
426
461
  let result;
@@ -482,13 +517,7 @@ class Registry {
482
517
  constructor(browsersJSON) {
483
518
  const descriptors = readDescriptors(browsersJSON);
484
519
  const findExecutablePath = (dir, name) => {
485
- let tokens = void 0;
486
- if (process.platform === "linux")
487
- tokens = EXECUTABLE_PATHS[name]["linux"];
488
- else if (process.platform === "darwin")
489
- tokens = EXECUTABLE_PATHS[name]["mac"];
490
- else if (process.platform === "win32")
491
- tokens = EXECUTABLE_PATHS[name]["win"];
520
+ const tokens = EXECUTABLE_PATHS[name][import_hostPlatform.shortPlatform];
492
521
  return tokens ? import_path.default.join(dir, ...tokens) : void 0;
493
522
  };
494
523
  const executablePathOrDie = (name, e, installByDefault, sdkLanguage) => {
@@ -555,7 +584,7 @@ ${(0, import_ascii.wrapInASCIIBox)(prettyMessage, 1)}`);
555
584
  _isHermeticInstallation: true
556
585
  });
557
586
  const chromiumTipOfTreeHeadlessShell = descriptors.find((d) => d.name === "chromium-tip-of-tree-headless-shell");
558
- const chromiumTipOfTreeHeadlessShellExecutable = findExecutablePath(chromiumTipOfTreeHeadlessShell.dir, "chromium-headless-shell");
587
+ const chromiumTipOfTreeHeadlessShellExecutable = findExecutablePath(chromiumTipOfTreeHeadlessShell.dir, "chromium-tip-of-tree-headless-shell");
559
588
  this._executables.push({
560
589
  type: "channel",
561
590
  name: "chromium-tip-of-tree-headless-shell",
@@ -572,7 +601,7 @@ ${(0, import_ascii.wrapInASCIIBox)(prettyMessage, 1)}`);
572
601
  _isHermeticInstallation: true
573
602
  });
574
603
  const chromiumTipOfTree = descriptors.find((d) => d.name === "chromium-tip-of-tree");
575
- const chromiumTipOfTreeExecutable = findExecutablePath(chromiumTipOfTree.dir, "chromium");
604
+ const chromiumTipOfTreeExecutable = findExecutablePath(chromiumTipOfTree.dir, "chromium-tip-of-tree");
576
605
  this._executables.push({
577
606
  type: "tool",
578
607
  name: "chromium-tip-of-tree",
@@ -674,9 +703,9 @@ ${(0, import_ascii.wrapInASCIIBox)(prettyMessage, 1)}`);
674
703
  "win32": `\\Google\\Chrome SxS\\Application\\chrome.exe`
675
704
  }));
676
705
  this._executables.push({
677
- type: "browser",
678
- name: "_bidiChromium",
679
- browserName: "_bidiChromium",
706
+ type: "channel",
707
+ name: "bidi-chromium",
708
+ browserName: "chromium",
680
709
  directory: chromium.dir,
681
710
  executablePath: () => chromiumExecutable,
682
711
  executablePathOrDie: (sdkLanguage) => executablePathOrDie("chromium", chromiumExecutable, chromium.installByDefault, sdkLanguage),
@@ -754,9 +783,8 @@ ${(0, import_ascii.wrapInASCIIBox)(prettyMessage, 1)}`);
754
783
  name: "webkit-wsl",
755
784
  browserName: "webkit",
756
785
  directory: webkit.dir,
757
- executablePath: () => process.execPath,
758
- executablePathOrDie: () => process.execPath,
759
- wslExecutablePath: `/home/pwuser/.cache/ms-playwright/webkit-${webkit.revision}/pw_run.sh`,
786
+ executablePath: () => webkitExecutable,
787
+ executablePathOrDie: (sdkLanguage) => executablePathOrDie("webkit", webkitExecutable, webkit.installByDefault, sdkLanguage),
760
788
  installType: "download-on-demand",
761
789
  _validateHostRequirements: (sdkLanguage) => Promise.resolve(),
762
790
  _isHermeticInstallation: true,
@@ -887,13 +915,14 @@ Run "${buildPlaywrightCLICommand(sdkLanguage, "install " + name)}"` : "";
887
915
  return executablePath2;
888
916
  }
889
917
  if (shouldThrow)
890
- throw new Error(`Cannot find Firefox installation for channel '${name}' at the standard system paths.`);
918
+ throw new Error(`Cannot find Firefox installation for channel '${name}' at the standard system paths. ${`Tried paths:
919
+ ${prefixes.map((p) => import_path.default.join(p, suffix)).join("\n ")}`}`);
891
920
  return void 0;
892
921
  };
893
922
  return {
894
923
  type: "channel",
895
924
  name,
896
- browserName: "_bidiFirefox",
925
+ browserName: "firefox",
897
926
  directory: void 0,
898
927
  executablePath: (sdkLanguage) => executablePath(sdkLanguage, false),
899
928
  executablePathOrDie: (sdkLanguage) => executablePath(sdkLanguage, true),
@@ -934,7 +963,7 @@ Run "${buildPlaywrightCLICommand(sdkLanguage, "install " + name)}"` : "";
934
963
  return {
935
964
  type: "channel",
936
965
  name,
937
- browserName: "_bidiChromium",
966
+ browserName: "chromium",
938
967
  directory: void 0,
939
968
  executablePath: (sdkLanguage) => executablePath(sdkLanguage, false),
940
969
  executablePathOrDie: (sdkLanguage) => executablePath(sdkLanguage, true),
@@ -975,7 +1004,7 @@ Run "${buildPlaywrightCLICommand(sdkLanguage, "install " + name)}"` : "";
975
1004
  if (import_os.default.platform() === "linux")
976
1005
  return await (0, import_dependencies2.installDependenciesLinux)(targets, dryRun);
977
1006
  }
978
- async install(executablesToInstall, forceReinstall) {
1007
+ async install(executablesToInstall, options) {
979
1008
  const executables = this._dedupe(executablesToInstall);
980
1009
  await import_fs.default.promises.mkdir(registryDirectory, { recursive: true });
981
1010
  const lockfilePath = import_path.default.join(registryDirectory, "__dirlock");
@@ -1003,7 +1032,7 @@ Run "${buildPlaywrightCLICommand(sdkLanguage, "install " + name)}"` : "";
1003
1032
  if (!executable._install)
1004
1033
  throw new Error(`ERROR: Playwright does not support installing ${executable.name}`);
1005
1034
  const { embedderName } = (0, import_userAgent.getEmbedderName)();
1006
- if (!(0, import_utils.getAsBooleanFromENV)("CI") && !executable._isHermeticInstallation && !forceReinstall && executable.executablePath(embedderName)) {
1035
+ if (!(0, import_utils.getAsBooleanFromENV)("CI") && !executable._isHermeticInstallation && !options?.force && executable.executablePath(embedderName)) {
1007
1036
  const command = buildPlaywrightCLICommand(embedderName, "install --force " + executable.name);
1008
1037
  process.stderr.write("\n" + (0, import_ascii.wrapInASCIIBox)([
1009
1038
  `ATTENTION: "${executable.name}" is already installed on the system!`,
@@ -1247,6 +1276,47 @@ ${e.stack}`);
1247
1276
  await import_fs.default.promises.unlink(linkPath).catch((e) => {
1248
1277
  });
1249
1278
  }
1279
+ _defaultBrowsersToInstall(options) {
1280
+ let executables = this.defaultExecutables();
1281
+ if (options.shell === "no")
1282
+ executables = executables.filter((e) => e.name !== "chromium-headless-shell");
1283
+ if (options.shell === "only")
1284
+ executables = executables.filter((e) => e.name !== "chromium");
1285
+ return executables;
1286
+ }
1287
+ suggestedBrowsersToInstall() {
1288
+ return this.executables().filter((e) => e.installType !== "none" && e.type !== "tool").map((e) => e.name).join(", ");
1289
+ }
1290
+ resolveBrowsers(aliases, options) {
1291
+ if (aliases.length === 0)
1292
+ return this._defaultBrowsersToInstall(options);
1293
+ const faultyArguments = [];
1294
+ const executables = [];
1295
+ const handleArgument = (arg) => {
1296
+ const executable = this.findExecutable(arg);
1297
+ if (!executable || executable.installType === "none")
1298
+ faultyArguments.push(arg);
1299
+ else
1300
+ executables.push(executable);
1301
+ if (executable?.browserName === "chromium")
1302
+ executables.push(this.findExecutable("ffmpeg"));
1303
+ };
1304
+ for (const alias of aliases) {
1305
+ if (alias === "chromium") {
1306
+ if (options.shell !== "only")
1307
+ handleArgument("chromium");
1308
+ if (options.shell !== "no")
1309
+ handleArgument("chromium-headless-shell");
1310
+ } else {
1311
+ handleArgument(alias);
1312
+ }
1313
+ }
1314
+ if (process.platform === "win32")
1315
+ executables.push(this.findExecutable("winldd"));
1316
+ if (faultyArguments.length)
1317
+ throw new Error(`Invalid installation targets: ${faultyArguments.map((name) => `'${name}'`).join(", ")}. Expecting one of: ${this.suggestedBrowsersToInstall()}`);
1318
+ return executables;
1319
+ }
1250
1320
  }
1251
1321
  function browserDirectoryToMarkerFilePath(browserDirectory) {
1252
1322
  return import_path.default.join(browserDirectory, "INSTALLATION_COMPLETE");
@@ -1279,11 +1349,7 @@ async function installBrowsersForNpmInstall(browsers) {
1279
1349
  throw new Error(`Cannot install ${browserName}`);
1280
1350
  executables.push(executable);
1281
1351
  }
1282
- await registry.install(
1283
- executables,
1284
- false
1285
- /* forceReinstall */
1286
- );
1352
+ await registry.install(executables);
1287
1353
  }
1288
1354
  function findChromiumChannelBestEffort(sdkLanguage) {
1289
1355
  let channel = null;
@@ -41,6 +41,7 @@ function browserDirectoryToMarkerFilePath(browserDirectory) {
41
41
  function downloadFile(options) {
42
42
  let downloadedBytes = 0;
43
43
  let totalBytes = 0;
44
+ let chunked = false;
44
45
  const promise = new import_manualPromise.ManualPromise();
45
46
  (0, import_network.httpRequest)({
46
47
  url: options.url,
@@ -60,11 +61,13 @@ function downloadFile(options) {
60
61
  response.on("data", (chunk) => content += chunk).on("end", handleError).on("error", handleError);
61
62
  return;
62
63
  }
64
+ chunked = response.headers["transfer-encoding"] === "chunked";
65
+ log(`-- is chunked: ${chunked}`);
63
66
  totalBytes = parseInt(response.headers["content-length"] || "0", 10);
64
67
  log(`-- total bytes: ${totalBytes}`);
65
68
  const file = import_fs.default.createWriteStream(options.zipPath);
66
69
  file.on("finish", () => {
67
- if (downloadedBytes !== totalBytes) {
70
+ if (!chunked && downloadedBytes !== totalBytes) {
68
71
  log(`-- download failed, size mismatch: ${downloadedBytes} != ${totalBytes}`);
69
72
  promise.reject(new Error(`Download failed: size mismatch, file size: ${downloadedBytes}, expected size: ${totalBytes} URL: ${options.url}`));
70
73
  } else {
@@ -89,7 +92,8 @@ function downloadFile(options) {
89
92
  return promise;
90
93
  function onData(chunk) {
91
94
  downloadedBytes += chunk.length;
92
- progress(downloadedBytes, totalBytes);
95
+ if (!chunked)
96
+ progress(downloadedBytes, totalBytes);
93
97
  }
94
98
  }
95
99
  async function main(options) {
@@ -82,7 +82,7 @@ class SocksProxyConnection {
82
82
  async connect() {
83
83
  const proxyAgent = this.socksProxy.getProxyAgent(this.host, this.port);
84
84
  if (proxyAgent)
85
- this._serverEncrypted = await proxyAgent.callback(new import_events.EventEmitter(), { host: rewriteToLocalhostIfNeeded(this.host), port: this.port, secureEndpoint: false });
85
+ this._serverEncrypted = await proxyAgent.connect(new import_events.EventEmitter(), { host: rewriteToLocalhostIfNeeded(this.host), port: this.port, secureEndpoint: false });
86
86
  else
87
87
  this._serverEncrypted = await (0, import_happyEyeballs.createSocket)(rewriteToLocalhostIfNeeded(this.host), this.port);
88
88
  this._serverEncrypted.once("close", this._serverCloseEventListener);
@@ -40,6 +40,7 @@ var import_assert = require("../../../utils/isomorphic/assert");
40
40
  var import_time = require("../../../utils/isomorphic/time");
41
41
  var import_eventsHelper = require("../../utils/eventsHelper");
42
42
  var import_crypto = require("../../utils/crypto");
43
+ var import_userAgent = require("../../utils/userAgent");
43
44
  var import_artifact = require("../../artifact");
44
45
  var import_browserContext = require("../../browserContext");
45
46
  var import_dispatcher = require("../../dispatchers/dispatcher");
@@ -74,6 +75,7 @@ class Tracing extends import_instrumentation.SdkObject {
74
75
  type: "context-options",
75
76
  origin: "library",
76
77
  browserName: "",
78
+ playwrightVersion: (0, import_userAgent.getPlaywrightVersion)(),
77
79
  options: {},
78
80
  platform: process.platform,
79
81
  wallTime: 0,
@@ -46,13 +46,21 @@ var import_launchApp = require("../../launchApp");
46
46
  var import_launchApp2 = require("../../launchApp");
47
47
  var import_playwright = require("../../playwright");
48
48
  var import_progress = require("../../progress");
49
- function validateTraceUrls(traceUrls) {
50
- for (const traceUrl of traceUrls) {
51
- let traceFile = traceUrl;
52
- if (traceUrl.endsWith(".json"))
53
- traceFile = traceUrl.substring(0, traceUrl.length - ".json".length);
54
- if (!traceUrl.startsWith("http://") && !traceUrl.startsWith("https://") && !import_fs.default.existsSync(traceFile) && !import_fs.default.existsSync(traceFile + ".trace"))
55
- throw new Error(`Trace file ${traceUrl} does not exist!`);
49
+ const tracesDirMarker = "traces.dir";
50
+ function validateTraceUrl(traceUrl) {
51
+ if (!traceUrl)
52
+ return traceUrl;
53
+ if (traceUrl.startsWith("http://") || traceUrl.startsWith("https://"))
54
+ return traceUrl;
55
+ if (traceUrl.endsWith(".json"))
56
+ return traceUrl;
57
+ try {
58
+ const stat = import_fs.default.statSync(traceUrl);
59
+ if (stat.isDirectory())
60
+ return import_path.default.join(traceUrl, tracesDirMarker);
61
+ return traceUrl;
62
+ } catch {
63
+ throw new Error(`Trace file ${traceUrl} does not exist!`);
56
64
  }
57
65
  }
58
66
  async function startTraceViewerServer(options) {
@@ -60,24 +68,18 @@ async function startTraceViewerServer(options) {
60
68
  server.routePrefix("/trace", (request, response) => {
61
69
  const url = new URL("http://localhost" + request.url);
62
70
  const relativePath = url.pathname.slice("/trace".length);
63
- if (process.env.PW_HMR) {
64
- response.appendHeader("Access-Control-Allow-Origin", "http://localhost:44223");
65
- }
66
- if (relativePath.endsWith("/stall.js"))
67
- return true;
68
71
  if (relativePath.startsWith("/file")) {
69
72
  try {
70
73
  const filePath = url.searchParams.get("path");
71
74
  if (import_fs.default.existsSync(filePath))
72
75
  return server.serveFile(request, response, url.searchParams.get("path"));
73
76
  if (filePath.endsWith(".json")) {
74
- const traceName = filePath.substring(0, filePath.length - ".json".length);
75
- response.statusCode = 200;
76
- response.setHeader("Content-Type", "application/json");
77
- response.end(JSON.stringify(traceDescriptor(traceName)));
78
- return true;
77
+ const fullPrefix = filePath.substring(0, filePath.length - ".json".length);
78
+ return sendTraceDescriptor(response, import_path.default.dirname(fullPrefix), import_path.default.basename(fullPrefix));
79
79
  }
80
- } catch (e) {
80
+ if (filePath.endsWith(tracesDirMarker))
81
+ return sendTraceDescriptor(response, import_path.default.dirname(filePath));
82
+ } catch {
81
83
  }
82
84
  response.statusCode = 404;
83
85
  response.end();
@@ -93,11 +95,11 @@ async function startTraceViewerServer(options) {
93
95
  await server.start({ preferredPort: port, host });
94
96
  return server;
95
97
  }
96
- async function installRootRedirect(server, traceUrls, options) {
98
+ async function installRootRedirect(server, traceUrl, options) {
97
99
  const params = new URLSearchParams();
98
100
  if (import_path.default.sep !== import_path.default.posix.sep)
99
101
  params.set("pathSeparator", import_path.default.sep);
100
- for (const traceUrl of traceUrls)
102
+ if (traceUrl)
101
103
  params.append("trace", traceUrl);
102
104
  if (server.wsGuid())
103
105
  params.append("ws", server.wsGuid());
@@ -115,12 +117,7 @@ async function installRootRedirect(server, traceUrls, options) {
115
117
  params.append("project", project);
116
118
  for (const reporter of options.reporter || [])
117
119
  params.append("reporter", reporter);
118
- let baseUrl = ".";
119
- if (process.env.PW_HMR) {
120
- baseUrl = "http://localhost:44223";
121
- params.set("server", server.urlPrefix("precise"));
122
- }
123
- const urlPath = `${baseUrl}/trace/${options.webApp || "index.html"}?${params.toString()}`;
120
+ const urlPath = `./trace/${options.webApp || "index.html"}?${params.toString()}`;
124
121
  server.routePath("/", (_, response) => {
125
122
  response.statusCode = 302;
126
123
  response.setHeader("Location", urlPath);
@@ -128,19 +125,19 @@ async function installRootRedirect(server, traceUrls, options) {
128
125
  return true;
129
126
  });
130
127
  }
131
- async function runTraceViewerApp(traceUrls, browserName, options, exitOnClose) {
132
- validateTraceUrls(traceUrls);
128
+ async function runTraceViewerApp(traceUrl, browserName, options, exitOnClose) {
129
+ traceUrl = validateTraceUrl(traceUrl);
133
130
  const server = await startTraceViewerServer(options);
134
- await installRootRedirect(server, traceUrls, options);
131
+ await installRootRedirect(server, traceUrl, options);
135
132
  const page = await openTraceViewerApp(server.urlPrefix("precise"), browserName, options);
136
133
  if (exitOnClose)
137
134
  page.on("close", () => (0, import_utils.gracefullyProcessExitDoNotHang)(0));
138
135
  return page;
139
136
  }
140
- async function runTraceInBrowser(traceUrls, options) {
141
- validateTraceUrls(traceUrls);
137
+ async function runTraceInBrowser(traceUrl, options) {
138
+ traceUrl = validateTraceUrl(traceUrl);
142
139
  const server = await startTraceViewerServer(options);
143
- await installRootRedirect(server, traceUrls, options);
140
+ await installRootRedirect(server, traceUrl, options);
144
141
  await openTraceInBrowser(server.urlPrefix("human-readable"));
145
142
  }
146
143
  async function openTraceViewerApp(url, browserName, options) {
@@ -212,14 +209,18 @@ class StdinServer {
212
209
  }, 500);
213
210
  }
214
211
  }
215
- function traceDescriptor(traceName) {
212
+ function sendTraceDescriptor(response, traceDir, tracePrefix) {
213
+ response.statusCode = 200;
214
+ response.setHeader("Content-Type", "application/json");
215
+ response.end(JSON.stringify(traceDescriptor(traceDir, tracePrefix)));
216
+ return true;
217
+ }
218
+ function traceDescriptor(traceDir, tracePrefix) {
216
219
  const result = {
217
220
  entries: []
218
221
  };
219
- const traceDir = import_path.default.dirname(traceName);
220
- const traceFile = import_path.default.basename(traceName);
221
222
  for (const name of import_fs.default.readdirSync(traceDir)) {
222
- if (name.startsWith(traceFile))
223
+ if (!tracePrefix || name.startsWith(tracePrefix))
223
224
  result.entries.push({ name, path: import_path.default.join(traceDir, name) });
224
225
  }
225
226
  const resourcesDir = import_path.default.join(traceDir, "resources");
@@ -37,6 +37,7 @@ var import_pixelmatch = __toESM(require("../../third_party/pixelmatch"));
37
37
  var import_utilsBundle = require("../../utilsBundle");
38
38
  var import_utilsBundle2 = require("../../utilsBundle");
39
39
  var import_utilsBundle3 = require("../../utilsBundle");
40
+ var import_imageUtils = require("./imageUtils");
40
41
  function getComparator(mimeType) {
41
42
  if (mimeType === "image/png")
42
43
  return compareImages.bind(null, "image/png");
@@ -66,8 +67,8 @@ function compareImages(mimeType, actualBuffer, expectedBuffer, options = {}) {
66
67
  let sizesMismatchError = "";
67
68
  if (expected.width !== actual.width || expected.height !== actual.height) {
68
69
  sizesMismatchError = `Expected an image ${expected.width}px by ${expected.height}px, received ${actual.width}px by ${actual.height}px. `;
69
- actual = resizeImage(actual, size);
70
- expected = resizeImage(expected, size);
70
+ actual = (0, import_imageUtils.padImageToSize)(actual, size);
71
+ expected = (0, import_imageUtils.padImageToSize)(expected, size);
71
72
  }
72
73
  const diff2 = new import_utilsBundle3.PNG({ width: size.width, height: size.height });
73
74
  let count;
@@ -131,29 +132,6 @@ function compareText(actual, expectedBuffer) {
131
132
  const errorMessage = coloredLines.join("\n");
132
133
  return { errorMessage };
133
134
  }
134
- function resizeImage(image, size) {
135
- if (image.width === size.width && image.height === size.height)
136
- return image;
137
- const buffer = new Uint8Array(size.width * size.height * 4);
138
- for (let y = 0; y < size.height; y++) {
139
- for (let x = 0; x < size.width; x++) {
140
- const to = (y * size.width + x) * 4;
141
- if (y < image.height && x < image.width) {
142
- const from = (y * image.width + x) * 4;
143
- buffer[to] = image.data[from];
144
- buffer[to + 1] = image.data[from + 1];
145
- buffer[to + 2] = image.data[from + 2];
146
- buffer[to + 3] = image.data[from + 3];
147
- } else {
148
- buffer[to] = 0;
149
- buffer[to + 1] = 0;
150
- buffer[to + 2] = 0;
151
- buffer[to + 3] = 0;
152
- }
153
- }
154
- }
155
- return { data: Buffer.from(buffer), width: size.width, height: size.height };
156
- }
157
135
  // Annotate the CommonJS export names for ESM import in node:
158
136
  0 && (module.exports = {
159
137
  compareBuffersOrStrings,
@@ -29,7 +29,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  var hostPlatform_exports = {};
30
30
  __export(hostPlatform_exports, {
31
31
  hostPlatform: () => hostPlatform,
32
- isOfficiallySupportedPlatform: () => isOfficiallySupportedPlatform
32
+ isOfficiallySupportedPlatform: () => isOfficiallySupportedPlatform,
33
+ shortPlatform: () => shortPlatform
33
34
  });
34
35
  module.exports = __toCommonJS(hostPlatform_exports);
35
36
  var import_os = __toESM(require("os"));
@@ -97,15 +98,26 @@ function calculatePlatform() {
97
98
  if (distroInfo?.version === "")
98
99
  return { hostPlatform: "debian13" + archSuffix, isOfficiallySupportedPlatform: isOfficiallySupportedPlatform2 };
99
100
  }
100
- return { hostPlatform: "ubuntu20.04" + archSuffix, isOfficiallySupportedPlatform: false };
101
+ return { hostPlatform: "ubuntu24.04" + archSuffix, isOfficiallySupportedPlatform: false };
101
102
  }
102
103
  if (platform === "win32")
103
104
  return { hostPlatform: "win64", isOfficiallySupportedPlatform: true };
104
105
  return { hostPlatform: "<unknown>", isOfficiallySupportedPlatform: false };
105
106
  }
106
107
  const { hostPlatform, isOfficiallySupportedPlatform } = calculatePlatform();
108
+ function toShortPlatform(hostPlatform2) {
109
+ if (hostPlatform2 === "<unknown>")
110
+ return "<unknown>";
111
+ if (hostPlatform2 === "win64")
112
+ return "win-x64";
113
+ if (hostPlatform2.startsWith("mac"))
114
+ return hostPlatform2.endsWith("arm64") ? "mac-arm64" : "mac-x64";
115
+ return hostPlatform2.endsWith("arm64") ? "linux-arm64" : "linux-x64";
116
+ }
117
+ const shortPlatform = toShortPlatform(hostPlatform);
107
118
  // Annotate the CommonJS export names for ESM import in node:
108
119
  0 && (module.exports = {
109
120
  hostPlatform,
110
- isOfficiallySupportedPlatform
121
+ isOfficiallySupportedPlatform,
122
+ shortPlatform
111
123
  });