@gfdelarue/testkit 0.3.3 → 0.3.5
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/README.md +11 -0
- package/dist/app/doctor/index.js +1 -1
- package/dist/app/inspect/artifacts.d.ts +1 -0
- package/dist/app/inspect/artifacts.js +1 -1
- package/dist/app/inspect/index.js +1 -1
- package/dist/app/lint/index.js +1 -1
- package/dist/app/lint/native.js +1 -1
- package/dist/app/lint/policy.js +1 -1
- package/dist/app/lint/rules/data.js +1 -1
- package/dist/app/lint/rules/engine-imports.js +1 -1
- package/dist/app/lint/rules/syntax.js +1 -1
- package/dist/app/lint/rules/unit.js +1 -1
- package/dist/app/lint/shared.d.ts +1 -1
- package/dist/app/lint/shared.js +1 -1
- package/dist/app/run/orchestrator.js +1 -1
- package/dist/app/run/request.js +1 -1
- package/dist/app/setup/playwright.js +1 -1
- package/dist/app/status/index.d.ts +2 -0
- package/dist/app/status/index.js +1 -1
- package/dist/app/status/runs.d.ts +2 -2
- package/dist/app/status/runs.js +1 -1
- package/dist/app/stop/index.js +1 -1
- package/dist/app/typecheck/index.d.ts +2 -0
- package/dist/app/typecheck/index.js +4 -4
- package/dist/cli/commands/artifacts.js +2 -2
- package/dist/cli/commands/db/schema/refresh.js +1 -1
- package/dist/cli/commands/db/schema/verify.js +1 -1
- package/dist/cli/commands/doctor.js +1 -1
- package/dist/cli/operations/db/schema/refresh/operation.d.ts +1 -0
- package/dist/cli/operations/db/schema/refresh/operation.js +1 -1
- package/dist/cli/operations/db/schema/verify/operation.d.ts +1 -0
- package/dist/cli/operations/db/schema/verify/operation.js +1 -1
- package/dist/cli/operations/run/operation.js +1 -1
- package/dist/config/loader/discover-tests.d.ts +5 -0
- package/dist/config/loader/discover-tests.js +1 -1
- package/dist/config/loader/discovery.js +2 -2
- package/dist/config/loader/file-metadata.js +1 -1
- package/dist/config/loader/index.d.ts +2 -1
- package/dist/config/loader/index.js +1 -1
- package/dist/config/loader/load.d.ts +2 -0
- package/dist/config/loader/load.js +1 -1
- package/dist/config/loader/managed-configs.d.ts +2 -0
- package/dist/config/loader/managed-configs.js +1 -1
- package/dist/config/loader/paths.d.ts +1 -1
- package/dist/config/loader/paths.js +1 -1
- package/dist/config/loader/skip-config.d.ts +1 -1
- package/dist/config/loader/test-selection.d.ts +15 -0
- package/dist/config/loader/test-selection.js +1 -0
- package/dist/config/loader/validation.js +1 -1
- package/dist/database/index.d.ts +1 -3
- package/dist/database/index.js +1 -1
- package/dist/database/lifecycle-cleanup.d.ts +7 -0
- package/dist/database/lifecycle-cleanup.js +1 -0
- package/dist/database/local-postgres.js +1 -1
- package/dist/database/schema-source.js +3 -3
- package/dist/engines/adapters/evidence-files.js +1 -1
- package/dist/engines/catalog.d.ts +3 -8
- package/dist/engines/catalog.js +1 -1
- package/dist/engines/definitions.d.ts +8 -1
- package/dist/engines/definitions.js +1 -1
- package/dist/engines/generated-performance.d.ts +1 -0
- package/dist/engines/generated-performance.js +12 -0
- package/dist/engines/installations/node-vitest.d.ts +8 -22
- package/dist/engines/installations/node-vitest.js +1 -1
- package/dist/engines/installations/package-requirements.d.ts +28 -0
- package/dist/engines/installations/package-requirements.js +1 -0
- package/dist/engines/installations/playwright.d.ts +1 -11
- package/dist/engines/installations/playwright.js +1 -1
- package/dist/engines/k6/adapter/repository-configuration.d.ts +1 -1
- package/dist/engines/k6/adapter/repository-configuration.js +1 -1
- package/dist/engines/managed-module-resolution.js +111 -21
- package/dist/engines/manager.d.ts +1 -0
- package/dist/engines/manager.js +1 -1
- package/dist/engines/node-vitest/adapter/adapter.d.ts +1 -1
- package/dist/engines/node-vitest/adapter/adapter.js +1 -1
- package/dist/engines/node-vitest/adapter/consumer-typescript-paths.js +1 -1
- package/dist/engines/node-vitest/adapter/resolution.d.ts +1 -1
- package/dist/engines/node-vitest/adapter/resolution.js +1 -1
- package/dist/engines/node-vitest/adapter/workspace.js +33 -9
- package/dist/engines/node-vitest/runtime/runtime-input.d.ts +1 -0
- package/dist/engines/node-vitest/runtime/runtime-input.js +1 -1
- package/dist/engines/runtime-input-file.d.ts +3 -1
- package/dist/engines/runtime-input-file.js +1 -1
- package/dist/environment/lifecycle-controller.d.ts +1 -2
- package/dist/environment/lifecycle-controller.js +1 -1
- package/dist/environment/lifecycle.js +1 -1
- package/dist/environment/maintenance.d.ts +1 -1
- package/dist/environment/maintenance.js +1 -1
- package/dist/environment/ready-environment.d.ts +1 -1
- package/dist/environment/ready-environment.js +1 -1
- package/dist/environment/runtime-contexts.d.ts +1 -1
- package/dist/environment/runtime-contexts.js +1 -1
- package/dist/environment/runtime-preparation.js +1 -1
- package/dist/environment/services.js +1 -1
- package/dist/environment/template.d.ts +1 -1
- package/dist/environment/template.js +1 -1
- package/dist/evidence/bundles.js +1 -1
- package/dist/evidence/read-run.js +1 -1
- package/dist/evidence/reading.d.ts +1 -1
- package/dist/evidence/reading.js +1 -1
- package/dist/evidence/storage.js +2 -2
- package/dist/kernel/error-serialization.js +1 -1
- package/dist/kernel/work-metrics.d.ts +6 -0
- package/dist/kernel/work-metrics.js +1 -0
- package/dist/process/capture-output.js +1 -1
- package/dist/process/execa-bundle.json +1 -1
- package/dist/process/files/product-dir.d.ts +1 -0
- package/dist/process/files/product-dir.js +1 -0
- package/dist/process/locks.js +4 -4
- package/dist/process/readiness.js +1 -1
- package/dist/process/runs/inspection.d.ts +5 -0
- package/dist/process/runs/inspection.js +1 -0
- package/dist/process/runs/manifest.d.ts +1 -0
- package/dist/process/runs/manifest.js +1 -1
- package/dist/process/service-processes.d.ts +1 -1
- package/dist/process/service-processes.js +1 -1
- package/dist/steps/environment.d.ts +6 -0
- package/dist/steps/environment.js +1 -1
- package/dist/steps/index.d.ts +1 -1
- package/dist/steps/index.js +1 -1
- package/dist/toolchains/index.js +2 -2
- package/docs/engine-architecture.md +4 -1
- package/docs/test-types.md +9 -0
- package/package.json +2 -1
- package/testkit-config-schema.md +52 -0
- package/dist/cli/renderers/artifact-preview.d.ts +0 -4
- package/dist/cli/renderers/artifact-preview.js +0 -1
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import o from"fs";import s from"path";import{createRequire as J}from"node:module";import{collectRepoState as
|
|
2
|
-
`))}export async function appendSourceSchemaCacheToHash(e,r,t=null){if(!(r.testkit.database?.sourceSchema||null))return;const a=t?.cachePath||await getSourceSchemaCachePath(r),n=t?.active&&t.cacheKey?t.cacheKey:s.relative(getSourceSchemaRootDir(r),s.dirname(a));if(e.update(`source-schema-key:${n}`),e.update(`source-schema-cache:${s.relative(r.productDir,a)}`),!o.existsSync(a)){e.update(":missing");return}const i=o.statSync(a);e.update(`:${i.size.toString()}:${i.mtimeMs.toString()}`)
|
|
3
|
-
`}function
|
|
1
|
+
import{recordWork as l}from"../kernel/work-metrics.js";import o from"fs";import s from"path";import{createRequire as J}from"node:module";import{collectRepoState as V,summarizeRepoStateForMetadata as _}from"../repo/state.js";import{findDatabasePlaceholders as X,resolveExecutionEnvValues as Z}from"../steps/index.js";import{dumpPostgresSchemaToFile as G,captureTemplateSnapshotText as Q,resolvePgDumpClientImage as Y,runTemplateStep as ee,sanitizeSnapshotText as re}from"./template-steps.js";import{getSourceSchemaRefreshLockPath as te,withSourceSchemaRefreshLock as ae}from"./source-refresh-lock.js";import{resolveSourceSchemaDumpUrl as ce}from"./source-url.js";import{makeTempDir as ne,removeTempDir as se}from"../process/files/temp-dir.js";import{requireContainedDatabaseStateDirectory as k,resolveContainedDatabaseStateDirectory as w}from"./state.js";const K=J(import.meta.url);let P;function ie(){if(P)return P;const e=K.resolve("diff/package.json"),t=JSON.parse(o.readFileSync(e,"utf8"))?.exports?.["."]?.import?.default;if(typeof t!="string"||!t.startsWith("./"))throw new Error("The diff package must declare a local ESM import entry");const c=s.dirname(e),a=s.resolve(c,t),n=s.relative(c,a);if(!n||n===".."||n.startsWith(`..${s.sep}`)||s.isAbsolute(n))throw new Error("The diff package ESM import entry must stay within its package directory");return P=K(a)}const U="db",$="source-schemas",b="source-schema.sql",E="source-schema.meta.json",oe="index.json",M=20,y=String;export function getSourceSchemaRootDir(e){return w(e.productDir,U,e.name,$)}export async function getSourceSchemaCachePath(e,r={}){return(await resolveSourceSchemaCacheLocation(e,r)).cachePath}export async function resolveSourceSchemaCacheLocation(e,r={}){const t=r.repoState||await V(e.productDir,{fingerprints:e.testkit?.fingerprints}),c=getSourceSchemaRootDir(e),a=w(e.productDir,U,e.name,$,...t.cacheKey.split("/").map(D));return{rootDir:c,cacheDir:a,cachePath:s.join(a,b),metadataPath:s.join(a,E),indexPath:s.join(c,oe),cacheKey:t.cacheKey,cacheKind:t.kind,repoState:t}}export async function resolveSourceSchemaState(e,r={}){const t=e.testkit.database?.sourceSchema||null;if(!t)return{active:!1};const c=await resolveSourceSchemaCacheLocation(e,r),a=c.cachePath,n=o.existsSync(a);n&&x(a);const i=r.env||process.env,u=t.kind==="env"?[t.env]:[j(e.name),"TESTKIT_SCHEMA_SOURCE_DATABASE_URL"];Ae(e,u);const h=Z(e,[...u,"CI"],i),m=u.find(z=>{const R=h[z];return typeof R=="string"&&R.trim().length>0})||null,S=m?h[m]:void 0,p=typeof S=="string"?S.trim():null;return t.kind==="env"||!!p||n?{active:!0,cachePath:a,metadataPath:c.metadataPath,indexPath:c.indexPath,rootDir:c.rootDir,cacheDir:c.cacheDir,cacheKey:c.cacheKey,cacheKind:c.cacheKind,repoState:c.repoState,envName:m,sourceUrl:p,sourceSchema:t,cacheExists:n,refreshed:!1,ci:h.CI==="true",unavailableMode:ge(t.unavailable,i)}:{active:!1,cachePath:a}}export async function prepareSourceSchemaCache(e,r={}){r.signal?.throwIfAborted();const t=await resolveSourceSchemaState(e,r);if(!t.active)return t;if(B(t)){if(pe(t))try{const a=await L(e,t,r),n={...t,refreshed:!0,cacheExists:!0,refreshInfo:a};return v(e,n,{refreshed:!0}),n}catch(a){r.signal?.throwIfAborted();const n=ue(e,t,a,r);if(n)return n;throw a}return v(e,t),r.setupRegistry?.recordCached({config:e,stage:"source-schema",kind:"database-source-schema",summary:"source schema cache hit"}),t}if(t.cacheExists&&t.unavailableMode==="warn-cache")return v(e,t),r.setupRegistry?.recordCached({config:e,stage:"source-schema",kind:"database-source-schema",summary:"source unavailable; using cached source schema"}),t;const c=t.sourceSchema.kind==="env"?t.sourceSchema.env:`${j(e.name)} or TESTKIT_SCHEMA_SOURCE_DATABASE_URL`;throw new Error(`Source schema database URL is unavailable for service "${e.name}". Set ${c}.`)}function ue(e,r,t,c={}){if(r.unavailableMode!=="warn-cache")return null;const a=he(e,r);if(!a)return null;const n={...r,...a,cacheExists:!0,refreshed:!1,refreshError:Ce(t)};return c.setupRegistry?.recordCached({config:e,stage:"source-schema",kind:"database-source-schema",summary:`source unavailable; using cached source schema: ${s.relative(e.productDir,a.cachePath)}`}),n}function he(e,r){const t=F(e,r,{cachePath:r.cachePath,metadataPath:r.metadataPath,cacheKey:r.cacheKey,cacheKind:r.cacheKind});if(t)return t;const c=O(r.indexPath);c.sort((a,n)=>Date.parse(n.lastUsedAt||n.refreshedAt||"0")-Date.parse(a.lastUsedAt||a.refreshedAt||"0"));for(const a of c){if(!a.cachePath)continue;const n=s.resolve(e.productDir,a.cachePath),i=F(e,r,{cachePath:n,metadataPath:s.join(s.dirname(n),E),cacheKey:a.cacheKey,cacheKind:a.kind||"unknown"});if(i)return i}return null}function F(e,r,t){const c=s.resolve(t.cachePath);if(s.basename(c)!==b)return null;const a=k(e.productDir,s.dirname(c),`Service "${e.name}" source schema cache directory`),n=s.join(a,b),i=s.resolve(r.rootDir);if(n!==i&&!n.startsWith(`${i}${s.sep}`)||!o.existsSync(n))return null;const u=o.lstatSync(n);if(u.isSymbolicLink()||!u.isFile())throw new Error(`Refusing unsafe source schema cache file at ${n}`);return{cachePath:n,metadataPath:s.join(a,E),cacheDir:a,cacheKey:t.cacheKey,cacheKind:t.cacheKind,indexPath:r.indexPath,rootDir:r.rootDir}}export async function forceRefreshSourceSchemaCache(e,r,t={}){const c=await resolveSourceSchemaState(e,t);if(!c.active||!B(c)){const i=r?.active?r.envName:null,u=r?.active&&r.sourceSchema.kind==="env"?r.sourceSchema.env:null,h=i||u||"source schema env";throw new Error(`Cannot refresh source schema for service "${e.name}" because ${h} is unavailable.`)}const a=await L(e,c,t),n={...c,refreshed:!0,cacheExists:!0,refreshInfo:a};return v(e,n,{refreshed:!0}),n}export async function applySourceSchemaCache(e,r,t,c={}){if(!t?.active)return!1;if(!o.existsSync(t.cachePath))throw new Error(`Missing source schema cache for service "${e.name}": ${t.cachePath}`);const a={kind:"sql-file",path:s.relative(e.productDir,t.cachePath).split(s.sep).join("/"),cwd:null,inputs:[]};return l("schema.sourceReplays"),await ee(e,"source-schema",a,0,r,c),!0}export async function verifyLocalSchemaMatchesSource(e,r,t,c={}){if(!t?.active)return{status:"disabled"};if(!t.sourceSchema.verify||c.skipSchemaSourceVerify)return c.setupRegistry?.recordCached({config:e,stage:"source-schema:verify",kind:"database-source-schema",summary:"source schema verification skipped"}),{status:"skipped"};De(e);const a=fe(t.cachePath);l("schema.verificationDumps");const n=await Q(e,r,{image:await c.resolveLocalSnapshotImage?.(),ownedContainer:c.ownedContainer||null,reporter:c.reporter||null,signal:c.signal});return l("schema.comparisons"),l("schema.bytesCompared",Buffer.byteLength(a)+Buffer.byteLength(n)),n===a?{status:"matched"}:{status:"mismatch",diagnostics:await Pe(e,t,a,n)}}export function createSourceSchemaMismatchError(e,r,t){const c=[`Local schema replay does not match source schema for service "${e.name}".`,`Source cache: ${s.relative(e.productDir,r.cachePath)}`];return t?.status==="mismatch"&&c.push(`Diff: ${s.relative(e.productDir,t.diagnostics.diffPath)}`),new Error(c.join(`
|
|
2
|
+
`))}export async function appendSourceSchemaCacheToHash(e,r,t=null){if(!(r.testkit.database?.sourceSchema||null))return;const a=t?.cachePath||await getSourceSchemaCachePath(r),n=t?.active&&t.cacheKey?t.cacheKey:s.relative(getSourceSchemaRootDir(r),s.dirname(a));if(e.update(`source-schema-key:${n}`),e.update(`source-schema-cache:${s.relative(r.productDir,a)}`),!o.existsSync(a)){e.update(":missing");return}const i=o.statSync(a);e.update(`:${i.size.toString()}:${i.mtimeMs.toString()}`);const u=o.readFileSync(a);l("schema.cacheHashFilesRead"),l("schema.cacheHashBytesRead",u.length),e.update(u)}async function L(e,r,t={}){const c=t.setupRegistry,a=c?.start({config:e,stage:"source-schema:refresh",kind:"database-source-schema",summary:`source schema refresh: ${s.relative(e.productDir,r.cachePath)}`});try{const n=await ae(te(r.cachePath),async({waited:u,requestedAt:h})=>{const m=de(r,h);if(m)return{reusedExistingRefresh:!0,waitedForLock:u,metadata:m};const S=await me(e,r.sourceUrl,r.cachePath,{reporter:t.reporter||null,logRecord:a?._logRecord||null,env:t.env||process.env,signal:t.signal}),p=le(e,r,S);return ye(r.metadataPath,p),{reusedExistingRefresh:!1,waitedForLock:u,metadata:p}},{signal:t.signal}),i=a&&c?c.finish(a,{status:"passed",summary:`source schema refresh: ${s.relative(e.productDir,r.cachePath)}`}):null;return i&&t.reporter?.setupOperationFinished?.(i),n}catch(n){const i=a?c?.finish(a,{status:"failed",summary:`source schema refresh: ${s.relative(e.productDir,r.cachePath)}`,error:Re(n)}):null;throw i&&t.reporter?.setupOperationFinished?.(i),n}}async function me(e,r,t,c={}){const a=ce(r);o.mkdirSync(s.dirname(t),{recursive:!0});const n=ne(".source-schema-",{parentDir:s.dirname(t)}),i=s.join(n,s.basename(t));try{const u=await Y(e,a.dumpUrl,{env:c.env||process.env,pgApplicationName:g(e.name),signal:c.signal});return l("schema.sourceDumps"),await G(e,i,a.dumpUrl,{...c,image:u,pgApplicationName:g(e.name)}),o.renameSync(i,t),{resolution:a,pgDump:{args:["--schema-only","--no-owner","--no-privileges"],applicationName:g(e.name),image:u}}}finally{se(n)}}function le(e,r,t){return{refreshedAt:new Date().toISOString(),serviceName:e.name,envName:r.envName,cacheKey:r.cacheKey,cacheKind:r.cacheKind,cachePath:s.relative(e.productDir,r.cachePath),repo:_(r.repoState),sourceUrl:t.resolution.metadata,pgDump:t.pgDump}}function de(e,r){if(!o.existsSync(e.cachePath))return null;const t=A(e.metadataPath);if(!Ke(t))return null;const c=Date.parse(t.refreshedAt);return!Number.isFinite(c)||c<r?null:t}function g(e){return`testkit:schema-source:${e.replace(/[^a-zA-Z0-9._:-]+/g,"-").slice(0,24)||"service"}`}function fe(e){const r=o.readFileSync(e);return l("schema.cacheFilesRead"),l("schema.cacheBytesRead",r.length),re(r.toString("utf8"))}function pe(e){if(!e.cacheExists)return!0;if(e.sourceSchema.refresh.mode==="auto")return e.ci;if(e.sourceSchema.refresh.mode==="ttl"){const r=C(e.metadataPath),t=r?Date.parse(r):0;return!Number.isFinite(t)||t<=0?!0:Date.now()-t>=e.sourceSchema.refresh.ttlSeconds*1e3}return!0}function v(e,r,t={}){if(!r?.active)return;const c=new Date().toISOString(),a=O(r.indexPath).filter(u=>u.cacheKey!==r.cacheKey),n=C(r.metadataPath);a.push({cacheKey:r.cacheKey,kind:r.cacheKind,commitSha:r.repoState.commitSha||null,branch:r.repoState.branch||null,detached:r.repoState.detached,dirty:r.repoState.dirty,dirtyFingerprint:r.repoState.dirtyFingerprint||null,contentFingerprint:r.repoState.contentFingerprint||null,remoteUrl:r.repoState.remoteUrl||null,repository:r.repoState.repository,cachePath:s.relative(e.productDir,r.cachePath),refreshedAt:t.refreshed?c:n,lastUsedAt:c});const i=Se(e,r,a);N(r.indexPath,{version:1,entries:i})}function Se(e,r,t){if(t.length<=M)return t;const c=[...t].sort((n,i)=>Date.parse(i.lastUsedAt||"0")-Date.parse(n.lastUsedAt||"0")),a=new Set(c.slice(0,M).map(n=>n.cacheKey));a.add(r.cacheKey);for(const n of t){if(a.has(n.cacheKey))continue;const i=n.cachePath?s.join(e.productDir,n.cachePath):null,u=i?s.resolve(i):null,h=s.resolve(r.rootDir);if(!i||!u||u!==h&&!u.startsWith(`${h}${s.sep}`))continue;const m=k(e.productDir,s.dirname(i),`Service "${e.name}" pruned source schema cache directory`);o.rmSync(m,{recursive:!0,force:!0})}return t.filter(n=>a.has(n.cacheKey))}function ye(e,r){I(e,r)}function N(e,r){I(e,r)}function I(e,r){o.mkdirSync(s.dirname(e),{recursive:!0}),x(e),o.writeFileSync(e,xe(r))}function A(e){if(!e||!o.existsSync(e))return null;x(e);try{return JSON.parse(o.readFileSync(e,"utf8"))}catch{return null}}function T(e){return w(e.productDir,"results","schema")}function x(e){if(!o.existsSync(e))return;const r=o.lstatSync(e);if(r.isSymbolicLink()||!r.isFile())throw new Error(`Refusing unsafe source schema state file at ${e}`)}function ve(e){return`${D(e.runtimeLabel||e.name)}__${D(e.name)}`}function De(e){const r=T(e);if(!o.existsSync(r))return;const t=D(e.name);for(const c of o.readdirSync(r))we(c,t)&&o.rmSync(s.join(r,c),{force:!0})}function we(e,r){for(const t of["__source-schema.sql","__local-replay-schema.sql","__schema.diff","__schema.meta.json"])if(e.endsWith(t))return e.slice(0,-t.length).endsWith(`__${r}`);return!1}async function Pe(e,r,t,c){const a=T(e);o.mkdirSync(a,{recursive:!0});const n=ve(e),i=s.join(a,`${n}__source-schema.sql`),u=s.join(a,`${n}__local-replay-schema.sql`),h=s.join(a,`${n}__schema.diff`),m=s.join(a,`${n}__schema.meta.json`);return o.writeFileSync(i,t),o.writeFileSync(u,c),o.writeFileSync(h,await Ee(i,u)),N(m,be(e,r)),{sourceCachePath:r.cachePath,sourcePath:i,localPath:u,diffPath:h,metaPath:m}}function be(e,r){const t=C(r.metadataPath);return{version:1,createdAt:new Date().toISOString(),serviceName:e.name,runtimeLabel:e.runtimeLabel||e.name,sourceSchema:{envName:r.envName||null,cacheKey:r.cacheKey||null,cacheKind:r.cacheKind||null,cachePath:s.relative(e.productDir,r.cachePath),refreshedAt:t},repo:_(r.repoState)}}function Ee(e,r){return new Promise(t=>{t(buildUnifiedDiffText(o.readFileSync(e,"utf8"),o.readFileSync(r,"utf8"),e,r))})}export function buildUnifiedDiffText(e,r,t="source",c="target"){if(e===r)return"";const{createTwoFilesPatch:a}=ie();return a(t,c,y(e),y(r),"","",{context:3})}function ge(e,r){return e==="fail"||e==="warn-cache"?e:r.CI==="true"?"fail":"warn-cache"}function j(e){return`TESTKIT_${e.toUpperCase().replace(/[^A-Z0-9]+/g,"_")}_SCHEMA_SOURCE_DATABASE_URL`}function Ae(e,r){const t={...e.testkit.serviceEnv,...e.testkit.local?.env};for(const c of r){const a=t[c];if(typeof a!="string")continue;const n=X(a).find(i=>(i.serviceName??e.name)===e.name);if(n)throw new Error(`Service "${e.name}" env ${c} uses ${n.placeholder}, which is the database the source schema verifies. Point it at another service's database or an external database URL.`)}}function D(e){return e.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"schema"}function O(e){const r=A(e);return!f(r)||!Array.isArray(r.entries)?[]:r.entries.filter(_e)}function C(e){const r=A(e);return f(r)&&typeof r.refreshedAt=="string"?r.refreshedAt:null}function xe(e){return`${y(JSON.stringify(e,null,2))}
|
|
3
|
+
`}function Ce(e){const r=H(e,"message");return!!r?r:y(e)}function Re(e){const r=H(e,"message");return!!r?r:e}function H(e,r){if(!(e===null||typeof e!="object"&&typeof e!="function"))return Reflect.get(e,r)}function B(e){return!!e.sourceUrl}function _e(e){return!f(e)||typeof e.cacheKey!="string"||e.cacheKey.length===0?!1:d(e.branch)&&d(e.cachePath)&&d(e.commitSha)&&d(e.contentFingerprint)&&W(e.detached)&&W(e.dirty)&&d(e.dirtyFingerprint)&&d(e.kind)&&d(e.lastUsedAt)&&d(e.refreshedAt)&&d(e.remoteUrl)&&ke(e.repository)}function ke(e){return e==null||f(e)&&typeof e.host=="string"&&typeof e.owner=="string"&&typeof e.name=="string"}function Ke(e){return f(e)&&typeof e.refreshedAt=="string"&&(e.sourceUrl===void 0||Ue(e.sourceUrl))}function Ue(e){return f(e)&&typeof e.originalHost=="string"&&q(e.originalClassification)&&typeof e.resolvedHost=="string"&&q(e.resolvedClassification)&&typeof e.rewritten=="boolean"}function q(e){return e==="neon-pooler"||e==="neon-direct"||e==="unsupported-pooler"||e==="unknown-direct"}function $e(e){return e===null||typeof e=="string"}function d(e){return e===void 0||$e(e)}function W(e){return e===void 0||typeof e=="boolean"}function f(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{requireNativeEvidenceJson as
|
|
1
|
+
import{requireNativeEvidenceJson as N}from"./native-report.js";import E from"node:crypto";import{constants as O}from"node:fs";import d from"node:fs/promises";import F from"node:path";import{readOnlyNoFollowOpenFlags as R,sameFileSnapshot as U,samePathAndHandleFileSnapshot as C}from"../../process/files/file-snapshot.js";const z=64*1024;export const evidenceFileAccess={lstat:async t=>d.lstat(t,{bigint:!0}),openReadOnly:async t=>d.open(t,R(process.platform,O)),platform:process.platform,readChunk:async(t,n)=>(await t.read(n,0,n.byteLength,null)).bytesRead,statHandle:async t=>t.stat({bigint:!0})};export function stableEvidenceFromBuffer(t){return{contents:t,sha256:E.createHash("sha256").update(t).digest("hex"),sizeBytes:t.byteLength}}export async function readStableJsonFile(t,n,e,r){let i;try{i=await readStableEvidenceFile(t,n,e,r)}catch(o){if(L(o))return{file:null,value:null};throw o}let a;try{a=JSON.parse(i.contents.toString("utf8"))}catch(o){throw new Error(`${e} is not valid JSON`,{cause:o})}return N(a,e),{file:i,value:a}}export async function readStableEvidenceFile(t,n,e,r,i){const a=i??await r.lstat(t);u(a,n,e);const o=await r.openReadOnly(t);try{const w=await r.statHandle(o);u(w,n,e),m(a,w,e,r.platform);const p=[],l=E.createHash("sha256");let h=0;const s=Buffer.allocUnsafe(z);for(;;){const f=await r.readChunk(o,s);if(I(f,s.byteLength,e),f===0)break;if(h+=f,h>n)throw new Error(`${e} exceeds its ${n.toString()} byte limit`);const g=Buffer.from(s.subarray(0,f));p.push(g),l.update(g)}const c=await r.statHandle(o),y=await r.lstat(t);if(u(c,n,e),u(y,n,e),S(w,c,e),S(a,y,e),m(y,c,e,r.platform),BigInt(h)!==w.size)throw new Error(`${e} changed while it was read`);return{contents:Buffer.concat(p,h),sha256:l.digest("hex"),sizeBytes:h}}finally{await o.close()}}export async function writeOwnedEvidenceFile(t,n,e){const r=F.join(t,n),i=F.join(t,`.${n}.${E.randomUUID()}.tmp`);let a=null;try{return a=await d.open(i,"wx",384),await a.writeFile(e),await a.sync(),await a.close(),a=null,await d.rename(i,r),process.platform!=="win32"&&await d.chmod(r,384),r}catch(o){throw a!==null&&await a.close().catch(()=>{}),await d.rm(i,{force:!0}).catch(()=>{}),o}}export async function snapshotStableEvidenceFile(t,n,e,r,i,a,o){const w=await r.lstat(t);u(w,n,e),S(i,w,e);const p=await r.openReadOnly(t),l=F.join(a,o),h=F.join(a,`.${o}.${E.randomUUID()}.tmp`);let s=null;try{const c=await r.statHandle(p);u(c,n,e),m(w,c,e,r.platform),s=await d.open(h,"wx",384);const y=E.createHash("sha256");let f=0;const g=Buffer.allocUnsafe(z);for(;;){const $=await r.readChunk(p,g);if(I($,g.byteLength,e),$===0)break;if(f+=$,f>n)throw new Error(`${e} exceeds its ${n.toString()} byte limit`);const k=g.subarray(0,$);await s.write(k),y.update(k)}const v=await r.statHandle(p),H=await r.lstat(t);if(u(v,n,e),u(H,n,e),S(c,v,e),S(w,H,e),m(H,v,e,r.platform),BigInt(f)!==c.size)throw new Error(`${e} changed while it was read`);return await s.sync(),await s.close(),s=null,await d.rename(h,l),process.platform!=="win32"&&await d.chmod(l,384),{filePath:l,identity:{sha256:y.digest("hex"),sizeBytes:f}}}catch(c){throw s!==null&&await s.close().catch(()=>{}),await d.rm(h,{force:!0}).catch(()=>{}),c}finally{await p.close()}}export function evidenceArtifact(t,n,e,r,i,a){return{contentType:e,kind:r,metadata:{sha256:n.sha256,sizeBytes:n.sizeBytes},name:i,path:t,summary:a}}function I(t,n,e){if(!Number.isSafeInteger(t)||t<0||t>n)throw new Error(`${e} returned an invalid read length`)}function u(t,n,e){if(!t.isFile()||t.isSymbolicLink())throw new Error(`${e} must be a regular non-symbolic-link file`);if(t.size<0n||t.size>BigInt(n))throw new Error(`${e} exceeds its ${n.toString()} byte limit`)}function S(t,n,e){if(!U(t,n))throw new Error(`${e} changed while it was read`)}function m(t,n,e,r){if(!C(t,n,r))throw new Error(`${e} changed while it was read`)}function L(t){return t instanceof Error&&"code"in t&&t.code==="ENOENT"}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { EngineJsonObject, RunnerProfileDescriptor } from "./api/index.js";
|
|
2
2
|
import { BUILT_IN_RUNNER_PROFILES } from "./definitions.js";
|
|
3
|
-
import {
|
|
4
|
-
export
|
|
5
|
-
readonly engineId: EngineId;
|
|
6
|
-
readonly profileId: RunnerProfileId;
|
|
7
|
-
readonly testType: PublicTestType;
|
|
8
|
-
}
|
|
3
|
+
import type { EngineId, PublicTestType, RunnerProfileId } from "../domain/identifiers.js";
|
|
4
|
+
export { isEngineProfileIdentity, type EngineProfileIdentity } from "./definitions.js";
|
|
9
5
|
export interface EngineCatalog {
|
|
10
6
|
readonly profiles: readonly RunnerProfileDescriptor[];
|
|
11
7
|
profilesForTestType(testType: PublicTestType): readonly RunnerProfileDescriptor[];
|
|
@@ -14,7 +10,6 @@ export interface EngineCatalog {
|
|
|
14
10
|
export declare const BUILT_IN_ENGINE_CATALOG: EngineCatalog;
|
|
15
11
|
export { BUILT_IN_RUNNER_PROFILES };
|
|
16
12
|
export declare function resolveEngineProfile<Id extends EngineId>(testType: PublicTestType, engineId: Id): RunnerProfileDescriptor<Id>;
|
|
17
|
-
export declare function isEngineProfileIdentity(value: unknown): value is EngineProfileIdentity;
|
|
18
13
|
type EngineAuthoringModule = "@gfdelarue/testkit/k6" | "@gfdelarue/testkit/node-vitest/data" | "@gfdelarue/testkit/node-vitest/contract" | "@gfdelarue/testkit/playwright";
|
|
19
14
|
export interface EngineAuthoringProfile {
|
|
20
15
|
readonly engineId: EngineId;
|
|
@@ -25,7 +20,7 @@ export interface ManagedPublicPackageOwner {
|
|
|
25
20
|
name: string;
|
|
26
21
|
}
|
|
27
22
|
export type EngineConfigurations = Readonly<Partial<Record<EngineId, EngineJsonObject>>>;
|
|
28
|
-
export declare function buildEngineConfigurations(config: object, engineIds: ReadonlySet<EngineId>): EngineConfigurations | undefined
|
|
23
|
+
export declare function buildEngineConfigurations(config: object, engineIds: ReadonlySet<EngineId>): Promise<EngineConfigurations | undefined>;
|
|
29
24
|
export declare function expectedEngineAuthoringModule(profileId: RunnerProfileId): EngineAuthoringModule;
|
|
30
25
|
export declare function invalidEngineAuthoringImport(filePath: string, metadata: Readonly<EngineAuthoringProfile>, specifier: string, expectedModule?: EngineAuthoringModule): Error;
|
|
31
26
|
export declare function requireMatchingHostImport(filePath: string, metadata: Readonly<EngineAuthoringProfile>, specifier: string): void;
|
package/dist/engines/catalog.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{builtinModules as
|
|
1
|
+
import{builtinModules as u}from"node:module";import{NODE_VITEST_PACKAGE_REQUIREMENTS as s,NODE_VITEST_PRIVATE_PACKAGE_PREFIXES as d}from"./installations/package-requirements.js";import{PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS as a}from"./installations/package-requirements.js";import{BUILT_IN_RUNNER_PROFILES as i}from"./definitions.js";export{isEngineProfileIdentity}from"./definitions.js";export const BUILT_IN_ENGINE_CATALOG=Object.freeze({profiles:i,profilesForTestType(e){return Object.freeze(i.filter(n=>n.supportedTestTypes.includes(e)))},resolve(e,n){const t=i.find(r=>r.engineId===n&&r.supportedTestTypes.includes(e));if(!t)throw new Error(`Unsupported engine/test-type pair: ${n}/${e}`);return t}});export{i as BUILT_IN_RUNNER_PROFILES};export function resolveEngineProfile(e,n){return BUILT_IN_ENGINE_CATALOG.resolve(e,n)}const p=new Set(u.map(e=>e.replace(/^node:/u,""))),l=Object.freeze([...s.map(({packageName:e})=>Object.freeze({engineId:"node-vitest",name:e})),...a.map(({packageName:e})=>Object.freeze({engineId:"playwright",name:e}))]);export async function buildEngineConfigurations(e,n){if(!n.has("k6"))return;const{buildK6RepositoryConfiguration:t}=await import("./k6/adapter/repository-configuration.js"),r=t(e);return r===void 0?void 0:{k6:r}}export function expectedEngineAuthoringModule(e){switch(e){case"k6-http":case"k6-dal":return"@gfdelarue/testkit/k6";case"node-vitest-data":return"@gfdelarue/testkit/node-vitest/data";case"node-vitest-contract":return"@gfdelarue/testkit/node-vitest/contract";case"playwright-ui":return"@gfdelarue/testkit/playwright"}}export function invalidEngineAuthoringImport(e,n,t,r=expectedEngineAuthoringModule(n.profileId)){return new Error(`Invalid Testkit authoring in "${e}": ${n.engineId}/${n.profileId} may not import "${t}"; use "${r}" for this suite`)}export function requireMatchingHostImport(e,n,t){if(n.engineId==="k6"&&g(t))throw new Error(`Invalid Testkit authoring in "${e}": k6 suites may not import Node built-in module "${t}"`);if(n.engineId!=="k6"&&I(t))throw new Error(`Invalid Testkit authoring in "${e}": ${n.engineId} suites may not import k6 module "${t}"`);if(d.some(o=>t.startsWith(o)))throw new Error(`Invalid Testkit authoring in "${e}": ${n.engineId} suites may not import private Vitest implementation package "${t}"`);const r=managedPublicPackageOwner(t);if(r!==null&&r.engineId!==n.engineId)throw new Error(`Invalid Testkit authoring in "${e}": ${n.engineId} suites may not import ${r.engineId} package "${t}"`)}export function managedPublicPackageOwner(e){for(const n of l)if(e===n.name||e.startsWith(`${n.name}/`))return n;return null}function g(e){const n=e.replace(/^node:/u,"");return p.has(n)}function I(e){return e==="k6"||e.startsWith("k6/")}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RunnerProfileDescriptor } from "./api/index.js";
|
|
2
|
-
import type { EngineId } from "../domain/identifiers.js";
|
|
2
|
+
import type { EngineId, PublicTestType, RunnerProfileId } from "../domain/identifiers.js";
|
|
3
3
|
import type { InternalEngineRegistrationById } from "./installation-catalog.js";
|
|
4
4
|
export type EndpointReadinessOwner = "adapter" | "orchestrator-http";
|
|
5
5
|
export interface BuiltInRunnerProfile<Id extends EngineId = EngineId> extends RunnerProfileDescriptor<Id> {
|
|
@@ -12,4 +12,11 @@ type BuiltInDefinitions = {
|
|
|
12
12
|
};
|
|
13
13
|
export declare const BUILT_IN_ENGINE_DEFINITIONS: BuiltInDefinitions;
|
|
14
14
|
export declare const BUILT_IN_RUNNER_PROFILES: readonly BuiltInRunnerProfile[];
|
|
15
|
+
export interface EngineProfileIdentity {
|
|
16
|
+
readonly engineId: EngineId;
|
|
17
|
+
readonly profileId: RunnerProfileId;
|
|
18
|
+
readonly testType: PublicTestType;
|
|
19
|
+
}
|
|
20
|
+
/** Validate persisted identities without loading engine configuration builders. */
|
|
21
|
+
export declare function isEngineProfileIdentity(value: unknown): value is EngineProfileIdentity;
|
|
15
22
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export const BUILT_IN_ENGINE_DEFINITIONS=Object.freeze({k6:Object.freeze({id:"k6",profiles:Object.freeze([t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"k6",id:"k6-http",supportedTestTypes:["int","e2e","load"],endpointReadinessOwner:"orchestrator-http"}),t({capabilities:{applicationRuntime:"none",databaseRuntime:"required",endpointAccess:"none",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"k6",id:"k6-dal",supportedTestTypes:["dal"],endpointReadinessOwner:"adapter"})]),async resolveInstallation(e){return(await import("./installations/k6.js")).resolveK6Installation(e)},async loadExecutor(){return(await import("./k6/adapter/index.js")).executeK6Engine}}),"node-vitest":Object.freeze({id:"node-vitest",profiles:Object.freeze([t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"node-vitest",id:"node-vitest-data",supportedTestTypes:["data"],endpointReadinessOwner:"adapter"}),t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"node-vitest",id:"node-vitest-contract",supportedTestTypes:["contract"],endpointReadinessOwner:"adapter"})]),async resolveInstallation(e){return(await import("./installations/node-vitest.js")).resolveNodeVitestInstallation(e)},async loadExecutor(){return(await import("./node-vitest/adapter/index.js")).executeNodeVitestEngine}}),playwright:Object.freeze({id:"playwright",profiles:Object.freeze([t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"compatible"},engineId:"playwright",id:"playwright-ui",supportedTestTypes:["ui"],endpointReadinessOwner:"orchestrator-http"})]),async resolveInstallation(e){return(await import("./installations/playwright.js")).resolvePlaywrightInstallation(e)},async loadExecutor(){return(await import("./playwright/adapter/index.js")).executePlaywrightEngine}})}),BUILT_IN_RUNNER_PROFILES=Object.freeze(Object.values(BUILT_IN_ENGINE_DEFINITIONS).flatMap(e=>e.profiles));export function isEngineProfileIdentity(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;const i=e,n=BUILT_IN_RUNNER_PROFILES.find(a=>a.engineId===i.engineId&&a.supportedTestTypes.some(o=>o===i.testType));return n!==void 0&&n.id===i.profileId}function t(e){return Object.freeze(e.capabilities),Object.freeze(e.supportedTestTypes),Object.freeze(e)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function ownedGeneratedScript(source: string, label: string): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const t=`
|
|
2
|
+
function __testkitWithOwner(owner, label, callback) {
|
|
3
|
+
const observer = globalThis[Symbol.for("testkit.performance.observer")];
|
|
4
|
+
const finish = observer?.beginPerformanceOwner?.(owner, label);
|
|
5
|
+
try { return callback(); }
|
|
6
|
+
finally { finish?.(); }
|
|
7
|
+
}
|
|
8
|
+
`;export function ownedGeneratedScript(e,n){return`${t}
|
|
9
|
+
__testkitWithOwner("testkit", ${JSON.stringify(n)}, () => {
|
|
10
|
+
${e}
|
|
11
|
+
});
|
|
12
|
+
`}
|
|
@@ -1,23 +1,6 @@
|
|
|
1
|
+
export { NODE_VITEST_PACKAGE_REQUIREMENTS, NODE_VITEST_PRIVATE_PACKAGE_PREFIXES } from "./package-requirements.js";
|
|
1
2
|
import { RootPackageResolver, type ResolvedPackageEntrypoint } from "./package-resolution.js";
|
|
2
3
|
import type { DirectPackageInstallation, EngineResolutionContext } from "./types.js";
|
|
3
|
-
export declare const NODE_VITEST_PACKAGE_REQUIREMENTS: readonly [Readonly<{
|
|
4
|
-
authoringResolution: "package-exports";
|
|
5
|
-
packageName: "vitest";
|
|
6
|
-
publicEntrypoints: readonly ["vitest"];
|
|
7
|
-
}>, Readonly<{
|
|
8
|
-
authoringResolution: "package-exports";
|
|
9
|
-
packageName: "vite";
|
|
10
|
-
publicEntrypoints: readonly ["vite"];
|
|
11
|
-
}>, Readonly<{
|
|
12
|
-
authoringResolution: "exact-entrypoint";
|
|
13
|
-
packageName: "typescript";
|
|
14
|
-
publicEntrypoints: readonly ["typescript"];
|
|
15
|
-
}>, Readonly<{
|
|
16
|
-
authoringResolution: "exact-entrypoint";
|
|
17
|
-
packageName: "esbuild";
|
|
18
|
-
publicEntrypoints: readonly ["esbuild"];
|
|
19
|
-
}>];
|
|
20
|
-
export declare const NODE_VITEST_PRIVATE_PACKAGE_PREFIXES: readonly ["@vitest/"];
|
|
21
4
|
interface VitestPackageInstallation extends DirectPackageInstallation<"vitest"> {
|
|
22
5
|
readonly cli: string;
|
|
23
6
|
}
|
|
@@ -39,9 +22,12 @@ export interface NodeVitestInstallation {
|
|
|
39
22
|
};
|
|
40
23
|
}
|
|
41
24
|
interface NodeVitestResolutionDependencies {
|
|
42
|
-
readonly importEntrypoint: (selectedPackage: Readonly<ResolvedPackageEntrypoint>) => Promise<unknown>;
|
|
43
25
|
readonly packageResolver: RootPackageResolver;
|
|
44
26
|
}
|
|
45
|
-
export declare function resolveNodeVitestInstallation(context: Readonly<EngineResolutionContext>, dependencies?: Readonly<NodeVitestResolutionDependencies>):
|
|
46
|
-
export declare function preflightNodeVitestInstallation(installation: Readonly<NodeVitestInstallation>, context: Readonly<
|
|
47
|
-
|
|
27
|
+
export declare function resolveNodeVitestInstallation(context: Readonly<EngineResolutionContext>, dependencies?: Readonly<NodeVitestResolutionDependencies>): NodeVitestInstallation;
|
|
28
|
+
export declare function preflightNodeVitestInstallation(installation: Readonly<NodeVitestInstallation>, context: Readonly<{
|
|
29
|
+
signal: {
|
|
30
|
+
readonly aborted: boolean;
|
|
31
|
+
readonly reason?: unknown;
|
|
32
|
+
};
|
|
33
|
+
}>, importEntrypoint?: (selectedPackage: Readonly<ResolvedPackageEntrypoint>) => Promise<unknown>): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import{NODE_VITEST_PACKAGE_REQUIREMENTS as u}from"./package-requirements.js";export{NODE_VITEST_PACKAGE_REQUIREMENTS,NODE_VITEST_PRIVATE_PACKAGE_PREFIXES}from"./package-requirements.js";import l from"node:fs";import p from"node:path";import{isPathWithin as d}from"../../process/files/paths.js";import{BrokenPackageInstallationError as f,RootPackageResolver as y,importResolvedPackageEntrypoint as g}from"./package-resolution.js";const v=Object.freeze({packageResolver:new y});export function resolveNodeVitestInstallation(t,e=v){t.signal.throwIfAborted();const o=new Map;for(const n of u)o.set(n.packageName,e.packageResolver.resolveImportFromRoot({dependencyGroup:"dependencies",packageName:n.packageName,publicEntrypoint:n.publicEntrypoints[0]}));const r=s(o,"vitest");return Object.freeze({authoringEntrypoints:m(e.packageResolver),engineId:"node-vitest",packages:Object.freeze({esbuild:c(s(o,"esbuild")),typescript:c(s(o,"typescript")),vite:c(s(o,"vite")),vitest:Object.freeze({...c(r),cli:h(r,e.packageResolver)})})})}function m(t){return Object.freeze({config:t.resolveRootPublicEntrypoint("@gfdelarue/testkit/config"),contract:t.resolveRootPublicEntrypoint("@gfdelarue/testkit/node-vitest/contract"),data:t.resolveRootPublicEntrypoint("@gfdelarue/testkit/node-vitest/data"),root:t.resolveRootPublicEntrypoint("@gfdelarue/testkit"),rootPackageJson:t.packageJsonPath})}export async function preflightNodeVitestInstallation(t,e,o=g){for(const r of u){b(e.signal);const i=t.packages[r.packageName];try{const n=await o(i);await k(r.packageName,n)}catch(n){throw b(e.signal),new f(i.name,i.version,`its public ${r.packageName} capability failed; reinstall without omitting optional dependencies`,{cause:T(n)})}}}function s(t,e){const o=t.get(e);if(o===void 0||o.name!==e)throw new TypeError(`Node/Vitest package resolution did not select ${e}`);return o}function c(t){return Object.freeze({entrypoint:t.entrypoint,name:t.name,root:t.root,version:t.version})}function h(t,e){try{const r=w(t.manifestPath).bin,i=typeof r=="object"&&r!==null&&!Array.isArray(r)?r.vitest:r;if(typeof i!="string"||p.isAbsolute(i))throw new TypeError("package bin.vitest must be a relative path");const n=l.realpathSync(p.resolve(t.root,i));if(!d(t.root,n)||!l.statSync(n).isFile())throw new TypeError("package bin.vitest must resolve to a contained regular file");return n}catch(o){throw e.brokenInstallation(t,"its public Vitest CLI is invalid",o)}}function w(t){const e=JSON.parse(l.readFileSync(t,"utf8"));if(typeof e!="object"||e===null||Array.isArray(e))throw new TypeError("package manifest must contain a JSON object");return e}async function k(t,e){const o=E(e,`${t} public module`);switch(t){case"vitest":a(o,"expect",t),a(o,"test",t);return;case"vite":return;case"typescript":{const r=E(o.ScriptTarget,"typescript ScriptTarget");a(o,"createSourceFile",t)("preflight.ts","export {};",r.Latest);return}case"esbuild":a(o,"stop",t),await a(o,"build",t)({stdin:{contents:"export {};",loader:"js"},write:!1})}}function E(t,e){if(typeof t!="object"||t===null)throw new TypeError(`${e} must be an object`);return t}function a(t,e,o){const r=t[e];if(typeof r!="function")throw new TypeError(`${o} public module must export function ${e}`);return r}function T(t){return t instanceof f&&t.cause!==void 0?t.cause:t}function b(t){if(t.aborted)throw t.reason instanceof Error?t.reason:new Error("Node/Vitest installation check cancelled",{cause:t.reason})}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const NODE_VITEST_PACKAGE_REQUIREMENTS: readonly [Readonly<{
|
|
2
|
+
authoringResolution: "package-exports";
|
|
3
|
+
packageName: "vitest";
|
|
4
|
+
publicEntrypoints: readonly ["vitest"];
|
|
5
|
+
}>, Readonly<{
|
|
6
|
+
authoringResolution: "package-exports";
|
|
7
|
+
packageName: "vite";
|
|
8
|
+
publicEntrypoints: readonly ["vite"];
|
|
9
|
+
}>, Readonly<{
|
|
10
|
+
authoringResolution: "exact-entrypoint";
|
|
11
|
+
packageName: "typescript";
|
|
12
|
+
publicEntrypoints: readonly ["typescript"];
|
|
13
|
+
}>, Readonly<{
|
|
14
|
+
authoringResolution: "exact-entrypoint";
|
|
15
|
+
packageName: "esbuild";
|
|
16
|
+
publicEntrypoints: readonly ["esbuild"];
|
|
17
|
+
}>];
|
|
18
|
+
export declare const NODE_VITEST_PRIVATE_PACKAGE_PREFIXES: readonly ["@vitest/"];
|
|
19
|
+
export declare const PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS: readonly [Readonly<{
|
|
20
|
+
packageName: "@playwright/test";
|
|
21
|
+
publicEntrypoints: readonly ["@playwright/test", "@playwright/test/cli"];
|
|
22
|
+
}>, Readonly<{
|
|
23
|
+
packageName: "playwright";
|
|
24
|
+
publicEntrypoints: readonly ["playwright"];
|
|
25
|
+
}>, Readonly<{
|
|
26
|
+
packageName: "playwright-core";
|
|
27
|
+
publicEntrypoints: readonly ["playwright-core"];
|
|
28
|
+
}>];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const NODE_VITEST_PACKAGE_REQUIREMENTS=Object.freeze([Object.freeze({authoringResolution:"package-exports",packageName:"vitest",publicEntrypoints:Object.freeze(["vitest"])}),Object.freeze({authoringResolution:"package-exports",packageName:"vite",publicEntrypoints:Object.freeze(["vite"])}),Object.freeze({authoringResolution:"exact-entrypoint",packageName:"typescript",publicEntrypoints:Object.freeze(["typescript"])}),Object.freeze({authoringResolution:"exact-entrypoint",packageName:"esbuild",publicEntrypoints:Object.freeze(["esbuild"])})]),NODE_VITEST_PRIVATE_PACKAGE_PREFIXES=Object.freeze(["@vitest/"]),PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS=Object.freeze([Object.freeze({packageName:"@playwright/test",publicEntrypoints:Object.freeze(["@playwright/test","@playwright/test/cli"])}),Object.freeze({packageName:"playwright",publicEntrypoints:Object.freeze(["playwright"])}),Object.freeze({packageName:"playwright-core",publicEntrypoints:Object.freeze(["playwright-core"])})]);
|
|
@@ -1,17 +1,8 @@
|
|
|
1
|
+
export { PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS } from "./package-requirements.js";
|
|
1
2
|
import { type ManagedProcessResult } from "../../process/index.js";
|
|
2
3
|
import { type LinuxLibc, type PlatformTarget } from "../../process/host/platform.js";
|
|
3
4
|
import { RootPackageResolver } from "./package-resolution.js";
|
|
4
5
|
import type { DirectPackageInstallation, EngineResolutionContext } from "./types.js";
|
|
5
|
-
export declare const PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS: readonly [Readonly<{
|
|
6
|
-
packageName: "@playwright/test";
|
|
7
|
-
publicEntrypoints: readonly ["@playwright/test", "@playwright/test/cli"];
|
|
8
|
-
}>, Readonly<{
|
|
9
|
-
packageName: "playwright";
|
|
10
|
-
publicEntrypoints: readonly ["playwright"];
|
|
11
|
-
}>, Readonly<{
|
|
12
|
-
packageName: "playwright-core";
|
|
13
|
-
publicEntrypoints: readonly ["playwright-core"];
|
|
14
|
-
}>];
|
|
15
6
|
export interface PlaywrightPackageFamily {
|
|
16
7
|
readonly cli: string;
|
|
17
8
|
readonly playwright: DirectPackageInstallation<"playwright">;
|
|
@@ -82,4 +73,3 @@ export declare function parsePlaywrightChildOutput(stdout: string): ParsedChildO
|
|
|
82
73
|
export declare function requireMatchingPlaywrightChildRequest(output: Readonly<PlaywrightChildSuccess>, request: Readonly<PlaywrightChildRequest>): void;
|
|
83
74
|
export declare function requireBrowserExecutable(value: string, target: Readonly<PlatformTarget>): string;
|
|
84
75
|
export declare function requireSupportedPlaywrightHost(host: Readonly<PlaywrightHost>): void;
|
|
85
|
-
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import c from"node:fs";import w from"node:os";import f from"node:path";import{fileURLToPath as h}from"node:url";import{runManagedProcess as
|
|
1
|
+
import{PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS as R}from"./package-requirements.js";export{PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS}from"./package-requirements.js";import c from"node:fs";import w from"node:os";import f from"node:path";import{fileURLToPath as h}from"node:url";import{runManagedProcess as x}from"../../process/index.js";import{currentLinuxLibc as T,currentPlatformTarget as _,platformTargetKey as d,SUPPORTED_PLATFORM_TARGETS as I}from"../../process/host/platform.js";import{RootPackageResolver as m}from"./package-resolution.js";const A=64*1024,O=6e4,b="PLAYWRIGHT_BROWSERS_PATH",S=new Set(["npm_config_playwright_browsers_path","npm_package_config_playwright_browsers_path"]);export class PlaywrightInstallationError extends Error{code="TESTKIT_PLAYWRIGHT_INSTALLATION_INVALID";constructor(r,t){super(`Playwright installation is invalid: ${r}. Run testkit setup playwright --force.`,t),this.name="PlaywrightInstallationError"}}export class UnsupportedPlaywrightPlatformError extends Error{code="TESTKIT_PLAYWRIGHT_PLATFORM_UNSUPPORTED";constructor(r,t){super(`Playwright does not support ${d(r)}${r.platform==="linux"?` with ${t??"unknown"} libc`:""}`),this.name="UnsupportedPlaywrightPlatformError"}}export function resolvePlaywrightPackageFamily(e=new m){const[r,t,o]=R,i=e.resolveRequireFromRoot(u(r)),n=e.resolveImportFromRoot(u(r));L(e,i,n);const a=e.resolveRequireFromPackage(i,u(t)),s=e.resolveRequireFromPackage(a,u(o)),P=e.resolveRequirePublicEntrypoint(i,r.publicEntrypoints[1]);return Object.freeze({cli:P,playwright:p(a,"playwright"),playwrightCore:p(s,"playwright-core"),playwrightTest:p(n,"@playwright/test")})}function L(e,r,t){if(!(r.name===t.name&&r.version===t.version&&r.root===t.root))throw e.brokenInstallation(r,"the import and require public entrypoints select different physical package roots",void 0)}export function resolvePlaywrightRegistry(e){const r=e.platform==="win32"?f.win32:f.posix;if(!r.isAbsolute(e.productRoot))throw new TypeError("Playwright product root must be absolute");const t=e.configuredValue;if(t==="0")return Object.freeze({canonicalValue:"0",mode:"hermetic"});if(t!==void 0&&t.length>0){const o=r.isAbsolute(t);return Object.freeze({canonicalValue:o?r.normalize(t):r.resolve(e.productRoot,t),mode:o?"configured-absolute":"configured-relative"})}return Object.freeze({canonicalValue:r.resolve(e.productRoot,r.join(C(e.platform,e.ambientEnvironment,e.homeDirectory??w.homedir(),r),"ms-playwright")),mode:"default"})}export function playwrightRegistryEnvironment(e,r){const t={};for(const[o,i]of Object.entries(e))typeof i=="string"&&!S.has(o.toLowerCase())&&o.toUpperCase()!==b&&(t[o]=i);return t[b]=r.canonicalValue,Object.freeze(t)}export async function resolvePlaywrightInstallation(e,r={}){e.signal.throwIfAborted();const t={linuxLibc:T(),target:_()};requireSupportedPlaywrightHost(t);const o=new m,i=r.ambientEnvironment??process.env,n=resolvePlaywrightPackageFamily(o),a=resolvePlaywrightRegistry({ambientEnvironment:i,configuredValue:r.configuredRegistry??i.PLAYWRIGHT_BROWSERS_PATH,homeDirectory:w.homedir(),platform:t.target.platform,productRoot:e.productRoot}),s=await k(e,{family:n,registry:a},i);return Object.freeze({authoringEntrypoints:Object.freeze({authoring:o.resolveRootPublicEntrypoint("@gfdelarue/testkit/playwright"),root:o.resolveRootPublicEntrypoint("@gfdelarue/testkit"),rootPackageJson:o.resolveRootPublicEntrypoint("@gfdelarue/testkit/package.json")}),browserExecutable:requireBrowserExecutable(s.browserExecutable,t.target),engineId:"playwright",family:n,registry:a})}async function k(e,r,t){const o=Buffer.from(JSON.stringify(r),"utf8").toString("base64url"),i=await x({args:[N(),o],cwd:e.productRoot,displayLabel:"Playwright installation resolver",env:playwrightRegistryEnvironment(t,r.registry),executable:process.execPath,signal:e.signal,timeoutMs:O}),n=j(i);throwIfPlaywrightProcessAborted(e.signal,i,n),requireBoundedPlaywrightChildOutput(i.stdout);let a;try{a=parsePlaywrightChildOutput(i.stdout)}catch(s){throw n!==null?new PlaywrightInstallationError(`isolated resolver failed: ${n.message}`,{cause:n}):s}if(n!==null)throw new PlaywrightInstallationError(`isolated resolver failed: ${n.message}`,{cause:n});if(!a.ok){if(i.exitCode!==1||i.exitSignal!==null){const s=E(i);throw new PlaywrightInstallationError(`isolated resolver failed: ${s.message}`,{cause:s})}throw new PlaywrightInstallationError(`isolated resolver failed: ${a.error.message}`,{cause:M(a.error)})}if(i.exitCode!==0||i.exitSignal!==null){const s=E(i);throw new PlaywrightInstallationError(`isolated resolver failed: ${s.message}`,{cause:s})}return requireMatchingPlaywrightChildRequest(a,r),a}export function throwIfPlaywrightProcessAborted(e,r,t){if(e.aborted){if(!v(r)||t===null){e.throwIfAborted();return}throw t===e.reason?t:new AggregateError([e.reason,t],"Playwright process was cancelled and process cleanup also failed",{cause:e.reason})}}function v(e){return e.terminationError!==null||e.error!==null||e.timedOut||e.outputLimitExceeded}export function requireBoundedPlaywrightChildOutput(e){if(Buffer.byteLength(e,"utf8")>A)throw new PlaywrightInstallationError("isolated resolver returned oversized output")}export function parsePlaywrightChildOutput(e){let r;try{r=JSON.parse(e)}catch(t){throw new PlaywrightInstallationError("isolated resolver did not return bounded JSON",{cause:t})}if(!l(r)||typeof r.ok!="boolean")throw new PlaywrightInstallationError("isolated resolver returned an invalid response");if(!r.ok){if(!l(r.error)||typeof r.error.name!="string"||typeof r.error.message!="string"||r.error.code!==void 0&&typeof r.error.code!="string")throw new PlaywrightInstallationError("isolated resolver returned an invalid error");return{error:{...r.error.code===void 0?{}:{code:r.error.code},message:r.error.message,name:r.error.name},ok:!1}}if(typeof r.browserExecutable!="string"||!$(r.family)||!H(r.registry))throw new PlaywrightInstallationError("isolated resolver returned an invalid installation");return{browserExecutable:r.browserExecutable,family:r.family,ok:!0,registry:r.registry}}export function requireMatchingPlaywrightChildRequest(e,r){if(JSON.stringify(e.family)!==JSON.stringify(r.family))throw new PlaywrightInstallationError("isolated resolver selected a different physical package family");if(e.registry.canonicalValue!==r.registry.canonicalValue||e.registry.mode!==r.registry.mode)throw new PlaywrightInstallationError("isolated resolver selected a different browser registry")}export function requireBrowserExecutable(e,r){if(!f.isAbsolute(e))throw new PlaywrightInstallationError(`public chromium.executablePath() returned a non-absolute path ${JSON.stringify(e)}`);let t;try{t=c.statSync(e)}catch(o){throw new PlaywrightInstallationError(`public chromium.executablePath() returned missing path ${JSON.stringify(e)}`,{cause:o})}if(!t.isFile())throw new PlaywrightInstallationError(`public chromium.executablePath() must identify a regular file; received ${JSON.stringify(e)}`);if(r.platform!=="win32")try{c.accessSync(e,c.constants.X_OK)}catch(o){throw new PlaywrightInstallationError(`public chromium.executablePath() is not executable: ${JSON.stringify(e)}`,{cause:o})}return e}export function requireSupportedPlaywrightHost(e){const r=d(e.target);if(!I.some(t=>d(t)===r)||e.target.platform==="linux"&&e.linuxLibc!=="glibc")throw new UnsupportedPlaywrightPlatformError(e.target,e.linuxLibc)}function C(e,r,t,o){return e==="linux"?r.XDG_CACHE_HOME||o.join(g(t),".cache"):e==="darwin"?o.join(g(t),"Library","Caches"):r.LOCALAPPDATA||o.join(g(t),"AppData","Local")}function g(e){if(e.length===0)throw new TypeError("Playwright default registry requires a home directory");return e}function u(e){return{dependencyGroup:"dependencies",packageName:e.packageName,publicEntrypoint:e.publicEntrypoints[0]}}function p(e,r){if(e.name!==r)throw new TypeError(`Playwright package family expected ${r}, received ${e.name}`);return Object.freeze({entrypoint:e.entrypoint,name:r,root:e.root,version:e.version})}function N(){const e=h(new URL("./playwright-resolution-child.js",import.meta.url));return c.existsSync(e)?e:h(new URL("../../../dist/engines/installations/playwright-resolution-child.js",import.meta.url))}function j(e){return e.terminationError!==null?e.terminationError:e.error!==null?e.error:e.timedOut?new Error("isolated resolver timed out"):e.cancelled?new Error("isolated resolver was cancelled"):e.outputLimitExceeded?new Error("isolated resolver output exceeded the bound"):null}function E(e){return new Error(`isolated resolver exited with ${e.exitCode===null?String(e.exitSignal):e.exitCode.toString()}`)}function M(e){const r=new Error(e.message);return r.name=e.name,e.code!==void 0&&Object.defineProperty(r,"code",{enumerable:!0,value:e.code}),r}function $(e){return l(e)&&typeof e.cli=="string"&&y(e.playwrightTest,"@playwright/test")&&y(e.playwright,"playwright")&&y(e.playwrightCore,"playwright-core")}function y(e,r){return l(e)&&e.name===r&&typeof e.version=="string"&&typeof e.root=="string"&&typeof e.entrypoint=="string"}function H(e){return l(e)&&typeof e.canonicalValue=="string"&&(e.mode==="configured-absolute"||e.mode==="configured-relative"||e.mode==="default"||e.mode==="hermetic")}function l(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { EngineJsonObject } from "../../api/evidence.js";
|
|
2
2
|
export declare function buildK6RepositoryConfiguration(config: object): EngineJsonObject | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{normalizeEngineJsonValue as c}from"../../api/
|
|
1
|
+
import{normalizeEngineJsonValue as c}from"../../api/runtime-artifact.js";import{K6_REPOSITORY_CONFIGURATION_VERSION as u}from"../../contracts/k6-repository-configuration.js";export function buildK6RepositoryConfiguration(e){const t=i(e,"profiles","testkit config profiles");if(t===void 0)return;const o=i(t,"http","testkit config profiles.http");if(o===void 0)return;const r=[];for(const[n,s]of Object.entries(o)){if(n.trim().length===0)throw new TypeError("testkit config profiles.http keys must be non-empty");r.push([n,p(s,`testkit config profiles.http.${n}`)])}const f=Object.fromEntries(r);return Object.freeze({httpProfiles:Object.freeze(f),kind:"testkit-k6-repository-configuration",version:u})}function p(e,t){try{return Object.freeze({kind:"json",value:l(c(e,t),t)})}catch(o){throw new TypeError(`${t} cannot cross the Node/k6 runtime boundary. Repository profiles must be JSON-only. Define setup and header functions in the k6 suite module instead.`,{cause:o})}}function l(e,t){if(e===null||Array.isArray(e)||typeof e!="object")throw new TypeError(`${t} must be a JSON object`);return e}function i(e,t,o){const r=Reflect.get(e,t);if(r!=null){if(!d(r))throw new TypeError(`${o} must be an object`);return r}}function d(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}
|