@interfere/test-utils 9.1.2 → 10.0.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/playwright/protection-bypass.d.mts +6 -4
- package/dist/playwright/protection-bypass.mjs +1 -1
- package/dist/vitest/otlp.d.mts +85 -0
- package/dist/vitest/otlp.mjs +1 -0
- package/dist/vitest/package-contract.d.mts +13 -13
- package/dist/vitest/package-contract.mjs +2 -4
- package/dist/vitest/packed-application.d.mts +23 -0
- package/dist/vitest/packed-application.mjs +1 -0
- package/dist/vitest/telemetry-receiver.d.mts +18 -0
- package/dist/vitest/telemetry-receiver.mjs +1 -0
- package/package.json +11 -53
- package/dist/lib/tags.d.mts +0 -6
- package/dist/lib/tags.mjs +0 -1
- package/dist/lib/viewports.d.mts +0 -13
- package/dist/lib/viewports.mjs +0 -1
- package/dist/playwright/base.d.mts +0 -48
- package/dist/playwright/base.mjs +0 -1
- package/dist/playwright/define-config.d.mts +0 -5
- package/dist/playwright/define-config.mjs +0 -1
- package/dist/vitest/base.d.mts +0 -52
- package/dist/vitest/base.mjs +0 -1
- package/dist/vitest/define-config.d.mts +0 -5
- package/dist/vitest/define-config.mjs +0 -1
- package/dist/vitest/msw/browser.d.mts +0 -5
- package/dist/vitest/msw/browser.mjs +0 -1
- package/dist/vitest/msw/http.d.mts +0 -15
- package/dist/vitest/msw/http.mjs +0 -1
- package/dist/vitest/msw/node.d.mts +0 -12
- package/dist/vitest/msw/node.mjs +0 -1
- package/dist/vitest/presets/browser.d.mts +0 -28
- package/dist/vitest/presets/browser.mjs +0 -1
- package/dist/vitest/presets/integration.d.mts +0 -47
- package/dist/vitest/presets/integration.mjs +0 -1
- package/dist/vitest/presets/node.d.mts +0 -14
- package/dist/vitest/presets/node.mjs +0 -1
- package/dist/vitest/presets/vite.d.mts +0 -14
- package/dist/vitest/presets/vite.mjs +0 -1
- package/dist/vitest/presets/workers.d.mts +0 -24
- package/dist/vitest/presets/workers.mjs +0 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
//#region src/playwright/protection-bypass.d.ts
|
|
2
|
-
type ProtectionProvider = "cloudflare-access";
|
|
3
|
-
declare function protectionBypassHeaders(baseURL: string | undefined, provider: ProtectionProvider):
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
export type ProtectionProvider = "cloudflare-access";
|
|
3
|
+
export declare function protectionBypassHeaders(baseURL: string | undefined, provider: ProtectionProvider): {
|
|
4
|
+
"CF-Access-Client-Id": string;
|
|
5
|
+
"CF-Access-Client-Secret": string;
|
|
6
|
+
} | undefined;
|
|
7
|
+
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const LOCAL_HOSTNAMES=new Set([`localhost`,`127.0.0.1`,`0.0.0.0`,`[::1]`]);function isLocal(baseURL){try{return LOCAL_HOSTNAMES.has(new URL(baseURL).hostname)}catch{return!1}}function cloudflareAccessHeaders(baseURL){let clientId=process.env.CF_ACCESS_CLIENT_ID,clientSecret=process.env.CF_ACCESS_CLIENT_SECRET;if(!(clientId&&clientSecret))throw Error([`Missing CF_ACCESS_CLIENT_ID / CF_ACCESS_CLIENT_SECRET while
|
|
1
|
+
const LOCAL_HOSTNAMES=new Set([`localhost`,`127.0.0.1`,`0.0.0.0`,`[::1]`]);function isLocal(baseURL){try{return LOCAL_HOSTNAMES.has(new URL(baseURL).hostname)}catch{return!1}}function cloudflareAccessHeaders(baseURL){let clientId=process.env.CF_ACCESS_CLIENT_ID,clientSecret=process.env.CF_ACCESS_CLIENT_SECRET;if(!(clientId&&clientSecret))throw Error([`Missing CF_ACCESS_CLIENT_ID / CF_ACCESS_CLIENT_SECRET while baseURL points at a remote Cloudflare deployment.`,`baseURL=${baseURL}`,`Set both environment variables to a Cloudflare Access service token authorized for this deployment.`].join(` `));return{"CF-Access-Client-Id":clientId,"CF-Access-Client-Secret":clientSecret}}function protectionBypassHeaders(baseURL,provider){if(baseURL&&!isLocal(baseURL)){if(provider===`cloudflare-access`)return cloudflareAccessHeaders(baseURL);throw Error(`Unsupported protection provider: ${String(provider)}`)}}export{protectionBypassHeaders};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ReceivedRequest } from "./telemetry-receiver.mjs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/vitest/otlp.d.ts
|
|
4
|
+
declare const attributes: z.ZodArray<z.ZodObject<{
|
|
5
|
+
key: z.ZodString;
|
|
6
|
+
value: z.ZodObject<{
|
|
7
|
+
stringValue: z.ZodOptional<z.ZodString>;
|
|
8
|
+
boolValue: z.ZodOptional<z.ZodBoolean>;
|
|
9
|
+
intValue: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
}, z.core.$strip>>;
|
|
12
|
+
export declare function exportedSpans(requests: ReceivedRequest[]): {
|
|
13
|
+
name: string;
|
|
14
|
+
traceId: string;
|
|
15
|
+
spanId: string;
|
|
16
|
+
parentSpanId?: string | undefined;
|
|
17
|
+
attributes: {
|
|
18
|
+
key: string;
|
|
19
|
+
value: {
|
|
20
|
+
stringValue?: string | undefined;
|
|
21
|
+
boolValue?: boolean | undefined;
|
|
22
|
+
intValue?: string | number | undefined;
|
|
23
|
+
};
|
|
24
|
+
}[];
|
|
25
|
+
events: {
|
|
26
|
+
name: string;
|
|
27
|
+
attributes: {
|
|
28
|
+
key: string;
|
|
29
|
+
value: {
|
|
30
|
+
stringValue?: string | undefined;
|
|
31
|
+
boolValue?: boolean | undefined;
|
|
32
|
+
intValue?: string | number | undefined;
|
|
33
|
+
};
|
|
34
|
+
}[];
|
|
35
|
+
}[];
|
|
36
|
+
status?: {
|
|
37
|
+
code?: number | undefined;
|
|
38
|
+
} | undefined;
|
|
39
|
+
resource: {
|
|
40
|
+
key: string;
|
|
41
|
+
value: {
|
|
42
|
+
stringValue?: string | undefined;
|
|
43
|
+
boolValue?: boolean | undefined;
|
|
44
|
+
intValue?: string | number | undefined;
|
|
45
|
+
};
|
|
46
|
+
}[];
|
|
47
|
+
}[];
|
|
48
|
+
export declare function attribute(values: z.infer<typeof attributes>, key: string): string | number | boolean | undefined;
|
|
49
|
+
export declare function exceptions(requests: ReceivedRequest[], message: string): {
|
|
50
|
+
name: string;
|
|
51
|
+
traceId: string;
|
|
52
|
+
spanId: string;
|
|
53
|
+
parentSpanId?: string | undefined;
|
|
54
|
+
attributes: {
|
|
55
|
+
key: string;
|
|
56
|
+
value: {
|
|
57
|
+
stringValue?: string | undefined;
|
|
58
|
+
boolValue?: boolean | undefined;
|
|
59
|
+
intValue?: string | number | undefined;
|
|
60
|
+
};
|
|
61
|
+
}[];
|
|
62
|
+
events: {
|
|
63
|
+
name: string;
|
|
64
|
+
attributes: {
|
|
65
|
+
key: string;
|
|
66
|
+
value: {
|
|
67
|
+
stringValue?: string | undefined;
|
|
68
|
+
boolValue?: boolean | undefined;
|
|
69
|
+
intValue?: string | number | undefined;
|
|
70
|
+
};
|
|
71
|
+
}[];
|
|
72
|
+
}[];
|
|
73
|
+
status?: {
|
|
74
|
+
code?: number | undefined;
|
|
75
|
+
} | undefined;
|
|
76
|
+
resource: {
|
|
77
|
+
key: string;
|
|
78
|
+
value: {
|
|
79
|
+
stringValue?: string | undefined;
|
|
80
|
+
boolValue?: boolean | undefined;
|
|
81
|
+
intValue?: string | number | undefined;
|
|
82
|
+
};
|
|
83
|
+
}[];
|
|
84
|
+
}[];
|
|
85
|
+
//#endregion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{z}from"zod";const attributes=z.array(z.object({key:z.string(),value:z.object({stringValue:z.string().optional(),boolValue:z.boolean().optional(),intValue:z.union([z.string(),z.number()]).optional()})})),span=z.object({name:z.string(),traceId:z.string(),spanId:z.string(),parentSpanId:z.string().optional(),attributes:attributes.default([]),events:z.array(z.object({name:z.string(),attributes:attributes.default([])})).default([]),status:z.object({code:z.number().optional()}).optional()}),traces=z.object({resourceSpans:z.array(z.object({resource:z.object({attributes}),scopeSpans:z.array(z.object({spans:z.array(span)}))}))});function exportedSpans(requests){return requests.filter(request=>request.url.startsWith(`/drain/v1/traces`)&&request.status<300).flatMap(request=>traces.parse(JSON.parse(request.body)).resourceSpans.flatMap(resource=>resource.scopeSpans.flatMap(scope=>scope.spans.map(item=>({...item,resource:resource.resource.attributes})))))}function attribute(values,key){let value=values.find(item=>item.key===key)?.value;return value?.stringValue??value?.boolValue??value?.intValue}function exceptions(requests,message){return exportedSpans(requests).filter(item=>item.events.some(event=>event.name===`exception`&&attribute(event.attributes,`exception.message`)===message))}export{attribute,exceptions,exportedSpans};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
//#region src/vitest/package-contract.d.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
interface PackageJson {
|
|
3
|
+
dependencies?: Record<string, string>;
|
|
4
|
+
devDependencies?: Record<string, string>;
|
|
5
|
+
name: string;
|
|
6
|
+
peerDependencies?: Record<string, string>;
|
|
7
|
+
private?: boolean;
|
|
5
8
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
declare function expectNodeCanLoadPackageSpecifiers({ packageJsonUrl, specifiers }: NodePackageResolutionOptions): Promise<void>;
|
|
14
|
-
//#endregion
|
|
15
|
-
export { PACKAGE_CONTRACT_TIMEOUT_MS, expectNodeCanLoadPackageSpecifiers, expectPackedPackageFiles };
|
|
9
|
+
export declare function createPackedPackage(packageJsonUrl: URL): Promise<{
|
|
10
|
+
cleanup: () => Promise<void>;
|
|
11
|
+
consumerDir: string;
|
|
12
|
+
files: string[];
|
|
13
|
+
packageJson: PackageJson;
|
|
14
|
+
}>;
|
|
15
|
+
//#endregion
|
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
`)){let packMatch=
|
|
3
|
-
`)}function requireScript(specifiers){return specifiers.map(specifier=>`require(${JSON.stringify(specifier)});`).join(`
|
|
4
|
-
`)}export{PACKAGE_CONTRACT_TIMEOUT_MS,expectNodeCanLoadPackageSpecifiers,expectPackedPackageFiles};
|
|
1
|
+
import{mapWithConcurrency}from"@interfere/helpers/map-with-concurrency";import{execFile}from"node:child_process";import{mkdir,mkdtemp,readFile,rename,rm,symlink}from"node:fs/promises";import{tmpdir}from"node:os";import path from"node:path";import{fileURLToPath}from"node:url";import{promisify}from"node:util";const execFileAsync=promisify(execFile),PACKED_LINE=/^packed\s+\S+\s+(?<file>.+)$/u,TGZ_LINE=/^(?<filename>\S+\.tgz)$/u;function isDependencyMap(value){return typeof value==`object`&&!!value&&!Array.isArray(value)&&Object.values(value).every(version=>typeof version==`string`)}function isPackageJson(value){return typeof value==`object`&&!!value&&`name`in value&&typeof value.name==`string`&&(!(`private`in value)||typeof value.private==`boolean`)&&(!(`dependencies`in value)||isDependencyMap(value.dependencies))&&(!(`devDependencies`in value)||isDependencyMap(value.devDependencies))&&(!(`peerDependencies`in value)||isDependencyMap(value.peerDependencies))}async function readPackageJson(file){let value=JSON.parse(await readFile(file,`utf8`));if(!isPackageJson(value))throw TypeError(`Package manifest has an invalid name, privacy flag, or dependency map.`);return value}async function createPackedPackage(packageJsonUrl){let packageDir=path.dirname(fileURLToPath(packageJsonUrl)),packageJson=await readPackageJson(packageJsonUrl),tempDir=await mkdtemp(path.join(tmpdir(),`interfere-package-contract-`)),consumerDir=path.join(tempDir,`consumer`),nodeModulesDir=path.join(consumerDir,`node_modules`);try{let installedPackageDir=joinPackageName(nodeModulesDir,packageJson.name);await mkdir(path.dirname(installedPackageDir),{recursive:!0});let{stdout}=await execFileAsync(`bun`,[`pm`,`pack`,`--ignore-scripts`,`--destination`,tempDir],{cwd:packageDir}),{filename,files}=parseBunPackOutput(stdout),tarballPath=path.join(tempDir,path.basename(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=await readPackageJson(path.join(installedPackageDir,`package.json`));return{cleanup:async()=>rm(tempDir,{force:!0,recursive:!0}),consumerDir,files:files.toSorted(),packageJson:packedPackageJson}}catch(error){throw await rm(tempDir,{force:!0,recursive:!0}),error}}function parseBunPackOutput(stdout){let files=[],filename=``;for(let line of stdout.split(`
|
|
2
|
+
`)){let packMatch=PACKED_LINE.exec(line);if(packMatch?.[1]){files.push(packMatch[1]);continue}let tgzName=TGZ_LINE.exec(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??{})]),results=await mapWithConcurrency([...dependencies],16,async dependencyName=>{if(dependencyName===packageJson.name)return{ok:!0};try{let source=joinPackageName(path.join(packageDir,`node_modules`),dependencyName),target=joinPackageName(nodeModulesDir,dependencyName);return await mkdir(path.dirname(target),{recursive:!0}),await symlink(source,target,`junction`),{ok:!0}}catch(error){return{ok:!1,error}}});for(let result of results)if(!result.ok)throw result.error}function joinPackageName(nodeModulesDir,packageName){let segments=packageName.split(`/`),validSegments=packageName.startsWith(`@`)?segments.length===2&&segments[0]!==`@`:segments.length===1,target=path.resolve(nodeModulesDir,packageName),relative=path.relative(nodeModulesDir,target);if(!validSegments||packageName.includes(`\\`)||segments.some(segment=>!segment||segment===`.`||segment===`..`)||!relative||relative===`..`||relative.startsWith(`..${path.sep}`)||path.isAbsolute(relative))throw Error(`Package path must remain inside the owned node_modules directory.`);return target}export{createPackedPackage};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/vitest/packed-application.d.ts
|
|
2
|
+
export declare function application(packageRoot: string, packages: string[]): Promise<{
|
|
3
|
+
root: string;
|
|
4
|
+
copyFixture(name: string): Promise<void>;
|
|
5
|
+
run(script: string, env?: Record<string, string | undefined>, runtime?: string): Promise<{
|
|
6
|
+
stdout: string;
|
|
7
|
+
stderr: string;
|
|
8
|
+
}>;
|
|
9
|
+
build(env: Record<string, string | undefined>): Promise<{
|
|
10
|
+
stdout: string;
|
|
11
|
+
stderr: string;
|
|
12
|
+
}>;
|
|
13
|
+
buildNext(env: Record<string, string | undefined>, bundler: "webpack" | "turbopack"): Promise<{
|
|
14
|
+
stdout: string;
|
|
15
|
+
stderr: string;
|
|
16
|
+
}>;
|
|
17
|
+
start(script: string, env: Record<string, string | undefined>): Promise<{
|
|
18
|
+
url: string;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}>;
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
}>;
|
|
23
|
+
//#endregion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createRequire}from"node:module";import{z}from"zod";import{execFile,spawn}from"node:child_process";import{cp,mkdir,mkdtemp,readFile,realpath,rm,symlink,writeFile}from"node:fs/promises";import{tmpdir}from"node:os";import{dirname,join}from"node:path";import{promisify}from"node:util";import{once}from"node:events";const exec=promisify(execFile),metadata=z.object({name:z.string(),dependencies:z.record(z.string(),z.string()).default({})});function childEnvironment(overrides){return Object.fromEntries([[`PATH`,process.env.PATH],[`NODE_ENV`,`production`],[`NEXT_TELEMETRY_DISABLED`,`1`],...Object.entries(overrides)])}async function application(packageRoot,packages){let root=await mkdtemp(join(tmpdir(),`interfere-packed-application-`)),installed=new Set,require=createRequire(join(packageRoot,`package.json`));async function install(name,from){if(installed.has(name))return;installed.add(name);let modules=join(from,`node_modules`,name),source=metadata.parse(JSON.parse(await readFile(join(from,`package.json`),`utf8`))).name===name?from:await realpath(modules),manifest=metadata.parse(JSON.parse(await readFile(join(source,`package.json`),`utf8`))),destination=join(root,`node_modules`,name);if(await mkdir(dirname(destination),{recursive:!0}),!name.startsWith(`@interfere/`)){await symlink(source,destination,`dir`);return}let tarball=join(root,`${name.replaceAll(`/`,`-`)}.tgz`);await exec(`bun`,[`pm`,`pack`,`--ignore-scripts`,`--quiet`,`--filename`,tarball],{cwd:source}),await mkdir(destination,{recursive:!0}),await exec(`tar`,[`-xzf`,tarball,`--strip-components=1`,`-C`,destination]),await Promise.all(Object.keys(manifest.dependencies).map(async dependency=>install(dependency,source)))}try{return await writeFile(join(root,`package.json`),JSON.stringify({private:!0,type:`module`})),await Promise.all(packages.map(async name=>install(name,packageRoot))),{root,async copyFixture(name){await cp(join(packageRoot,`test/fixtures`,name),root,{recursive:!0})},async run(script,env={},runtime=process.execPath){return exec(runtime,[script],{cwd:root,timeout:3e4,maxBuffer:5242880,env:childEnvironment(env)})},async build(env){return exec(process.execPath,[join(dirname(require.resolve(`vite/package.json`)),`bin/vite.js`),`build`],{cwd:root,timeout:9e4,maxBuffer:5242880,env:childEnvironment(env)})},async buildNext(env,bundler){return exec(process.execPath,[require.resolve(`next/dist/bin/next`),`build`,`--${bundler}`],{cwd:root,timeout:15e4,maxBuffer:10485760,env:childEnvironment(env)})},async start(script,env){let child=spawn(process.execPath,[script],{cwd:root,env:childEnvironment(env),stdio:[`ignore`,`pipe`,`pipe`,`ipc`]}),output=``;child.stdout?.on(`data`,chunk=>{output+=chunk.toString()}),child.stderr?.on(`data`,chunk=>{output+=chunk.toString()});let exited=once(child,`exit`);try{let messages=await once(child,`message`,{signal:AbortSignal.timeout(3e4)});return{url:z.url().parse(messages[0]),async close(){child.kill(`SIGTERM`),await exited}}}catch(error){throw child.kill(`SIGKILL`),await exited,Error(`Application startup failed: ${output}`,{cause:error})}},async close(){await rm(root,{recursive:!0,force:!0})}}}catch(error){throw await rm(root,{recursive:!0,force:!0}),error}}export{application};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/vitest/telemetry-receiver.d.ts
|
|
2
|
+
export interface ReceivedRequest {
|
|
3
|
+
method: string;
|
|
4
|
+
url: string;
|
|
5
|
+
headers: Headers;
|
|
6
|
+
body: string;
|
|
7
|
+
status: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function receiver(): Promise<{
|
|
10
|
+
url: string;
|
|
11
|
+
requests: ReceivedRequest[];
|
|
12
|
+
serve(directory: string): void;
|
|
13
|
+
forward(handler: (request: Request) => Promise<Response>): void;
|
|
14
|
+
reset(): void;
|
|
15
|
+
fail(path: string, status: number, attempts?: number, body?: string): void;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}>;
|
|
18
|
+
//#endregion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFile}from"node:fs/promises";import{extname,resolve,sep}from"node:path";import{once}from"node:events";import{HttpResponse,getResponse,http}from"msw";import{buffer}from"node:stream/consumers";import{createServer}from"node:http";import{gunzipSync}from"node:zlib";async function receiver(){let requests=[],failures=new Map,assets,upstream;async function resolveResponse(request,incoming){let url=new URL(request.url),{headers}=request,responseHeaders=new Headers({"access-control-allow-origin":`*`,"access-control-allow-headers":headers.get(`access-control-request-headers`)??`*`,"access-control-allow-methods":`GET, POST, OPTIONS`});try{if(request.method===`OPTIONS`)return new HttpResponse(null,{status:204,headers:responseHeaders});if(assets&&request.method===`GET`&&!url.pathname.startsWith(`/v3/`)){let file=resolve(assets,`.${url.pathname===`/`?`/index.html`:url.pathname}`);return file.startsWith(`${resolve(assets)}${sep}`)?(responseHeaders.set(`content-type`,extname(file)===`.html`?`text/html`:`text/javascript`),new HttpResponse(await readFile(file),{headers:responseHeaders})):new HttpResponse(null,{status:403,headers:responseHeaders})}let raw=await buffer(incoming),body=headers.get(`content-encoding`)===`gzip`?gunzipSync(raw).toString():raw.toString(),failure=[...failures].find(([prefix])=>url.pathname.startsWith(prefix))?.[1],entry={method:request.method,url:url.pathname+url.search,headers,body,status:200};if(requests.push(entry),failure&&failure.remaining>0)return--failure.remaining,entry.status=failure.status,responseHeaders.set(`content-type`,`application/json`),new HttpResponse([204,205,304].includes(failure.status)?null:failure.body,{status:failure.status,headers:responseHeaders});if(upstream){let init={method:entry.method,headers};raw.length>0&&(init.body=raw);let result=await upstream(new Request(url,init));entry.status=result.status;for(let[key,value]of result.headers)responseHeaders.set(key,value);return new HttpResponse(result.body===null?null:await result.arrayBuffer(),{status:result.status,headers:responseHeaders})}return HttpResponse.json(url.pathname.includes(`config`)?{plugins:{errors:!0,logs:!0,device:!0,pageEvents:!0,rageClick:!0,replay:!0}}:{},{headers:responseHeaders})}catch(error){return new HttpResponse(new TextEncoder().encode(String(error)),{status:500,headers:responseHeaders})}}async function handle(request,response){try{let headers=new Headers;for(let[key,value]of Object.entries(request.headers))value!==void 0&&headers.set(key,Array.isArray(value)?value.join(`, `):value);let init={method:request.method??`GET`,headers},resolved=await getResponse([http.all(`*`,async({request:intercepted})=>resolveResponse(intercepted,request))],new Request(new URL(request.url??`/`,`http://localhost`),init));if(!resolved)throw Error(`Missing telemetry receiver response`);for(let[key,value]of resolved.headers)response.setHeader(key,value);response.writeHead(resolved.status).end(Buffer.from(await resolved.arrayBuffer()))}catch(error){response.destroy(error instanceof Error?error:Error(String(error)))}}let server=createServer((request,response)=>{handle(request,response)});server.listen(0,`127.0.0.1`),await once(server,`listening`);let address=server.address();if(!(address instanceof Object))throw Error(`Receiver did not bind a TCP port`);return{url:`http://127.0.0.1:${address.port}`,requests,serve(directory){assets=directory},forward(handler){upstream=handler},reset(){requests.length=0,failures.clear()},fail(path,status,attempts=1,body=`{}`){failures.set(path,{status,remaining:attempts,body})},async close(){server.closeAllConnections(),await new Promise((resolve,reject)=>{server.close(error=>{error?reject(error):resolve()})})}}}export{receiver};
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interfere/test-utils",
|
|
3
|
-
"version": "
|
|
4
|
-
"license": "MIT",
|
|
3
|
+
"version": "10.0.1",
|
|
5
4
|
"description": "Shared test utilities used across Interfere packages.",
|
|
6
5
|
"homepage": "https://interfere.com",
|
|
7
6
|
"bugs": {
|
|
8
7
|
"url": "mailto:support@interfere.com"
|
|
9
8
|
},
|
|
9
|
+
"license": "MIT",
|
|
10
10
|
"author": "Interfere <support@interfere.com> (https://interfere.com)",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
@@ -18,11 +18,6 @@
|
|
|
18
18
|
],
|
|
19
19
|
"type": "module",
|
|
20
20
|
"exports": {
|
|
21
|
-
"./lib/*": {
|
|
22
|
-
"monorepo": "./src/lib/*.ts",
|
|
23
|
-
"types": "./dist/lib/*.d.mts",
|
|
24
|
-
"default": "./dist/lib/*.mjs"
|
|
25
|
-
},
|
|
26
21
|
"./playwright/*": {
|
|
27
22
|
"monorepo": "./src/playwright/*.ts",
|
|
28
23
|
"types": "./dist/playwright/*.d.mts",
|
|
@@ -33,16 +28,6 @@
|
|
|
33
28
|
"types": "./dist/vitest/*.d.mts",
|
|
34
29
|
"default": "./dist/vitest/*.mjs"
|
|
35
30
|
},
|
|
36
|
-
"./vitest/presets/*": {
|
|
37
|
-
"monorepo": "./src/vitest/presets/*.ts",
|
|
38
|
-
"types": "./dist/vitest/presets/*.d.mts",
|
|
39
|
-
"default": "./dist/vitest/presets/*.mjs"
|
|
40
|
-
},
|
|
41
|
-
"./vitest/msw/*": {
|
|
42
|
-
"monorepo": "./src/vitest/msw/*.ts",
|
|
43
|
-
"types": "./dist/vitest/msw/*.d.mts",
|
|
44
|
-
"default": "./dist/vitest/msw/*.mjs"
|
|
45
|
-
},
|
|
46
31
|
"./package.json": "./package.json"
|
|
47
32
|
},
|
|
48
33
|
"publishConfig": {
|
|
@@ -50,47 +35,20 @@
|
|
|
50
35
|
},
|
|
51
36
|
"scripts": {
|
|
52
37
|
"build": "tsdown",
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
"peerDependencies": {
|
|
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",
|
|
60
|
-
"msw": "^2.14.6",
|
|
61
|
-
"vitest": "4.1.10"
|
|
62
|
-
},
|
|
63
|
-
"peerDependenciesMeta": {
|
|
64
|
-
"@cloudflare/vitest-pool-workers": {
|
|
65
|
-
"optional": true
|
|
66
|
-
},
|
|
67
|
-
"@playwright/test": {
|
|
68
|
-
"optional": true
|
|
69
|
-
},
|
|
70
|
-
"@vitejs/plugin-react": {
|
|
71
|
-
"optional": true
|
|
72
|
-
},
|
|
73
|
-
"@vitest/browser-playwright": {
|
|
74
|
-
"optional": true
|
|
75
|
-
},
|
|
76
|
-
"msw": {
|
|
77
|
-
"optional": true
|
|
78
|
-
}
|
|
38
|
+
"test": "vitest run --config ../../../../vitest.config.ts",
|
|
39
|
+
"typecheck": "bun check"
|
|
79
40
|
},
|
|
80
41
|
"dependencies": {
|
|
81
|
-
"@interfere/helpers": "^9.1
|
|
82
|
-
"
|
|
42
|
+
"@interfere/helpers": "^9.2.1",
|
|
43
|
+
"msw": "^2.14.6",
|
|
44
|
+
"zod": "^4.5.4"
|
|
83
45
|
},
|
|
84
46
|
"devDependencies": {
|
|
85
|
-
"@cloudflare/vitest-pool-workers": "^0.21.0",
|
|
86
47
|
"@interfere/typescript-config": "^9.0.2",
|
|
87
|
-
"@
|
|
88
|
-
"@types/node": "^26.
|
|
89
|
-
"
|
|
90
|
-
"@vitest/browser-playwright": "4.1.10",
|
|
91
|
-
"msw": "^2.14.6",
|
|
92
|
-
"tsdown": "^0.22.2",
|
|
48
|
+
"@interfere/vitest-config": "0.0.0",
|
|
49
|
+
"@types/node": "^26.4.1",
|
|
50
|
+
"tsdown": "^0.23.0",
|
|
93
51
|
"typescript": "^7.0.2",
|
|
94
|
-
"vitest": "
|
|
52
|
+
"vitest": "5.0.5"
|
|
95
53
|
}
|
|
96
54
|
}
|
package/dist/lib/tags.d.mts
DELETED
package/dist/lib/tags.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const COMMON=`@common`,DESKTOP=`@desktop`,MOBILE=`@mobile`;export{COMMON,DESKTOP,MOBILE};
|
package/dist/lib/viewports.d.mts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { TestUserConfig } from "vitest/config";
|
|
2
|
-
//#region src/lib/viewports.d.ts
|
|
3
|
-
type Viewport = NonNullable<TestUserConfig["browser"]>["viewport"];
|
|
4
|
-
declare const DESKTOP: {
|
|
5
|
-
readonly width: 1280;
|
|
6
|
-
readonly height: 720;
|
|
7
|
-
};
|
|
8
|
-
declare const MOBILE: {
|
|
9
|
-
readonly width: 390;
|
|
10
|
-
readonly height: 844;
|
|
11
|
-
};
|
|
12
|
-
//#endregion
|
|
13
|
-
export { DESKTOP, MOBILE, Viewport };
|
package/dist/lib/viewports.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const DESKTOP={width:1280,height:720},MOBILE={width:390,height:844};export{DESKTOP,MOBILE};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
//#region src/playwright/base.d.ts
|
|
2
|
-
declare const _default: {
|
|
3
|
-
fullyParallel: true;
|
|
4
|
-
forbidOnly: boolean;
|
|
5
|
-
retries: number;
|
|
6
|
-
reporter: ["html"][] | (["github"] | ["junit", {
|
|
7
|
-
outputFile: string;
|
|
8
|
-
}])[];
|
|
9
|
-
use: {
|
|
10
|
-
trace: "on-first-retry";
|
|
11
|
-
screenshot: "only-on-failure";
|
|
12
|
-
actionTimeout?: number;
|
|
13
|
-
launchOptions?: {
|
|
14
|
-
executablePath: string;
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
expect?: {
|
|
18
|
-
timeout: number;
|
|
19
|
-
};
|
|
20
|
-
projects: ({
|
|
21
|
-
name: string;
|
|
22
|
-
grep: RegExp;
|
|
23
|
-
use: {
|
|
24
|
-
viewport: import("@playwright/test").ViewportSize;
|
|
25
|
-
userAgent: string;
|
|
26
|
-
deviceScaleFactor: number;
|
|
27
|
-
isMobile: boolean;
|
|
28
|
-
hasTouch: boolean;
|
|
29
|
-
defaultBrowserType: 'chromium' | 'firefox' | 'webkit';
|
|
30
|
-
};
|
|
31
|
-
} | {
|
|
32
|
-
name: string;
|
|
33
|
-
grep: RegExp;
|
|
34
|
-
use: {
|
|
35
|
-
userAgent: string;
|
|
36
|
-
deviceScaleFactor: number;
|
|
37
|
-
defaultBrowserType: 'chromium' | 'firefox' | 'webkit';
|
|
38
|
-
viewport: {
|
|
39
|
-
readonly width: 390;
|
|
40
|
-
readonly height: 844;
|
|
41
|
-
};
|
|
42
|
-
isMobile: true;
|
|
43
|
-
hasTouch: true;
|
|
44
|
-
};
|
|
45
|
-
})[];
|
|
46
|
-
};
|
|
47
|
-
//#endregion
|
|
48
|
-
export { _default as default };
|
package/dist/playwright/base.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
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 +0,0 @@
|
|
|
1
|
-
import base_default from"./base.mjs";import{defineConfig as defineConfig$1}from"@playwright/test";import{deepMerge}from"@interfere/helpers/deep-merge";function defineConfig(...overrides){return defineConfig$1(deepMerge(base_default,...overrides))}export{defineConfig};
|
package/dist/vitest/base.d.mts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
//#region src/vitest/base.d.ts
|
|
2
|
-
declare const _default: {
|
|
3
|
-
root: string;
|
|
4
|
-
resolve: {
|
|
5
|
-
conditions: string[];
|
|
6
|
-
};
|
|
7
|
-
ssr: {
|
|
8
|
-
resolve: {
|
|
9
|
-
conditions: string[];
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
test: {
|
|
13
|
-
env: {
|
|
14
|
-
NODE_ENV: string;
|
|
15
|
-
};
|
|
16
|
-
environment: "node";
|
|
17
|
-
globals: true;
|
|
18
|
-
isolate: true;
|
|
19
|
-
pool: "forks";
|
|
20
|
-
maxWorkers: string;
|
|
21
|
-
clearMocks: true;
|
|
22
|
-
restoreMocks: true;
|
|
23
|
-
ui: boolean;
|
|
24
|
-
unstubEnvs: true;
|
|
25
|
-
unstubGlobals: true;
|
|
26
|
-
sequence: {
|
|
27
|
-
shuffle: boolean;
|
|
28
|
-
};
|
|
29
|
-
server: {
|
|
30
|
-
deps: {
|
|
31
|
-
inline: string[];
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
include: string[];
|
|
35
|
-
exclude: string[];
|
|
36
|
-
reporters: ("default" | "junit")[];
|
|
37
|
-
coverage: {
|
|
38
|
-
enabled: true;
|
|
39
|
-
provider: "v8";
|
|
40
|
-
include: string[];
|
|
41
|
-
exclude: string[];
|
|
42
|
-
reportOnFailure: true;
|
|
43
|
-
reporter: ("html" | "lcov" | "text-summary")[] | ("json" | "json-summary" | "lcov")[];
|
|
44
|
-
};
|
|
45
|
-
outputFile: {
|
|
46
|
-
junit: string;
|
|
47
|
-
};
|
|
48
|
-
setupFiles: string[];
|
|
49
|
-
};
|
|
50
|
-
};
|
|
51
|
-
//#endregion
|
|
52
|
-
export { _default as default };
|
package/dist/vitest/base.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
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 +0,0 @@
|
|
|
1
|
-
import base_default from"./base.mjs";import{deepMerge}from"@interfere/helpers/deep-merge";import{defineConfig as defineConfig$1}from"vitest/config";function defineConfig(...overrides){return defineConfig$1(deepMerge(base_default,...overrides))}export{defineConfig};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{afterAll,afterEach,beforeAll}from"vitest";import{setupWorker}from"msw/browser";const worker=setupWorker();function enableMSW(){beforeAll(async()=>{await worker.start({onUnhandledRequest:`bypass`,quiet:!0})}),afterEach(()=>{worker.resetHandlers()}),afterAll(()=>{worker.stop()})}export{enableMSW,worker};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
//#region src/vitest/msw/http.d.ts
|
|
2
|
-
type HttpMethod = "post" | "get" | "put" | "delete" | "patch";
|
|
3
|
-
type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
4
|
-
[key: string]: JsonValue;
|
|
5
|
-
};
|
|
6
|
-
interface CapturedHttpCall {
|
|
7
|
-
body: unknown;
|
|
8
|
-
params: Record<string, string | readonly string[] | undefined>;
|
|
9
|
-
}
|
|
10
|
-
declare function createHttpInterceptor(baseUrl: string): {
|
|
11
|
-
intercept: (method: HttpMethod, path: string, response: JsonValue, status?: number) => CapturedHttpCall[];
|
|
12
|
-
interceptNetworkError: (method: HttpMethod, path: string) => void;
|
|
13
|
-
};
|
|
14
|
-
//#endregion
|
|
15
|
-
export { CapturedHttpCall, HttpMethod, JsonValue, createHttpInterceptor };
|
package/dist/vitest/msw/http.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{worker}from"./browser.mjs";import{HttpResponse,http}from"msw";async function parseBody(request){let clone=request.clone();if((clone.headers.get(`content-type`)??``).includes(`multipart/form-data`)){let formData=await clone.formData();return Object.fromEntries(formData.entries())}return clone.json().catch(()=>null)}function createHttpInterceptor(baseUrl){function intercept(method,path,response,status=200){let calls=[];return worker.use(http[method](`${baseUrl}${path}`,async({request,params})=>(calls.push({body:await parseBody(request),params}),HttpResponse.json(response,{status})))),calls}function interceptNetworkError(method,path){worker.use(http[method](`${baseUrl}${path}`,()=>HttpResponse.error()))}return{intercept,interceptNetworkError}}export{createHttpInterceptor};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { HttpMethod, JsonValue } from "./http.mjs";
|
|
2
|
-
//#region src/vitest/msw/node.d.ts
|
|
3
|
-
declare const server: import("msw/node").SetupServer;
|
|
4
|
-
declare function useMswServer(): typeof server;
|
|
5
|
-
interface CapturedRequest {
|
|
6
|
-
headers: Headers;
|
|
7
|
-
url: URL;
|
|
8
|
-
}
|
|
9
|
-
declare function interceptJson(method: HttpMethod, url: string, response: JsonValue, status?: number): CapturedRequest[];
|
|
10
|
-
declare function interceptError(method: HttpMethod, url: string): void;
|
|
11
|
-
//#endregion
|
|
12
|
-
export { CapturedRequest, interceptError, interceptJson, server, useMswServer };
|
package/dist/vitest/msw/node.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{afterAll,afterEach,beforeAll}from"vitest";import{HttpResponse,http}from"msw";import{setupServer}from"msw/node";const server=setupServer();function useMswServer(){return beforeAll(()=>server.listen({onUnhandledRequest:`error`})),afterEach(()=>server.resetHandlers()),afterAll(()=>server.close()),server}function interceptJson(method,url,response,status=200){let calls=[];return server.use(http[method](url,({request})=>(calls.push({headers:request.headers,url:new URL(request.url)}),HttpResponse.json(response,{status})))),calls}function interceptError(method,url){server.use(http[method](url,()=>HttpResponse.error()))}export{interceptError,interceptJson,server,useMswServer};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { TestUserConfig, UserWorkspaceConfig } from "vitest/config";
|
|
2
|
-
//#region src/vitest/presets/browser.d.ts
|
|
3
|
-
type BrowserConfig = NonNullable<TestUserConfig["browser"]>;
|
|
4
|
-
type BrowserInstance = NonNullable<BrowserConfig["instances"]>[number];
|
|
5
|
-
interface BrowserProjectOptions {
|
|
6
|
-
/**
|
|
7
|
-
* Playwright browser instances to run against. Use `dualViewport()` for the
|
|
8
|
-
* standard Desktop + Mobile split keyed on the `src/**/mobile/**` glob
|
|
9
|
-
* convention.
|
|
10
|
-
*/
|
|
11
|
-
instances: BrowserInstance[];
|
|
12
|
-
testAlias?: string | false;
|
|
13
|
-
trace?: boolean;
|
|
14
|
-
[key: string]: unknown;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Glob matching all tests under a `mobile/` directory. Used by `dualViewport`
|
|
18
|
-
* to split the Desktop / Mobile test runs from a single file tree.
|
|
19
|
-
*/
|
|
20
|
-
declare const MOBILE_TESTS = "src/**/mobile/*.{test,spec}.?(c|m)[jt]s?(x)";
|
|
21
|
-
/**
|
|
22
|
-
* Standard Desktop + Mobile viewport split for UI apps. Desktop runs every
|
|
23
|
-
* test except those under `src/**/mobile/**`; Mobile runs only those.
|
|
24
|
-
*/
|
|
25
|
-
declare function dualViewport(): BrowserInstance[];
|
|
26
|
-
declare function browserProject(opts: BrowserProjectOptions): UserWorkspaceConfig;
|
|
27
|
-
//#endregion
|
|
28
|
-
export { BrowserInstance, BrowserProjectOptions, MOBILE_TESTS, browserProject, dualViewport };
|
|
@@ -1 +0,0 @@
|
|
|
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};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { ViteUserConfig } from "vitest/config";
|
|
2
|
-
//#region src/vitest/presets/integration.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* Integration test resources. Each entry maps to a globalSetup module in
|
|
5
|
-
* `@interfere/internal-test-utils` that owns a single shared container for
|
|
6
|
-
* the duration of the run and tears it down on success, failure, and most
|
|
7
|
-
* signal scenarios.
|
|
8
|
-
*
|
|
9
|
-
* The matching per-worker harness lives at
|
|
10
|
-
* `@interfere/internal-test-utils/lifecycle/<resource>/harness` — import it
|
|
11
|
-
* from your `test/setup.ts`.
|
|
12
|
-
*/
|
|
13
|
-
type IntegrationResource = "pg" | "redis";
|
|
14
|
-
interface IntegrationOptions {
|
|
15
|
-
/**
|
|
16
|
-
* Container resources to provision once per run. Defaults to `["pg"]`.
|
|
17
|
-
*/
|
|
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;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Build a Vitest config for an integration-test package. Wires up the
|
|
34
|
-
* shared-container globalSetup modules so each test run spins up exactly
|
|
35
|
-
* one of each requested resource (instead of one per worker fork) and tears
|
|
36
|
-
* them down reliably on exit.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```ts
|
|
40
|
-
* export default defineIntegrationConfig({ resources: ["pg", "redis"] }, {
|
|
41
|
-
* test: { coverage: { provider: "v8" } },
|
|
42
|
-
* });
|
|
43
|
-
* ```
|
|
44
|
-
*/
|
|
45
|
-
declare function defineIntegrationConfig(options?: IntegrationOptions, ...overrides: (Partial<ViteUserConfig> | undefined)[]): ViteUserConfig;
|
|
46
|
-
//#endregion
|
|
47
|
-
export { IntegrationOptions, IntegrationResource, defineIntegrationConfig };
|
|
@@ -1 +0,0 @@
|
|
|
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,14 +0,0 @@
|
|
|
1
|
-
import { UserWorkspaceConfig } from "vitest/config";
|
|
2
|
-
//#region src/vitest/presets/node.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* Build a Vitest project config running against the Node environment.
|
|
5
|
-
* Spreads `opts` over a shared base; caller-provided fields win.
|
|
6
|
-
*
|
|
7
|
-
* `*.test.{tsx,jsx}` files are excluded by default — React test files can't
|
|
8
|
-
* import `vitest-browser-react` outside of Browser Mode, so they always
|
|
9
|
-
* belong in the `browserProject`. Opt a specific TSX test in by adding its
|
|
10
|
-
* path to the caller's `test.include`.
|
|
11
|
-
*/
|
|
12
|
-
declare function nodeProject(opts?: Partial<UserWorkspaceConfig>): UserWorkspaceConfig;
|
|
13
|
-
//#endregion
|
|
14
|
-
export { nodeProject };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import base_default from"../base.mjs";import{deepMerge}from"@interfere/helpers/deep-merge";function nodeProject(opts={}){return deepMerge(base_default,{test:{name:`node`,environment:`node`,exclude:[`**/*.{test,spec}.tsx`,`**/*.{test,spec}.jsx`,`**/*.{test,spec}.mtsx`,`**/*.{test,spec}.mjsx`]}},opts)}export{nodeProject};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { TestUserConfig, UserWorkspaceConfig } from "vitest/config";
|
|
2
|
-
//#region src/vitest/presets/vite.d.ts
|
|
3
|
-
type BrowserConfig = NonNullable<TestUserConfig["browser"]>;
|
|
4
|
-
type BrowserInstance = NonNullable<BrowserConfig["instances"]>[number];
|
|
5
|
-
interface BrowserProjectOptions {
|
|
6
|
-
instances: BrowserInstance[];
|
|
7
|
-
testAlias?: string | false;
|
|
8
|
-
trace?: boolean;
|
|
9
|
-
[key: string]: unknown;
|
|
10
|
-
}
|
|
11
|
-
declare function dualViewport(): BrowserInstance[];
|
|
12
|
-
declare function viteProject(opts: BrowserProjectOptions): UserWorkspaceConfig;
|
|
13
|
-
//#endregion
|
|
14
|
-
export { BrowserInstance, BrowserProjectOptions, dualViewport, viteProject };
|
|
@@ -1 +0,0 @@
|
|
|
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};
|
|
@@ -1,24 +0,0 @@
|
|
|
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 };
|
|
@@ -1 +0,0 @@
|
|
|
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};
|