diff --git a/lib/shrinkwrap.js b/lib/shrinkwrap.js index 5d4a1ada982a4..fc70b1bb7f546 100644 --- a/lib/shrinkwrap.js +++ b/lib/shrinkwrap.js @@ -1,7 +1,5 @@ const { resolve, basename } = require('path') -const util = require('util') -const fs = require('fs') -const { unlink } = fs.promises || { unlink: util.promisify(fs.unlink) } +const { unlink } = require('fs').promises const Arborist = require('@npmcli/arborist') const log = require('npmlog') @@ -25,7 +23,6 @@ class Shrinkwrap extends BaseCommand { // if has a npm-shrinkwrap.json, nothing to do // if has a package-lock.json, rename to npm-shrinkwrap.json // if has neither, load the actual tree and save that as npm-shrinkwrap.json - // in all cases, re-cast to current lockfile version // // loadVirtual, fall back to loadActual // rename shrinkwrap file type, and tree.meta.save() @@ -44,17 +41,37 @@ class Shrinkwrap extends BaseCommand { const oldFilename = meta.filename const notSW = !newFile && basename(oldFilename) !== 'npm-shrinkwrap.json' + // The computed lockfile version of a hidden lockfile is always 3 + // even if the actual value of the property is a different. + // When shrinkwrap is run with only a hidden lockfile we want to + // set the shrinkwrap lockfile version as whatever was explicitly + // requested with a fallback to the actual value from the hidden + // lockfile. + if (meta.hiddenLockfile) { + meta.lockfileVersion = arb.options.lockfileVersion || + meta.originalLockfileVersion + } meta.hiddenLockfile = false meta.filename = sw await meta.save() - if (newFile) - log.notice('', 'created a lockfile as npm-shrinkwrap.json') - else if (notSW) { + const updatedVersion = meta.originalLockfileVersion !== meta.lockfileVersion + ? meta.lockfileVersion + : null + + if (newFile) { + let message = 'created a lockfile as npm-shrinkwrap.json' + if (updatedVersion) + message += ` with version ${updatedVersion}` + log.notice('', message) + } else if (notSW) { await unlink(oldFilename) - log.notice('', 'package-lock.json has been renamed to npm-shrinkwrap.json') - } else if (meta.originalLockfileVersion !== this.npm.lockfileVersion) - log.notice('', `npm-shrinkwrap.json updated to version ${this.npm.lockfileVersion}`) + let message = 'package-lock.json has been renamed to npm-shrinkwrap.json' + if (updatedVersion) + message += ` and updated to version ${updatedVersion}` + log.notice('', message) + } else if (updatedVersion) + log.notice('', `npm-shrinkwrap.json updated to version ${updatedVersion}`) else log.notice('', 'npm-shrinkwrap.json up to date') } diff --git a/tap-snapshots/test/lib/shrinkwrap.js.test.cjs b/tap-snapshots/test/lib/shrinkwrap.js.test.cjs new file mode 100644 index 0000000000000..e966d6650c11f --- /dev/null +++ b/tap-snapshots/test/lib/shrinkwrap.js.test.cjs @@ -0,0 +1,362 @@ +/* IMPORTANT + * This snapshot file is auto-generated, but designed for humans. + * It should be checked into source control and tracked carefully. + * Re-generate by setting TAP_SNAPSHOT=1 and running tests. + * Make sure to inspect the output below. Do not ignore changes! + */ +'use strict' +exports[`test/lib/shrinkwrap.js TAP with hidden lockfile ancient > must match snapshot 1`] = ` + localPrefix = { + "node_modules": { + ".package-lock.json": { + "lockfileVersion": 1 + } + } + } + config = {} + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-ancient", + "lockfileVersion": 1, + "requires": true + } + logs = [ + "created a lockfile as npm-shrinkwrap.json" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with hidden lockfile ancient upgrade > must match snapshot 1`] = ` + localPrefix = { + "node_modules": { + ".package-lock.json": { + "lockfileVersion": 1 + } + } + } + config = { + "lockfileVersion": 3 + } + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-ancient-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": {} + } + logs = [ + "created a lockfile as npm-shrinkwrap.json with version 3" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with hidden lockfile existing > must match snapshot 1`] = ` + localPrefix = { + "node_modules": { + ".package-lock.json": { + "lockfileVersion": 2 + } + } + } + config = {} + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-existing", + "lockfileVersion": 2, + "requires": true, + "packages": {} + } + logs = [ + "created a lockfile as npm-shrinkwrap.json" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with hidden lockfile existing downgrade > must match snapshot 1`] = ` + localPrefix = { + "node_modules": { + ".package-lock.json": { + "lockfileVersion": 2 + } + } + } + config = { + "lockfileVersion": 1 + } + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-existing-downgrade", + "lockfileVersion": 1, + "requires": true + } + logs = [ + "created a lockfile as npm-shrinkwrap.json with version 1" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with hidden lockfile existing upgrade > must match snapshot 1`] = ` + localPrefix = { + "node_modules": { + ".package-lock.json": { + "lockfileVersion": 2 + } + } + } + config = { + "lockfileVersion": 3 + } + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-existing-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": {} + } + logs = [ + "created a lockfile as npm-shrinkwrap.json with version 3" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with nothing ancient > must match snapshot 1`] = ` + localPrefix = {} + config = {} + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-nothing-ancient", + "lockfileVersion": 2, + "requires": true, + "packages": {} + } + logs = [ + "created a lockfile as npm-shrinkwrap.json with version 2" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with nothing ancient upgrade > must match snapshot 1`] = ` + localPrefix = {} + config = { + "lockfileVersion": 3 + } + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-nothing-ancient-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": {} + } + logs = [ + "created a lockfile as npm-shrinkwrap.json with version 3" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with npm-shrinkwrap.json ancient > must match snapshot 1`] = ` + localPrefix = { + "npm-shrinkwrap.json": { + "lockfileVersion": 1 + } + } + config = {} + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient" + } + } + } + logs = [ + "npm-shrinkwrap.json updated to version 2" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with npm-shrinkwrap.json ancient upgrade > must match snapshot 1`] = ` + localPrefix = { + "npm-shrinkwrap.json": { + "lockfileVersion": 1 + } + } + config = { + "lockfileVersion": 3 + } + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient-upgrade" + } + } + } + logs = [ + "npm-shrinkwrap.json updated to version 3" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with npm-shrinkwrap.json existing > must match snapshot 1`] = ` + localPrefix = { + "npm-shrinkwrap.json": { + "lockfileVersion": 2 + } + } + config = {} + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing" + } + } + } + logs = [ + "npm-shrinkwrap.json up to date" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with npm-shrinkwrap.json existing downgrade > must match snapshot 1`] = ` + localPrefix = { + "npm-shrinkwrap.json": { + "lockfileVersion": 2 + } + } + config = { + "lockfileVersion": 1 + } + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing-downgrade", + "lockfileVersion": 1, + "requires": true + } + logs = [ + "npm-shrinkwrap.json updated to version 1" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with npm-shrinkwrap.json existing upgrade > must match snapshot 1`] = ` + localPrefix = { + "npm-shrinkwrap.json": { + "lockfileVersion": 2 + } + } + config = { + "lockfileVersion": 3 + } + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing-upgrade" + } + } + } + logs = [ + "npm-shrinkwrap.json updated to version 3" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with package-lock.json ancient > must match snapshot 1`] = ` + localPrefix = { + "package-lock.json": { + "lockfileVersion": 1 + } + } + config = {} + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient" + } + } + } + logs = [ + "package-lock.json has been renamed to npm-shrinkwrap.json and updated to version 2" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with package-lock.json ancient upgrade > must match snapshot 1`] = ` + localPrefix = { + "package-lock.json": { + "lockfileVersion": 1 + } + } + config = { + "lockfileVersion": 3 + } + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient-upgrade" + } + } + } + logs = [ + "package-lock.json has been renamed to npm-shrinkwrap.json and updated to version 3" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with package-lock.json existing > must match snapshot 1`] = ` + localPrefix = { + "package-lock.json": { + "lockfileVersion": 2 + } + } + config = {} + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing" + } + } + } + logs = [ + "package-lock.json has been renamed to npm-shrinkwrap.json" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with package-lock.json existing downgrade > must match snapshot 1`] = ` + localPrefix = { + "package-lock.json": { + "lockfileVersion": 2 + } + } + config = { + "lockfileVersion": 1 + } + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing-downgrade", + "lockfileVersion": 1, + "requires": true + } + logs = [ + "package-lock.json has been renamed to npm-shrinkwrap.json and updated to version 1" + ] +` + +exports[`test/lib/shrinkwrap.js TAP with package-lock.json existing upgrade > must match snapshot 1`] = ` + localPrefix = { + "package-lock.json": { + "lockfileVersion": 2 + } + } + config = { + "lockfileVersion": 3 + } + npm-shrinkwrap.json = { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing-upgrade" + } + } + } + logs = [ + "package-lock.json has been renamed to npm-shrinkwrap.json and updated to version 3" + ] +` diff --git a/test/lib/shrinkwrap.js b/test/lib/shrinkwrap.js index ab3b8d0ffe447..bf53089d18401 100644 --- a/test/lib/shrinkwrap.js +++ b/test/lib/shrinkwrap.js @@ -1,349 +1,211 @@ const t = require('tap') const fs = require('fs') -const { fake: mockNpm } = require('../fixtures/mock-npm') - -const config = { - global: false, -} -const flatOptions = { - depth: 0, -} -const npm = mockNpm({ - config, - flatOptions, - lockfileVersion: 2, - globalDir: '', - prefix: '', -}) -const tree = { - meta: { - hiddenLockfile: null, - loadedFromDisk: false, - filename: '', - originalLockfileVersion: 2, - save () {}, - }, -} -const mocks = { - npmlog: { notice () {} }, - '@npmcli/arborist': class { - loadVirtual () { - return tree - } - - loadActual () { - return tree - } - }, - '../../lib/utils/usage.js': () => 'usage instructions', - '../../lib/utils/config/definitions.js': {}, -} - -t.afterEach(() => { - npm.prefix = '' - config.global = false - npm.globalDir = '' -}) - -t.test('no args', t => { - t.plan(4) - - npm.prefix = '/project/a' - - class Arborist { - constructor (args) { - t.same( - args, - { ...flatOptions, path: npm.prefix }, - 'should call arborist constructor with expected args' - ) - } - - async loadVirtual () { - t.ok('should load virtual tree') - return { - ...tree, - meta: { - ...tree.meta, - save () { - t.ok('should save the lockfile') - }, - }, - } - } - } - - const npmlog = { - notice (title, msg) { - t.equal( - msg, - 'created a lockfile as npm-shrinkwrap.json', - 'should log notice msg that file was successfully created' - ) - }, - } - - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - npmlog, - '@npmcli/arborist': Arborist, - }) - const shrinkwrap = new Shrinkwrap(npm) - - shrinkwrap.exec([], err => { - if (err) - throw err - }) -}) - -t.test('no virtual tree', t => { - t.plan(4) - - npm.prefix = '/project/a' - - class Arborist { - constructor (args) { - t.same( - args, - { ...flatOptions, path: npm.prefix }, - 'should call arborist constructor with expected args' - ) - } - - async loadVirtual () { - throw new Error('ERR') - } - - async loadActual () { - t.ok('should load actual tree') - return { - ...tree, - meta: { - ...tree.meta, - save () { - t.ok('should save the lockfile') - }, - }, - } - } - } - - const npmlog = { - notice (title, msg) { - t.equal( - msg, - 'created a lockfile as npm-shrinkwrap.json', - 'should log notice msg that file was successfully created' - ) - }, - } - - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - npmlog, - '@npmcli/arborist': Arborist, - }) - const shrinkwrap = new Shrinkwrap(npm) - - shrinkwrap.exec([], err => { - if (err) - throw err - }) -}) - -t.test('existing package-json file', t => { - t.plan(5) - - npm.prefix = '/project/a' - - class Arborist { - constructor (args) { - t.same( - args, - { ...flatOptions, path: npm.prefix }, - 'should call arborist constructor with expected args' - ) - } - - async loadVirtual () { - t.ok('should load virtual tree') - return { - ...tree, - meta: { - hiddenLockfile: false, - loadedFromDisk: true, - filename: 'package-lock.json', - save () { - t.ok('should save the lockfile') - }, - }, - } - } - } - - const npmlog = { - notice (title, msg) { - t.equal( - msg, - 'package-lock.json has been renamed to npm-shrinkwrap.json', - 'should log notice msg that file was renamed' - ) - }, - } - - const fs = { - promises: { - unlink (filename) { - t.equal(filename, 'package-lock.json', 'should remove old lockfile') - }, - }, - } - - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - fs, - npmlog, - '@npmcli/arborist': Arborist, - }) - const shrinkwrap = new Shrinkwrap(npm) - - shrinkwrap.exec([], err => { - if (err) - throw err - }) -}) - -t.test('update shrinkwrap file version', t => { - t.plan(4) - - npm.prefix = '/project/a' - - class Arborist { - constructor (args) { - t.same( - args, - { ...flatOptions, path: npm.prefix }, - 'should call arborist constructor with expected args' - ) - } - - async loadVirtual () { - t.ok('should load virtual tree') - return { - ...tree, - meta: { - hiddenLockfile: false, - loadedFromDisk: true, - filename: 'npm-shrinkwrap.json', - originalLockfileVersion: 1, - save () { - t.ok('should save the lockfile') - }, - }, - } - } +const { resolve } = require('path') +const { real: mockNpm } = require('../fixtures/mock-npm') + +// Attempt to parse json values in snapshots before +// stringifying to remove escaped values +const stringify = (obj) => JSON.stringify(obj, (k, v) => { + try { + return JSON.parse(v) + } catch (_) {} + return v +}, 2) + +t.formatSnapshot = (obj) => [ + `localPrefix = ${stringify(obj.testdir)}`, + `config = ${stringify(obj.config)}`, + `npm-shrinkwrap.json = ${stringify(obj.shrinkwrap)}`, + `logs = ${stringify(obj.logs)}`, +].join('\n').split('\n').map((s) => ` ${s}`).join('\n') + +// Run shrinkwrap against a specified testdir with config items +// and make some assertions that should always be true. Sets +// the results on t.context for use in child tests +const shrinkwrap = async ( + t, + testdir = {}, + config = {}, + mocks = {} +) => { + const { command, npm, logs } = mockNpm(t, mocks) + await npm.load() + + npm.localPrefix = t.testdir(testdir) + if (config.lockfileVersion) + npm.flatOptions.lockfileVersion = config.lockfileVersion + if (config.global) + npm.config.set('global', config.global) + + await command('shrinkwrap') + + const newFile = resolve(npm.localPrefix, 'npm-shrinkwrap.json') + const oldFile = resolve(npm.localPrefix, 'package-lock.json') + const notices = logs + .filter(([title]) => title === 'notice') + .map(([,, msg]) => msg) + const warnings = logs + .filter(([title]) => title === 'warn') + .map(([,, msg]) => msg) + + t.notOk(fs.existsSync(oldFile), 'package-lock is always deleted') + t.same(warnings, [], 'no warnings') + t.teardown(() => delete t.context) + t.context = { + testdir, + config, + shrinkwrap: JSON.parse(fs.readFileSync(newFile)), + logs: notices, } +} - const npmlog = { - notice (title, msg) { - t.equal( - msg, - 'npm-shrinkwrap.json updated to version 2', - 'should log notice msg that file was updated' - ) - }, +// Run shrinkwrap against all combinations of existing and config +// lockfile versions +const shrinkwrapMatrix = async (t, file, assertions) => { + const ancient = JSON.stringify({ lockfileVersion: 1 }) + const existing = JSON.stringify({ lockfileVersion: 2 }) + const upgrade = { lockfileVersion: 3 } + const downgrade = { lockfileVersion: 1 } + + let ancientDir = {} + let existingDir = null + if (file === 'package-lock') { + ancientDir = { 'package-lock.json': ancient } + existingDir = { 'package-lock.json': existing } + } else if (file === 'npm-shrinkwrap') { + ancientDir = { 'npm-shrinkwrap.json': ancient } + existingDir = { 'npm-shrinkwrap.json': existing } + } else if (file === 'hidden-lockfile') { + ancientDir = { node_modules: { '.package-lock.json': ancient } } + existingDir = { node_modules: { '.package-lock.json': existing } } } - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - npmlog, - '@npmcli/arborist': Arborist, + await t.test('ancient', async (t) => { + await shrinkwrap(t, ancientDir) + t.match(t.context, assertions.ancient) + t.matchSnapshot(t.context) }) - const shrinkwrap = new Shrinkwrap(npm) - - shrinkwrap.exec([], err => { - if (err) - throw err + await t.test('ancient upgrade', async (t) => { + await shrinkwrap(t, ancientDir, upgrade) + t.match(t.context, assertions.ancientUpgrade) + t.matchSnapshot(t.context) }) -}) - -t.test('update to date shrinkwrap file', t => { - t.plan(4) - npm.prefix = '/project/a' - - class Arborist { - constructor (args) { - t.same( - args, - { ...flatOptions, path: npm.prefix }, - 'should call arborist constructor with expected args' - ) - } - - async loadVirtual () { - t.ok('should load virtual tree') - return { - ...tree, - meta: { - hiddenLockfile: false, - loadedFromDisk: true, - filename: 'npm-shrinkwrap.json', - originalLockfileVersion: 2, - save () { - t.ok('should save the lockfile') - }, - }, - } - } - } - - const npmlog = { - notice (title, msg) { - t.equal( - msg, - 'npm-shrinkwrap.json up to date', - 'should log notice msg shrinkwrap up to date' - ) - }, + if (existingDir) { + await t.test('existing', async (t) => { + await shrinkwrap(t, existingDir) + t.match(t.context, assertions.existing) + t.matchSnapshot(t.context) + }) + await t.test('existing upgrade', async (t) => { + await shrinkwrap(t, existingDir, upgrade) + t.match(t.context, assertions.existingUpgrade) + t.matchSnapshot(t.context) + }) + await t.test('existing downgrade', async (t) => { + await shrinkwrap(t, existingDir, downgrade) + t.match(t.context, assertions.existingDowngrade) + t.matchSnapshot(t.context) + }) } +} - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - npmlog, - '@npmcli/arborist': Arborist, - }) - const shrinkwrap = new Shrinkwrap(npm) - - shrinkwrap.exec([], err => { - if (err) - throw err - }) -}) +const NOTICES = { + CREATED: (v = '') => + [`created a lockfile as npm-shrinkwrap.json${v && ` with version ${v}`}`], + RENAMED: (v = '') => + [`package-lock.json has been renamed to npm-shrinkwrap.json${v && ` and updated to version ${v}`}`], + UPDATED: (v = '') => + [`npm-shrinkwrap.json updated to version ${v}`], + SAME: () => + [`npm-shrinkwrap.json up to date`], +} -t.test('shrinkwrap --global', t => { - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', mocks) +t.test('with nothing', t => shrinkwrapMatrix(t, null, { + ancient: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.CREATED(2), + }, + ancientUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.CREATED(3), + }, +})) - config.global = true - const shrinkwrap = new Shrinkwrap(npm) +t.test('with package-lock.json', t => shrinkwrapMatrix(t, 'package-lock', { + ancient: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.RENAMED(2), + }, + ancientUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.RENAMED(3), + }, + existing: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.RENAMED(), + }, + existingUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.RENAMED(3), + }, + existingDowngrade: { + shrinkwrap: { lockfileVersion: 1 }, + logs: NOTICES.RENAMED(1), + }, +})) - shrinkwrap.exec([], err => { - t.match( - err, - /does not work for global packages/, - 'should throw no global support msg' - ) - t.equal(err.code, 'ESHRINKWRAPGLOBAL', 'should throw expected error code') - t.end() - }) -}) +t.test('with npm-shrinkwrap.json', t => shrinkwrapMatrix(t, 'npm-shrinkwrap', { + ancient: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.UPDATED(2), + }, + ancientUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.UPDATED(3), + }, + existing: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.SAME(), + }, + existingUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.UPDATED(3), + }, + existingDowngrade: { + shrinkwrap: { lockfileVersion: 1 }, + logs: NOTICES.UPDATED(1), + }, +})) -t.test('works without fs.promises', async t => { - t.doesNotThrow(() => { - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - fs: { ...fs, promises: null }, - }) - new Shrinkwrap(npm) +t.test('with hidden lockfile', t => shrinkwrapMatrix(t, 'hidden-lockfile', { + ancient: { + shrinkwrap: { lockfileVersion: 1 }, + logs: NOTICES.CREATED(), + }, + ancientUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.CREATED(), + }, + existing: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.CREATED(), + }, + existingUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.CREATED(3), + }, + existingDowngrade: { + shrinkwrap: { lockfileVersion: 1 }, + logs: NOTICES.CREATED(1), + }, +})) + +t.test('throws in global mode', async t => { + t.rejects(shrinkwrap(t, {}, { + global: true, + }), { + message: '`npm shrinkwrap` does not work for global packages', + code: 'ESHRINKWRAPGLOBAL', }) })