1const t = require('tap') 2const path = require('path') 3const tspawk = require('../../fixtures/tspawk') 4const { load: loadMockNpm } = require('../../fixtures/mock-npm') 5 6const spawk = tspawk(t) 7 8const npmConfig = { 9 config: { 10 'ignore-scripts': false, 11 editor: 'testeditor', 12 'script-shell': process.platform === 'win32' ? process.env.COMSPEC : 'sh', 13 }, 14 prefixDir: { 15 node_modules: { 16 semver: { 17 'package.json': JSON.stringify({ 18 scripts: { 19 install: 'testinstall', 20 }, 21 }), 22 node_modules: { 23 abbrev: {}, 24 }, 25 }, 26 '@npmcli': { 27 'scoped-package': {}, 28 }, 29 }, 30 }, 31} 32 33const isCmdRe = /(?:^|\\)cmd(?:\.exe)?$/i 34 35t.test('npm edit', async t => { 36 const { npm, joinedOutput } = await loadMockNpm(t, npmConfig) 37 38 const semverPath = path.resolve(npm.prefix, 'node_modules', 'semver') 39 spawk.spawn('testeditor', [semverPath]) 40 41 const scriptShell = npm.config.get('script-shell') 42 const scriptArgs = isCmdRe.test(scriptShell) 43 ? ['/d', '/s', '/c', 'testinstall'] 44 : ['-c', 'testinstall'] 45 spawk.spawn(scriptShell, scriptArgs, { cwd: semverPath }) 46 47 await npm.exec('edit', ['semver']) 48 t.match(joinedOutput(), 'rebuilt dependencies successfully') 49}) 50 51t.test('rebuild failure', async t => { 52 const { npm } = await loadMockNpm(t, npmConfig) 53 54 const semverPath = path.resolve(npm.prefix, 'node_modules', 'semver') 55 spawk.spawn('testeditor', [semverPath]) 56 57 const scriptShell = npm.config.get('script-shell') 58 const scriptArgs = isCmdRe.test(scriptShell) 59 ? ['/d', '/s', '/c', 'testinstall'] 60 : ['-c', 'testinstall'] 61 spawk.spawn(scriptShell, scriptArgs, { cwd: semverPath }).exit(1).stdout('test error') 62 await t.rejects( 63 npm.exec('edit', ['semver']), 64 { message: 'command failed' } 65 ) 66}) 67 68t.test('editor failure', async t => { 69 const { npm } = await loadMockNpm(t, npmConfig) 70 71 const semverPath = path.resolve(npm.prefix, 'node_modules', 'semver') 72 spawk.spawn('testeditor', [semverPath]).exit(1).stdout('test editor failure') 73 74 await t.rejects( 75 npm.exec('edit', ['semver']), 76 { message: 'editor process exited with code: 1' } 77 ) 78}) 79 80t.test('npm edit editor has flags', async t => { 81 const { npm } = await loadMockNpm(t, { 82 ...npmConfig, 83 config: { 84 ...npmConfig.config, 85 editor: 'testeditor --flag', 86 }, 87 }) 88 89 const semverPath = path.resolve(npm.prefix, 'node_modules', 'semver') 90 spawk.spawn('testeditor', ['--flag', semverPath]) 91 92 const scriptShell = npm.config.get('script-shell') 93 const scriptArgs = isCmdRe.test(scriptShell) 94 ? ['/d', '/s', '/c', 'testinstall'] 95 : ['-c', 'testinstall'] 96 spawk.spawn(scriptShell, scriptArgs, { cwd: semverPath }) 97 98 await npm.exec('edit', ['semver']) 99}) 100 101t.test('npm edit no args', async t => { 102 const { npm } = await loadMockNpm(t) 103 await t.rejects( 104 npm.exec('edit', []), 105 { code: 'EUSAGE' }, 106 'throws usage error' 107 ) 108}) 109 110t.test('npm edit nonexistent package', async t => { 111 const { npm } = await loadMockNpm(t, npmConfig) 112 113 await t.rejects( 114 npm.exec('edit', ['abbrev']), 115 /lstat/ 116 ) 117}) 118 119t.test('scoped package', async t => { 120 const { npm } = await loadMockNpm(t, npmConfig) 121 const scopedPath = path.resolve(npm.prefix, 'node_modules', '@npmcli', 'scoped-package') 122 spawk.spawn('testeditor', [scopedPath]) 123 await npm.exec('edit', ['@npmcli/scoped-package']) 124}) 125 126t.test('subdependency', async t => { 127 const { npm } = await loadMockNpm(t, npmConfig) 128 const subdepPath = path.resolve(npm.prefix, 'node_modules', 'semver', 'node_modules', 'abbrev') 129 spawk.spawn('testeditor', [subdepPath]) 130 await npm.exec('edit', ['semver/abbrev']) 131}) 132