From 2a26e5e21af788f025a5731d88f15f6dc88b4c0c Mon Sep 17 00:00:00 2001 From: Gar Date: Wed, 30 Mar 2022 15:37:01 -0700 Subject: [PATCH] fix: remove dedupe --save * Removed dedupe --save documentation and attempted implementation. * Remove some unneeded otplease mocks from test `npm dedupe --save` didn't work in a easy to understand way. It would only update a top level dependency that was duplicated in the tree. Found this out rewriting the dedupe tests to be real. This is not very intuitive and it's best if folks use update or install for saving to package.json. --- docs/content/commands/npm-dedupe.md | 24 +- lib/commands/dedupe.js | 13 +- lib/npm.js | 3 + .../test/lib/load-all-commands.js.test.cjs | 1 - .../test/lib/utils/npm-usage.js.test.cjs | 1 - test/fixtures/mock-npm.js | 4 + test/fixtures/mock-registry.js | 113 +++++++ test/lib/commands/dedupe.js | 103 +++++-- test/lib/commands/unpublish.js | 281 ++++++++++-------- test/lib/npm.js | 11 +- 10 files changed, 357 insertions(+), 197 deletions(-) create mode 100644 test/fixtures/mock-registry.js diff --git a/docs/content/commands/npm-dedupe.md b/docs/content/commands/npm-dedupe.md index b5a64831c0bba..91f0105e35f21 100644 --- a/docs/content/commands/npm-dedupe.md +++ b/docs/content/commands/npm-dedupe.md @@ -80,11 +80,9 @@ result in new modules being installed. Using `npm find-dupes` will run the command in `--dry-run` mode. -Note that by default `npm dedupe` will not update the semver values of direct -dependencies in your project `package.json`, if you want to also update -values in `package.json` you can run: `npm dedupe --save` (or add the -`save=true` option to a [configuration file](/configuring-npm/npmrc) -to make that the default behavior). +Note: `npm dedupe` will never update the semver values of direct +dependencies in your project `package.json`, if you want to update +values in `package.json` you can run: `npm update --save` instead. ### Configuration @@ -158,22 +156,6 @@ This configuration does not affect `npm ci`. -#### `save` - -* Default: `true` unless when using `npm update` or `npm dedupe` where it - defaults to `false` -* Type: Boolean - -Save installed packages to a `package.json` file as dependencies. - -When used with the `npm rm` command, removes the dependency from -`package.json`. - -Will also prevent writing to `package-lock.json` if set to `false`. - - - - #### `omit` * Default: 'dev' if the `NODE_ENV` environment variable is set to diff --git a/lib/commands/dedupe.js b/lib/commands/dedupe.js index 4662ce3241b24..96d1ac2ae9a74 100644 --- a/lib/commands/dedupe.js +++ b/lib/commands/dedupe.js @@ -12,7 +12,6 @@ class Dedupe extends ArboristWorkspaceCmd { 'legacy-bundling', 'strict-peer-deps', 'package-lock', - 'save', 'omit', 'ignore-scripts', 'audit', @@ -29,19 +28,17 @@ class Dedupe extends ArboristWorkspaceCmd { throw er } - // In the context of `npm dedupe` the save - // config value should default to `false` - const save = this.npm.config.isDefault('save') - ? false - : this.npm.config.get('save') - const dryRun = this.npm.config.get('dry-run') const where = this.npm.prefix const opts = { ...this.npm.flatOptions, path: where, dryRun, - save, + // Saving during dedupe would only update if one of your direct + // dependencies was also duplicated somewhere in your tree. It would be + // confusing if running this were to also update your package.json. In + // order to reduce potential confusion we set this to false. + save: false, workspaces: this.workspaceNames, } const arb = new Arborist(opts) diff --git a/lib/npm.js b/lib/npm.js index 74825c97c2355..c819a0807b507 100644 --- a/lib/npm.js +++ b/lib/npm.js @@ -131,6 +131,7 @@ class Npm extends EventEmitter { const isGlobal = this.config.get('global') const workspacesEnabled = this.config.get('workspaces') + // if cwd is a workspace, the default is set to [that workspace] const implicitWorkspace = this.config.get('workspace', 'default').length > 0 const workspacesFilters = this.config.get('workspace') const includeWorkspaceRoot = this.config.get('include-workspace-root') @@ -138,6 +139,8 @@ class Npm extends EventEmitter { // or when it is implicit and not in our ignore list const hasWorkspaceFilters = workspacesFilters.length > 0 const invalidWorkspaceConfig = workspacesEnabled === false && hasWorkspaceFilters + + // (-ws || -w foo) && (cwd is not a workspace || command is not ignoring implicit workspaces) const filterByWorkspaces = (workspacesEnabled || hasWorkspaceFilters) && (!implicitWorkspace || !command.ignoreImplicitWorkspace) // normally this would go in the constructor, but our tests don't diff --git a/tap-snapshots/test/lib/load-all-commands.js.test.cjs b/tap-snapshots/test/lib/load-all-commands.js.test.cjs index 0ad87b945fce7..cd8b0592c36e8 100644 --- a/tap-snapshots/test/lib/load-all-commands.js.test.cjs +++ b/tap-snapshots/test/lib/load-all-commands.js.test.cjs @@ -161,7 +161,6 @@ npm dedupe Options: [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] -[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [--omit [--omit ...]] [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] diff --git a/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs b/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs index e6afc973ab10e..fef4cc65edc65 100644 --- a/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs +++ b/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs @@ -293,7 +293,6 @@ All commands: Options: [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] - [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [--omit [--omit ...]] [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] diff --git a/test/fixtures/mock-npm.js b/test/fixtures/mock-npm.js index 13f8a0ea01c7e..07e4cb8283b4c 100644 --- a/test/fixtures/mock-npm.js +++ b/test/fixtures/mock-npm.js @@ -83,6 +83,10 @@ const LoadMockNpm = async (t, { const { Npm, ...rest } = RealMockNpm(t, mocks) + // We want to fail fast when writing tests. Default this to 0 unless it was + // explicitly set in a test. + config = { 'fetch-retries': 0, ...config } + if (!init && load) { throw new Error('cant `load` without `init`') } diff --git a/test/fixtures/mock-registry.js b/test/fixtures/mock-registry.js new file mode 100644 index 0000000000000..ec4ebc2a4c24f --- /dev/null +++ b/test/fixtures/mock-registry.js @@ -0,0 +1,113 @@ +/* + * Mock registry class + * + * This should end up as the centralized place where we generate test fixtures + * for tests against any registry data. + */ +const pacote = require('pacote') +class MockRegistry { + #tap + #nock + #registry + #authorization + + constructor (opts) { + if (!opts.registry) { + throw new Error('mock registry requires a registry value') + } + this.#registry = (new URL(opts.registry)).origin + this.#authorization = opts.authorization + // Required for this.package + this.#tap = opts.tap + } + + get nock () { + if (!this.#nock) { + const tnock = require('./tnock.js') + const reqheaders = {} + if (this.#authorization) { + reqheaders.authorization = `Bearer ${this.#authorization}` + } + this.#nock = tnock(this.#tap, this.#registry, { reqheaders }) + } + return this.#nock + } + + set nock (nock) { + this.#nock = nock + } + + async package ({ manifest, times = 1, query, tarballs }) { + let nock = this.nock + if (!nock) { + throw new Error('cannot mock packages without a tap fixture') + } + nock = nock.get(`/${manifest.name}`).times(times) + if (query) { + nock = nock.query(query) + } + nock = nock.reply(200, manifest) + if (tarballs) { + for (const version in manifest.versions) { + const packument = manifest.versions[version] + const dist = new URL(packument.dist.tarball) + const tarball = await pacote.tarball(tarballs[version]) + nock.get(dist.pathname).reply(200, tarball) + } + } + this.nock = nock + } + + // the last packument in the packuments array will be tagged as latest + manifest ({ name = 'test-package', packuments } = {}) { + packuments = this.packuments(packuments, name) + const latest = packuments.slice(-1)[0] + const manifest = { + _id: `${name}@${latest.version}`, + _rev: '00-testdeadbeef', + name, + description: 'test package mock manifest', + dependencies: {}, + versions: {}, + time: {}, + 'dist-tags': { latest: latest.version }, + ...latest, + } + + for (const packument of packuments) { + manifest.versions[packument.version] = { + _id: `${name}@${packument.version}`, + name, + description: 'test package mock manifest', + dependencies: {}, + dist: { + tarball: `${this.#registry}/${name}/-/${name}-${packument.version}.tgz`, + }, + ...packument, + } + manifest.time[packument.version] = new Date() + } + + return manifest + } + + packuments (packuments = ['1.0.0'], name) { + return packuments.map(p => this.packument(p, name)) + } + + // Generate packument from shorthand + packument (packument, name = 'test-package') { + if (!packument.version) { + packument = { version: packument } + } + return { + name, + version: '1.0.0', + description: 'mocked test package', + dependencies: {}, + ...packument, + } + } +} + +module.exports = MockRegistry diff --git a/test/lib/commands/dedupe.js b/test/lib/commands/dedupe.js index bf6964081ca79..a985f4a710753 100644 --- a/test/lib/commands/dedupe.js +++ b/test/lib/commands/dedupe.js @@ -1,5 +1,9 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm') +const path = require('path') +const fs = require('fs') + +const MockRegistry = require('../../fixtures/mock-registry.js') t.test('should throw in global mode', async (t) => { const { npm } = await loadMockNpm(t, { @@ -14,45 +18,78 @@ t.test('should throw in global mode', async (t) => { ) }) -t.test('should remove dupes using Arborist', async (t) => { - t.plan(5) - const { npm } = await loadMockNpm(t, { - mocks: { - '@npmcli/arborist': function (args) { - t.ok(args, 'gets options object') - t.ok(args.path, 'gets path option') - t.ok(args.dryRun, 'gets dryRun from user') - this.dedupe = () => { - t.ok(true, 'dedupe is called') - } - }, - '../../lib/utils/reify-finish.js': (npm, arb) => { - t.ok(arb, 'gets arborist tree') +const testTop = { + name: 'test-top', + version: '1.0.0', + dependencies: { + 'test-dep-a': '*', + 'test-dep-b': '*', + }, +} +const testDepA = { + name: 'test-dep-a', + version: '1.0.1', + dependencies: { 'test-sub': '*' }, +} +const testDepB = { + name: 'test-dep-b', + version: '1.0.0', + dependencies: { 'test-sub': '*' }, +} +const testSub = { + name: 'test-sub', + version: '1.0.0', +} + +const treeWithDupes = { + 'package.json': JSON.stringify(testTop), + node_modules: { + 'test-dep-a': { + 'package.json': JSON.stringify(testDepA), + node_modules: { + 'test-sub': { + 'package.json': JSON.stringify(testSub), + }, }, }, - config: { - 'dry-run': 'true', + 'test-dep-b': { + 'package.json': JSON.stringify(testDepB), + node_modules: { + 'test-sub': { + 'package.json': JSON.stringify(testSub), + }, + }, }, + }, +} + +t.test('dedupe', async (t) => { + const { npm, joinedOutput } = await loadMockNpm(t, { + prefixDir: treeWithDupes, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + const manifestSub = registry.manifest({ + name: 'test-sub', + packuments: [{ version: '1.0.0' }], }) - await npm.exec('dedupe', []) -}) -t.test('should remove dupes using Arborist - no arguments', async (t) => { - t.plan(2) - const { npm } = await loadMockNpm(t, { - mocks: { - '@npmcli/arborist': function (args) { - t.ok(args.dryRun, 'gets dryRun from config') - t.ok(args.save, 'gets user-set save value from config') - this.dedupe = () => {} - }, - '../../lib/utils/reify-output.js': () => {}, - '../../lib/utils/reify-finish.js': () => {}, - }, - config: { - 'dry-run': true, - save: true, + await registry.package({ + manifest: manifestSub, + tarballs: { + '1.0.0': path.join(npm.prefix, 'node_modules', 'test-dep-a', 'node_modules', 'test-sub'), }, }) await npm.exec('dedupe', []) + t.match(joinedOutput(), /added 1 package, and removed 2 packages/) + t.ok(fs.existsSync(path.join(npm.prefix, 'node_modules', 'test-sub')), 'test-sub was hoisted') + t.notOk( + fs.existsSync(path.join(npm.prefix, 'node_modules', 'test-dep-a', 'node_modules', 'test-sub')), + 'test-dep-a/test-sub was removed' + ) + t.notOk( + fs.existsSync(path.join(npm.prefix, 'node_modules', 'test-dep-b', 'node_modules', 'test-sub')), + 'test-dep-b/test-sub was removed') }) diff --git a/test/lib/commands/unpublish.js b/test/lib/commands/unpublish.js index 71be4a5d6908d..829d41c5bb875 100644 --- a/test/lib/commands/unpublish.js +++ b/test/lib/commands/unpublish.js @@ -1,36 +1,7 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm') -const tnock = require('../../fixtures/tnock.js') - -const pkgManifest = (name, version = '1.0.0') => { - return { - _id: `${name}@${version}`, - _rev: '00-testdeadbeef', - name, - versions: { - '1.0.0': { - name, - version: '1.0.0', - dist: { - tarball: `https://registry.npmjs.org/${name}/-/${name}-1.0.0.tgz`, - }, - }, - [version]: { - name, - version: version, - dist: { - tarball: `https://registry.npmjs.org/${name}/-/${name}-${version}.tgz`, - }, - }, - }, - time: { - '1.0.0': new Date(), - [version]: new Date(), - }, - 'dist-tags': { latest: version }, - } -} +const MockRegistry = require('../../fixtures/mock-registry.js') const user = 'test-user' const pkg = 'test-package' const auth = { '//registry.npmjs.org/:_authToken': 'test-auth-token' } @@ -49,12 +20,14 @@ t.test('no args --force success', async t => { }, }) - const manifest = pkgManifest(pkg) - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get(`/${pkg}?write=true`).reply(200, manifest) - .delete(`/${pkg}/-rev/${manifest._rev}`).reply(201) - + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + const manifest = registry.manifest({ name: pkg }) + await registry.package({ manifest, query: { write: true } }) + registry.nock.delete(`/${pkg}/-rev/${manifest._rev}`).reply(201) await npm.exec('unpublish', []) t.equal(joinedOutput(), '- test-package@1.0.0') }) @@ -116,14 +89,20 @@ t.test('unpublish @version not the last version', async t => { ...auth, }, }) - const manifest = pkgManifest(pkg, '1.0.1') - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get(`/${pkg}?write=true`).times(3).reply(200, manifest) - .put(`/${pkg}/-rev/${manifest._rev}`, body => { - // sets latest and deletes version 1.0.1 - return body['dist-tags'].latest === '1.0.0' && body.versions['1.0.1'] === undefined - }).reply(201) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + const manifest = registry.manifest({ + name: pkg, + packuments: ['1.0.0', '1.0.1'], + }) + await registry.package({ manifest, query: { write: true }, times: 3 }) + registry.nock.put(`/${pkg}/-rev/${manifest._rev}`, body => { + // sets latest and deletes version 1.0.1 + return body['dist-tags'].latest === '1.0.0' && body.versions['1.0.1'] === undefined + }).reply(201) .intercept(`/${pkg}/-/${pkg}-1.0.1.tgz/-rev/${manifest._rev}`, 'DELETE').reply(201) await npm.exec('unpublish', ['test-package@1.0.1']) @@ -136,10 +115,13 @@ t.test('unpublish @version last version', async t => { ...auth, }, }) - const manifest = pkgManifest(pkg) - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get(`/${pkg}?write=true`).reply(200, manifest) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + const manifest = registry.manifest({ name: pkg }) + await registry.package({ manifest, query: { write: true } }) await t.rejects( npm.exec('unpublish', ['test-package@1.0.0']), @@ -159,13 +141,14 @@ t.test('no version found in package.json', async t => { }, null, 2), }, }) - - const manifest = pkgManifest(pkg) - - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get(`/${pkg}?write=true`).reply(200, manifest) - .delete(`/${pkg}/-rev/${manifest._rev}`).reply(201) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + const manifest = registry.manifest({ name: pkg }) + await registry.package({ manifest, query: { write: true } }) + registry.nock.delete(`/${pkg}/-rev/${manifest._rev}`).reply(201) await npm.exec('unpublish', []) t.equal(joinedOutput(), '- test-package') @@ -178,11 +161,14 @@ t.test('unpublish --force no version set', async t => { ...auth, }, }) - const manifest = pkgManifest(pkg) - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get(`/${pkg}?write=true`).times(2).reply(200, manifest) - .delete(`/${pkg}/-rev/${manifest._rev}`).reply(201) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + const manifest = registry.manifest({ name: pkg }) + await registry.package({ manifest, query: { write: true }, times: 2 }) + registry.nock.delete(`/${pkg}/-rev/${manifest._rev}`).reply(201) await npm.exec('unpublish', ['test-package']) t.equal(joinedOutput(), '- test-package') @@ -196,14 +182,20 @@ t.test('silent', async t => { ...auth, }, }) - const manifest = pkgManifest(pkg, '1.0.1') - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get(`/${pkg}?write=true`).times(3).reply(200, manifest) - .put(`/${pkg}/-rev/${manifest._rev}`, body => { - // sets latest and deletes version 1.0.1 - return body['dist-tags'].latest === '1.0.0' && body.versions['1.0.1'] === undefined - }).reply(201) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + const manifest = registry.manifest({ + name: pkg, + packuments: ['1.0.0', '1.0.1'], + }) + await registry.package({ manifest, query: { write: true }, times: 3 }) + registry.nock.put(`/${pkg}/-rev/${manifest._rev}`, body => { + // sets latest and deletes version 1.0.1 + return body['dist-tags'].latest === '1.0.0' && body.versions['1.0.1'] === undefined + }).reply(201) .delete(`/${pkg}/-/${pkg}-1.0.1.tgz/-rev/${manifest._rev}`).reply(201) await npm.exec('unpublish', ['test-package@1.0.1']) @@ -261,16 +253,19 @@ t.test('workspaces', async t => { }, prefixDir, }) - const manifestA = pkgManifest('workspace-a') - const manifestB = pkgManifest('workspace-b') - const manifestN = pkgManifest('workspace-n') - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get('/workspace-a?write=true').times(2).reply(200, manifestA) - .delete(`/workspace-a/-rev/${manifestA._rev}`).reply(201) - .get('/workspace-b?write=true').times(2).reply(200, manifestB) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + const manifestA = registry.manifest({ name: 'workspace-a' }) + const manifestB = registry.manifest({ name: 'workspace-b' }) + const manifestN = registry.manifest({ name: 'workspace-n' }) + await registry.package({ manifest: manifestA, query: { write: true }, times: 2 }) + await registry.package({ manifest: manifestB, query: { write: true }, times: 2 }) + await registry.package({ manifest: manifestN, query: { write: true }, times: 2 }) + registry.nock.delete(`/workspace-a/-rev/${manifestA._rev}`).reply(201) .delete(`/workspace-b/-rev/${manifestB._rev}`).reply(201) - .get('/workspace-n?write=true').times(2).reply(200, manifestN) .delete(`/workspace-n/-rev/${manifestN._rev}`).reply(201) await npm.exec('unpublish', []) @@ -286,11 +281,14 @@ t.test('workspaces', async t => { }, prefixDir, }) - const manifestA = pkgManifest('workspace-a') - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get('/workspace-a?write=true').times(2).reply(200, manifestA) - .delete(`/workspace-a/-rev/${manifestA._rev}`).reply(201) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + const manifestA = registry.manifest({ name: 'workspace-a' }) + await registry.package({ manifest: manifestA, query: { write: true }, times: 2 }) + registry.nock.delete(`/workspace-a/-rev/${manifestA._rev}`).reply(201) await npm.exec('unpublish', []) t.equal(joinedOutput(), '- workspace-a') @@ -304,11 +302,16 @@ t.test('dryRun with spec', async t => { ...auth, }, }) - - const manifest = pkgManifest(pkg, '1.0.1') - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get(`/${pkg}?write=true`).reply(200, manifest) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + const manifest = registry.manifest({ + name: pkg, + packuments: ['1.0.0', '1.0.1'], + }) + await registry.package({ manifest, query: { write: true } }) await npm.exec('unpublish', ['test-package@1.0.1']) t.equal(joinedOutput(), '- test-package@1.0.1') @@ -338,7 +341,6 @@ t.test('publishConfig no spec', async t => { const { joinedOutput, npm } = await loadMockNpm(t, { config: { force: true, - 'fetch-retries': 0, '//other.registry.npmjs.org/:_authToken': 'test-other-token', }, prefixDir: { @@ -352,11 +354,14 @@ t.test('publishConfig no spec', async t => { }, }) - const manifest = pkgManifest(pkg) - tnock(t, alternateRegistry, - { reqheaders: { authorization: 'Bearer test-other-token' } }) - .get(`/${pkg}?write=true`).reply(200, manifest) - .delete(`/${pkg}/-rev/${manifest._rev}`).reply(201) + const registry = new MockRegistry({ + tap: t, + registry: alternateRegistry, + authorization: 'test-other-token', + }) + const manifest = registry.manifest({ name: pkg }) + await registry.package({ manifest, query: { write: true } }) + registry.nock.delete(`/${pkg}/-rev/${manifest._rev}`).reply(201) await npm.exec('unpublish', []) t.equal(joinedOutput(), '- test-package@1.0.0') }) @@ -366,7 +371,6 @@ t.test('publishConfig with spec', async t => { const { joinedOutput, npm } = await loadMockNpm(t, { config: { force: true, - 'fetch-retries': 0, '//other.registry.npmjs.org/:_authToken': 'test-other-token', }, prefixDir: { @@ -380,11 +384,14 @@ t.test('publishConfig with spec', async t => { }, }) - const manifest = pkgManifest(pkg) - tnock(t, alternateRegistry, - { reqheaders: { authorization: 'Bearer test-other-token' } }) - .get(`/${pkg}?write=true`).reply(200, manifest) - .delete(`/${pkg}/-rev/${manifest._rev}`).reply(201) + const registry = new MockRegistry({ + tap: t, + registry: alternateRegistry, + authorization: 'test-other-token', + }) + const manifest = registry.manifest({ name: pkg }) + await registry.package({ manifest, query: { write: true }, times: 2 }) + registry.nock.delete(`/${pkg}/-rev/${manifest._rev}`).reply(201) await npm.exec('unpublish', ['test-package']) t.equal(joinedOutput(), '- test-package') }) @@ -406,12 +413,18 @@ t.test('completion', async t => { } t.test('completing with multiple versions from the registry', async t => { - const manifest = pkgManifest(pkg, '1.0.1') - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get('/-/whoami').reply(200, { username: user }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + const manifest = registry.manifest({ + name: pkg, + packuments: ['1.0.0', '1.0.1'], + }) + await registry.package({ manifest, query: { write: true } }) + registry.nock.get('/-/whoami').reply(200, { username: user }) .get('/-/org/test-user/package?format=cli').reply(200, { [pkg]: 'write' }) - .get(`/${pkg}?write=true`).reply(200, manifest) await testComp(t, { argv: ['npm', 'unpublish'], @@ -424,13 +437,16 @@ t.test('completion', async t => { }) t.test('no versions retrieved', async t => { - const manifest = pkgManifest(pkg) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + const manifest = registry.manifest({ name: pkg }) manifest.versions = {} - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get('/-/whoami').reply(200, { username: user }) + await registry.package({ manifest, query: { write: true } }) + registry.nock.get('/-/whoami').reply(200, { username: user }) .get('/-/org/test-user/package?format=cli').reply(200, { [pkg]: 'write' }) - .get(`/${pkg}?write=true`).reply(200, manifest) await testComp(t, { argv: ['npm', 'unpublish'], @@ -443,9 +459,12 @@ t.test('completion', async t => { }) t.test('packages starting with same letters', async t => { - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get('/-/whoami').reply(200, { username: user }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + registry.nock.get('/-/whoami').reply(200, { username: user }) .get('/-/org/test-user/package?format=cli').reply(200, { [pkg]: 'write', [`${pkg}a`]: 'write', @@ -464,10 +483,13 @@ t.test('completion', async t => { }) t.test('no packages retrieved', async t => { - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get('/-/whoami').reply(200, { username: user }) - .get('/-/org/test-user/package?format=cli').reply(200, {}) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + registry.nock.get('/-/whoami').reply(200, { username: user }) + registry.nock.get('/-/org/test-user/package?format=cli').reply(200, {}) await testComp(t, { argv: ['npm', 'unpublish'], @@ -478,9 +500,12 @@ t.test('completion', async t => { }) t.test('no pkg name to complete', async t => { - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get('/-/whoami').reply(200, { username: user }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + registry.nock.get('/-/whoami').reply(200, { username: user }) .get('/-/org/test-user/package?format=cli').reply(200, { [pkg]: 'write', [`${pkg}a`]: 'write', @@ -495,9 +520,12 @@ t.test('completion', async t => { }) t.test('no pkg names retrieved from user account', async t => { - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get('/-/whoami').reply(200, { username: user }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + registry.nock.get('/-/whoami').reply(200, { username: user }) .get('/-/org/test-user/package?format=cli').reply(200, null) await testComp(t, { @@ -509,9 +537,12 @@ t.test('completion', async t => { }) t.test('logged out user', async t => { - tnock(t, npm.config.get('registry'), - { reqheaders: { authorization: 'Bearer test-auth-token' } }) - .get('/-/whoami').reply(404) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: 'test-auth-token', + }) + registry.nock.get('/-/whoami').reply(404) await testComp(t, { argv: ['npm', 'unpublish'], diff --git a/test/lib/npm.js b/test/lib/npm.js index 998e96314d2b4..1966ca9600088 100644 --- a/test/lib/npm.js +++ b/test/lib/npm.js @@ -609,16 +609,14 @@ t.test('implicit workspace rejection', async t => { workspaces: ['./packages/a'], }), }, - globals: { + globals: ({ prefix }) => ({ + 'process.cwd': () => join(prefix, 'packages', 'a'), 'process.argv': [ process.execPath, process.argv[1], '--color', 'false', '--workspace', './packages/a', ], - }, - config: ({ prefix }) => ({ - workspace: { value: [join(prefix, 'packages', 'a')], where: 'default' }, }), }) await t.rejects( @@ -646,16 +644,13 @@ t.test('implicit workspace accept', async t => { }), }, globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, + 'process.cwd': () => join(prefix, 'packages', 'a'), 'process.argv': [ process.execPath, process.argv[1], '--color', 'false', ], }), - config: ({ prefix }) => ({ - workspace: { value: [join(prefix, 'packages', 'a')], where: 'default' }, - }), }) await t.rejects(mock.npm.exec('org', []), /.*Usage/) })