@@ -178,6 +178,51 @@ t.test('approve-scripts --json outputs structured summary', async t => {
178178 } )
179179} )
180180
181+ t . test ( 'approve-scripts --pending --json lists unreviewed packages as JSON' , async t => {
182+ const { npm, joinedOutput } = await mockNpm ( t , {
183+ prefixDir : setupProject ( { withScripts : [ 'canvas' , 'sharp' ] } ) ,
184+ config : { 'allow-scripts-pending' : true , json : true } ,
185+ } )
186+ await npm . exec ( 'approve-scripts' , [ ] )
187+ const parsed = JSON . parse ( joinedOutput ( ) )
188+ const byName = Object . fromEntries ( parsed . allowScripts . map ( ( e ) => [ e . name , e . changes ] ) )
189+ t . strictSame ( byName , {
190+ canvas : [ { key : 'canvas@1.0.0' , change : 'pending' } ] ,
191+ sharp : [ { key : 'sharp@1.0.0' , change : 'pending' } ] ,
192+ } )
193+ } )
194+
195+ t . test ( 'approve-scripts --pending --json with no unreviewed emits empty list' , async t => {
196+ const { npm, joinedOutput } = await mockNpm ( t , {
197+ prefixDir : setupProject ( {
198+ allowScripts : { canvas : true } ,
199+ withScripts : [ 'canvas' ] ,
200+ } ) ,
201+ config : { 'allow-scripts-pending' : true , json : true } ,
202+ } )
203+ await npm . exec ( 'approve-scripts' , [ ] )
204+ t . strictSame ( JSON . parse ( joinedOutput ( ) ) , { allowScripts : [ ] } )
205+ } )
206+
207+ t . test ( 'approve-scripts --all --json with no unreviewed emits empty list' , async t => {
208+ const { npm, joinedOutput } = await _mockNpm ( t , {
209+ prefixDir : {
210+ 'package.json' : JSON . stringify ( { name : 'host' , version : '1.0.0' } ) ,
211+ 'package-lock.json' : JSON . stringify ( {
212+ name : 'host' ,
213+ version : '1.0.0' ,
214+ lockfileVersion : 3 ,
215+ requires : true ,
216+ packages : { '' : { name : 'host' , version : '1.0.0' } } ,
217+ } ) ,
218+ node_modules : { } ,
219+ } ,
220+ config : { all : true , json : true } ,
221+ } )
222+ await npm . exec ( 'approve-scripts' , [ ] )
223+ t . strictSame ( JSON . parse ( joinedOutput ( ) ) , { allowScripts : [ ] } )
224+ } )
225+
181226t . test ( 'approve-scripts --all with no unreviewed packages prints message' , async t => {
182227 const { npm, joinedOutput } = await _mockNpm ( t , {
183228 prefixDir : {
@@ -231,63 +276,83 @@ t.test('approve-scripts --pending lists package with no version', async t => {
231276 t . pass ( )
232277} )
233278
234- t . test ( 'approve-scripts groups multiple installed versions of the same package' , async t => {
235- // Two versions of lodash exist in the tree; both have install scripts.
236- // groupByPackage should put them in the same group (hits the
237- // `if (!groups[key])` falsy branch on the second node).
238- const { npm, prefix } = await _mockNpm ( t , {
239- prefixDir : {
240- 'package.json' : JSON . stringify ( {
241- name : 'host' ,
242- version : '1.0.0' ,
243- dependencies : { 'top-of-tree' : '*' } ,
244- } ) ,
245- 'package-lock.json' : JSON . stringify ( {
246- name : 'host' ,
279+ const twoVersionFixture = {
280+ 'package.json' : JSON . stringify ( {
281+ name : 'host' ,
282+ version : '1.0.0' ,
283+ dependencies : { 'top-of-tree' : '*' } ,
284+ } ) ,
285+ 'package-lock.json' : JSON . stringify ( {
286+ name : 'host' ,
287+ version : '1.0.0' ,
288+ lockfileVersion : 3 ,
289+ requires : true ,
290+ packages : {
291+ '' : { name : 'host' , version : '1.0.0' , dependencies : { 'top-of-tree' : '*' } } ,
292+ 'node_modules/lodash' : {
293+ version : '4.17.21' ,
294+ resolved : 'https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz' ,
295+ hasInstallScript : true ,
296+ } ,
297+ 'node_modules/top-of-tree' : {
247298 version : '1.0.0' ,
248- lockfileVersion : 3 ,
249- requires : true ,
250- packages : {
251- '' : { name : 'host' , version : '1.0.0' , dependencies : { 'top-of-tree' : '*' } } ,
252- 'node_modules/lodash' : {
253- version : '4.17.21' ,
254- resolved : 'https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz' ,
255- hasInstallScript : true ,
256- } ,
257- 'node_modules/top-of-tree' : {
258- version : '1.0.0' ,
259- resolved : 'https://registry.npmjs.org/top-of-tree/-/top-of-tree-1.0.0.tgz' ,
260- dependencies : { lodash : '3.10.1' } ,
261- } ,
262- 'node_modules/top-of-tree/node_modules/lodash' : {
263- version : '3.10.1' ,
264- resolved : 'https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz' ,
265- hasInstallScript : true ,
266- } ,
267- } ,
299+ resolved : 'https://registry.npmjs.org/top-of-tree/-/top-of-tree-1.0.0.tgz' ,
300+ dependencies : { lodash : '3.10.1' } ,
301+ } ,
302+ 'node_modules/top-of-tree/node_modules/lodash' : {
303+ version : '3.10.1' ,
304+ resolved : 'https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz' ,
305+ hasInstallScript : true ,
306+ } ,
307+ } ,
308+ } ) ,
309+ node_modules : {
310+ lodash : {
311+ 'package.json' : JSON . stringify ( {
312+ name : 'lodash' ,
313+ version : '4.17.21' ,
314+ scripts : { install : 'echo install' } ,
268315 } ) ,
316+ } ,
317+ 'top-of-tree' : {
318+ 'package.json' : JSON . stringify ( { name : 'top-of-tree' , version : '1.0.0' } ) ,
269319 node_modules : {
270320 lodash : {
271321 'package.json' : JSON . stringify ( {
272322 name : 'lodash' ,
273- version : '4.17.21 ' ,
323+ version : '3.10.1 ' ,
274324 scripts : { install : 'echo install' } ,
275325 } ) ,
276326 } ,
277- 'top-of-tree' : {
278- 'package.json' : JSON . stringify ( { name : 'top-of-tree' , version : '1.0.0' } ) ,
279- node_modules : {
280- lodash : {
281- 'package.json' : JSON . stringify ( {
282- name : 'lodash' ,
283- version : '3.10.1' ,
284- scripts : { install : 'echo install' } ,
285- } ) ,
286- } ,
287- } ,
288- } ,
289327 } ,
290328 } ,
329+ } ,
330+ }
331+
332+ t . test ( 'approve-scripts --pending --json groups multiple versions under one name' , async t => {
333+ // Two versions of lodash are unreviewed; pendingSummary must collapse
334+ // them into a single `lodash` entry (hits the `groups.has(display)`
335+ // truthy branch on the second node).
336+ const { npm, joinedOutput } = await _mockNpm ( t , {
337+ prefixDir : twoVersionFixture ,
338+ config : { 'allow-scripts-pending' : true , json : true } ,
339+ } )
340+ await npm . exec ( 'approve-scripts' , [ ] )
341+ const parsed = JSON . parse ( joinedOutput ( ) )
342+ t . strictSame ( parsed . allowScripts . map ( ( e ) => e . name ) , [ 'lodash' ] )
343+ t . strictSame ( parsed . allowScripts [ 0 ] . changes . map ( ( c ) => c . key ) . sort ( ) , [
344+ 'lodash@3.10.1' ,
345+ 'lodash@4.17.21' ,
346+ ] )
347+ t . ok ( parsed . allowScripts [ 0 ] . changes . every ( ( c ) => c . change === 'pending' ) )
348+ } )
349+
350+ t . test ( 'approve-scripts groups multiple installed versions of the same package' , async t => {
351+ // Two versions of lodash exist in the tree; both have install scripts.
352+ // groupByPackage should put them in the same group (hits the
353+ // `if (!groups[key])` falsy branch on the second node).
354+ const { npm, prefix } = await _mockNpm ( t , {
355+ prefixDir : twoVersionFixture ,
291356 } )
292357 await npm . exec ( 'approve-scripts' , [ 'lodash' ] )
293358
@@ -328,6 +393,37 @@ t.test('approve-scripts --pending handles node with no version', async t => {
328393 t . match ( mockSync . joinedOutput ( ) , / n o - v e r s i o n - p k g \( i n s t a l l : d o - s t u f f \) / )
329394} )
330395
396+ t . test ( 'approve-scripts --pending --json handles node with no version' , async t => {
397+ // Exercise pendingSummary's `version ? ... : display` falsy branch: the
398+ // key is the bare name when the node has no version field.
399+ const { npm, joinedOutput } = await _mockNpm ( t , {
400+ prefixDir : {
401+ 'package.json' : JSON . stringify ( { name : 'host' , version : '1.0.0' } ) ,
402+ 'package-lock.json' : JSON . stringify ( {
403+ name : 'host' ,
404+ version : '1.0.0' ,
405+ lockfileVersion : 3 ,
406+ requires : true ,
407+ packages : { '' : { name : 'host' , version : '1.0.0' } } ,
408+ } ) ,
409+ node_modules : { } ,
410+ } ,
411+ config : { 'allow-scripts-pending' : true , json : true } ,
412+ mocks : {
413+ '{LIB}/utils/check-allow-scripts.js' : async ( ) => [ {
414+ node : { packageName : 'no-version-pkg' , name : 'no-version-pkg' , version : undefined } ,
415+ scripts : { install : 'do-stuff' } ,
416+ } ] ,
417+ } ,
418+ } )
419+ await npm . exec ( 'approve-scripts' , [ ] )
420+ t . strictSame ( JSON . parse ( joinedOutput ( ) ) , {
421+ allowScripts : [
422+ { name : 'no-version-pkg' , changes : [ { key : 'no-version-pkg' , change : 'pending' } ] } ,
423+ ] ,
424+ } )
425+ } )
426+
331427t . test ( 'forbidden semver range in package.json#allowScripts is dropped with a warning' , async t => {
332428 // End-to-end: project declares a caret range in allowScripts. The
333429 // resolver must drop the entry, emit a warning, and the matching node
0 commit comments