From b82c1a6704677cbe238c9268c9c382e73b44b748 Mon Sep 17 00:00:00 2001 From: Gar Date: Mon, 12 Dec 2022 08:47:26 -0800 Subject: [PATCH] chore: refactor tests to use mock registry Co-authored by @bdehamer --- DEPENDENCIES.md | 4 +- package-lock.json | 2 +- workspaces/libnpmpublish/package.json | 2 +- .../npmcli-libnpmpublish-test-1.0.0.tgz | Bin 0 -> 208 bytes .../libnpmpublish/test/fixtures/tnock.js | 12 - workspaces/libnpmpublish/test/index.js | 6 - workspaces/libnpmpublish/test/publish.js | 384 ++++++++--------- workspaces/libnpmpublish/test/unpublish.js | 390 ++++++------------ 8 files changed, 311 insertions(+), 489 deletions(-) create mode 100644 workspaces/libnpmpublish/test/fixtures/npmcli-libnpmpublish-test-1.0.0.tgz delete mode 100644 workspaces/libnpmpublish/test/fixtures/tnock.js delete mode 100644 workspaces/libnpmpublish/test/index.js diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index ca8568db78b2b..3774551e2c4a1 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -58,11 +58,11 @@ graph LR; libnpmpack-->npmcli-run-script["@npmcli/run-script"]; libnpmpack-->npmcli-template-oss["@npmcli/template-oss"]; libnpmpack-->pacote; - libnpmpublish-->libnpmpack; libnpmpublish-->normalize-package-data; libnpmpublish-->npm-package-arg; libnpmpublish-->npm-registry-fetch; libnpmpublish-->npmcli-eslint-config["@npmcli/eslint-config"]; + libnpmpublish-->npmcli-mock-registry["@npmcli/mock-registry"]; libnpmpublish-->npmcli-template-oss["@npmcli/template-oss"]; libnpmpublish-->semver; libnpmpublish-->ssri; @@ -399,13 +399,13 @@ graph LR; libnpmpack-->pacote; libnpmpack-->spawk; libnpmpack-->tap; - libnpmpublish-->libnpmpack; libnpmpublish-->lodash.clonedeep; libnpmpublish-->nock; libnpmpublish-->normalize-package-data; libnpmpublish-->npm-package-arg; libnpmpublish-->npm-registry-fetch; libnpmpublish-->npmcli-eslint-config["@npmcli/eslint-config"]; + libnpmpublish-->npmcli-mock-registry["@npmcli/mock-registry"]; libnpmpublish-->npmcli-template-oss["@npmcli/template-oss"]; libnpmpublish-->semver; libnpmpublish-->ssri; diff --git a/package-lock.json b/package-lock.json index 189b9151f7ddd..6f03db3fc0e44 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14547,8 +14547,8 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", + "@npmcli/mock-registry": "^1.0.0", "@npmcli/template-oss": "4.11.0", - "libnpmpack": "^5.0.6", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", "tap": "^16.3.2" diff --git a/workspaces/libnpmpublish/package.json b/workspaces/libnpmpublish/package.json index 6e537237efd1d..c293d566d1dc2 100644 --- a/workspaces/libnpmpublish/package.json +++ b/workspaces/libnpmpublish/package.json @@ -25,8 +25,8 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", + "@npmcli/mock-registry": "^1.0.0", "@npmcli/template-oss": "4.11.0", - "libnpmpack": "^5.0.6", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", "tap": "^16.3.2" diff --git a/workspaces/libnpmpublish/test/fixtures/npmcli-libnpmpublish-test-1.0.0.tgz b/workspaces/libnpmpublish/test/fixtures/npmcli-libnpmpublish-test-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..c03d06de5c1635f6ea6525d7ffe1a57028ca0868 GIT binary patch literal 208 zcmV;>05AU^iwFP!00002|Lv5~3c?^1hP~cXh}X3p+h)*Jui`domN}U&g6Q3IOoF1z z8by9Lznt?U3ggG+)j(flaL29vEe$6Cou z$;zM1P$_BKr4!bX#ppYU-pWpoR+>TzQ?(Jc?xk^|GurXP4LA%JNv?6zL?V&Mmv94S KJNroh3;+N>p=G)N literal 0 HcmV?d00001 diff --git a/workspaces/libnpmpublish/test/fixtures/tnock.js b/workspaces/libnpmpublish/test/fixtures/tnock.js deleted file mode 100644 index 048639a504e08..0000000000000 --- a/workspaces/libnpmpublish/test/fixtures/tnock.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict' - -const nock = require('nock') - -module.exports = tnock -function tnock (t, host) { - const server = nock(host) - t.teardown(function () { - server.done() - }) - return server -} diff --git a/workspaces/libnpmpublish/test/index.js b/workspaces/libnpmpublish/test/index.js deleted file mode 100644 index 7238e65a40172..0000000000000 --- a/workspaces/libnpmpublish/test/index.js +++ /dev/null @@ -1,6 +0,0 @@ -const t = require('tap') -const index = require('../lib/index.js') -t.strictSame(index, { - publish: require('../lib/publish.js'), - unpublish: require('../lib/unpublish.js'), -}) diff --git a/workspaces/libnpmpublish/test/publish.js b/workspaces/libnpmpublish/test/publish.js index c696e82b22544..0818c94fbe494 100644 --- a/workspaces/libnpmpublish/test/publish.js +++ b/workspaces/libnpmpublish/test/publish.js @@ -1,62 +1,63 @@ 'use strict' -const t = require('tap') -const ssri = require('ssri') -const crypto = require('crypto') -const pack = require('libnpmpack') const cloneDeep = require('lodash.clonedeep') +const crypto = require('crypto') +const fs = require('fs') +const npa = require('npm-package-arg') +const ssri = require('ssri') +const t = require('tap') -const publish = require('../lib/publish.js') -const tnock = require('./fixtures/tnock.js') +const MockRegistry = require('@npmcli/mock-registry') -const testDir = t.testdir({ - 'package.json': JSON.stringify({ - name: 'libnpmpublish', - version: '1.0.0', - }, null, 2), - 'index.js': 'hello', -}) +// TODO use registry.manifest (requires json date wrangling for nock) -const OPTS = { - registry: 'https://mock.reg/', -} +const tarData = fs.readFileSync('./test/fixtures/npmcli-libnpmpublish-test-1.0.0.tgz') +const shasum = crypto.createHash('sha1').update(tarData).digest('hex') +const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) -const REG = OPTS.registry +const token = 'test-auth-token' +const opts = { + npmVersion: '1.0.0-test', + registry: 'https://mock.reg', + '//mock.reg/:_authToken': token, +} -t.test('basic publish', async t => { +t.test('basic publish - no npmVersion', async t => { + const { publish } = t.mock('..') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) const manifest = { - name: 'libnpmpublish', + name: 'libnpmpublish-test', version: '1.0.0', - description: 'some stuff', + description: 'test libnpmpublish package', } + const spec = npa(manifest.name) - const tarData = await pack(`file:${testDir}`, { ...OPTS }) - const shasum = crypto.createHash('sha1').update(tarData).digest('hex') - const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { - _id: 'libnpmpublish', - name: 'libnpmpublish', - description: 'some stuff', + _id: manifest.name, + name: manifest.name, + description: manifest.description, 'dist-tags': { latest: '1.0.0', }, versions: { '1.0.0': { - _id: 'libnpmpublish@1.0.0', + _id: `${manifest.name}@${manifest.version}`, _nodeVersion: process.versions.node, - name: 'libnpmpublish', - version: '1.0.0', - description: 'some stuff', + ...manifest, dist: { shasum, - integrity: integrity.toString(), - tarball: 'http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz', + integrity: integrity.sha512[0].toString(), + tarball: 'http://mock.reg/libnpmpublish-test/-/libnpmpublish-test-1.0.0.tgz', }, }, }, access: 'public', _attachments: { - 'libnpmpublish-1.0.0.tgz': { + 'libnpmpublish-test-1.0.0.tgz': { content_type: 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length, @@ -64,57 +65,52 @@ t.test('basic publish', async t => { }, } - const srv = tnock(t, REG) - srv.put('/libnpmpublish', body => { - t.same(body, packument, 'posted packument matches expectations') - return true - }, { - authorization: 'Bearer deadbeef', - }).reply(201, {}) - + registry.nock.put(`/${spec.escapedName}`, packument).reply(201, {}) const ret = await publish(manifest, tarData, { - ...OPTS, - token: 'deadbeef', + ...opts, + npmVersion: null, }) t.ok(ret, 'publish succeeded') }) -t.test('scoped publish - default access', async t => { +t.test('scoped publish', async t => { + const { publish } = t.mock('..') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) const manifest = { - name: '@claudiahdz/libnpmpublish', + name: '@npmcli/libnpmpublish-test', version: '1.0.0', - description: 'some stuff', + description: 'test libnpmpublish package', } + const spec = npa(manifest.name) - const tarData = await pack(`file:${testDir}`, { ...OPTS }) - const shasum = crypto.createHash('sha1').update(tarData).digest('hex') - const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { - _id: '@claudiahdz/libnpmpublish', - name: '@claudiahdz/libnpmpublish', - description: 'some stuff', + _id: manifest.name, + name: manifest.name, + description: manifest.description, 'dist-tags': { latest: '1.0.0', }, versions: { '1.0.0': { - _id: '@claudiahdz/libnpmpublish@1.0.0', + _id: `${manifest.name}@${manifest.version}`, _nodeVersion: process.versions.node, - _npmVersion: '6.13.7', - name: '@claudiahdz/libnpmpublish', - version: '1.0.0', - description: 'some stuff', + _npmVersion: opts.npmVersion, + ...manifest, dist: { shasum, - integrity: integrity.toString(), - tarball: 'http://mock.reg/@claudiahdz/libnpmpublish/' - + '-/@claudiahdz/libnpmpublish-1.0.0.tgz', + integrity: integrity.sha512[0].toString(), + /* eslint-disable-next-line max-len */ + tarball: 'http://mock.reg/@npmcli/libnpmpublish-test/-/@npmcli/libnpmpublish-test-1.0.0.tgz', }, }, }, access: 'public', _attachments: { - '@claudiahdz/libnpmpublish-1.0.0.tgz': { + '@npmcli/libnpmpublish-test-1.0.0.tgz': { content_type: 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length, @@ -122,58 +118,51 @@ t.test('scoped publish - default access', async t => { }, } - const srv = tnock(t, REG) - srv.put('/@claudiahdz%2flibnpmpublish', body => { - t.same(body, packument, 'posted packument matches expectations') - return true - }, { - authorization: 'Bearer deadbeef', - }).reply(201, {}) + registry.nock.put(`/${spec.escapedName}`, packument).reply(201, {}) - const ret = await publish(manifest, tarData, { - ...OPTS, - npmVersion: '6.13.7', - token: 'deadbeef', - }) + const ret = await publish(manifest, tarData, opts) t.ok(ret, 'publish succeeded') }) t.test('scoped publish - restricted access', async t => { + const { publish } = t.mock('..') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) const manifest = { - name: '@claudiahdz/libnpmpublish', + name: '@npmcli/libnpmpublish-test', version: '1.0.0', - description: 'some stuff', + description: 'test libnpmpublish package', } + const spec = npa(manifest.name) - const tarData = await pack(`file:${testDir}`, { ...OPTS }) - const shasum = crypto.createHash('sha1').update(tarData).digest('hex') - const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { - _id: '@claudiahdz/libnpmpublish', - name: '@claudiahdz/libnpmpublish', - description: 'some stuff', + _id: manifest.name, + name: manifest.name, + description: manifest.description, 'dist-tags': { latest: '1.0.0', }, versions: { '1.0.0': { - _id: '@claudiahdz/libnpmpublish@1.0.0', + _id: '@npmcli/libnpmpublish-test@1.0.0', _nodeVersion: process.versions.node, - _npmVersion: '6.13.7', - name: '@claudiahdz/libnpmpublish', - version: '1.0.0', - description: 'some stuff', + _npmVersion: opts.npmVersion, + name: '@npmcli/libnpmpublish-test', + ...manifest, dist: { shasum, - integrity: integrity.toString(), - tarball: 'http://mock.reg/@claudiahdz/libnpmpublish/' - + '-/@claudiahdz/libnpmpublish-1.0.0.tgz', + integrity: integrity.sha512[0].toString(), + /* eslint-disable-next-line max-len */ + tarball: 'http://mock.reg/@npmcli/libnpmpublish-test/-/@npmcli/libnpmpublish-test-1.0.0.tgz', }, }, }, access: 'restricted', _attachments: { - '@claudiahdz/libnpmpublish-1.0.0.tgz': { + '@npmcli/libnpmpublish-test-1.0.0.tgz': { content_type: 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length, @@ -181,24 +170,22 @@ t.test('scoped publish - restricted access', async t => { }, } - const srv = tnock(t, REG) - srv.put('/@claudiahdz%2flibnpmpublish', body => { - t.same(body, packument, 'posted packument matches expectations') - return true - }, { - authorization: 'Bearer deadbeef', - }).reply(201, {}) + registry.nock.put(`/${spec.escapedName}`, packument).reply(201, {}) const ret = await publish(manifest, tarData, { - ...OPTS, + ...opts, access: 'restricted', - npmVersion: '6.13.7', - token: 'deadbeef', }) t.ok(ret, 'publish succeeded') }) t.test('retry after a conflict', async t => { + const { publish } = t.mock('..') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) const REV = '72-47f2986bfd8e8b55068b204588bbf484' const manifest = { name: 'libnpmpublish', @@ -206,10 +193,6 @@ t.test('retry after a conflict', async t => { description: 'some stuff', } - const tarData = await pack(`file:${testDir}`, { ...OPTS }) - const shasum = crypto.createHash('sha1').update(tarData).digest('hex') - const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) - const basePackument = { name: 'libnpmpublish', description: 'some stuff', @@ -231,7 +214,7 @@ t.test('retry after a conflict', async t => { '1.0.1': { _id: 'libnpmpublish@1.0.1', _nodeVersion: process.versions.node, - _npmVersion: '13.7.0', + _npmVersion: opts.npmVersion, name: 'libnpmpublish', version: '1.0.1', description: 'some stuff', @@ -257,7 +240,7 @@ t.test('retry after a conflict', async t => { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, - _npmVersion: '6.13.7', + _npmVersion: opts.npmVersion, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', @@ -284,19 +267,18 @@ t.test('retry after a conflict', async t => { _attachments: { ...currentPackument._attachments, ...newPackument._attachments }, }) - const srv = tnock(t, REG) - srv.put('/libnpmpublish', body => { + registry.nock.put('/libnpmpublish', body => { t.notOk(body._rev, 'no _rev in initial post') t.same(body, newPackument, 'got conflicting packument') return true }).reply(409, { error: 'gimme _rev plz' }) - srv.get('/libnpmpublish?write=true').reply(200, { + registry.nock.get('/libnpmpublish?write=true').reply(200, { _rev: REV, ...currentPackument, }) - srv.put('/libnpmpublish', body => { + registry.nock.put('/libnpmpublish', body => { t.same(body, { _rev: REV, ...mergedPackument, @@ -304,16 +286,17 @@ t.test('retry after a conflict', async t => { return true }).reply(201, {}) - const ret = await publish(manifest, tarData, { - ...OPTS, - token: 'deadbeef', - npmVersion: '6.13.7', - }) - + const ret = await publish(manifest, tarData, opts) t.ok(ret, 'publish succeeded') }) t.test('retry after a conflict -- no versions on remote', async t => { + const { publish } = t.mock('..') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) const REV = '72-47f2986bfd8e8b55068b204588bbf484' const manifest = { name: 'libnpmpublish', @@ -321,10 +304,6 @@ t.test('retry after a conflict -- no versions on remote', async t => { description: 'some stuff', } - const tarData = await pack(`file:${testDir}`, { ...OPTS }) - const shasum = crypto.createHash('sha1').update(tarData).digest('hex') - const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) - const basePackument = { name: 'libnpmpublish', description: 'some stuff', @@ -339,7 +318,7 @@ t.test('retry after a conflict -- no versions on remote', async t => { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, - _npmVersion: '6.13.7', + _npmVersion: opts.npmVersion, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', @@ -365,19 +344,18 @@ t.test('retry after a conflict -- no versions on remote', async t => { _attachments: { ...newPackument._attachments }, }) - const srv = tnock(t, REG) - srv.put('/libnpmpublish', body => { + registry.nock.put('/libnpmpublish', body => { t.notOk(body._rev, 'no _rev in initial post') t.same(body, newPackument, 'got conflicting packument') return true }).reply(409, { error: 'gimme _rev plz' }) - srv.get('/libnpmpublish?write=true').reply(200, { + registry.nock.get('/libnpmpublish?write=true').reply(200, { _rev: REV, ...currentPackument, }) - srv.put('/libnpmpublish', body => { + registry.nock.put('/libnpmpublish', body => { t.same(body, { _rev: REV, ...mergedPackument, @@ -385,16 +363,18 @@ t.test('retry after a conflict -- no versions on remote', async t => { return true }).reply(201, {}) - const ret = await publish(manifest, tarData, { - ...OPTS, - npmVersion: '6.13.7', - token: 'deadbeef', - }) + const ret = await publish(manifest, tarData, opts) t.ok(ret, 'publish succeeded') }) t.test('version conflict', async t => { + const { publish } = t.mock('..') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) const REV = '72-47f2986bfd8e8b55068b204588bbf484' const manifest = { name: 'libnpmpublish', @@ -402,9 +382,6 @@ t.test('version conflict', async t => { description: 'some stuff', } - const tarData = await pack(`file:${testDir}`, { ...OPTS }) - const shasum = crypto.createHash('sha1').update(tarData).digest('hex') - const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const basePackument = { name: 'libnpmpublish', description: 'some stuff', @@ -440,21 +417,20 @@ t.test('version conflict', async t => { }, })) - const srv = tnock(t, REG) - srv.put('/libnpmpublish', body => { + registry.nock.put('/libnpmpublish', body => { t.notOk(body._rev, 'no _rev in initial post') t.same(body, newPackument, 'got conflicting packument') return true }).reply(409, { error: 'gimme _rev plz' }) - srv.get('/libnpmpublish?write=true').reply(200, { + registry.nock.get('/libnpmpublish?write=true').reply(200, { _rev: REV, ...newPackument, }) try { await publish(manifest, tarData, { - ...OPTS, + ...opts, npmVersion: '6.13.7', token: 'deadbeef', }) @@ -464,34 +440,36 @@ t.test('version conflict', async t => { }) t.test('refuse if package marked private', async t => { - const manifest = { - name: 'libnpmpublish', - version: '1.0.0', - description: 'some stuff', - private: true, - } - - try { - await publish(manifest, Buffer.from(''), { - ...OPTS, - npmVersion: '6.9.0', - token: 'deadbeef', - }) - } catch (err) { - t.equal(err.code, 'EPRIVATE', 'got correct error code') - } + const { publish } = t.mock('..') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) + const manifest = registry.manifest({ name: '@npmcli/libnpmpublish-test' }) + manifest.private = true + + await t.rejects( + publish(manifest, Buffer.from(''), opts), + { code: 'EPRIVATE' }, + 'got correct error code' + ) }) t.test('publish includes access', async t => { + const { publish } = t.mock('..') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) + const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', } - const tarData = await pack(`file:${testDir}`, { ...OPTS }) - const shasum = crypto.createHash('sha1').update(tarData).digest('hex') - const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', @@ -504,6 +482,7 @@ t.test('publish includes access', async t => { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, + _npmVersion: opts.npmVersion, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', @@ -523,17 +502,10 @@ t.test('publish includes access', async t => { }, } - const srv = tnock(t, REG) - srv.put('/libnpmpublish', body => { - t.same(body, packument, 'posted packument matches expectations') - return true - }, { - authorization: 'Bearer deadbeef', - }).reply(201, {}) + registry.nock.put('/libnpmpublish', packument).reply(201, {}) const ret = await publish(manifest, tarData, { - ...OPTS, - token: 'deadbeef', + ...opts, access: 'public', }) @@ -541,47 +513,49 @@ t.test('publish includes access', async t => { }) t.test('refuse if package is unscoped plus `restricted` access', async t => { - const manifest = { - name: 'libnpmpublish', - version: '1.0.0', - description: 'some stuff', - } - - try { - await publish(manifest, Buffer.from(''), { - ...OPTS, - npmVersion: '6.13.7', - access: 'restricted', - }) - } catch (err) { - t.equal(err.code, 'EUNSCOPED', 'got correct error code') - } + const { publish } = t.mock('..') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) + const manifest = registry.manifest({ name: 'libnpmpublish-test' }) + await t.rejects(publish(manifest, Buffer.from(''), { + ...opts, + access: 'restricted', + }), + { code: 'EUNSCOPED' } + ) }) t.test('refuse if bad semver on manifest', async t => { - const manifest = { - name: 'libnpmpublish', - version: 'lmao', - description: 'some stuff', - } + const { publish } = t.mock('..') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) + const manifest = registry.manifest({ name: 'libnpmpublish-test', versions: ['notsemver'] }) - try { - await publish(manifest, Buffer.from(''), OPTS) - } catch (err) { - t.equal(err.code, 'EBADSEMVER', 'got correct error code') - } + await t.rejects( + publish(manifest, Buffer.from(''), opts), + { code: 'EBADSEMVER' } + ) }) t.test('other error code', async t => { + const { publish } = t.mock('..') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', } - const tarData = await pack(`file:${testDir}`, { ...OPTS }) - const shasum = crypto.createHash('sha1').update(tarData).digest('hex') - const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', @@ -594,7 +568,7 @@ t.test('other error code', async t => { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, - _npmVersion: '6.13.7', + _npmVersion: opts.npmVersion, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', @@ -614,21 +588,11 @@ t.test('other error code', async t => { }, } - const srv = tnock(t, REG) - srv.put('/libnpmpublish', body => { - t.same(body, packument, 'posted packument matches expectations') - return true - }, { - authorization: 'Bearer deadbeef', - }).reply(500, { error: 'go away' }) + registry.nock.put('/libnpmpublish', packument).reply(500, { error: 'go away' }) - try { - await publish(manifest, tarData, { - ...OPTS, - npmVersion: '6.13.7', - token: 'deadbeef', - }) - } catch (err) { - t.match(err.message, /go away/, 'no retry on non-409') - } + await t.rejects( + publish(manifest, tarData, opts), + /go away/, + 'no retry on non-409' + ) }) diff --git a/workspaces/libnpmpublish/test/unpublish.js b/workspaces/libnpmpublish/test/unpublish.js index b59dad6d36a06..6bb3c32e6d88f 100644 --- a/workspaces/libnpmpublish/test/unpublish.js +++ b/workspaces/libnpmpublish/test/unpublish.js @@ -1,297 +1,173 @@ 'use strict' const t = require('tap') -const tnock = require('./fixtures/tnock.js') +const MockRegistry = require('@npmcli/mock-registry') +const npa = require('npm-package-arg') -const OPTS = { +const opts = { registry: 'https://mock.reg/', } -const REG = OPTS.registry -const REV = '72-47f2986bfd8e8b55068b204588bbf484' -const unpub = require('../lib/unpublish.js') - -t.test('basic test', async t => { - const doc = { - _id: 'foo', - _rev: REV, - name: 'foo', - 'dist-tags': { - latest: '1.0.0', - }, - versions: { - '1.0.0': { - name: 'foo', - dist: { - tarball: `${REG}/foo/-/foo-1.0.0.tgz`, - }, - }, - }, - } - const srv = tnock(t, REG) - srv.get('/foo?write=true').reply(200, doc) - srv.delete(`/foo/-rev/${REV}`).reply(201) - const ret = await unpub('foo', OPTS) - t.ok(ret, 'foo was unpublished') +const { unpublish } = require('..') + +t.test('basic test with no scope', async t => { + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + }) + const manifest = registry.manifest({ name: 'npm-unpublish-test' }) + registry.package({ manifest, query: { write: true } }) + registry.unpublish({ manifest }) + const ret = await unpublish('npm-unpublish-test', opts) + t.ok(ret, 'npm-unpublish-test was unpublished') }) -t.test('scoped basic test', async t => { - const doc = { - _id: '@foo/bar', - _rev: REV, - name: '@foo/bar', - 'dist-tags': { - latest: '1.0.0', - }, - versions: { - '1.0.0': { - name: '@foo/bar', - dist: { - tarball: `${REG}/@foo/bar/-/foo-1.0.0.tgz`, - }, - }, - }, - } - const srv = tnock(t, REG) - srv.get('/@foo%2fbar?write=true').reply(200, doc) - srv.delete(`/@foo%2fbar/-rev/${REV}`).reply(201) - const ret = await unpub('@foo/bar', OPTS) - t.ok(ret, 'foo was unpublished') +t.test('basic test with scope', async t => { + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + }) + const manifest = registry.manifest({ name: '@npmcli/npm-unpublish-test' }) + registry.package({ manifest, query: { write: true } }) + registry.unpublish({ manifest }) + const ret = await unpublish('@npmcli/npm-unpublish-test', opts) + t.ok(ret, '@npmcli/npm-unpublish-test was unpublished') }) t.test('unpublish specific, last version', async t => { - const doc = { - _id: 'foo', - _rev: REV, - name: 'foo', - 'dist-tags': { - latest: '1.0.0', - }, - versions: { - '1.0.0': { - name: 'foo', - dist: { - tarball: `${REG}/foo/-/foo-1.0.0.tgz`, - }, - }, - }, - } - const srv = tnock(t, REG) - srv.get('/foo?write=true').reply(200, doc) - srv.delete(`/foo/-rev/${REV}`).reply(201) - const ret = await unpub('foo@1.0.0', OPTS) - t.ok(ret, 'foo was unpublished') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + }) + const manifest = registry.manifest({ name: 'npm-unpublish-test' }) + registry.package({ manifest, query: { write: true } }) + registry.unpublish({ manifest }) + const ret = await unpublish('npm-unpublish-test@1.0.0', opts) + t.ok(ret, 'npm-unpublish-test was unpublished') }) t.test('unpublish specific version', async t => { - const doc = { - _id: 'foo', - _rev: REV, - _revisions: [1, 2, 3], - _attachments: [1, 2, 3], - name: 'foo', - 'dist-tags': { - latest: '1.0.1', - }, - versions: { - '1.0.0': { - name: 'foo', - dist: { - tarball: `${REG}/foo/-/foo-1.0.0.tgz`, - }, - }, - '1.0.1': { - name: 'foo', - dist: { - tarball: `${REG}/foo/-/foo-1.0.1.tgz`, - }, - }, - }, - } - const postEdit = { - _id: 'foo', - _rev: REV, - name: 'foo', - 'dist-tags': { - latest: '1.0.0', - }, - versions: { - '1.0.0': { - name: 'foo', - dist: { - tarball: `${REG}/foo/-/foo-1.0.0.tgz`, - }, - }, - }, + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + }) + const manifest = registry.manifest({ name: 'npm-unpublish-test', versions: ['1.0.0', '1.0.1'] }) + const unpublished = { + ...manifest, + versions: { '1.0.0': manifest.versions['1.0.0'] }, + 'dist-tags': { latest: '1.0.0' }, } - - const srv = tnock(t, REG) - srv.get('/foo?write=true').reply(200, doc) - srv.put(`/foo/-rev/${REV}`, postEdit).reply(200) - srv.get('/foo?write=true').reply(200, postEdit) - srv.delete(`/foo/-/foo-1.0.1.tgz/-rev/${REV}`).reply(200) - const ret = await unpub('foo@1.0.1', OPTS) + registry.package({ manifest, query: { write: true } }) + // nock does not properly compare json payloads with Date objects in them, + // hence the pre-stringifying + /* eslint-disable-next-line max-len */ + registry.nock.put(`/npm-unpublish-test/-rev/${manifest._rev}`, JSON.stringify(unpublished)).reply(200) + registry.package({ manifest: unpublished, query: { write: true } }) + /* eslint-disable-next-line max-len */ + registry.nock.delete(`/npm-unpublish-test/-/npm-unpublish-test-1.0.1.tgz/-rev/${manifest._rev}`).reply(200) + const ret = await unpublish('npm-unpublish-test@1.0.1', opts) t.ok(ret, 'foo was unpublished') }) -t.test('unpublishing from a custom registry', async t => { - const opt = { +t.test('unpublishing specific version from a registry with a pathname', async t => { + const _opts = { registry: 'https://artifactory.example.com/api/npm/npm-snapshots/', } - const reg = opt.registry - const doc = { - _id: 'foo', - _rev: REV, - _revisions: [1, 2, 3], - _attachments: [1, 2, 3], - name: 'foo', - 'dist-tags': { - latest: '1.0.1', - }, - versions: { - '1.0.0': { - name: 'foo', - dist: { - tarball: `${reg}/foo/-/foo-1.0.0.tgz`, - }, - }, - '1.0.1': { - name: 'foo', - dist: { - tarball: `${reg}/foo/-/foo-1.0.1.tgz`, - }, - }, - }, - } - const postEdit = { - _id: 'foo', - _rev: REV, - name: 'foo', - 'dist-tags': { - latest: '1.0.0', - }, - versions: { - '1.0.0': { - name: 'foo', - dist: { - tarball: `${reg}/foo/-/foo-1.0.0.tgz`, - }, - }, - }, + const registry = new MockRegistry({ + tap: t, + registry: _opts.registry, + }) + const manifest = registry.manifest({ name: 'npm-unpublish-test', versions: ['1.0.0', '1.0.1'] }) + const unpublished = { + ...manifest, + versions: { '1.0.0': manifest.versions['1.0.0'] }, + 'dist-tags': { latest: '1.0.0' }, } - - const srv = tnock(t, reg) - srv.get('/foo?write=true').reply(200, doc) - srv.put(`/foo/-rev/${REV}`, postEdit).reply(200) - srv.get('/foo?write=true').reply(200, postEdit) - srv.delete(`/foo/-/foo-1.0.1.tgz/-rev/${REV}`).reply(200) - const ret = await unpub('foo@1.0.1', opt) - t.ok(ret, 'foo was unpublished') + registry.package({ manifest, query: { write: true } }) + // nock does not properly compare json payloads with Date objects in them, + // hence the pre-stringifying + /* eslint-disable-next-line max-len */ + registry.nock.put(`${registry.pathname}/npm-unpublish-test/-rev/${manifest._rev}`, JSON.stringify(unpublished)).reply(200) + registry.package({ manifest: unpublished, query: { write: true } }) + /* eslint-disable-next-line max-len */ + registry.nock.delete(`${registry.pathname}/npm-unpublish-test/-/npm-unpublish-test-1.0.1.tgz/-rev/${manifest._rev}`).reply(200) + const ret = await unpublish('npm-unpublish-test@1.0.1', _opts) + t.ok(ret, 'npm-unpublish-test was unpublished') }) t.test('404 considered a success', async t => { - const srv = tnock(t, REG) - srv.get('/foo?write=true').reply(404) - const ret = await unpub('foo', OPTS) - t.ok(ret, 'foo was unpublished') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + }) + const manifest = registry.manifest({ name: '@npmcli/npm-unpublish-test' }) + const spec = npa(manifest.name) + registry.nock.get(`/${spec.escapedName}?write=true`).reply(404) + const ret = await unpublish('@npmcli/npm-unpublish-test', opts) + t.ok(ret, '@npmcli/npm-unpublish-test was unpublished') }) t.test('non-404 errors', async t => { - const srv = tnock(t, REG) - srv.get('/foo?write=true').reply(500) - - try { - await unpub('foo', OPTS) - } catch (err) { - t.equal(err.code, 'E500', 'got right error from server') - } + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + }) + const manifest = registry.manifest({ name: '@npmcli/npm-unpublish-test' }) + const spec = npa(manifest.name) + registry.nock.get(`/${spec.escapedName}?write=true`).reply(500) + await t.rejects( + unpublish('@npmcli/npm-unpublish-test', opts), + { code: 'E500' }, + 'got correct error from server' + ) }) t.test('packument with missing versions unpublishes whole thing', async t => { - const doc = { - _id: 'foo', - _rev: REV, - name: 'foo', - 'dist-tags': { - latest: '1.0.0', - }, - } - const srv = tnock(t, REG) - srv.get('/foo?write=true').reply(200, doc) - srv.delete(`/foo/-rev/${REV}`).reply(201) - const ret = await unpub('foo@1.0.0', OPTS) - t.ok(ret, 'foo was unpublished') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + }) + const manifest = registry.manifest({ name: '@npmcli/npm-unpublish-test' }) + delete manifest.versions + delete manifest.time + registry.package({ manifest, query: { write: true } }) + registry.unpublish({ manifest }) + const ret = await unpublish('@npmcli/npm-unpublish-test@1.0.0', opts) + t.ok(ret, '@npmcli/npm-unpublish-test was unpublished') }) t.test('packument with missing specific version assumed unpublished', async t => { - const doc = { - _id: 'foo', - _rev: REV, - name: 'foo', - 'dist-tags': { - latest: '1.0.0', - }, - versions: { - '1.0.0': { - name: 'foo', - dist: { - tarball: `${REG}/foo/-/foo-1.0.0.tgz`, - }, - }, - }, - } - const srv = tnock(t, REG) - srv.get('/foo?write=true').reply(200, doc) - const ret = await unpub('foo@1.0.1', OPTS) - t.ok(ret, 'foo was unpublished') + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + }) + const manifest = registry.manifest({ name: '@npmcli/npm-unpublish-test' }) + registry.package({ manifest, query: { write: true } }) + const ret = await unpublish('@npmcli/npm-unpublish-test@1.0.1', opts) + t.ok(ret, '@npmcli/npm-unpublish-test was unpublished') }) t.test('unpublish specific version without dist-tag update', async t => { - const doc = { - _id: 'foo', - _rev: REV, - _revisions: [1, 2, 3], - _attachments: [1, 2, 3], - name: 'foo', - 'dist-tags': { - latest: '1.0.0', - }, - versions: { - '1.0.0': { - name: 'foo', - dist: { - tarball: `${REG}/foo/-/foo-1.0.0.tgz`, - }, - }, - '1.0.1': { - name: 'foo', - dist: { - tarball: `${REG}/foo/-/foo-1.0.1.tgz`, - }, - }, - }, - } - const postEdit = { - _id: 'foo', - _rev: REV, - name: 'foo', - 'dist-tags': { - latest: '1.0.0', - }, - versions: { - '1.0.0': { - name: 'foo', - dist: { - tarball: `${REG}/foo/-/foo-1.0.0.tgz`, - }, - }, - }, + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + }) + const manifest = registry.manifest({ name: 'npm-unpublish-test', versions: ['1.0.0', '1.0.1'] }) + manifest['dist-tags'].latest = '1.0.0' + const unpublished = { + ...manifest, + versions: { '1.0.0': manifest.versions['1.0.0'] }, + 'dist-tags': { latest: '1.0.0' }, } - const srv = tnock(t, REG) - srv.get('/foo?write=true').reply(200, doc) - srv.put(`/foo/-rev/${REV}`, postEdit).reply(200) - srv.get('/foo?write=true').reply(200, postEdit) - srv.delete(`/foo/-/foo-1.0.1.tgz/-rev/${REV}`).reply(200) - const ret = await unpub('foo@1.0.1', OPTS) + registry.package({ manifest, query: { write: true } }) + // nock does not properly compare json payloads with Date objects in them, + // hence the pre-stringifying + /* eslint-disable-next-line max-len */ + registry.nock.put(`/npm-unpublish-test/-rev/${manifest._rev}`, JSON.stringify(unpublished)).reply(200) + /* eslint-disable-next-line max-len */ + registry.package({ manifest: unpublished, query: { write: true } }) + /* eslint-disable-next-line max-len */ + registry.nock.delete(`/npm-unpublish-test/-/npm-unpublish-test-1.0.1.tgz/-rev/${manifest._rev}`).reply(200) + const ret = await unpublish('npm-unpublish-test@1.0.1', opts) t.ok(ret, 'foo was unpublished') })