1const t = require('tap') 2const fs = require('fs') 3const { resolve } = require('path') 4const _mockNpm = require('../../fixtures/mock-npm') 5 6const mockNpm = async (t, opts = {}) => { 7 const res = await _mockNpm(t, { 8 ...opts, 9 mocks: { 10 ...opts.mocks, 11 '{LIB}/utils/reify-finish.js': async () => {}, 12 }, 13 }) 14 15 return { 16 ...res, 17 uninstall: (args) => res.npm.exec('uninstall', args), 18 } 19} 20 21t.test('remove single installed lib', async t => { 22 const { uninstall, prefix } = await mockNpm(t, { 23 prefixDir: { 24 'package.json': JSON.stringify({ 25 name: 'test-rm-single-lib', 26 version: '1.0.0', 27 dependencies: { 28 a: '*', 29 b: '*', 30 }, 31 }), 32 node_modules: { 33 a: { 34 'package.json': JSON.stringify({ 35 name: 'a', 36 version: '1.0.0', 37 }), 38 }, 39 b: { 40 'package.json': JSON.stringify({ 41 name: 'b', 42 version: '1.0.0', 43 }), 44 }, 45 }, 46 'package-lock.json': JSON.stringify({ 47 name: 'test-rm-single-lib', 48 version: '1.0.0', 49 lockfileVersion: 2, 50 requires: true, 51 packages: { 52 '': { 53 name: 'test-rm-single-lib', 54 version: '1.0.0', 55 dependencies: { 56 a: '*', 57 }, 58 }, 59 'node_modules/a': { 60 version: '1.0.0', 61 }, 62 'node_modules/b': { 63 version: '1.0.0', 64 }, 65 }, 66 dependencies: { 67 a: { 68 version: '1.0.0', 69 }, 70 b: { 71 version: '1.0.0', 72 }, 73 }, 74 }), 75 }, 76 }) 77 78 const b = resolve(prefix, 'node_modules/b') 79 t.ok(fs.statSync(b)) 80 81 await uninstall(['b']) 82 83 t.throws(() => fs.statSync(b), 'should have removed package from npm') 84}) 85 86t.test('remove multiple installed libs', async t => { 87 const { uninstall, prefix } = await mockNpm(t, { 88 prefixDir: { 89 node_modules: { 90 a: { 91 'package.json': JSON.stringify({ 92 name: 'a', 93 version: '1.0.0', 94 }), 95 }, 96 b: { 97 'package.json': JSON.stringify({ 98 name: 'b', 99 version: '1.0.0', 100 }), 101 }, 102 }, 103 'package-lock.json': JSON.stringify({ 104 name: 'test-rm-single-lib', 105 version: '1.0.0', 106 lockfileVersion: 2, 107 requires: true, 108 packages: { 109 '': { 110 name: 'test-rm-single-lib', 111 version: '1.0.0', 112 dependencies: { 113 a: '*', 114 }, 115 }, 116 'node_modules/a': { 117 version: '1.0.0', 118 }, 119 'node_modules/b': { 120 version: '1.0.0', 121 }, 122 }, 123 dependencies: { 124 a: { 125 version: '1.0.0', 126 }, 127 b: { 128 version: '1.0.0', 129 }, 130 }, 131 }), 132 }, 133 }) 134 135 const a = resolve(prefix, 'node_modules/a') 136 const b = resolve(prefix, 'node_modules/b') 137 t.ok(fs.statSync(a)) 138 t.ok(fs.statSync(b)) 139 140 await uninstall(['b']) 141 142 t.throws(() => fs.statSync(a), 'should have removed a package from nm') 143 t.throws(() => fs.statSync(b), 'should have removed b package from nm') 144}) 145 146t.test('no args local', async t => { 147 const { uninstall } = await mockNpm(t) 148 149 await t.rejects( 150 uninstall([]), 151 /Must provide a package name to remove/, 152 'should throw package name required error' 153 ) 154}) 155 156t.test('no args global', async t => { 157 const { uninstall, npm } = await mockNpm(t, { 158 prefixDir: { 159 'package.json': JSON.stringify({ 160 name: 'a', 161 version: '1.0.0', 162 }), 163 }, 164 globalPrefixDir: { 165 node_modules: { 166 a: t.fixture('symlink', '../../prefix'), 167 }, 168 }, 169 config: { global: true }, 170 }) 171 172 const a = resolve(npm.globalDir, 'a') 173 t.ok(fs.statSync(a)) 174 175 await uninstall([]) 176 177 t.throws(() => fs.statSync(a), 'should have removed global nm symlink') 178}) 179 180t.test('no args global but no package.json', async t => { 181 const { uninstall } = await mockNpm(t, { 182 config: { global: true }, 183 }) 184 185 await t.rejects( 186 uninstall([]), 187 /npm uninstall/ 188 ) 189}) 190 191t.test('non ENOENT error reading from localPrefix package.json', async t => { 192 const { uninstall } = await mockNpm(t, { 193 config: { global: true }, 194 prefixDir: { 'package.json': 'not[json]' }, 195 }) 196 197 await t.rejects( 198 uninstall([]), 199 { code: 'EJSONPARSE' }, 200 'should throw non ENOENT error' 201 ) 202}) 203