1const t = require('tap')
2const { load: loadMockNpm } = require('../../fixtures/mock-npm')
3const { cleanZlib } = require('../../fixtures/clean-snapshot')
4const MockRegistry = require('@npmcli/mock-registry')
5const pacote = require('pacote')
6const Arborist = require('@npmcli/arborist')
7const path = require('path')
8const fs = require('fs')
9const npa = require('npm-package-arg')
10
11const pkg = 'test-package'
12const token = 'test-auth-token'
13const auth = { '//registry.npmjs.org/:_authToken': token }
14const alternateRegistry = 'https://other.registry.npmjs.org'
15const basic = Buffer.from('test-user:test-password').toString('base64')
16
17const pkgJson = {
18  name: pkg,
19  description: 'npm test package',
20  version: '1.0.0',
21}
22
23t.cleanSnapshot = data => cleanZlib(data)
24
25t.test('respects publishConfig.registry, runs appropriate scripts', async t => {
26  const { npm, joinedOutput, prefix } = await loadMockNpm(t, {
27    config: {
28      loglevel: 'silent',
29      [`${alternateRegistry.slice(6)}/:_authToken`]: 'test-other-token',
30    },
31    prefixDir: {
32      'package.json': JSON.stringify({
33        ...pkgJson,
34        scripts: {
35          prepublishOnly: 'touch scripts-prepublishonly',
36          prepublish: 'touch scripts-prepublish', // should NOT run this one
37          publish: 'touch scripts-publish',
38          postpublish: 'touch scripts-postpublish',
39        },
40        publishConfig: { registry: alternateRegistry },
41      }, null, 2),
42    },
43  })
44  const registry = new MockRegistry({
45    tap: t,
46    registry: alternateRegistry,
47    authorization: 'test-other-token',
48  })
49  registry.nock.put(`/${pkg}`, body => {
50    return t.match(body, {
51      _id: pkg,
52      name: pkg,
53      'dist-tags': { latest: '1.0.0' },
54      access: null,
55      versions: {
56        '1.0.0': {
57          name: pkg,
58          version: '1.0.0',
59          _id: `${pkg}@1.0.0`,
60          dist: {
61            shasum: /\.*/,
62            tarball: `http:${alternateRegistry.slice(6)}/test-package/-/test-package-1.0.0.tgz`,
63          },
64          publishConfig: {
65            registry: alternateRegistry,
66          },
67        },
68      },
69      _attachments: {
70        [`${pkg}-1.0.0.tgz`]: {},
71      },
72    })
73  }).reply(200, {})
74  await npm.exec('publish', [])
75  t.matchSnapshot(joinedOutput(), 'new package version')
76  t.equal(fs.existsSync(path.join(prefix, 'scripts-prepublishonly')), true, 'ran prepublishOnly')
77  t.equal(fs.existsSync(path.join(prefix, 'scripts-prepublish')), false, 'did not run prepublish')
78  t.equal(fs.existsSync(path.join(prefix, 'scripts-publish')), true, 'ran publish')
79  t.equal(fs.existsSync(path.join(prefix, 'scripts-postpublish')), true, 'ran postpublish')
80})
81
82t.test('re-loads publishConfig.registry if added during script process', async t => {
83  const { joinedOutput, npm } = await loadMockNpm(t, {
84    config: {
85      [`${alternateRegistry.slice(6)}/:_authToken`]: 'test-other-token',
86    },
87    prefixDir: {
88      'package.json': JSON.stringify({
89        ...pkgJson,
90        scripts: {
91          prepare: 'cp new.json package.json',
92        },
93      }, null, 2),
94      'new.json': JSON.stringify({
95        ...pkgJson,
96        publishConfig: { registry: alternateRegistry },
97      }),
98    },
99  })
100  const registry = new MockRegistry({
101    tap: t,
102    registry: alternateRegistry,
103    authorization: 'test-other-token',
104  })
105  registry.nock.put(`/${pkg}`, body => {
106    return t.match(body, {
107      _id: pkg,
108      name: pkg,
109      'dist-tags': { latest: '1.0.0' },
110      access: null,
111      versions: {
112        '1.0.0': {
113          name: pkg,
114          version: '1.0.0',
115          _id: `${pkg}@1.0.0`,
116          dist: {
117            shasum: /\.*/,
118            tarball: `http:${alternateRegistry.slice(6)}/test-package/-/test-package-1.0.0.tgz`,
119          },
120          publishConfig: {
121            registry: alternateRegistry,
122          },
123        },
124      },
125      _attachments: {
126        [`${pkg}-1.0.0.tgz`]: {},
127      },
128    })
129  }).reply(200, {})
130  await npm.exec('publish', [])
131  t.matchSnapshot(joinedOutput(), 'new package version')
132})
133
134t.test('json', async t => {
135  const { joinedOutput, npm, logs } = await loadMockNpm(t, {
136    config: {
137      json: true,
138      ...auth,
139    },
140    prefixDir: {
141      'package.json': JSON.stringify(pkgJson, null, 2),
142    },
143  })
144  const registry = new MockRegistry({
145    tap: t,
146    registry: npm.config.get('registry'),
147    authorization: token,
148  })
149  registry.nock.put(`/${pkg}`).reply(200, {})
150  await npm.exec('publish', [])
151  t.matchSnapshot(logs.notice)
152  t.matchSnapshot(joinedOutput(), 'new package json')
153})
154
155t.test('dry-run', async t => {
156  const { joinedOutput, npm, logs } = await loadMockNpm(t, {
157    config: {
158      'dry-run': true,
159      ...auth,
160    },
161    prefixDir: {
162      'package.json': JSON.stringify(pkgJson, null, 2),
163    },
164  })
165  await npm.exec('publish', [])
166  t.equal(joinedOutput(), `+ ${pkg}@1.0.0`)
167  t.matchSnapshot(logs.notice)
168})
169
170t.test('foreground-scripts defaults to true', async t => {
171  const { joinedOutput, npm, logs } = await loadMockNpm(t, {
172    config: {
173      'dry-run': true,
174      ...auth,
175    },
176    prefixDir: {
177      'package.json': JSON.stringify({
178        name: 'test-fg-scripts',
179        version: '0.0.0',
180        scripts: {
181          prepack: 'echo prepack!',
182          postpack: 'echo postpack!',
183        },
184      }
185      ),
186    },
187  })
188
189  /* eslint no-console: 0 */
190  // TODO: replace this with `const results = t.intercept(console, 'log')`
191  const log = console.log
192  t.teardown(() => {
193    console.log = log
194  })
195  const caughtLogs = []
196  console.log = (...args) => {
197    caughtLogs.push(args)
198  }
199  // end TODO
200
201  await npm.exec('publish', [])
202  t.equal(joinedOutput(), `+ test-fg-scripts@0.0.0`)
203  t.matchSnapshot(logs.notice)
204
205  t.same(
206    caughtLogs,
207    [
208      ['\n> test-fg-scripts@0.0.0 prepack\n> echo prepack!\n'],
209      ['\n> test-fg-scripts@0.0.0 postpack\n> echo postpack!\n'],
210    ],
211    'prepack and postpack log to stdout')
212})
213
214t.test('foreground-scripts can still be set to false', async t => {
215  const { joinedOutput, npm, logs } = await loadMockNpm(t, {
216    config: {
217      'dry-run': true,
218      'foreground-scripts': false,
219      ...auth,
220    },
221    prefixDir: {
222      'package.json': JSON.stringify({
223        name: 'test-fg-scripts',
224        version: '0.0.0',
225        scripts: {
226          prepack: 'echo prepack!',
227          postpack: 'echo postpack!',
228        },
229      }
230      ),
231    },
232  })
233
234  /* eslint no-console: 0 */
235  // TODO: replace this with `const results = t.intercept(console, 'log')`
236  const log = console.log
237  t.teardown(() => {
238    console.log = log
239  })
240  const caughtLogs = []
241  console.log = (...args) => {
242    caughtLogs.push(args)
243  }
244  // end TODO
245
246  await npm.exec('publish', [])
247  t.equal(joinedOutput(), `+ test-fg-scripts@0.0.0`)
248  t.matchSnapshot(logs.notice)
249
250  t.same(
251    caughtLogs,
252    [],
253    'prepack and postpack do not log to stdout')
254})
255
256t.test('shows usage with wrong set of arguments', async t => {
257  const { publish } = await loadMockNpm(t, { command: 'publish' })
258  await t.rejects(publish.exec(['a', 'b', 'c']), publish.usage)
259})
260
261t.test('throws when invalid tag', async t => {
262  const { npm } = await loadMockNpm(t, {
263    config: {
264      tag: '0.0.13',
265    },
266    prefixDir: {
267      'package.json': JSON.stringify(pkgJson, null, 2),
268    },
269  })
270  await t.rejects(
271    npm.exec('publish', []),
272    { message: 'Tag name must not be a valid SemVer range: 0.0.13' }
273  )
274})
275
276t.test('tarball', async t => {
277  const { npm, joinedOutput, logs, home } = await loadMockNpm(t, {
278    config: {
279      'fetch-retries': 0,
280      ...auth,
281    },
282    homeDir: {
283      'package.json': JSON.stringify({
284        name: 'test-tar-package',
285        description: 'this was from a tarball',
286        version: '1.0.0',
287      }, null, 2),
288      'index.js': 'console.log("hello world"}',
289    },
290  })
291  const tarball = await pacote.tarball(home, { Arborist })
292  const tarFilename = path.join(home, 'tarball.tgz')
293  fs.writeFileSync(tarFilename, tarball)
294  const registry = new MockRegistry({
295    tap: t,
296    registry: npm.config.get('registry'),
297    authorization: token,
298  })
299  registry.nock.put('/test-tar-package', body => {
300    return t.match(body, {
301      name: 'test-tar-package',
302    })
303  }).reply(200, {})
304  await npm.exec('publish', [tarFilename])
305  t.matchSnapshot(logs.notice)
306  t.matchSnapshot(joinedOutput(), 'new package json')
307})
308
309t.test('no auth default registry', async t => {
310  const { npm } = await loadMockNpm(t, {
311    prefixDir: {
312      'package.json': JSON.stringify(pkgJson, null, 2),
313    },
314  })
315  await t.rejects(
316    npm.exec('publish', []),
317    {
318      message: 'This command requires you to be logged in to https://registry.npmjs.org/',
319      code: 'ENEEDAUTH',
320    }
321  )
322})
323
324t.test('no auth dry-run', async t => {
325  const { npm, joinedOutput, logs } = await loadMockNpm(t, {
326    config: {
327      'dry-run': true,
328    },
329    prefixDir: {
330      'package.json': JSON.stringify(pkgJson, null, 2),
331    },
332  })
333  await npm.exec('publish', [])
334  t.matchSnapshot(joinedOutput())
335  t.matchSnapshot(logs.warn, 'warns about auth being needed')
336})
337
338t.test('no auth for configured registry', async t => {
339  const { npm } = await loadMockNpm(t, {
340    config: {
341      registry: alternateRegistry,
342      ...auth,
343    },
344    prefixDir: {
345      'package.json': JSON.stringify(pkgJson, null, 2),
346    },
347  })
348  await t.rejects(
349    npm.exec('publish', []),
350    {
351      message: `This command requires you to be logged in to ${alternateRegistry}`,
352      code: 'ENEEDAUTH',
353    }
354  )
355})
356
357t.test('no auth for scope configured registry', async t => {
358  const { npm } = await loadMockNpm(t, {
359    config: {
360      scope: '@npm',
361      registry: alternateRegistry,
362      ...auth,
363    },
364    prefixDir: {
365      'package.json': JSON.stringify({
366        name: '@npm/test-package',
367        version: '1.0.0',
368      }, null, 2),
369    },
370  })
371  await t.rejects(
372    npm.exec('publish', []),
373    {
374      message: `This command requires you to be logged in to ${alternateRegistry}`,
375      code: 'ENEEDAUTH',
376    }
377  )
378})
379
380t.test('has token auth for scope configured registry', async t => {
381  const spec = npa('@npm/test-package')
382  const { npm, joinedOutput } = await loadMockNpm(t, {
383    config: {
384      scope: '@npm',
385      registry: alternateRegistry,
386      [`${alternateRegistry.slice(6)}/:_authToken`]: 'test-scope-token',
387    },
388    prefixDir: {
389      'package.json': JSON.stringify({
390        name: '@npm/test-package',
391        version: '1.0.0',
392      }, null, 2),
393    },
394  })
395  const registry = new MockRegistry({
396    tap: t,
397    registry: alternateRegistry,
398    authorization: 'test-scope-token',
399  })
400  registry.nock.put(`/${spec.escapedName}`, body => {
401    return t.match(body, { name: '@npm/test-package' })
402  }).reply(200, {})
403  await npm.exec('publish', [])
404  t.matchSnapshot(joinedOutput(), 'new package version')
405})
406
407t.test('has mTLS auth for scope configured registry', async t => {
408  const spec = npa('@npm/test-package')
409  const { npm, joinedOutput } = await loadMockNpm(t, {
410    config: {
411      scope: '@npm',
412      registry: alternateRegistry,
413      [`${alternateRegistry.slice(6)}/:certfile`]: '/some.cert',
414      [`${alternateRegistry.slice(6)}/:keyfile`]: '/some.key',
415    },
416    prefixDir: {
417      'package.json': JSON.stringify({
418        name: '@npm/test-package',
419        version: '1.0.0',
420      }, null, 2),
421    },
422  })
423  const registry = new MockRegistry({
424    tap: t,
425    registry: alternateRegistry,
426  })
427  registry.nock.put(`/${spec.escapedName}`, body => {
428    return t.match(body, { name: '@npm/test-package' })
429  }).reply(200, {})
430  await npm.exec('publish', [])
431  t.matchSnapshot(joinedOutput(), 'new package version')
432})
433
434t.test('workspaces', t => {
435  const dir = {
436    'package.json': JSON.stringify(
437      {
438        ...pkgJson,
439        workspaces: ['workspace-a', 'workspace-b', 'workspace-c', 'workspace-p'],
440      }, null, 2),
441    'workspace-a': {
442      'package.json': JSON.stringify({
443        name: 'workspace-a',
444        version: '1.2.3-a',
445        repository: 'http://repo.workspace-a/',
446      }),
447    },
448    'workspace-b': {
449      'package.json': JSON.stringify({
450        name: 'workspace-b',
451        version: '1.2.3-n',
452        repository: 'https://github.com/npm/workspace-b',
453      }),
454    },
455    'workspace-c': {
456      'package.json': JSON.stringify({
457        name: 'workspace-n',
458        version: '1.2.3-n',
459      }),
460    },
461    'workspace-p': {
462      'package.json': JSON.stringify({
463        name: 'workspace-p',
464        version: '1.2.3-p',
465        private: true,
466      }),
467    },
468  }
469
470  t.test('all workspaces - no color', async t => {
471    const { npm, joinedOutput, logs } = await loadMockNpm(t, {
472      config: {
473        color: false,
474        ...auth,
475        workspaces: true,
476      },
477      prefixDir: dir,
478    })
479    const registry = new MockRegistry({
480      tap: t,
481      registry: npm.config.get('registry'),
482      authorization: token,
483    })
484    registry.nock
485      .put('/workspace-a', body => {
486        return t.match(body, { name: 'workspace-a' })
487      }).reply(200, {})
488      .put('/workspace-b', body => {
489        return t.match(body, { name: 'workspace-b' })
490      }).reply(200, {})
491      .put('/workspace-n', body => {
492        return t.match(body, { name: 'workspace-n' })
493      }).reply(200, {})
494    await npm.exec('publish', [])
495    t.matchSnapshot(joinedOutput(), 'all public workspaces')
496    t.matchSnapshot(logs.warn, 'warns about skipped private workspace')
497  })
498
499  t.test('all workspaces - color', async t => {
500    const { npm, joinedOutput, logs } = await loadMockNpm(t, {
501      config: {
502        ...auth,
503        color: 'always',
504        workspaces: true,
505      },
506      prefixDir: dir,
507    })
508    const registry = new MockRegistry({
509      tap: t,
510      registry: npm.config.get('registry'),
511      authorization: token,
512    })
513    registry.nock
514      .put('/workspace-a', body => {
515        return t.match(body, { name: 'workspace-a' })
516      }).reply(200, {})
517      .put('/workspace-b', body => {
518        return t.match(body, { name: 'workspace-b' })
519      }).reply(200, {})
520      .put('/workspace-n', body => {
521        return t.match(body, { name: 'workspace-n' })
522      }).reply(200, {})
523    await npm.exec('publish', [])
524    t.matchSnapshot(joinedOutput(), 'all public workspaces')
525    t.matchSnapshot(logs.warn, 'warns about skipped private workspace in color')
526  })
527
528  t.test('one workspace - success', async t => {
529    const { npm, joinedOutput } = await loadMockNpm(t, {
530      config: {
531        ...auth,
532        workspace: ['workspace-a'],
533      },
534      prefixDir: dir,
535    })
536    const registry = new MockRegistry({
537      tap: t,
538      registry: npm.config.get('registry'),
539      authorization: token,
540    })
541    registry.nock
542      .put('/workspace-a', body => {
543        return t.match(body, { name: 'workspace-a' })
544      }).reply(200, {})
545    await npm.exec('publish', [])
546    t.matchSnapshot(joinedOutput(), 'single workspace')
547  })
548
549  t.test('one workspace - failure', async t => {
550    const { npm } = await loadMockNpm(t, {
551      config: {
552        ...auth,
553        workspace: ['workspace-a'],
554      },
555      prefixDir: dir,
556    })
557    const registry = new MockRegistry({
558      tap: t,
559      registry: npm.config.get('registry'),
560      authorization: token,
561    })
562    registry.nock
563      .put('/workspace-a', body => {
564        return t.match(body, { name: 'workspace-a' })
565      }).reply(404, {})
566    await t.rejects(npm.exec('publish', []), { code: 'E404' })
567  })
568
569  t.test('invalid workspace', async t => {
570    const { npm } = await loadMockNpm(t, {
571      config: {
572        ...auth,
573        workspace: ['workspace-x'],
574      },
575      prefixDir: dir,
576    })
577    await t.rejects(
578      npm.exec('publish', []),
579      { message: 'No workspaces found:\n  --workspace=workspace-x' }
580    )
581  })
582
583  t.test('json', async t => {
584    const { npm, joinedOutput } = await loadMockNpm(t, {
585      config: {
586        ...auth,
587        workspaces: true,
588        json: true,
589      },
590      prefixDir: dir,
591    })
592    const registry = new MockRegistry({
593      tap: t,
594      registry: npm.config.get('registry'),
595      authorization: token,
596    })
597    registry.nock
598      .put('/workspace-a', body => {
599        return t.match(body, { name: 'workspace-a' })
600      }).reply(200, {})
601      .put('/workspace-b', body => {
602        return t.match(body, { name: 'workspace-b' })
603      }).reply(200, {})
604      .put('/workspace-n', body => {
605        return t.match(body, { name: 'workspace-n' })
606      }).reply(200, {})
607    await npm.exec('publish', [])
608    t.matchSnapshot(joinedOutput(), 'all workspaces in json')
609  })
610  t.end()
611})
612
613t.test('ignore-scripts', async t => {
614  const { npm, joinedOutput, prefix } = await loadMockNpm(t, {
615    config: {
616      ...auth,
617      'ignore-scripts': true,
618    },
619    prefixDir: {
620      'package.json': JSON.stringify({
621        ...pkgJson,
622        scripts: {
623          prepublishOnly: 'touch scripts-prepublishonly',
624          prepublish: 'touch scripts-prepublish', // should NOT run this one
625          publish: 'touch scripts-publish',
626          postpublish: 'touch scripts-postpublish',
627        },
628      }, null, 2),
629    },
630  })
631  const registry = new MockRegistry({
632    tap: t,
633    registry: npm.config.get('registry'),
634    authorization: token,
635  })
636  registry.nock.put(`/${pkg}`).reply(200, {})
637  await npm.exec('publish', [])
638  t.matchSnapshot(joinedOutput(), 'new package version')
639  t.equal(
640    fs.existsSync(path.join(prefix, 'scripts-prepublishonly')),
641    false,
642    'did not run prepublishOnly'
643  )
644  t.equal(
645    fs.existsSync(path.join(prefix, 'scripts-prepublish')),
646    false,
647    'did not run prepublish'
648  )
649  t.equal(
650    fs.existsSync(path.join(prefix, 'scripts-publish')),
651    false,
652    'did not run publish'
653  )
654  t.equal(
655    fs.existsSync(path.join(prefix, 'scripts-postpublish')),
656    false,
657    'did not run postpublish'
658  )
659})
660
661t.test('_auth config default registry', async t => {
662  const { npm, joinedOutput } = await loadMockNpm(t, {
663    config: {
664      '//registry.npmjs.org/:_auth': basic,
665    },
666    prefixDir: {
667      'package.json': JSON.stringify(pkgJson),
668    },
669  })
670  const registry = new MockRegistry({
671    tap: t,
672    registry: npm.config.get('registry'),
673    basic,
674  })
675  registry.nock.put(`/${pkg}`).reply(200, {})
676  await npm.exec('publish', [])
677  t.matchSnapshot(joinedOutput(), 'new package version')
678})
679
680t.test('bare _auth and registry config', async t => {
681  const spec = npa('@npm/test-package')
682  const { npm, joinedOutput } = await loadMockNpm(t, {
683    config: {
684      registry: alternateRegistry,
685      '//other.registry.npmjs.org/:_auth': basic,
686    },
687    prefixDir: {
688      'package.json': JSON.stringify({
689        name: '@npm/test-package',
690        version: '1.0.0',
691      }, null, 2),
692    },
693  })
694  const registry = new MockRegistry({
695    tap: t,
696    registry: alternateRegistry,
697    basic,
698  })
699  registry.nock.put(`/${spec.escapedName}`).reply(200, {})
700  await npm.exec('publish', [])
701  t.matchSnapshot(joinedOutput(), 'new package version')
702})
703
704t.test('bare _auth config scoped registry', async t => {
705  const { npm } = await loadMockNpm(t, {
706    config: {
707      scope: '@npm',
708      registry: alternateRegistry,
709      _auth: basic,
710    },
711    prefixDir: {
712      'package.json': JSON.stringify({
713        name: '@npm/test-package',
714        version: '1.0.0',
715      }, null, 2),
716    },
717  })
718  await t.rejects(
719    npm.exec('publish', []),
720    { message: `This command requires you to be logged in to ${alternateRegistry}` }
721  )
722})
723
724t.test('scoped _auth config scoped registry', async t => {
725  const spec = npa('@npm/test-package')
726  const { npm, joinedOutput } = await loadMockNpm(t, {
727    config: {
728      scope: '@npm',
729      registry: alternateRegistry,
730      [`${alternateRegistry.slice(6)}/:_auth`]: basic,
731    },
732    prefixDir: {
733      'package.json': JSON.stringify({
734        name: '@npm/test-package',
735        version: '1.0.0',
736      }, null, 2),
737    },
738  })
739  const registry = new MockRegistry({
740    tap: t,
741    registry: alternateRegistry,
742    basic,
743  })
744  registry.nock.put(`/${spec.escapedName}`).reply(200, {})
745  await npm.exec('publish', [])
746  t.matchSnapshot(joinedOutput(), 'new package version')
747})
748
749t.test('restricted access', async t => {
750  const spec = npa('@npm/test-package')
751  const { npm, joinedOutput, logs } = await loadMockNpm(t, {
752    config: {
753      ...auth,
754      access: 'restricted',
755    },
756    prefixDir: {
757      'package.json': JSON.stringify({
758        name: '@npm/test-package',
759        version: '1.0.0',
760      }, null, 2),
761    },
762  })
763  const registry = new MockRegistry({
764    tap: t,
765    registry: npm.config.get('registry'),
766    authorization: token,
767  })
768  registry.nock.put(`/${spec.escapedName}`, body => {
769    t.equal(body.access, 'restricted', 'access is explicitly set to restricted')
770    return true
771  }).reply(200, {})
772  await npm.exec('publish', [])
773  t.matchSnapshot(joinedOutput(), 'new package version')
774  t.matchSnapshot(logs.notice)
775})
776
777t.test('public access', async t => {
778  const spec = npa('@npm/test-package')
779  const { npm, joinedOutput, logs } = await loadMockNpm(t, {
780    config: {
781      ...auth,
782      access: 'public',
783    },
784    prefixDir: {
785      'package.json': JSON.stringify({
786        name: '@npm/test-package',
787        version: '1.0.0',
788      }, null, 2),
789    },
790  })
791  const registry = new MockRegistry({
792    tap: t,
793    registry: npm.config.get('registry'),
794    authorization: token,
795  })
796  registry.nock.put(`/${spec.escapedName}`, body => {
797    t.equal(body.access, 'public', 'access is explicitly set to public')
798    return true
799  }).reply(200, {})
800  await npm.exec('publish', [])
801  t.matchSnapshot(joinedOutput(), 'new package version')
802  t.matchSnapshot(logs.notice)
803})
804
805t.test('manifest', async t => {
806  // https://github.com/npm/cli/pull/6470#issuecomment-1571234863
807
808  // snapshot test that was generated against v9.6.7 originally to ensure our
809  // own manifest does not change unexpectedly when publishing. this test
810  // asserts a bunch of keys are there that will change often and then snapshots
811  // the rest of the manifest.
812
813  const root = path.resolve(__dirname, '../../..')
814  const npmPkg = require(path.join(root, 'package.json'))
815
816  t.cleanSnapshot = (s) => s.replace(new RegExp(npmPkg.version, 'g'), '{VERSION}')
817
818  let manifest = null
819  const { npm } = await loadMockNpm(t, {
820    config: {
821      ...auth,
822    },
823    chdir: () => root,
824    mocks: {
825      libnpmpublish: {
826        publish: (m) => manifest = m,
827      },
828    },
829  })
830  await npm.exec('publish', [])
831
832  const okKeys = [
833    'contributors',
834    'bundleDependencies',
835    'dependencies',
836    'devDependencies',
837    'templateOSS',
838    'scripts',
839    'tap',
840    'readme',
841    'engines',
842    'workspaces',
843  ]
844
845  for (const k of okKeys) {
846    t.ok(manifest[k], k)
847    delete manifest[k]
848  }
849  delete manifest.gitHead
850
851  manifest.man.sort()
852
853  t.matchSnapshot(manifest, 'manifest')
854})
855