2021-11-04 20:42:47 +00:00
|
|
|
const t = require('tap')
|
2024-05-30 04:21:05 -07:00
|
|
|
const fs = require('node:fs')
|
|
|
|
const { resolve } = require('node:path')
|
2021-12-02 22:04:46 +00:00
|
|
|
const { load: loadMockNpm } = require('../../fixtures/mock-npm')
|
2021-11-04 20:42:47 +00:00
|
|
|
|
|
|
|
// Attempt to parse json values in snapshots before
|
|
|
|
// stringifying to remove escaped values like \\"
|
|
|
|
// This also doesn't reorder the keys of the object
|
|
|
|
// like tap does by default which is nice in this case
|
2021-11-18 20:58:02 +00:00
|
|
|
t.formatSnapshot = obj =>
|
|
|
|
JSON.stringify(
|
|
|
|
obj,
|
|
|
|
(k, v) => {
|
|
|
|
try {
|
|
|
|
return JSON.parse(v)
|
2022-09-02 05:48:00 -07:00
|
|
|
} catch {
|
|
|
|
// leave invalid JSON as a string
|
|
|
|
}
|
2021-11-18 20:58:02 +00:00
|
|
|
return v
|
|
|
|
},
|
|
|
|
2
|
|
|
|
)
|
2021-11-04 20:42:47 +00:00
|
|
|
|
2022-03-17 20:22:31 +00:00
|
|
|
// Run shrinkwrap against a specified prefixDir with config items
|
2021-11-04 20:42:47 +00:00
|
|
|
// and make some assertions that should always be true. Sets
|
|
|
|
// the results on t.context for use in child tests
|
2024-04-30 23:53:22 -07:00
|
|
|
const shrinkwrap = async (t, prefixDir = {}, config = {}) => {
|
2021-12-02 22:04:46 +00:00
|
|
|
const { npm, logs } = await loadMockNpm(t, {
|
|
|
|
config,
|
2022-03-17 20:22:31 +00:00
|
|
|
prefixDir,
|
2021-12-02 22:04:46 +00:00
|
|
|
})
|
2021-11-04 20:42:47 +00:00
|
|
|
|
|
|
|
await npm.exec('shrinkwrap', [])
|
|
|
|
|
2021-12-02 22:04:46 +00:00
|
|
|
const newFile = resolve(npm.prefix, 'npm-shrinkwrap.json')
|
|
|
|
const oldFile = resolve(npm.prefix, 'package-lock.json')
|
2021-11-04 20:42:47 +00:00
|
|
|
|
|
|
|
t.notOk(fs.existsSync(oldFile), 'package-lock is always deleted')
|
|
|
|
t.teardown(() => delete t.context)
|
|
|
|
t.context = {
|
2022-03-17 20:22:31 +00:00
|
|
|
localPrefix: prefixDir,
|
2021-11-04 20:42:47 +00:00
|
|
|
config,
|
|
|
|
shrinkwrap: JSON.parse(fs.readFileSync(newFile)),
|
2024-04-30 23:53:22 -07:00
|
|
|
logs: logs.notice,
|
|
|
|
warn: logs.warn,
|
2021-11-04 20:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 })
|
2021-12-02 22:04:46 +00:00
|
|
|
const upgrade = { 'lockfile-version': 3 }
|
|
|
|
const downgrade = { 'lockfile-version': 1 }
|
2021-11-04 20:42:47 +00:00
|
|
|
|
|
|
|
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 } }
|
|
|
|
}
|
|
|
|
|
2021-11-18 20:58:02 +00:00
|
|
|
await t.test('ancient', async t => {
|
2021-11-04 20:42:47 +00:00
|
|
|
await shrinkwrap(t, ancientDir)
|
|
|
|
t.match(t.context, assertions.ancient)
|
|
|
|
t.matchSnapshot(t.context)
|
|
|
|
})
|
2021-11-18 20:58:02 +00:00
|
|
|
await t.test('ancient upgrade', async t => {
|
2021-11-04 20:42:47 +00:00
|
|
|
await shrinkwrap(t, ancientDir, upgrade)
|
|
|
|
t.match(t.context, assertions.ancientUpgrade)
|
|
|
|
t.matchSnapshot(t.context)
|
|
|
|
})
|
|
|
|
|
|
|
|
if (existingDir) {
|
2021-11-18 20:58:02 +00:00
|
|
|
await t.test('existing', async t => {
|
2021-11-04 20:42:47 +00:00
|
|
|
await shrinkwrap(t, existingDir)
|
|
|
|
t.match(t.context, assertions.existing)
|
|
|
|
t.matchSnapshot(t.context)
|
|
|
|
})
|
2021-11-18 20:58:02 +00:00
|
|
|
await t.test('existing upgrade', async t => {
|
2021-11-04 20:42:47 +00:00
|
|
|
await shrinkwrap(t, existingDir, upgrade)
|
|
|
|
t.match(t.context, assertions.existingUpgrade)
|
|
|
|
t.matchSnapshot(t.context)
|
|
|
|
})
|
2021-11-18 20:58:02 +00:00
|
|
|
await t.test('existing downgrade', async t => {
|
2021-11-04 20:42:47 +00:00
|
|
|
await shrinkwrap(t, existingDir, downgrade)
|
|
|
|
t.match(t.context, assertions.existingDowngrade)
|
|
|
|
t.matchSnapshot(t.context)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const NOTICES = {
|
2021-11-18 20:58:02 +00:00
|
|
|
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`],
|
2024-04-30 23:53:22 -07:00
|
|
|
CONVERTING: (current, next) =>
|
|
|
|
[`Converting lock file (npm-shrinkwrap.json) from v${current} -> v${next}`],
|
2021-11-04 20:42:47 +00:00
|
|
|
}
|
|
|
|
|
2021-11-18 20:58:02 +00:00
|
|
|
t.test('with nothing', t =>
|
|
|
|
shrinkwrapMatrix(t, null, {
|
|
|
|
ancient: {
|
2022-12-06 22:18:33 -05:00
|
|
|
shrinkwrap: { lockfileVersion: 3 },
|
|
|
|
logs: NOTICES.CREATED(3),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: [],
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
ancientUpgrade: {
|
|
|
|
shrinkwrap: { lockfileVersion: 3 },
|
|
|
|
logs: NOTICES.CREATED(3),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: [],
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
t.test('with package-lock.json', t =>
|
|
|
|
shrinkwrapMatrix(t, 'package-lock', {
|
|
|
|
ancient: {
|
2022-12-06 22:18:33 -05:00
|
|
|
shrinkwrap: { lockfileVersion: 3 },
|
|
|
|
logs: NOTICES.RENAMED(3),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: NOTICES.CONVERTING(1, 3),
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
ancientUpgrade: {
|
|
|
|
shrinkwrap: { lockfileVersion: 3 },
|
|
|
|
logs: NOTICES.RENAMED(3),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: NOTICES.CONVERTING(1, 3),
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
existing: {
|
|
|
|
shrinkwrap: { lockfileVersion: 2 },
|
|
|
|
logs: NOTICES.RENAMED(),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: [],
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
existingUpgrade: {
|
|
|
|
shrinkwrap: { lockfileVersion: 3 },
|
|
|
|
logs: NOTICES.RENAMED(3),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: NOTICES.CONVERTING(2, 3),
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
existingDowngrade: {
|
|
|
|
shrinkwrap: { lockfileVersion: 1 },
|
|
|
|
logs: NOTICES.RENAMED(1),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: NOTICES.CONVERTING(2, 1),
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
t.test('with npm-shrinkwrap.json', t =>
|
|
|
|
shrinkwrapMatrix(t, 'npm-shrinkwrap', {
|
|
|
|
ancient: {
|
2022-12-06 22:18:33 -05:00
|
|
|
shrinkwrap: { lockfileVersion: 3 },
|
|
|
|
logs: NOTICES.UPDATED(3),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: NOTICES.CONVERTING(1, 3),
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
ancientUpgrade: {
|
|
|
|
shrinkwrap: { lockfileVersion: 3 },
|
|
|
|
logs: NOTICES.UPDATED(3),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: NOTICES.CONVERTING(1, 3),
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
existing: {
|
|
|
|
shrinkwrap: { lockfileVersion: 2 },
|
|
|
|
logs: NOTICES.SAME(),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: [],
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
existingUpgrade: {
|
|
|
|
shrinkwrap: { lockfileVersion: 3 },
|
|
|
|
logs: NOTICES.UPDATED(3),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: NOTICES.CONVERTING(2, 3),
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
existingDowngrade: {
|
|
|
|
shrinkwrap: { lockfileVersion: 1 },
|
|
|
|
logs: NOTICES.UPDATED(1),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: NOTICES.CONVERTING(2, 1),
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
t.test('with hidden lockfile', t =>
|
|
|
|
shrinkwrapMatrix(t, 'hidden-lockfile', {
|
|
|
|
ancient: {
|
|
|
|
shrinkwrap: { lockfileVersion: 1 },
|
|
|
|
logs: NOTICES.CREATED(),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: [],
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
ancientUpgrade: {
|
|
|
|
shrinkwrap: { lockfileVersion: 3 },
|
|
|
|
logs: NOTICES.CREATED(),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: NOTICES.CONVERTING(1, 3),
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
existing: {
|
|
|
|
shrinkwrap: { lockfileVersion: 2 },
|
|
|
|
logs: NOTICES.CREATED(),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: [],
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
existingUpgrade: {
|
|
|
|
shrinkwrap: { lockfileVersion: 3 },
|
|
|
|
logs: NOTICES.CREATED(3),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: NOTICES.CONVERTING(2, 3),
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
existingDowngrade: {
|
|
|
|
shrinkwrap: { lockfileVersion: 1 },
|
|
|
|
logs: NOTICES.CREATED(1),
|
2024-04-30 23:53:22 -07:00
|
|
|
warn: NOTICES.CONVERTING(2, 1),
|
2021-11-18 20:58:02 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
)
|
2021-11-04 20:42:47 +00:00
|
|
|
|
|
|
|
t.test('throws in global mode', async t => {
|
2021-11-18 20:58:02 +00:00
|
|
|
t.rejects(
|
|
|
|
shrinkwrap(
|
|
|
|
t,
|
|
|
|
{},
|
|
|
|
{
|
|
|
|
global: true,
|
|
|
|
}
|
|
|
|
),
|
|
|
|
{
|
|
|
|
message: '`npm shrinkwrap` does not work for global packages',
|
|
|
|
code: 'ESHRINKWRAPGLOBAL',
|
|
|
|
}
|
|
|
|
)
|
2021-11-04 20:42:47 +00:00
|
|
|
})
|