@vitest/browser-playwright 5.0.0-beta.6 → 5.0.0-beta.7

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 (2) hide show
  1. package/dist/index.js +110 -20
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -847,11 +847,102 @@ function playwright(options = {}) {
847
847
  name: "playwright",
848
848
  supportedBrowser: playwrightBrowsers,
849
849
  options,
850
+ prewarm(ctx) {
851
+ prewarmBrowser(ctx, options);
852
+ },
850
853
  providerFactory(project) {
851
854
  return new PlaywrightBrowserProvider(project, options);
852
855
  }
853
856
  });
854
857
  }
858
+ // The resolved config object is passed unchanged to the eventual TestProject,
859
+ // so it identifies the browser this project can adopt.
860
+ const warmBrowsers = new WeakMap();
861
+ const pendingWarmBrowsers = new WeakMap();
862
+ // starts importing playwright and launching the browser while the node side
863
+ // is still creating the vite server, so the launch latency overlaps it. The
864
+ // launch options are resolved by the same code as the real launch — if they
865
+ // still differ by the time the provider opens the browser, the warm instance
866
+ // is discarded, so this is always safe
867
+ function prewarmBrowser(project, options) {
868
+ const browserName = project.config.browser.name;
869
+ if (options.connectOptions || options.persistentContext || project.vitest.config.inspector.enabled) {
870
+ return;
871
+ }
872
+ if (!browserName || !playwrightBrowsers.includes(browserName)) {
873
+ return;
874
+ }
875
+ if (warmBrowsers.has(project.config)) {
876
+ return;
877
+ }
878
+ let pending = pendingWarmBrowsers.get(project.vitest);
879
+ if (!pending) {
880
+ const pendingBrowsers = new Set();
881
+ pending = pendingBrowsers;
882
+ pendingWarmBrowsers.set(project.vitest, pendingBrowsers);
883
+ // Browsers whose projects never initialize a provider (they have no test
884
+ // files to run) are cleaned up when Vitest closes.
885
+ project.vitest.onClose(() => closeWarmBrowsers(pendingBrowsers));
886
+ }
887
+ const launchOptions = resolveLaunchOptions(project.config.browser, project.vitest.config.inspector, options, browserName);
888
+ const entry = {
889
+ launchOptionsJson: JSON.stringify(launchOptions),
890
+ pending,
891
+ promise: (async () => {
892
+ debug?.("[%s] prewarming the browser", browserName);
893
+ const playwright = await import('playwright');
894
+ return playwright[browserName].launch(launchOptions);
895
+ })()
896
+ };
897
+ // if the warm launch fails, drop it so the real launch retries
898
+ // and surfaces the error through the normal path
899
+ entry.promise.catch(() => {
900
+ if (warmBrowsers.get(project.config) === entry) {
901
+ warmBrowsers.delete(project.config);
902
+ entry.pending.delete(entry);
903
+ }
904
+ });
905
+ pending.add(entry);
906
+ warmBrowsers.set(project.config, entry);
907
+ }
908
+ function takeWarmBrowser(config) {
909
+ const warm = warmBrowsers.get(config);
910
+ if (warm) {
911
+ warmBrowsers.delete(config);
912
+ warm.pending.delete(warm);
913
+ }
914
+ return warm;
915
+ }
916
+ async function closeWarmBrowsers(pending) {
917
+ const closing = Array.from(pending, (warm) => warm.promise.then((browser) => browser.close()).catch(() => {}));
918
+ pending.clear();
919
+ await Promise.all(closing);
920
+ }
921
+ function resolveLaunchOptions(browser, inspector, providerOptions, browserName) {
922
+ const launchOptions = {
923
+ ...providerOptions.launchOptions,
924
+ headless: browser.headless
925
+ };
926
+ if (typeof browser.trace === "object" && browser.trace.tracesDir) {
927
+ launchOptions.tracesDir = browser.trace.tracesDir;
928
+ }
929
+ if (inspector.enabled) {
930
+ // NodeJS equivalent defaults: https://nodejs.org/en/learn/getting-started/debugging#enable-inspector
931
+ const port = inspector.port || 9229;
932
+ launchOptions.args ||= [];
933
+ launchOptions.args.push(`--remote-debugging-port=${port}`);
934
+ }
935
+ // start Vitest UI maximized only on supported browsers
936
+ if (browser.ui && browserName === "chromium") {
937
+ if (!launchOptions.args) {
938
+ launchOptions.args = [];
939
+ }
940
+ if (!launchOptions.args.includes("--start-maximized") && !launchOptions.args.includes("--start-fullscreen")) {
941
+ launchOptions.args.push("--start-maximized");
942
+ }
943
+ }
944
+ return launchOptions;
945
+ }
855
946
  class PlaywrightBrowserProvider {
856
947
  name = "playwright";
857
948
  supportsParallelism = true;
@@ -901,36 +992,17 @@ class PlaywrightBrowserProvider {
901
992
  return this.browser;
902
993
  }
903
994
  this.browserPromise = (async () => {
904
- const options = this.project.config.browser;
905
995
  const playwright = await import('playwright');
906
- const launchOptions = {
907
- ...this.options.launchOptions,
908
- headless: options.headless
909
- };
910
- if (typeof options.trace === "object" && options.trace.tracesDir) {
911
- launchOptions.tracesDir = options.trace?.tracesDir;
912
- }
996
+ const launchOptions = resolveLaunchOptions(this.project.config.browser, this.project.vitest.config.inspector, this.options, this.browserName);
913
997
  const inspector = this.project.vitest.config.inspector;
914
998
  if (inspector.enabled) {
915
- // NodeJS equivalent defaults: https://nodejs.org/en/learn/getting-started/debugging#enable-inspector
916
999
  const port = inspector.port || 9229;
917
1000
  const host = inspector.host || "127.0.0.1";
918
- launchOptions.args ||= [];
919
- launchOptions.args.push(`--remote-debugging-port=${port}`);
920
1001
  if (host !== "localhost" && host !== "127.0.0.1" && host !== "::1") {
921
1002
  this.project.vitest.logger.warn(`Custom inspector host "${host}" will be ignored. Chromium only allows remote debugging on localhost.`);
922
1003
  }
923
1004
  this.project.vitest.logger.log(`Debugger listening on ws://127.0.0.1:${port}`);
924
1005
  }
925
- // start Vitest UI maximized only on supported browsers
926
- if (this.project.config.browser.ui && this.browserName === "chromium") {
927
- if (!launchOptions.args) {
928
- launchOptions.args = [];
929
- }
930
- if (!launchOptions.args.includes("--start-maximized") && !launchOptions.args.includes("--start-fullscreen")) {
931
- launchOptions.args.push("--start-maximized");
932
- }
933
- }
934
1006
  debug?.("[%s] initializing the browser with launch options: %O", this.browserName, launchOptions);
935
1007
  if (this.options.connectOptions) {
936
1008
  let { wsEndpoint, headers = {}, ...connectOptions } = this.options.connectOptions;
@@ -963,6 +1035,19 @@ class PlaywrightBrowserProvider {
963
1035
  });
964
1036
  this.browser = this.persistentContext.browser();
965
1037
  } else {
1038
+ const warm = takeWarmBrowser(this.project.config);
1039
+ if (warm && warm.launchOptionsJson === JSON.stringify(launchOptions)) {
1040
+ const browser = await warm.promise.catch(() => null);
1041
+ if (browser?.isConnected()) {
1042
+ debug?.("[%s] adopting the prewarmed browser", this.browserName);
1043
+ this.browser = browser;
1044
+ this.browserPromise = null;
1045
+ return this.browser;
1046
+ }
1047
+ } else if (warm) {
1048
+ debug?.("[%s] discarding the prewarmed browser, launch options changed", this.browserName);
1049
+ void warm.promise.then((browser) => browser.close()).catch(() => {});
1050
+ }
966
1051
  this.browser = await playwright[this.browserName].launch(launchOptions);
967
1052
  }
968
1053
  this.browserPromise = null;
@@ -1217,6 +1302,11 @@ class PlaywrightBrowserProvider {
1217
1302
  process.off("SIGTERM", this.onSIGTERM);
1218
1303
  debug?.("[%s] closing provider", this.browserName);
1219
1304
  this.closing = true;
1305
+ // a prewarmed browser that was never adopted must not outlive the provider
1306
+ const warm = takeWarmBrowser(this.project.config);
1307
+ if (warm) {
1308
+ void warm.promise.then((browser) => browser.close()).catch(() => {});
1309
+ }
1220
1310
  if (this.browserPromise) {
1221
1311
  await this.browserPromise;
1222
1312
  this.browserPromise = null;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/browser-playwright",
3
3
  "type": "module",
4
- "version": "5.0.0-beta.6",
4
+ "version": "5.0.0-beta.7",
5
5
  "description": "Browser running for Vitest using playwright",
6
6
  "license": "MIT",
7
7
  "funding": "https://opencollective.com/vitest",
@@ -42,7 +42,7 @@
42
42
  ],
43
43
  "peerDependencies": {
44
44
  "playwright": "*",
45
- "vitest": "5.0.0-beta.6"
45
+ "vitest": "5.0.0-beta.7"
46
46
  },
47
47
  "peerDependenciesMeta": {
48
48
  "playwright": {
@@ -51,12 +51,12 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "tinyrainbow": "^3.1.0",
54
- "@vitest/browser": "5.0.0-beta.6",
55
- "@vitest/mocker": "5.0.0-beta.6"
54
+ "@vitest/browser": "5.0.0-beta.7",
55
+ "@vitest/mocker": "5.0.0-beta.7"
56
56
  },
57
57
  "devDependencies": {
58
58
  "playwright": "^1.61.0",
59
- "vitest": "5.0.0-beta.6"
59
+ "vitest": "5.0.0-beta.7"
60
60
  },
61
61
  "scripts": {
62
62
  "build": "premove dist && pnpm rollup -c",