node/deps/npm/test/lib/commands/uninstall.js
npm CLI robot 36bcfa7913
deps: upgrade npm to 11.17.0
PR-URL: https://github.com/nodejs/node/pull/63857
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Jordan Harband <ljharb@gmail.com>
2026-06-13 19:08:33 +00:00

243 lines
5.5 KiB
JavaScript

const t = require('tap')
const fs = require('node:fs')
const { resolve } = require('node:path')
const _mockNpm = require('../../fixtures/mock-npm')
const mockNpm = async (t, opts = {}) => {
const res = await _mockNpm(t, {
...opts,
mocks: {
...opts.mocks,
'{LIB}/utils/reify-finish.js': async () => {},
},
})
return {
...res,
uninstall: (args) => res.npm.exec('uninstall', args),
}
}
t.test('remove single installed lib', async t => {
const { uninstall, prefix } = await mockNpm(t, {
prefixDir: {
'package.json': JSON.stringify({
name: 'test-rm-single-lib',
version: '1.0.0',
dependencies: {
a: '*',
b: '*',
},
}),
node_modules: {
a: {
'package.json': JSON.stringify({
name: 'a',
version: '1.0.0',
}),
},
b: {
'package.json': JSON.stringify({
name: 'b',
version: '1.0.0',
}),
},
},
'package-lock.json': JSON.stringify({
name: 'test-rm-single-lib',
version: '1.0.0',
lockfileVersion: 2,
requires: true,
packages: {
'': {
name: 'test-rm-single-lib',
version: '1.0.0',
dependencies: {
a: '*',
},
},
'node_modules/a': {
version: '1.0.0',
},
'node_modules/b': {
version: '1.0.0',
},
},
dependencies: {
a: {
version: '1.0.0',
},
b: {
version: '1.0.0',
},
},
}),
},
})
const b = resolve(prefix, 'node_modules/b')
t.ok(fs.statSync(b))
await uninstall(['b'])
t.throws(() => fs.statSync(b), 'should have removed package from npm')
})
t.test('remove multiple installed libs', async t => {
const { uninstall, prefix } = await mockNpm(t, {
prefixDir: {
node_modules: {
a: {
'package.json': JSON.stringify({
name: 'a',
version: '1.0.0',
}),
},
b: {
'package.json': JSON.stringify({
name: 'b',
version: '1.0.0',
}),
},
},
'package-lock.json': JSON.stringify({
name: 'test-rm-single-lib',
version: '1.0.0',
lockfileVersion: 2,
requires: true,
packages: {
'': {
name: 'test-rm-single-lib',
version: '1.0.0',
dependencies: {
a: '*',
},
},
'node_modules/a': {
version: '1.0.0',
},
'node_modules/b': {
version: '1.0.0',
},
},
dependencies: {
a: {
version: '1.0.0',
},
b: {
version: '1.0.0',
},
},
}),
},
})
const a = resolve(prefix, 'node_modules/a')
const b = resolve(prefix, 'node_modules/b')
t.ok(fs.statSync(a))
t.ok(fs.statSync(b))
await uninstall(['b'])
t.throws(() => fs.statSync(a), 'should have removed a package from nm')
t.throws(() => fs.statSync(b), 'should have removed b package from nm')
})
t.test('no args local', async t => {
const { uninstall } = await mockNpm(t)
await t.rejects(
uninstall([]),
/Must provide a package name to remove/,
'should throw package name required error'
)
})
t.test('no args global', async t => {
const { uninstall, npm } = await mockNpm(t, {
prefixDir: {
'package.json': JSON.stringify({
name: 'a',
version: '1.0.0',
}),
},
globalPrefixDir: {
node_modules: {
a: t.fixture('symlink', '../../prefix'),
},
},
config: { global: true },
})
const a = resolve(npm.globalDir, 'a')
t.ok(fs.statSync(a))
await uninstall([])
t.throws(() => fs.statSync(a), 'should have removed global nm symlink')
})
t.test('no args global but no package.json', async t => {
const { uninstall } = await mockNpm(t, {
config: { global: true },
})
await t.rejects(
uninstall([]),
/npm uninstall/
)
})
t.test('non ENOENT error reading from localPrefix package.json', async t => {
const { uninstall } = await mockNpm(t, {
config: { global: true },
prefixDir: { 'package.json': 'not[json]' },
})
await t.rejects(
uninstall([]),
{ code: 'EJSONPARSE' },
'should throw non ENOENT error'
)
})
t.test('completion', async t => {
const { uninstall } = await _mockNpm(t, {
command: 'uninstall',
prefixDir: {
node_modules: {
foo: {},
bar: {},
},
},
})
const res = await uninstall.completion({ conf: { argv: { remain: ['npm', 'uninstall'] } } })
t.match(res, ['bar', 'foo'])
})
t.test('uninstall threads allowScripts policy through to arborist', async t => {
let capturedOpts
const FakeArborist = function (opts) {
capturedOpts = opts
this.options = opts
this.actualTree = { inventory: new Map() }
}
FakeArborist.prototype.reify = async () => {}
const { npm } = await _mockNpm(t, {
prefixDir: {
'package.json': JSON.stringify({
name: 'host',
version: '1.0.0',
allowScripts: { canvas: true },
}),
},
mocks: {
'@npmcli/arborist': FakeArborist,
'{LIB}/utils/reify-finish.js': async () => {},
},
})
await npm.exec('uninstall', ['canvas'])
t.strictSame(capturedOpts.allowScripts, { canvas: true },
'opts.allowScripts populated from package.json')
})