@vitest/browser-playwright 5.0.0-beta.6 → 5.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -847,12 +847,105 @@ 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 {
947
+ project;
948
+ options;
856
949
  name = "playwright";
857
950
  supportsParallelism = true;
858
951
  browser = null;
@@ -901,36 +994,17 @@ class PlaywrightBrowserProvider {
901
994
  return this.browser;
902
995
  }
903
996
  this.browserPromise = (async () => {
904
- const options = this.project.config.browser;
905
997
  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
- }
998
+ const launchOptions = resolveLaunchOptions(this.project.config.browser, this.project.vitest.config.inspector, this.options, this.browserName);
913
999
  const inspector = this.project.vitest.config.inspector;
914
1000
  if (inspector.enabled) {
915
- // NodeJS equivalent defaults: https://nodejs.org/en/learn/getting-started/debugging#enable-inspector
916
1001
  const port = inspector.port || 9229;
917
1002
  const host = inspector.host || "127.0.0.1";
918
- launchOptions.args ||= [];
919
- launchOptions.args.push(`--remote-debugging-port=${port}`);
920
1003
  if (host !== "localhost" && host !== "127.0.0.1" && host !== "::1") {
921
1004
  this.project.vitest.logger.warn(`Custom inspector host "${host}" will be ignored. Chromium only allows remote debugging on localhost.`);
922
1005
  }
923
1006
  this.project.vitest.logger.log(`Debugger listening on ws://127.0.0.1:${port}`);
924
1007
  }
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
1008
  debug?.("[%s] initializing the browser with launch options: %O", this.browserName, launchOptions);
935
1009
  if (this.options.connectOptions) {
936
1010
  let { wsEndpoint, headers = {}, ...connectOptions } = this.options.connectOptions;
@@ -963,6 +1037,19 @@ class PlaywrightBrowserProvider {
963
1037
  });
964
1038
  this.browser = this.persistentContext.browser();
965
1039
  } else {
1040
+ const warm = takeWarmBrowser(this.project.config);
1041
+ if (warm && warm.launchOptionsJson === JSON.stringify(launchOptions)) {
1042
+ const browser = await warm.promise.catch(() => null);
1043
+ if (browser?.isConnected()) {
1044
+ debug?.("[%s] adopting the prewarmed browser", this.browserName);
1045
+ this.browser = browser;
1046
+ this.browserPromise = null;
1047
+ return this.browser;
1048
+ }
1049
+ } else if (warm) {
1050
+ debug?.("[%s] discarding the prewarmed browser, launch options changed", this.browserName);
1051
+ void warm.promise.then((browser) => browser.close()).catch(() => {});
1052
+ }
966
1053
  this.browser = await playwright[this.browserName].launch(launchOptions);
967
1054
  }
968
1055
  this.browserPromise = null;
@@ -1021,8 +1108,8 @@ class PlaywrightBrowserProvider {
1021
1108
  idPredicates.set(key, predicate);
1022
1109
  await page.context().route(predicate, async (route) => {
1023
1110
  if (module.type === "manual") {
1024
- const exports$1 = Object.keys(await module.resolve());
1025
- const body = createManualModuleSource(module.url, exports$1);
1111
+ const exports = Object.keys(await module.resolve());
1112
+ const body = createManualModuleSource(module.url, exports);
1026
1113
  return route.fulfill({
1027
1114
  body,
1028
1115
  headers: getHeaders(this.project.browser.vite.config)
@@ -1217,6 +1304,11 @@ class PlaywrightBrowserProvider {
1217
1304
  process.off("SIGTERM", this.onSIGTERM);
1218
1305
  debug?.("[%s] closing provider", this.browserName);
1219
1306
  this.closing = true;
1307
+ // a prewarmed browser that was never adopted must not outlive the provider
1308
+ const warm = takeWarmBrowser(this.project.config);
1309
+ if (warm) {
1310
+ void warm.promise.then((browser) => browser.close()).catch(() => {});
1311
+ }
1220
1312
  if (this.browserPromise) {
1221
1313
  await this.browserPromise;
1222
1314
  this.browserPromise = null;
package/dist/locators.js CHANGED
@@ -3,6 +3,8 @@ import { page, server } from 'vitest/browser';
3
3
  import { __INTERNAL } from 'vitest/internal/browser';
4
4
 
5
5
  class PlaywrightLocator extends Locator {
6
+ selector;
7
+ _container;
6
8
  constructor(selector, _container) {
7
9
  super();
8
10
  this.selector = selector;
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-rc.1",
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-rc.1"
46
46
  },
47
47
  "peerDependenciesMeta": {
48
48
  "playwright": {
@@ -50,13 +50,13 @@
50
50
  }
51
51
  },
52
52
  "dependencies": {
53
- "tinyrainbow": "^3.1.0",
54
- "@vitest/browser": "5.0.0-beta.6",
55
- "@vitest/mocker": "5.0.0-beta.6"
53
+ "tinyrainbow": "^3.1.1",
54
+ "@vitest/browser": "5.0.0-rc.1",
55
+ "@vitest/mocker": "5.0.0-rc.1"
56
56
  },
57
57
  "devDependencies": {
58
- "playwright": "^1.61.0",
59
- "vitest": "5.0.0-beta.6"
58
+ "playwright": "^1.62.1",
59
+ "vitest": "5.0.0-rc.1"
60
60
  },
61
61
  "scripts": {
62
62
  "build": "premove dist && pnpm rollup -c",