@@ -174,6 +174,9 @@ export function createEsmAndCjsTests(
174
174
testFn : typeof test | typeof test . fails ,
175
175
mode : 'esm' | 'cjs' ,
176
176
) => 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
177
180
options ?: { failsOnCjs ?: boolean ; failsOnEsm ?: boolean ; additionalDependencies ?: Record < string , string > } ,
178
181
) : void {
179
182
const mjsScenarioPath = join ( cwd , scenarioPath ) ;
@@ -193,6 +196,18 @@ export function createEsmAndCjsTests(
193
196
const tmpDirPath = join ( cwd , `tmp_${ uniqueId } ` ) ;
194
197
mkdirSync ( tmpDirPath ) ;
195
198
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
+
196
211
// Copy ESM files as-is into tmp dir
197
212
const esmScenarioBasename = basename ( scenarioPath ) ;
198
213
const esmInstrumentBasename = basename ( instrumentPath ) ;
@@ -228,21 +243,20 @@ export function createEsmAndCjsTests(
228
243
} ) ;
229
244
230
245
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' ] , {
235
249
cwd : tmpDirPath ,
236
250
encoding : 'utf8' ,
237
251
} ) ;
238
252
239
253
if ( process . env . DEBUG ) {
240
254
// eslint-disable-next-line no-console
241
- console . log ( '[additionalDependencies]' , deps . join ( ' ' ) ) ;
255
+ console . log ( '[additionalDependencies via npm ]' , deps . join ( ' ' ) ) ;
242
256
// eslint-disable-next-line no-console
243
- console . log ( '[yarn stdout]' , result . stdout ) ;
257
+ console . log ( '[npm stdout]' , result . stdout ) ;
244
258
// eslint-disable-next-line no-console
245
- console . log ( '[yarn stderr]' , result . stderr ) ;
259
+ console . log ( '[npm stderr]' , result . stderr ) ;
246
260
}
247
261
248
262
if ( result . error ) {
@@ -263,13 +277,22 @@ export function createEsmAndCjsTests(
263
277
}
264
278
}
265
279
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
+ } ) ;
270
289
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
273
296
afterAll ( ( ) => {
274
297
try {
275
298
rmSync ( tmpDirPath , { recursive : true , force : true } ) ;
@@ -280,9 +303,6 @@ export function createEsmAndCjsTests(
280
303
}
281
304
}
282
305
} ) ;
283
-
284
- const testFn = options ?. failsOnCjs ? test . fails : test ;
285
- callback ( ( ) => createRunner ( cjsScenarioPath ) . withFlags ( '--require' , cjsInstrumentPath ) , testFn , 'cjs' ) ;
286
306
} ) ;
287
307
}
288
308
0 commit comments