@@ -174,6 +174,9 @@ export function createEsmAndCjsTests(
174174 testFn : typeof test | typeof test . fails ,
175175 mode : 'esm' | 'cjs' ,
176176 ) => void ,
177+ // `additionalDependencies` to install in a tmp dir for the esm and cjs tests
178+ // This could be used to override packages that live in the parent package.json for the specific run of the test
179+ // e.g. `{ ai: '^5.0.0' }` to test Vercel AI v5
177180 options ?: { failsOnCjs ?: boolean ; failsOnEsm ?: boolean ; additionalDependencies ?: Record < string , string > } ,
178181) : void {
179182 const mjsScenarioPath = join ( cwd , scenarioPath ) ;
@@ -193,6 +196,18 @@ export function createEsmAndCjsTests(
193196 const tmpDirPath = join ( cwd , `tmp_${ uniqueId } ` ) ;
194197 mkdirSync ( tmpDirPath ) ;
195198
199+ // Ensure tmp dir is removed on process exit as a fallback
200+ CLEANUP_STEPS . add ( ( ) => {
201+ try {
202+ rmSync ( tmpDirPath , { recursive : true , force : true } ) ;
203+ } catch {
204+ if ( process . env . DEBUG ) {
205+ // eslint-disable-next-line no-console
206+ console . error ( `Failed to remove tmp dir: ${ tmpDirPath } ` ) ;
207+ }
208+ }
209+ } ) ;
210+
196211 // Copy ESM files as-is into tmp dir
197212 const esmScenarioBasename = basename ( scenarioPath ) ;
198213 const esmInstrumentBasename = basename ( instrumentPath ) ;
@@ -228,21 +243,20 @@ export function createEsmAndCjsTests(
228243 } ) ;
229244
230245 if ( deps . length > 0 ) {
231- // --ignore-engines is needed to avoid engine mismatches when installing deps in the tmp dir
232- // (e.g. Vercel AI v5 requires a package that requires Node >= 20 while the system Node is 18)
233- // https://github.com/vercel/ai/issues/7777
234- const result = spawnSync ( 'yarn' , [ 'add' , '--non-interactive' , '--ignore-engines' , ...deps ] , {
246+ // Prefer npm for temp installs to avoid Yarn engine strictness; see https://github.com/vercel/ai/issues/7777
247+ // We rely on the generated package.json dependencies and run a plain install.
248+ const result = spawnSync ( 'npm' , [ 'install' , '--silent' , '--no-audit' , '--no-fund' ] , {
235249 cwd : tmpDirPath ,
236250 encoding : 'utf8' ,
237251 } ) ;
238252
239253 if ( process . env . DEBUG ) {
240254 // eslint-disable-next-line no-console
241- console . log ( '[additionalDependencies]' , deps . join ( ' ' ) ) ;
255+ console . log ( '[additionalDependencies via npm ]' , deps . join ( ' ' ) ) ;
242256 // eslint-disable-next-line no-console
243- console . log ( '[yarn stdout]' , result . stdout ) ;
257+ console . log ( '[npm stdout]' , result . stdout ) ;
244258 // eslint-disable-next-line no-console
245- console . log ( '[yarn stderr]' , result . stderr ) ;
259+ console . log ( '[npm stderr]' , result . stderr ) ;
246260 }
247261
248262 if ( result . error ) {
@@ -263,13 +277,22 @@ export function createEsmAndCjsTests(
263277 }
264278 }
265279
266- describe ( 'esm' , ( ) => {
267- const testFn = options ?. failsOnEsm ? test . fails : test ;
268- callback ( ( ) => createRunner ( esmScenarioPathForRun ) . withFlags ( '--import' , esmInstrumentPathForRun ) , testFn , 'esm' ) ;
269- } ) ;
280+ describe ( 'esm/cjs' , ( ) => {
281+ const esmTestFn = options ?. failsOnEsm ? test . fails : test ;
282+ describe ( 'esm' , ( ) => {
283+ callback (
284+ ( ) => createRunner ( esmScenarioPathForRun ) . withFlags ( '--import' , esmInstrumentPathForRun ) ,
285+ esmTestFn ,
286+ 'esm' ,
287+ ) ;
288+ } ) ;
270289
271- describe ( 'cjs' , ( ) => {
272- // Clean up the tmp directory once CJS tests are finished
290+ const cjsTestFn = options ?. failsOnCjs ? test . fails : test ;
291+ describe ( 'cjs' , ( ) => {
292+ callback ( ( ) => createRunner ( cjsScenarioPath ) . withFlags ( '--require' , cjsInstrumentPath ) , cjsTestFn , 'cjs' ) ;
293+ } ) ;
294+
295+ // Clean up the tmp directory after both esm and cjs suites have run
273296 afterAll ( ( ) => {
274297 try {
275298 rmSync ( tmpDirPath , { recursive : true , force : true } ) ;
@@ -280,9 +303,6 @@ export function createEsmAndCjsTests(
280303 }
281304 }
282305 } ) ;
283-
284- const testFn = options ?. failsOnCjs ? test . fails : test ;
285- callback ( ( ) => createRunner ( cjsScenarioPath ) . withFlags ( '--require' , cjsInstrumentPath ) , testFn , 'cjs' ) ;
286306 } ) ;
287307}
288308
0 commit comments