@@ -885,6 +885,67 @@ describe('package-environment', () => {
885885 }
886886 } )
887887
888+ it ( 'lowers pkgMinAgentVersion from package engines field (lines 366-373)' , async ( ) => {
889+ mockFindUp . mockImplementation ( async files => {
890+ if ( Array . isArray ( files ) && files . includes ( 'package-lock.json' ) ) {
891+ return '/project/package-lock.json'
892+ }
893+ if ( files === 'package.json' ) {
894+ return '/project/package.json'
895+ }
896+ return undefined
897+ } )
898+ mockExistsSync . mockReturnValue ( true )
899+ mockWhichBin . mockResolvedValue ( '/usr/local/bin/npm' )
900+ // Engines pin npm to >=8.0.0 and node to >=16.0.0 — both < the
901+ // minimum supported defaults, so they lower pkgMin*Version.
902+ mockReadPackageJson . mockResolvedValue ( {
903+ name : 'test-project' ,
904+ version : '1.0.0' ,
905+ engines : {
906+ npm : '>=8.0.0' ,
907+ node : '>=16.0.0' ,
908+ } ,
909+ } )
910+ // Stub semver.lt: any coerced < default is true.
911+ mockSatisfies . mockReturnValue ( true )
912+
913+ const result = await detectAndValidatePackageEnvironment ( '/project' )
914+
915+ expect ( result . ok ) . toBe ( true )
916+ } )
917+
918+ it ( 'lowers pkgMinNodeVersion from browserslist node targets (lines 387-399)' , async ( ) => {
919+ mockFindUp . mockImplementation ( async files => {
920+ if ( Array . isArray ( files ) && files . includes ( 'package-lock.json' ) ) {
921+ return '/project/package-lock.json'
922+ }
923+ if ( files === 'package.json' ) {
924+ return '/project/package.json'
925+ }
926+ return undefined
927+ } )
928+ mockExistsSync . mockReturnValue ( true )
929+ mockWhichBin . mockResolvedValue ( '/usr/local/bin/npm' )
930+ mockReadPackageJson . mockResolvedValue ( {
931+ name : 'test-project' ,
932+ version : '1.0.0' ,
933+ browserslist : [ 'node 16.0.0' , 'node 18.0.0' , 'chrome 120' ] ,
934+ } )
935+ // browserslist returns the targets sorted by browserslist itself; we
936+ // also want the node-* filter to keep ['node 16.0.0', 'node 18.0.0'].
937+ const mockBrowserslist = ( await import ( 'browserslist' ) ) . default as any
938+ mockBrowserslist . mockReturnValue ( [
939+ 'node 16.0.0' ,
940+ 'node 18.0.0' ,
941+ 'chrome 120' ,
942+ ] )
943+
944+ const result = await detectAndValidatePackageEnvironment ( '/project' )
945+
946+ expect ( result . ok ) . toBe ( true )
947+ } )
948+
888949 it ( 'detects yarn-berry when yarn-classic agent has major > 1 (lines 348-349)' , async ( ) => {
889950 mockFindUp . mockImplementation ( async files => {
890951 if ( Array . isArray ( files ) && files . includes ( 'yarn.lock' ) ) {
0 commit comments