mirror of
https://github.com/nodejs/node.git
synced 2025-08-16 22:28:51 +02:00

PR-URL: https://github.com/nodejs/node/pull/53207 Reviewed-By: Richard Lau <rlau@redhat.com> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com> Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
1044 lines
25 KiB
JavaScript
1044 lines
25 KiB
JavaScript
const t = require('tap')
|
|
const { join, extname } = require('node:path')
|
|
const MockRegistry = require('@npmcli/mock-registry')
|
|
const { load: loadMockNpm } = require('../../fixtures/mock-npm')
|
|
|
|
const jsonifyTestdir = (obj) => {
|
|
for (const [key, value] of Object.entries(obj || {})) {
|
|
if (extname(key) === '.json') {
|
|
obj[key] = JSON.stringify(value, null, 2) + '\n'
|
|
} else if (typeof value === 'object') {
|
|
obj[key] = jsonifyTestdir(value)
|
|
} else {
|
|
obj[key] = value.trim() + '\n'
|
|
}
|
|
}
|
|
return obj
|
|
}
|
|
|
|
// generic helper to call diff with a specified dir contents and registry calls
|
|
const mockDiff = async (t, {
|
|
exec,
|
|
diff = [],
|
|
tarballs = {},
|
|
times = {},
|
|
...opts
|
|
} = {}) => {
|
|
const tarballFixtures = Object.entries(tarballs).reduce((acc, [spec, fixture]) => {
|
|
const lastAt = spec.lastIndexOf('@')
|
|
const name = spec.slice(0, lastAt)
|
|
const version = spec.slice(lastAt + 1)
|
|
acc[name] = acc[name] || {}
|
|
acc[name][version] = fixture
|
|
if (!acc[name][version]['package.json']) {
|
|
acc[name][version]['package.json'] = { name, version }
|
|
} else {
|
|
acc[name][version]['package.json'].name = name
|
|
acc[name][version]['package.json'].version = version
|
|
}
|
|
return acc
|
|
}, {})
|
|
|
|
const { prefixDir, globalPrefixDir, otherDirs, config, ...rest } = opts
|
|
const { npm, ...res } = await loadMockNpm(t, {
|
|
command: 'diff',
|
|
prefixDir: jsonifyTestdir(prefixDir),
|
|
otherDirs: jsonifyTestdir({ tarballs: tarballFixtures, ...otherDirs }),
|
|
globalPrefixDir: jsonifyTestdir(globalPrefixDir),
|
|
config: {
|
|
...config,
|
|
diff: [].concat(diff),
|
|
},
|
|
...rest,
|
|
})
|
|
|
|
const registry = new MockRegistry({
|
|
tap: t,
|
|
registry: npm.config.get('registry'),
|
|
strict: true,
|
|
debug: true,
|
|
})
|
|
|
|
const manifests = Object.entries(tarballFixtures).reduce((acc, [name, versions]) => {
|
|
acc[name] = registry.manifest({
|
|
name,
|
|
packuments: Object.keys(versions).map((version) => ({ version })),
|
|
})
|
|
return acc
|
|
}, {})
|
|
|
|
for (const [name, manifest] of Object.entries(manifests)) {
|
|
await registry.package({ manifest, times: times[name] ?? 1 })
|
|
for (const [version, tarballManifest] of Object.entries(manifest.versions)) {
|
|
await registry.tarball({
|
|
manifest: tarballManifest,
|
|
tarball: join(res.other, 'tarballs', name, version),
|
|
})
|
|
}
|
|
}
|
|
|
|
if (exec) {
|
|
await res.diff.exec(exec)
|
|
res.output = res.joinedOutput()
|
|
}
|
|
|
|
return { npm, registry, ...res }
|
|
}
|
|
|
|
// a more specific helper to call diff against a local package and a registry package
|
|
// and assert the diff output contains the matching strings
|
|
const assertFoo = async (t, arg) => {
|
|
let diff = []
|
|
let exec = []
|
|
|
|
if (typeof arg === 'string' || Array.isArray(arg)) {
|
|
diff = arg
|
|
} else if (arg && typeof arg === 'object') {
|
|
diff = arg.diff
|
|
exec = arg.exec
|
|
}
|
|
|
|
const { output } = await mockDiff(t, {
|
|
diff,
|
|
prefixDir: {
|
|
'package.json': { name: '@npmcli/foo', version: '1.0.0' },
|
|
'index.js': 'const version = "1.0.0"',
|
|
'a.js': 'const a = "a@1.0.0"',
|
|
'b.js': 'const b = "b@1.0.0"',
|
|
},
|
|
tarballs: {
|
|
'@npmcli/foo@0.1.0': {
|
|
'index.js': 'const version = "0.1.0"',
|
|
'a.js': 'const a = "a@0.1.0"',
|
|
'b.js': 'const b = "b@0.1.0"',
|
|
},
|
|
},
|
|
exec,
|
|
})
|
|
|
|
const hasFile = (f) => !exec.length || exec.some(e => e.endsWith(f))
|
|
|
|
if (hasFile('package.json')) {
|
|
t.match(output, /-\s*"version": "0\.1\.0"/)
|
|
t.match(output, /\+\s*"version": "1\.0\.0"/)
|
|
}
|
|
|
|
if (hasFile('index.js')) {
|
|
t.match(output, /-\s*const version = "0\.1\.0"/)
|
|
t.match(output, /\+\s*const version = "1\.0\.0"/)
|
|
}
|
|
|
|
if (hasFile('a.js')) {
|
|
t.match(output, /-\s*const a = "a@0\.1\.0"/)
|
|
t.match(output, /\+\s*const a = "a@1\.0\.0"/)
|
|
}
|
|
|
|
if (hasFile('b.js')) {
|
|
t.match(output, /-\s*const b = "b@0\.1\.0"/)
|
|
t.match(output, /\+\s*const b = "b@1\.0\.0"/)
|
|
}
|
|
|
|
return output
|
|
}
|
|
|
|
const rejectDiff = async (t, msg, opts) => {
|
|
const { npm } = await mockDiff(t, opts)
|
|
await t.rejects(npm.exec('diff', []), msg)
|
|
}
|
|
|
|
t.test('no args', async t => {
|
|
t.test('in a project dir', async t => {
|
|
const output = await assertFoo(t)
|
|
t.matchSnapshot(output)
|
|
})
|
|
|
|
t.test('no args, missing package.json name in cwd', async t => {
|
|
await rejectDiff(t, /Needs multiple arguments to compare or run from a project dir./)
|
|
})
|
|
|
|
t.test('no args, bad package.json in cwd', async t => {
|
|
await rejectDiff(t, /Needs multiple arguments to compare or run from a project dir./, {
|
|
prefixDir: { 'package.json': '{invalid"json' },
|
|
})
|
|
})
|
|
})
|
|
|
|
t.test('single arg', async t => {
|
|
t.test('spec using cwd package name', async t => {
|
|
await assertFoo(t, '@npmcli/foo@0.1.0')
|
|
})
|
|
|
|
t.test('unknown spec, no package.json', async t => {
|
|
await rejectDiff(t, /Needs multiple arguments to compare or run from a project dir./, {
|
|
diff: ['@npmcli/foo@1.0.0'],
|
|
})
|
|
})
|
|
|
|
t.test('spec using semver range', async t => {
|
|
await assertFoo(t, '@npmcli/foo@~0.1.0')
|
|
})
|
|
|
|
t.test('version', async t => {
|
|
await assertFoo(t, '0.1.0')
|
|
})
|
|
|
|
t.test('version, no package.json', async t => {
|
|
await rejectDiff(t, /Needs multiple arguments to compare or run from a project dir./, {
|
|
diff: ['0.1.0'],
|
|
})
|
|
})
|
|
|
|
t.test('version, filtering by files', async t => {
|
|
const output = await assertFoo(t, { diff: '0.1.0', exec: ['./a.js', './b.js'] })
|
|
t.matchSnapshot(output)
|
|
})
|
|
|
|
t.test('spec is not a dep', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
diff: 'bar@1.0.0',
|
|
prefixDir: {
|
|
node_modules: {},
|
|
'package.json': { name: 'my-project', version: '1.0.0' },
|
|
},
|
|
tarballs: {
|
|
'bar@1.0.0': {},
|
|
},
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, /-\s*"name": "bar"/)
|
|
t.match(output, /\+\s*"name": "my-project"/)
|
|
})
|
|
|
|
t.test('unknown package name', async t => {
|
|
const { npm, registry } = await mockDiff(t, {
|
|
diff: 'bar',
|
|
prefixDir: {
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
},
|
|
},
|
|
})
|
|
registry.getPackage('bar', { times: 2, code: 404 })
|
|
t.rejects(npm.exec('diff', []), /404 Not Found.*bar/)
|
|
})
|
|
|
|
t.test('unknown package name, no package.json', async t => {
|
|
const { npm } = await mockDiff(t, {
|
|
diff: 'bar',
|
|
})
|
|
t.rejects(npm.exec('diff', []),
|
|
/Needs multiple arguments to compare or run from a project dir./)
|
|
})
|
|
|
|
t.test('transform single direct dep name into spec comparison', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
diff: 'bar',
|
|
prefixDir: {
|
|
node_modules: {
|
|
bar: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
},
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
},
|
|
},
|
|
tarballs: {
|
|
'bar@1.8.0': {},
|
|
},
|
|
times: { bar: 2 },
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "1\.8\.0"/)
|
|
})
|
|
|
|
t.test('global space, transform single direct dep name', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
diff: 'lorem',
|
|
config: {
|
|
global: true,
|
|
},
|
|
globalPrefixDir: {
|
|
node_modules: {
|
|
lorem: {
|
|
'package.json': {
|
|
name: 'lorem',
|
|
version: '2.0.0',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
prefixDir: {
|
|
node_modules: {
|
|
lorem: {
|
|
'package.json': {
|
|
name: 'lorem',
|
|
version: '3.0.0',
|
|
},
|
|
},
|
|
},
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
lorem: '^3.0.0',
|
|
},
|
|
},
|
|
},
|
|
tarballs: {
|
|
'lorem@1.0.0': {},
|
|
},
|
|
times: {
|
|
lorem: 2,
|
|
},
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'lorem')
|
|
t.match(output, /-\s*"version": "2\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "1\.0\.0"/)
|
|
})
|
|
|
|
t.test('transform single spec into spec comparison', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
diff: 'bar@2.0.0',
|
|
prefixDir: {
|
|
node_modules: {
|
|
bar: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
},
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
},
|
|
},
|
|
tarballs: {
|
|
'bar@2.0.0': {},
|
|
},
|
|
times: {
|
|
lorem: 2,
|
|
},
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
|
|
t.test('transform single spec from transitive deps', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
diff: 'lorem',
|
|
prefixDir: {
|
|
node_modules: {
|
|
bar: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
lorem: '^2.0.0',
|
|
},
|
|
},
|
|
},
|
|
lorem: {
|
|
'package.json': {
|
|
name: 'lorem',
|
|
version: '2.0.0',
|
|
},
|
|
},
|
|
},
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
},
|
|
},
|
|
tarballs: {
|
|
'lorem@2.2.2': {},
|
|
},
|
|
times: {
|
|
lorem: 2,
|
|
},
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'lorem')
|
|
t.match(output, /-\s*"version": "2\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.2\.2"/)
|
|
})
|
|
|
|
t.test('missing actual tree', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
diff: 'lorem',
|
|
prefixDir: {
|
|
'package.json': {
|
|
name: 'lorem',
|
|
version: '2.0.0',
|
|
},
|
|
},
|
|
mocks: {
|
|
'@npmcli/arborist': class {
|
|
constructor () {
|
|
throw new Error('ERR')
|
|
}
|
|
},
|
|
},
|
|
tarballs: {
|
|
'lorem@2.2.2': {},
|
|
},
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'lorem')
|
|
t.match(output, /-\s*"version": "2\.2\.2"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
|
|
t.test('unknown package name', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
diff: 'bar',
|
|
prefixDir: {
|
|
'package.json': { version: '1.0.0' },
|
|
},
|
|
|
|
tarballs: {
|
|
'bar@2.2.2': {},
|
|
},
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "2\.2\.2"/)
|
|
t.match(output, /\+\s*"version": "1\.0\.0"/)
|
|
})
|
|
|
|
t.test('use project name in project dir', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
diff: '@npmcli/foo',
|
|
prefixDir: {
|
|
'package.json': { name: '@npmcli/foo', version: '1.0.0' },
|
|
},
|
|
tarballs: {
|
|
'@npmcli/foo@2.2.2': {},
|
|
},
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, '@npmcli/foo')
|
|
t.match(output, /-\s*"version": "2\.2\.2"/)
|
|
t.match(output, /\+\s*"version": "1\.0\.0"/)
|
|
})
|
|
|
|
t.test('dir spec type', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
diff: '../other/other-pkg',
|
|
prefixDir: {
|
|
'package.json': { name: '@npmcli/foo', version: '1.0.0' },
|
|
},
|
|
otherDirs: {
|
|
'other-pkg': {
|
|
'package.json': { name: '@npmcli/foo', version: '2.0.0' },
|
|
},
|
|
},
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, '@npmcli/foo')
|
|
t.match(output, /-\s*"version": "2\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "1\.0\.0"/)
|
|
})
|
|
|
|
t.test('unsupported spec type', async t => {
|
|
const p = mockDiff(t, {
|
|
diff: 'git+https://github.com/user/foo',
|
|
exec: [],
|
|
})
|
|
|
|
await t.rejects(
|
|
p,
|
|
/Spec type git not supported./,
|
|
'should throw spec type not supported error.'
|
|
)
|
|
})
|
|
})
|
|
|
|
t.test('first arg is a qualified spec', async t => {
|
|
t.test('second arg is ALSO a qualified spec', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
diff: ['bar@1.0.0', 'bar@^2.0.0'],
|
|
tarballs: {
|
|
'bar@1.0.0': {},
|
|
'bar@2.2.2': {},
|
|
},
|
|
times: {
|
|
bar: 2,
|
|
},
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.2\.2"/)
|
|
})
|
|
|
|
t.test('second arg is a known dependency name', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
prefixDir: {
|
|
node_modules: {
|
|
bar: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
},
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
},
|
|
},
|
|
tarballs: {
|
|
'bar@2.0.0': {},
|
|
},
|
|
diff: ['bar@2.0.0', 'bar'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "2\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "1\.0\.0"/)
|
|
})
|
|
|
|
t.test('second arg is a valid semver version', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
tarballs: {
|
|
'bar@1.0.0': {},
|
|
'bar@2.0.0': {},
|
|
},
|
|
times: {
|
|
bar: 2,
|
|
},
|
|
diff: ['bar@1.0.0', '2.0.0'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
|
|
t.test('second arg is an unknown dependency name', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
tarballs: {
|
|
'bar@1.0.0': {},
|
|
'bar-fork@2.0.0': {},
|
|
},
|
|
diff: ['bar@1.0.0', 'bar-fork'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, /-\s*"name": "bar"/)
|
|
t.match(output, /\+\s*"name": "bar-fork"/)
|
|
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
})
|
|
|
|
t.test('first arg is a known dependency name', async t => {
|
|
t.test('second arg is a qualified spec', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
prefixDir: {
|
|
node_modules: {
|
|
bar: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
},
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
},
|
|
},
|
|
tarballs: {
|
|
'bar@2.0.0': {},
|
|
},
|
|
diff: ['bar', 'bar@2.0.0'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
|
|
t.test('second arg is ALSO a known dependency', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
prefixDir: {
|
|
node_modules: {
|
|
bar: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
'bar-fork': {
|
|
'package.json': {
|
|
name: 'bar-fork',
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
},
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
},
|
|
},
|
|
diff: ['bar', 'bar-fork'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, /-\s*"name": "bar"/)
|
|
t.match(output, /\+\s*"name": "bar-fork"/)
|
|
})
|
|
|
|
t.test('second arg is a valid semver version', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
prefixDir: {
|
|
node_modules: {
|
|
bar: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
},
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
},
|
|
},
|
|
tarballs: {
|
|
'bar@2.0.0': {},
|
|
},
|
|
diff: ['bar', '2.0.0'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
|
|
t.test('second arg is an unknown dependency name', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
prefixDir: {
|
|
node_modules: {
|
|
bar: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
},
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
},
|
|
},
|
|
tarballs: {
|
|
'bar-fork@1.0.0': {},
|
|
},
|
|
diff: ['bar', 'bar-fork'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, /-\s*"name": "bar"/)
|
|
t.match(output, /\+\s*"name": "bar-fork"/)
|
|
})
|
|
})
|
|
|
|
t.test('first arg is a valid semver range', async t => {
|
|
t.test('second arg is a qualified spec', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
tarballs: {
|
|
'bar@1.0.0': {},
|
|
'bar@2.0.0': {},
|
|
},
|
|
diff: ['1.0.0', 'bar@2.0.0'],
|
|
times: { bar: 2 },
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
|
|
t.test('second arg is a known dependency', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
prefixDir: {
|
|
node_modules: {
|
|
bar: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
version: '2.0.0',
|
|
},
|
|
},
|
|
},
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
},
|
|
},
|
|
tarballs: {
|
|
'bar@1.0.0': {},
|
|
},
|
|
diff: ['1.0.0', 'bar'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
|
|
t.test('second arg is ALSO a semver version', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
prefixDir: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
},
|
|
},
|
|
tarballs: {
|
|
'bar@1.0.0': {},
|
|
'bar@2.0.0': {},
|
|
},
|
|
diff: ['1.0.0', '2.0.0'],
|
|
times: { bar: 2 },
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
|
|
t.test('second arg is ALSO a semver version BUT cwd not a project dir', async t => {
|
|
const p = mockDiff(t, {
|
|
diff: ['1.0.0', '2.0.0'],
|
|
exec: [],
|
|
})
|
|
await t.rejects(
|
|
p,
|
|
/Needs to be run from a project dir in order to diff two versions./,
|
|
'should throw two versions need project dir error usage msg'
|
|
)
|
|
})
|
|
|
|
t.test('second arg is an unknown dependency name', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
prefixDir: {
|
|
prefixDir: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
},
|
|
},
|
|
},
|
|
tarballs: {
|
|
'bar@1.0.0': {},
|
|
'bar@2.0.0': {},
|
|
},
|
|
diff: ['1.0.0', 'bar'],
|
|
times: { bar: 2 },
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
|
|
t.test('second arg is a qualified spec, missing actual tree', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
prefixDir: {
|
|
'package.json': {
|
|
name: 'lorem',
|
|
version: '2.0.0',
|
|
},
|
|
},
|
|
mocks: {
|
|
'@npmcli/arborist': class {
|
|
constructor () {
|
|
throw new Error('ERR')
|
|
}
|
|
},
|
|
},
|
|
tarballs: {
|
|
'lorem@1.0.0': {},
|
|
'lorem@2.0.0': {},
|
|
},
|
|
times: { lorem: 2 },
|
|
diff: ['1.0.0', 'lorem@2.0.0'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'lorem')
|
|
t.match(output, /-\s*"version": "1\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
})
|
|
|
|
t.test('first arg is an unknown dependency name', async t => {
|
|
t.test('second arg is a qualified spec', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
tarballs: {
|
|
'bar@2.0.0': {},
|
|
'bar@3.0.0': {},
|
|
},
|
|
times: { bar: 2 },
|
|
diff: ['bar', 'bar@2.0.0'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "3\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "2\.0\.0"/)
|
|
})
|
|
|
|
t.test('second arg is a known dependency', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
prefixDir: {
|
|
node_modules: {
|
|
bar: {
|
|
'package.json': {
|
|
name: 'bar',
|
|
version: '2.0.0',
|
|
},
|
|
},
|
|
},
|
|
'package.json': {
|
|
name: 'my-project',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
},
|
|
},
|
|
tarballs: {
|
|
'bar-fork@2.0.0': {},
|
|
},
|
|
diff: ['bar-fork', 'bar'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, /-\s*"name": "bar-fork"/)
|
|
t.match(output, /\+\s*"name": "bar"/)
|
|
})
|
|
|
|
t.test('second arg is a valid semver version', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
tarballs: {
|
|
'bar@1.5.0': {},
|
|
'bar@2.0.0': {},
|
|
},
|
|
times: { bar: 2 },
|
|
diff: ['bar', '^1.0.0'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, 'bar')
|
|
t.match(output, /-\s*"version": "2\.0\.0"/)
|
|
t.match(output, /\+\s*"version": "1\.5\.0"/)
|
|
})
|
|
|
|
t.test('second arg is ALSO an unknown dependency name', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
prefixDir: {
|
|
'package.json': {
|
|
name: 'my-project',
|
|
},
|
|
},
|
|
tarballs: {
|
|
'bar@1.0.0': {},
|
|
'bar-fork@1.0.0': {},
|
|
},
|
|
diff: ['bar', 'bar-fork'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, /-\s*"name": "bar"/)
|
|
t.match(output, /\+\s*"name": "bar-fork"/)
|
|
})
|
|
|
|
t.test('cwd not a project dir', async t => {
|
|
const { output } = await mockDiff(t, {
|
|
tarballs: {
|
|
'bar@1.0.0': {},
|
|
'bar-fork@1.0.0': {},
|
|
},
|
|
diff: ['bar', 'bar-fork'],
|
|
exec: [],
|
|
})
|
|
|
|
t.match(output, /-\s*"name": "bar"/)
|
|
t.match(output, /\+\s*"name": "bar-fork"/)
|
|
})
|
|
})
|
|
|
|
t.test('various options', async t => {
|
|
const mockOptions = async (t, config) => {
|
|
const file = (v) => new Array(50).fill(0).map((_, i) => `${i}${i === 20 ? v : ''}`).join('\n')
|
|
const mock = await mockDiff(t, {
|
|
diff: ['bar@2.0.0', 'bar@3.0.0'],
|
|
config,
|
|
exec: [],
|
|
tarballs: {
|
|
'bar@2.0.0': { 'index.js': file('2.0.0') },
|
|
'bar@3.0.0': { 'index.js': file('3.0.0') },
|
|
},
|
|
times: { bar: 2 },
|
|
})
|
|
|
|
return mock
|
|
}
|
|
|
|
t.test('using --name-only option', async t => {
|
|
const { output } = await mockOptions(t, {
|
|
'diff-name-only': true,
|
|
})
|
|
t.matchSnapshot(output)
|
|
})
|
|
|
|
t.test('using diff option', async t => {
|
|
const { output } = await mockOptions(t, {
|
|
'diff-context': 5,
|
|
'diff-ignore-whitespace': true,
|
|
'diff-no-prefix': false,
|
|
'diff-drc-prefix': 'foo/',
|
|
'diff-fst-prefix': 'bar/',
|
|
'diff-text': true,
|
|
|
|
})
|
|
t.matchSnapshot(output)
|
|
})
|
|
})
|
|
|
|
t.test('too many args', async t => {
|
|
const { npm } = await mockDiff(t, {
|
|
diff: ['a', 'b', 'c'],
|
|
})
|
|
|
|
await t.rejects(
|
|
npm.exec('diff', []),
|
|
/Can't use more than two --diff arguments./,
|
|
'should throw usage error'
|
|
)
|
|
})
|
|
|
|
t.test('workspaces', async t => {
|
|
const mockWorkspaces = (t, workspaces = true, opts) => mockDiff(t, {
|
|
prefixDir: {
|
|
'package.json': {
|
|
name: 'workspaces-test',
|
|
version: '1.2.3',
|
|
workspaces: ['workspace-a', 'workspace-b', 'workspace-c'],
|
|
},
|
|
'workspace-a': {
|
|
'package.json': {
|
|
name: 'workspace-a',
|
|
version: '1.2.3-a',
|
|
},
|
|
},
|
|
'workspace-b': {
|
|
'package.json': {
|
|
name: 'workspace-b',
|
|
version: '1.2.3-b',
|
|
},
|
|
},
|
|
'workspace-c': {
|
|
'package.json': {
|
|
name: 'workspace-c',
|
|
version: '1.2.3-c',
|
|
},
|
|
},
|
|
},
|
|
exec: [],
|
|
config: workspaces === true ? { workspaces } : { workspace: workspaces },
|
|
...opts,
|
|
})
|
|
|
|
t.test('all workspaces', async t => {
|
|
const { output } = await mockWorkspaces(t, true, {
|
|
tarballs: {
|
|
'workspace-a@2.0.0-a': {},
|
|
'workspace-b@2.0.0-b': {},
|
|
'workspace-c@2.0.0-c': {},
|
|
},
|
|
})
|
|
|
|
t.match(output, '"name": "workspace-a"')
|
|
t.match(output, /-\s*"version": "2\.0\.0-a"/)
|
|
t.match(output, /\+\s*"version": "1\.2\.3-a"/)
|
|
|
|
t.match(output, '"name": "workspace-b"')
|
|
t.match(output, /-\s*"version": "2\.0\.0-b"/)
|
|
t.match(output, /\+\s*"version": "1\.2\.3-b"/)
|
|
|
|
t.match(output, '"name": "workspace-c"')
|
|
t.match(output, /-\s*"version": "2\.0\.0-c"/)
|
|
t.match(output, /\+\s*"version": "1\.2\.3-c"/)
|
|
})
|
|
|
|
t.test('one workspace', async t => {
|
|
const { output } = await mockWorkspaces(t, 'workspace-a', {
|
|
tarballs: {
|
|
'workspace-a@2.0.0-a': {},
|
|
},
|
|
})
|
|
|
|
t.match(output, '"name": "workspace-a"')
|
|
t.match(output, /-\s*"version": "2\.0\.0-a"/)
|
|
t.match(output, /\+\s*"version": "1\.2\.3-a"/)
|
|
|
|
t.notMatch(output, '"name": "workspace-b"')
|
|
t.notMatch(output, '"name": "workspace-c"')
|
|
})
|
|
|
|
t.test('invalid workspace', async t => {
|
|
const p = mockWorkspaces(t, 'workspace-x')
|
|
await t.rejects(p, /No workspaces found/)
|
|
await t.rejects(p, /workspace-x/)
|
|
})
|
|
})
|