@interfere/test-utils 9.0.4 → 9.1.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.
@@ -26,7 +26,7 @@ declare const _default: {
26
26
  deviceScaleFactor: number;
27
27
  isMobile: boolean;
28
28
  hasTouch: boolean;
29
- defaultBrowserType: "chromium" | "firefox" | "webkit";
29
+ defaultBrowserType: 'chromium' | 'firefox' | 'webkit';
30
30
  };
31
31
  } | {
32
32
  name: string;
@@ -34,7 +34,7 @@ declare const _default: {
34
34
  use: {
35
35
  userAgent: string;
36
36
  deviceScaleFactor: number;
37
- defaultBrowserType: "chromium" | "firefox" | "webkit";
37
+ defaultBrowserType: 'chromium' | 'firefox' | 'webkit';
38
38
  viewport: {
39
39
  readonly width: 390;
40
40
  readonly height: 844;
@@ -1 +1 @@
1
- import{COMMON,DESKTOP,MOBILE}from"../lib/tags.mjs";import{MOBILE as MOBILE$1}from"../lib/viewports.mjs";import{devices}from"@playwright/test";const ci=!!process.env.CI,chromiumExecutablePath=process.env.CHROMIUM_EXECUTABLE_PATH;var base_default={fullyParallel:!0,forbidOnly:ci,retries:ci?2:0,reporter:ci?[[`github`],[`junit`,{outputFile:`./test-results/e2e-junit.xml`}]]:[[`html`]],use:{trace:`on-first-retry`,screenshot:`only-on-failure`,...ci&&{actionTimeout:1e4},...chromiumExecutablePath&&{launchOptions:{executablePath:chromiumExecutablePath}}},...ci&&{expect:{timeout:1e4}},projects:[{name:`desktop`,grep:RegExp(`${DESKTOP}|${COMMON}`),use:{...devices[`Desktop Chrome`]}},{name:`mobile`,grep:RegExp(`${MOBILE}|${COMMON}`),use:{...devices[`Desktop Chrome`],viewport:MOBILE$1,isMobile:!0,hasTouch:!0}}]};export{base_default as default};
1
+ import{COMMON,DESKTOP,MOBILE}from"../lib/tags.mjs";import{MOBILE as MOBILE$1}from"../lib/viewports.mjs";import{devices}from"@playwright/test";const ci=!!process.env.CI,chromiumExecutablePath=process.env.CHROMIUM_EXECUTABLE_PATH;var base_default={fullyParallel:!0,forbidOnly:ci,retries:ci?2:0,reporter:ci?[[`github`],[`junit`,{outputFile:`./test-results/e2e-junit.xml`}]]:[[`html`]],use:{trace:`on-first-retry`,screenshot:`only-on-failure`,...ci&&{actionTimeout:1e4},...chromiumExecutablePath&&{launchOptions:{executablePath:chromiumExecutablePath}}},...ci&&{expect:{timeout:1e4}},projects:[{name:`desktop`,grep:RegExp(`${DESKTOP}|${COMMON}`,`u`),use:{...devices[`Desktop Chrome`]}},{name:`mobile`,grep:RegExp(`${MOBILE}|${COMMON}`,`u`),use:{...devices[`Desktop Chrome`],viewport:MOBILE$1,isMobile:!0,hasTouch:!0}}]};export{base_default as default};
@@ -1,5 +1,5 @@
1
1
  import { PlaywrightTestConfig } from "@playwright/test";
2
2
  //#region src/playwright/define-config.d.ts
3
- declare function defineConfig(...overrides: Array<Partial<PlaywrightTestConfig> | undefined>): PlaywrightTestConfig<{}, {}>;
3
+ declare function defineConfig(...overrides: (Partial<PlaywrightTestConfig> | undefined)[]): PlaywrightTestConfig<{}, {}>;
4
4
  //#endregion
5
5
  export { defineConfig };
@@ -40,12 +40,12 @@ declare const _default: {
40
40
  include: string[];
41
41
  exclude: string[];
42
42
  reportOnFailure: true;
43
- reporter: ("json" | "json-summary" | "lcov")[] | ("clover" | "html" | "json" | "text")[];
43
+ reporter: ("html" | "lcov" | "text-summary")[] | ("json" | "json-summary" | "lcov")[];
44
44
  };
45
- setupFiles?: string[];
46
- outputFile?: {
45
+ outputFile: {
47
46
  junit: string;
48
47
  };
48
+ setupFiles: string[];
49
49
  };
50
50
  };
51
51
  //#endregion
@@ -1 +1 @@
1
- import{omitUndefined}from"@interfere/helpers/omit-undefined";import{existsSync}from"node:fs";import{resolve}from"node:path";import{config}from"dotenv";import{configDefaults}from"vitest/config";const root=process.cwd(),isCI=!!process.env.CI,env=config({path:resolve(root,`.env.test`),quiet:!0}).parsed??{},setupFiles=[`./test/setup.ts`,`./test/unit/setup.ts`].filter(rel=>existsSync(resolve(root,rel)));var base_default={root,resolve:{conditions:[`monorepo`]},ssr:{resolve:{conditions:[`monorepo`]}},test:{env:{...env,NODE_ENV:`test`},environment:`node`,globals:!0,isolate:!0,pool:`forks`,maxWorkers:`50%`,clearMocks:!0,restoreMocks:!0,ui:!!process.env.UI,unstubEnvs:!0,unstubGlobals:!0,sequence:{shuffle:!isCI},server:{deps:{inline:[`zod`]}},include:[`src/**/*.{test,spec}.?(c|m)[jt]s?(x)`,`test/**/*.{test,spec}.?(c|m)[jt]s?(x)`],exclude:[`test/e2e/**/*.{test,spec}.?(c|m)[jt]s?(x)`,...configDefaults.exclude],reporters:isCI?[`default`,`junit`]:[`default`],coverage:{enabled:!0,provider:`v8`,include:[`src/**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}`],exclude:[`**/*.json`,...configDefaults.coverage?.exclude??[]],reportOnFailure:!0,reporter:isCI?[`json`,`json-summary`,`lcov`]:[`text`,`html`,`clover`,`json`]},...omitUndefined({setupFiles:setupFiles.length>0?setupFiles:void 0,outputFile:isCI?{junit:`./test-results/junit.xml`}:void 0})}};export{base_default as default};
1
+ import{existsSync}from"node:fs";import path from"node:path";import{config}from"dotenv";import{configDefaults}from"vitest/config";const root=process.cwd(),isCI=!!process.env.CI,env=config({path:path.resolve(root,`.env.test`),quiet:!0}).parsed??{},setupFiles=[`./test/setup.ts`,`./test/unit/setup.ts`].filter(rel=>existsSync(path.resolve(root,rel)));var base_default={root,resolve:{conditions:[`monorepo`]},ssr:{resolve:{conditions:[`monorepo`]}},test:{env:{...env,NODE_ENV:`test`},environment:`node`,globals:!0,isolate:!0,pool:`forks`,maxWorkers:`50%`,clearMocks:!0,restoreMocks:!0,ui:!!process.env.UI,unstubEnvs:!0,unstubGlobals:!0,sequence:{shuffle:!isCI},server:{deps:{inline:[`zod`]}},include:[`src/**/*.{test,spec}.?(c|m)[jt]s?(x)`,`test/**/*.{test,spec}.?(c|m)[jt]s?(x)`],exclude:[`test/e2e/**/*.{test,spec}.?(c|m)[jt]s?(x)`,...configDefaults.exclude],reporters:[`default`,`junit`],coverage:{enabled:!0,provider:`v8`,include:[`src/**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}`],exclude:[`**/*.json`,...configDefaults.coverage?.exclude??[]],reportOnFailure:!0,reporter:isCI?[`json`,`json-summary`,`lcov`]:[`text-summary`,`html`,`lcov`]},outputFile:{junit:`./test-results/junit.xml`},setupFiles}};export{base_default as default};
@@ -1,5 +1,5 @@
1
1
  import { ViteUserConfig } from "vitest/config";
2
2
  //#region src/vitest/define-config.d.ts
3
- declare function defineConfig(...overrides: Array<Partial<ViteUserConfig> | undefined>): ViteUserConfig;
3
+ declare function defineConfig(...overrides: (Partial<ViteUserConfig> | undefined)[]): ViteUserConfig;
4
4
  //#endregion
5
5
  export { defineConfig };
@@ -1,4 +1,4 @@
1
- import{dirname,join}from"node:path";import{execFile}from"node:child_process";import{mkdir,mkdtemp,readFile,rename,rm,symlink}from"node:fs/promises";import{tmpdir}from"node:os";import{fileURLToPath}from"node:url";import{promisify}from"node:util";import{expect}from"vitest";const execFileAsync=promisify(execFile),PACKED_LINE=/^packed\s+\S+\s+(.+)$/,TGZ_LINE=/^(\S+\.tgz)$/,PACKAGE_CONTRACT_TIMEOUT_MS=3e4;async function expectPackedPackageFiles({expectedFiles,packageJsonUrl}){let packedPackage=await createPackedPackage(packageJsonUrl);try{expect(packedPackage.files).toEqual(expect.arrayContaining(expectedFiles)),expect(packedPackage.files.filter(path=>path.startsWith(`src/`))).toEqual([]),expect(packedPackage.files.filter(path=>path.endsWith(`.map`))).toEqual([]),expect(packedPackage.packageJson.private).toBeUndefined(),expect(Object.keys(packedPackage.packageJson.devDependencies??{})).not.toContain(`@interfere/tsdown-config`)}finally{await packedPackage.cleanup()}}async function expectNodeCanLoadPackageSpecifiers({packageJsonUrl,specifiers}){let packedPackage=await createPackedPackage(packageJsonUrl);try{await runNodeScript({args:[`--input-type=module`,`--eval`,importScript(specifiers)],cwd:packedPackage.consumerDir,label:`ESM import`}),await runNodeScript({args:[`--eval`,requireScript(specifiers)],cwd:packedPackage.consumerDir,label:`CommonJS require`})}finally{await packedPackage.cleanup()}}async function createPackedPackage(packageJsonUrl){let packageDir=dirname(fileURLToPath(packageJsonUrl)),tempDir=await mkdtemp(join(tmpdir(),`interfere-package-contract-`)),consumerDir=join(tempDir,`consumer`),nodeModulesDir=join(consumerDir,`node_modules`),packageJson=JSON.parse(await readFile(packageJsonUrl,`utf8`)),installedPackageDir=joinPackageName(nodeModulesDir,packageJson.name);await mkdir(dirname(installedPackageDir),{recursive:!0});let{stdout}=await execFileAsync(`bun`,[`pm`,`pack`,`--ignore-scripts`],{cwd:packageDir}),{filename,files}=parseBunPackOutput(stdout),tarballPath=join(packageDir,filename),extractedDir=join(tempDir,`extracted`);await mkdir(extractedDir),await execFileAsync(`tar`,[`-xzf`,tarballPath,`-C`,extractedDir]),await rm(tarballPath),await rename(join(extractedDir,`package`),installedPackageDir),await linkRuntimeDependencies({nodeModulesDir,packageDir,packageJson});let packedPackageJson=JSON.parse(await readFile(join(installedPackageDir,`package.json`),`utf8`));return{cleanup:()=>rm(tempDir,{force:!0,recursive:!0}),consumerDir,files:files.toSorted(),packageJson:packedPackageJson}}function parseBunPackOutput(stdout){let files=[],filename=``;for(let line of stdout.split(`
2
- `)){let packMatch=line.match(PACKED_LINE);if(packMatch?.[1]){files.push(packMatch[1]);continue}let tgzMatch=line.match(TGZ_LINE);tgzMatch?.[1]&&(filename=tgzMatch[1])}if(!filename)throw Error(`bun pm pack did not produce a tarball:\n${stdout}`);return{filename,files}}async function linkRuntimeDependencies({nodeModulesDir,packageDir,packageJson}){let dependencies=new Set([...Object.keys(packageJson.dependencies??{}),...Object.keys(packageJson.peerDependencies??{})]);for(let dependencyName of Array.from(dependencies)){if(dependencyName===packageJson.name)continue;let source=joinPackageName(join(packageDir,`node_modules`),dependencyName),target=joinPackageName(nodeModulesDir,dependencyName);await mkdir(dirname(target),{recursive:!0}),await symlink(source,target,`junction`)}}function joinPackageName(nodeModulesDir,packageName){return join(nodeModulesDir,...packageName.split(`/`))}async function runNodeScript({args,cwd,label}){try{await execFileAsync(process.execPath,args,{cwd})}catch(error){throw error instanceof Error?Error(`${label} package contract failed:\n${error.message}`):error}}function importScript(specifiers){return specifiers.map(specifier=>`await import(${JSON.stringify(specifier)});`).join(`
1
+ import path from"node:path";import{execFile}from"node:child_process";import{mkdir,mkdtemp,readFile,rename,rm,symlink}from"node:fs/promises";import{tmpdir}from"node:os";import{fileURLToPath}from"node:url";import{promisify}from"node:util";import{expect}from"vitest";const execFileAsync=promisify(execFile),PACKED_LINE=/^packed\s+\S+\s+(?<file>.+)$/u,TGZ_LINE=/^(?<filename>\S+\.tgz)$/u,PACKAGE_CONTRACT_TIMEOUT_MS=3e4;async function expectPackedPackageFiles({expectedFiles,packageJsonUrl}){let packedPackage=await createPackedPackage(packageJsonUrl);try{expect(packedPackage.files).toEqual(expect.arrayContaining(expectedFiles)),expect(packedPackage.files.filter(file=>file.startsWith(`src/`))).toEqual([]),expect(packedPackage.files.filter(file=>file.endsWith(`.map`))).toEqual([]),expect(packedPackage.packageJson.private).toBeUndefined(),expect(Object.keys(packedPackage.packageJson.devDependencies??{})).not.toContain(`@interfere/tsdown-config`)}finally{await packedPackage.cleanup()}}async function expectNodeCanLoadPackageSpecifiers({packageJsonUrl,specifiers}){let packedPackage=await createPackedPackage(packageJsonUrl);try{await runNodeScript({args:[`--input-type=module`,`--eval`,importScript(specifiers)],cwd:packedPackage.consumerDir,label:`ESM import`}),await runNodeScript({args:[`--eval`,requireScript(specifiers)],cwd:packedPackage.consumerDir,label:`CommonJS require`})}finally{await packedPackage.cleanup()}}async function createPackedPackage(packageJsonUrl){let packageDir=path.dirname(fileURLToPath(packageJsonUrl)),tempDir=await mkdtemp(path.join(tmpdir(),`interfere-package-contract-`)),consumerDir=path.join(tempDir,`consumer`),nodeModulesDir=path.join(consumerDir,`node_modules`),packageJson=JSON.parse(await readFile(packageJsonUrl,`utf-8`)),installedPackageDir=joinPackageName(nodeModulesDir,packageJson.name);await mkdir(path.dirname(installedPackageDir),{recursive:!0});let{stdout}=await execFileAsync(`bun`,[`pm`,`pack`,`--ignore-scripts`],{cwd:packageDir}),{filename,files}=parseBunPackOutput(stdout),tarballPath=path.join(packageDir,filename),extractedDir=path.join(tempDir,`extracted`);await mkdir(extractedDir),await execFileAsync(`tar`,[`-xzf`,tarballPath,`-C`,extractedDir]),await rm(tarballPath),await rename(path.join(extractedDir,`package`),installedPackageDir),await linkRuntimeDependencies({nodeModulesDir,packageDir,packageJson});let packedPackageJson=JSON.parse(await readFile(path.join(installedPackageDir,`package.json`),`utf-8`));return{cleanup:()=>rm(tempDir,{force:!0,recursive:!0}),consumerDir,files:files.toSorted(),packageJson:packedPackageJson}}function parseBunPackOutput(stdout){let files=[],filename=``;for(let line of stdout.split(`
2
+ `)){let packMatch=line.match(PACKED_LINE);if(packMatch?.[1]){files.push(packMatch[1]);continue}let tgzName=line.match(TGZ_LINE)?.groups?.filename;tgzName&&(filename=tgzName)}if(!filename)throw Error(`bun pm pack did not produce a tarball:\n${stdout}`);return{filename,files}}async function linkRuntimeDependencies({nodeModulesDir,packageDir,packageJson}){let dependencies=new Set([...Object.keys(packageJson.dependencies??{}),...Object.keys(packageJson.peerDependencies??{})]);for(let dependencyName of dependencies){if(dependencyName===packageJson.name)continue;let source=joinPackageName(path.join(packageDir,`node_modules`),dependencyName),target=joinPackageName(nodeModulesDir,dependencyName);await mkdir(path.dirname(target),{recursive:!0}),await symlink(source,target,`junction`)}}function joinPackageName(nodeModulesDir,packageName){return path.join(nodeModulesDir,...packageName.split(`/`))}async function runNodeScript({args,cwd,label}){try{await execFileAsync(process.execPath,args,{cwd})}catch(error){throw error instanceof Error?TypeError(`${label} package contract failed:\n${error.message}`,{cause:error}):error}}function importScript(specifiers){return specifiers.map(specifier=>`await import(${JSON.stringify(specifier)});`).join(`
3
3
  `)}function requireScript(specifiers){return specifiers.map(specifier=>`require(${JSON.stringify(specifier)});`).join(`
4
4
  `)}export{PACKAGE_CONTRACT_TIMEOUT_MS,expectNodeCanLoadPackageSpecifiers,expectPackedPackageFiles};
@@ -1 +1 @@
1
- import{DESKTOP,MOBILE}from"../../lib/viewports.mjs";import base_default from"../base.mjs";import{deepMerge}from"@interfere/helpers/deep-merge";import{resolve}from"node:path";import react from"@vitejs/plugin-react";import{playwright}from"@vitest/browser-playwright";const INSTANCE_BASELINE_EXCLUDE=[`test/e2e/**/*.{test,spec}.?(c|m)[jt]s?(x)`],chromiumExecutablePath=process.env.CHROMIUM_EXECUTABLE_PATH,MOBILE_TESTS=`src/**/mobile/*.{test,spec}.?(c|m)[jt]s?(x)`;function dualViewport(){return[{browser:`chromium`,name:`Chrome - Desktop`,viewport:DESKTOP,exclude:[...INSTANCE_BASELINE_EXCLUDE,MOBILE_TESTS]},{browser:`chromium`,name:`Chrome - Mobile`,viewport:MOBILE,exclude:INSTANCE_BASELINE_EXCLUDE,include:[MOBILE_TESTS]}]}function browserProject(opts){let{instances,trace,testAlias=`test/unit`,...rest}=opts;return deepMerge(base_default,{server:{port:0,strictPort:!1},test:{name:`browser`,browser:{enabled:!0,provider:chromiumExecutablePath?playwright({launchOptions:{executablePath:chromiumExecutablePath}}):playwright(),screenshotFailures:!1,instances,...trace&&{trace:{mode:`retain-on-failure`}}}},plugins:[react()],optimizeDeps:{entries:[`src/**/*.{ts,tsx}`,`test/unit/**/*.{ts,tsx}`],exclude:[`fsevents`,`@opentelemetry/otlp-transformer`]},...testAlias!==!1&&{resolve:{tsconfigPaths:!0,alias:{"@test":resolve(process.cwd(),testAlias)}}}},rest)}export{MOBILE_TESTS,browserProject,dualViewport};
1
+ import{DESKTOP,MOBILE}from"../../lib/viewports.mjs";import base_default from"../base.mjs";import{deepMerge}from"@interfere/helpers/deep-merge";import path from"node:path";import react from"@vitejs/plugin-react";import{playwright}from"@vitest/browser-playwright";const INSTANCE_BASELINE_EXCLUDE=[`test/e2e/**/*.{test,spec}.?(c|m)[jt]s?(x)`],chromiumExecutablePath=process.env.CHROMIUM_EXECUTABLE_PATH,MOBILE_TESTS=`src/**/mobile/*.{test,spec}.?(c|m)[jt]s?(x)`;function dualViewport(){return[{browser:`chromium`,name:`Chrome - Desktop`,viewport:DESKTOP,exclude:[...INSTANCE_BASELINE_EXCLUDE,MOBILE_TESTS]},{browser:`chromium`,name:`Chrome - Mobile`,viewport:MOBILE,exclude:INSTANCE_BASELINE_EXCLUDE,include:[MOBILE_TESTS]}]}function browserProject(opts){let{instances,trace,testAlias=`test/unit`,...rest}=opts,basis={server:{port:0,strictPort:!1},test:{name:`browser`,browser:{enabled:!0,headless:!process.env.UI,provider:chromiumExecutablePath?playwright({launchOptions:{executablePath:chromiumExecutablePath}}):playwright(),screenshotFailures:!1,instances,...trace&&{trace:{mode:`retain-on-failure`}}}},plugins:[react()],optimizeDeps:{entries:[`src/**/*.{ts,tsx}`,`test/unit/**/*.{ts,tsx}`],exclude:[`fsevents`,`@opentelemetry/otlp-transformer`]},...testAlias!==!1&&{resolve:{tsconfigPaths:!0,alias:{"@test":path.resolve(process.cwd(),testAlias)}}}};return deepMerge(base_default,basis,rest)}export{MOBILE_TESTS,browserProject,dualViewport};
@@ -16,6 +16,18 @@ interface IntegrationOptions {
16
16
  * Container resources to provision once per run. Defaults to `["pg"]`.
17
17
  */
18
18
  resources?: IntegrationResource[];
19
+ /**
20
+ * Give every worker fork its own logical Valkey database, keyed on
21
+ * `VITEST_POOL_ID`, so test files can run in parallel. Without this the
22
+ * redis harness flushes one shared database between tests, which forces
23
+ * `fileParallelism: false` for the whole package.
24
+ *
25
+ * Every Valkey client in the package MUST come from
26
+ * `@interfere/internal-test-utils/lifecycle/redis/harness`. Code that reads
27
+ * `REDIS_URL` and connects for itself lands on database 0 and escapes the
28
+ * per-worker isolation.
29
+ */
30
+ redisPerWorkerDatabase?: boolean;
19
31
  }
20
32
  /**
21
33
  * Build a Vitest config for an integration-test package. Wires up the
@@ -30,6 +42,6 @@ interface IntegrationOptions {
30
42
  * });
31
43
  * ```
32
44
  */
33
- declare function defineIntegrationConfig(options?: IntegrationOptions, ...overrides: Array<Partial<ViteUserConfig> | undefined>): ViteUserConfig;
45
+ declare function defineIntegrationConfig(options?: IntegrationOptions, ...overrides: (Partial<ViteUserConfig> | undefined)[]): ViteUserConfig;
34
46
  //#endregion
35
47
  export { IntegrationOptions, IntegrationResource, defineIntegrationConfig };
@@ -1 +1 @@
1
- import base_default from"../base.mjs";import{deepMerge}from"@interfere/helpers/deep-merge";import{defineConfig}from"vitest/config";const GLOBAL_SETUP_BY_RESOURCE={pg:`@interfere/internal-test-utils/lifecycle/pg/global-setup`,redis:`@interfere/internal-test-utils/lifecycle/redis/global-setup`};function defineIntegrationConfig(options={},...overrides){let resources=options.resources??[`pg`],globalSetup=resources.map(r=>GLOBAL_SETUP_BY_RESOURCE[r]),redisOverrides=resources.includes(`redis`)?{test:{fileParallelism:!1}}:{};return defineConfig(deepMerge(base_default,{test:{globalSetup}},redisOverrides,...overrides))}export{defineIntegrationConfig};
1
+ import base_default from"../base.mjs";import{deepMerge}from"@interfere/helpers/deep-merge";import{defineConfig}from"vitest/config";const GLOBAL_SETUP_BY_RESOURCE={pg:`@interfere/internal-test-utils/lifecycle/pg/global-setup`,redis:`@interfere/internal-test-utils/lifecycle/redis/global-setup`};function defineIntegrationConfig(options={},...overrides){let resources=options.resources??[`pg`],globalSetup=resources.map(r=>GLOBAL_SETUP_BY_RESOURCE[r]),perWorkerDatabase=resources.includes(`redis`)&&options.redisPerWorkerDatabase===!0,redisOverrides=resources.includes(`redis`)&&!perWorkerDatabase?{test:{fileParallelism:!1}}:{};return defineConfig(deepMerge(base_default,{test:{globalSetup}},redisOverrides,perWorkerDatabase?{test:{env:{TEST_REDIS_PER_WORKER_DATABASE:`1`}}}:{},...overrides))}export{defineIntegrationConfig};
@@ -1 +1 @@
1
- import{DESKTOP,MOBILE}from"../../lib/viewports.mjs";import base_default from"../base.mjs";import{deepMerge}from"@interfere/helpers/deep-merge";import{playwright}from"@vitest/browser-playwright";const INSTANCE_BASELINE_EXCLUDE=[`test/e2e/**/*.{test,spec}.?(c|m)[jt]s?(x)`],chromiumExecutablePath=process.env.CHROMIUM_EXECUTABLE_PATH;function dualViewport(){return[{browser:`chromium`,name:`Chrome - Desktop`,viewport:DESKTOP,exclude:INSTANCE_BASELINE_EXCLUDE},{browser:`chromium`,name:`Chrome - Mobile`,viewport:MOBILE,exclude:INSTANCE_BASELINE_EXCLUDE}]}function viteProject(opts){let{instances,trace,testAlias=`test/unit`,...rest}=opts;return deepMerge({server:{port:0,strictPort:!1}},base_default,{test:{name:`vite`,browser:{enabled:!0,provider:chromiumExecutablePath?playwright({launchOptions:{executablePath:chromiumExecutablePath}}):playwright(),screenshotFailures:!1,instances,...trace&&{trace:{mode:`retain-on-failure`}}}}},rest)}export{dualViewport,viteProject};
1
+ import{DESKTOP,MOBILE}from"../../lib/viewports.mjs";import base_default from"../base.mjs";import{deepMerge}from"@interfere/helpers/deep-merge";import{playwright}from"@vitest/browser-playwright";const INSTANCE_BASELINE_EXCLUDE=[`test/e2e/**/*.{test,spec}.?(c|m)[jt]s?(x)`],chromiumExecutablePath=process.env.CHROMIUM_EXECUTABLE_PATH;function dualViewport(){return[{browser:`chromium`,name:`Chrome - Desktop`,viewport:DESKTOP,exclude:INSTANCE_BASELINE_EXCLUDE},{browser:`chromium`,name:`Chrome - Mobile`,viewport:MOBILE,exclude:INSTANCE_BASELINE_EXCLUDE}]}function viteProject(opts){let{instances,trace,testAlias:_testAlias,...rest}=opts;return deepMerge({server:{port:0,strictPort:!1}},base_default,{test:{name:`vite`,browser:{enabled:!0,provider:chromiumExecutablePath?playwright({launchOptions:{executablePath:chromiumExecutablePath}}):playwright(),screenshotFailures:!1,instances,...trace&&{trace:{mode:`retain-on-failure`}}}}},rest)}export{dualViewport,viteProject};
@@ -0,0 +1,24 @@
1
+ import { ViteUserConfig } from "vitest/config";
2
+ import { cloudflareTest } from "@cloudflare/vitest-pool-workers";
3
+ //#region src/vitest/presets/workers.d.ts
4
+ type CloudflareTestOptions = NonNullable<Parameters<typeof cloudflareTest>[0]>;
5
+ interface WorkersProjectOptions extends Partial<ViteUserConfig> {
6
+ /**
7
+ * Passed through to `cloudflareTest()`, merged over a default that points at
8
+ * the worker's own `wrangler.jsonc`. Use it for Miniflare service bindings
9
+ * and outbound request mocks.
10
+ */
11
+ cloudflare?: CloudflareTestOptions;
12
+ }
13
+ /**
14
+ * Build a Vitest config that runs a Cloudflare Worker's tests inside workerd
15
+ * via the Workers Vitest integration.
16
+ *
17
+ * Intentionally does not extend the shared Node base config: that pins
18
+ * `environment: "node"` and `pool: "forks"`, both of which contradict running
19
+ * inside the Workers runtime. Coverage uses Istanbul because V8 coverage is
20
+ * unavailable in workerd.
21
+ */
22
+ declare function workersProject(opts?: WorkersProjectOptions): ViteUserConfig;
23
+ //#endregion
24
+ export { WorkersProjectOptions, workersProject };
@@ -0,0 +1 @@
1
+ import{deepMerge}from"@interfere/helpers/deep-merge";import{cloudflareTest}from"@cloudflare/vitest-pool-workers";const isCI=!!process.env.CI;function workersProject(opts={}){let{cloudflare={},...overrides}=opts;return deepMerge({plugins:[cloudflareTest(deepMerge({wrangler:{configPath:`./wrangler.jsonc`}},cloudflare))],test:{reporters:isCI?[`default`,`junit`]:[`default`],...isCI&&{outputFile:{junit:`./test-results/junit.xml`}},coverage:{enabled:!0,provider:`istanbul`,include:[`src/**/*.{ts,mts}`],reporter:isCI?[`json`,`json-summary`,`lcov`]:[`text`,`html`]}}},overrides)}export{workersProject};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interfere/test-utils",
3
- "version": "9.0.4",
3
+ "version": "9.1.0",
4
4
  "license": "MIT",
5
5
  "description": "Shared test utilities used across Interfere packages.",
6
6
  "homepage": "https://interfere.com",
@@ -50,16 +50,20 @@
50
50
  },
51
51
  "scripts": {
52
52
  "build": "tsdown",
53
- "typecheck": "tsgo --noEmit"
53
+ "typecheck": "tsc --noEmit"
54
54
  },
55
55
  "peerDependencies": {
56
- "@playwright/test": "^1.61.1",
57
- "@vitejs/plugin-react": "^6.0.3",
58
- "@vitest/browser-playwright": "4.1.9",
56
+ "@cloudflare/vitest-pool-workers": "^0.21.0",
57
+ "@playwright/test": "^1.62.1",
58
+ "@vitejs/plugin-react": "^6.0.5",
59
+ "@vitest/browser-playwright": "4.1.10",
59
60
  "msw": "^2.14.6",
60
- "vitest": "4.1.9"
61
+ "vitest": "4.1.10"
61
62
  },
62
63
  "peerDependenciesMeta": {
64
+ "@cloudflare/vitest-pool-workers": {
65
+ "optional": true
66
+ },
63
67
  "@playwright/test": {
64
68
  "optional": true
65
69
  },
@@ -74,18 +78,19 @@
74
78
  }
75
79
  },
76
80
  "dependencies": {
77
- "@interfere/helpers": "^9.0.3",
81
+ "@interfere/helpers": "^9.1.0",
78
82
  "dotenv": "^17.4.2"
79
83
  },
80
84
  "devDependencies": {
81
- "@interfere/typescript-config": "^9.0.1",
82
- "@playwright/test": "^1.61.1",
83
- "@types/node": "^26.1.0",
84
- "@typescript/native-preview": "7.0.0-dev.20260701.1",
85
- "@vitejs/plugin-react": "^6.0.3",
86
- "@vitest/browser-playwright": "4.1.9",
85
+ "@cloudflare/vitest-pool-workers": "^0.21.0",
86
+ "@interfere/typescript-config": "^9.0.2",
87
+ "@playwright/test": "^1.62.1",
88
+ "@types/node": "^26.2.0",
89
+ "@vitejs/plugin-react": "^6.0.5",
90
+ "@vitest/browser-playwright": "4.1.10",
87
91
  "msw": "^2.14.6",
88
92
  "tsdown": "^0.22.2",
89
- "vitest": "4.1.9"
93
+ "typescript": "^7.0.2",
94
+ "vitest": "4.1.10"
90
95
  }
91
96
  }