Skip to content

test: add lib/uninstall.js tests #2269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions lib/uninstall.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
// remove a package.
'use strict'

const { resolve } = require('path')
const Arborist = require('@npmcli/arborist')
const npm = require('./npm.js')
const rpj = require('read-package-json-fast')
const { resolve } = require('path')

const npm = require('./npm.js')
const usageUtil = require('./utils/usage.js')
const reifyFinish = require('./utils/reify-finish.js')
const completion = require('./utils/completion/installed-shallow.js')

const usage = usageUtil(
'uninstall',
'npm uninstall [<@scope>/]<pkg>[@<version>]... [--save-prod|--save-dev|--save-optional] [--no-save]'
)

const cmd = (args, cb) => rm(args).then(() => cb()).catch(cb)

Expand All @@ -16,12 +23,19 @@ const rm = async args => {

if (!args.length) {
if (!global)
throw new Error('must provide a package name to remove')
throw new Error('Must provide a package name to remove')
else {
const pkg = await rpj(resolve(npm.localPrefix, 'package.json'))
.catch(er => {
throw er.code !== 'ENOENT' && er.code !== 'ENOTDIR' ? er : usage()
})
let pkg

try {
pkg = await rpj(resolve(npm.localPrefix, 'package.json'))
} catch (er) {
if (er.code !== 'ENOENT' && er.code !== 'ENOTDIR')
throw er
else
throw usage
}

args.push(pkg.name)
}
}
Expand All @@ -35,11 +49,4 @@ const rm = async args => {
await reifyFinish(arb)
}

const usage = usageUtil(
'uninstall',
'npm uninstall [<@scope>/]<pkg>[@<version>]... [--save-prod|--save-dev|--save-optional] [--no-save]'
)

const completion = require('./utils/completion/installed-shallow.js')

module.exports = Object.assign(cmd, { usage, completion })
253 changes: 253 additions & 0 deletions test/lib/uninstall.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
const fs = require('fs')
const { resolve } = require('path')
const t = require('tap')
const requireInject = require('require-inject')

const npm = {
globalDir: '',
flatOptions: {
global: false,
prefix: '',
},
localPrefix: '',
}
const mocks = {
'../../lib/npm.js': npm,
'../../lib/utils/reify-finish.js': () => Promise.resolve(),
'../../lib/utils/usage.js': () => 'usage instructions',
}

const uninstall = requireInject('../../lib/uninstall.js', mocks)

t.afterEach(cb => {
npm.globalDir = ''
npm.prefix = ''
npm.flatOptions.global = false
npm.flatOptions.prefix = ''
cb()
})

t.test('remove single installed lib', t => {
const path = t.testdir({
'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(path, 'node_modules/b')
t.ok(() => fs.statSync(b))

npm.flatOptions.prefix = path

uninstall(['b'], err => {
if (err)
throw err

t.throws(() => fs.statSync(b), 'should have removed package from nm')
t.end()
})
})

t.test('remove multiple installed libs', t => {
const path = t.testdir({
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(path, 'node_modules/a')
const b = resolve(path, 'node_modules/b')
t.ok(() => fs.statSync(a))
t.ok(() => fs.statSync(b))

npm.flatOptions.prefix = path

uninstall(['b'], err => {
if (err)
throw err

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.end()
})
})

t.test('no args local', t => {
const path = t.testdir()

npm.flatOptions.prefix = path

uninstall([], err => {
t.match(
err,
/Must provide a package name to remove/,
'should throw package name required error'
)

t.end()
})
})

t.test('no args global', t => {
const path = t.testdir({
lib: {
node_modules: {
a: t.fixture('symlink', '../../projects/a'),
},
},
projects: {
a: {
'package.json': JSON.stringify({
name: 'a',
version: '1.0.0',
}),
},
},
})

npm.localPrefix = resolve(path, 'projects', 'a')
npm.globalDir = resolve(path, 'lib', 'node_modules')
npm.flatOptions.global = true
npm.flatOptions.prefix = path

const a = resolve(path, 'lib/node_modules/a')
t.ok(() => fs.statSync(a))

uninstall([], err => {
if (err)
throw err

t.throws(() => fs.statSync(a), 'should have removed global nm symlink')

t.end()
})
})

t.test('no args global but no package.json', t => {
const path = t.testdir({})

npm.prefix = path
npm.localPrefix = path
npm.flatOptions.global = true

uninstall([], err => {
t.match(
err,
'usage instructions',
'should throw usage instructions'
)

t.end()
})
})

t.test('unknown error reading from localPrefix package.json', t => {
const path = t.testdir({})

const uninstall = requireInject('../../lib/uninstall.js', {
...mocks,
'read-package-json-fast': () => Promise.reject(new Error('ERR')),
})

npm.prefix = path
npm.localPrefix = path
npm.flatOptions.global = true

uninstall([], err => {
t.match(
err,
/ERR/,
'should throw unknown error'
)

t.end()
})
})