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