1const t = require('tap') 2const fs = require('fs/promises') 3const path = require('path') 4const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') 5const MockRegistry = require('@npmcli/mock-registry') 6 7t.test('call with args', async t => { 8 const { npm } = await loadMockNpm(t, { 9 config: { 10 call: 'foo', 11 }, 12 }) 13 14 await t.rejects( 15 npm.exec('exec', ['bar']), 16 { code: 'EUSAGE' } 17 ) 18}) 19 20t.test('registry package', async t => { 21 const registry = new MockRegistry({ 22 tap: t, 23 registry: 'https://registry.npmjs.org/', 24 }) 25 26 const manifest = registry.manifest({ name: '@npmcli/npx-test' }) 27 manifest.versions['1.0.0'].bin = { 'npx-test': 'index.js' } 28 29 const { npm } = await loadMockNpm(t, { 30 config: { 31 audit: false, 32 yes: true, 33 }, 34 prefixDir: { 35 'npm-exec-test': { 36 'package.json': JSON.stringify(manifest), 37 'index.js': `#!/usr/bin/env node 38 require('fs').writeFileSync('npm-exec-test-success', '')`, 39 }, 40 }, 41 }) 42 43 await registry.package({ 44 times: 2, 45 manifest, 46 tarballs: { 47 '1.0.0': path.join(npm.prefix, 'npm-exec-test'), 48 } }) 49 50 await npm.exec('exec', ['@npmcli/npx-test']) 51 const exists = await fs.stat(path.join(npm.prefix, 'npm-exec-test-success')) 52 t.ok(exists.isFile(), 'bin ran, creating file') 53}) 54 55t.test('--prefix', async t => { 56 const registry = new MockRegistry({ 57 tap: t, 58 registry: 'https://registry.npmjs.org/', 59 }) 60 61 const manifest = registry.manifest({ name: '@npmcli/npx-test' }) 62 manifest.versions['1.0.0'].bin = { 'npx-test': 'index.js' } 63 64 const { npm } = await loadMockNpm(t, { 65 config: { 66 audit: false, 67 yes: true, 68 }, 69 prefixDir: { 70 'npm-exec-test': { 71 'package.json': JSON.stringify(manifest), 72 'index.js': `#!/usr/bin/env node 73 require('fs').writeFileSync('npm-exec-test-success', '')`, 74 }, 75 }, 76 }) 77 78 // This is what `--prefix` does 79 npm.globalPrefix = npm.localPrefix 80 81 await registry.package({ 82 manifest, 83 tarballs: { 84 '1.0.0': path.join(npm.prefix, 'npm-exec-test'), 85 } }) 86 87 await npm.exec('exec', ['@npmcli/npx-test']) 88 const exists = await fs.stat(path.join(npm.prefix, 'npm-exec-test-success')) 89 t.ok(exists.isFile(), 'bin ran, creating file') 90}) 91 92t.test('runs in workspace path', async t => { 93 const registry = new MockRegistry({ 94 tap: t, 95 registry: 'https://registry.npmjs.org/', 96 }) 97 98 const manifest = registry.manifest({ name: '@npmcli/npx-test' }) 99 manifest.versions['1.0.0'].bin = { 'npx-test': 'index.js' } 100 101 const { npm } = await loadMockNpm(t, { 102 config: { 103 audit: false, 104 yes: true, 105 workspace: ['workspace-a'], 106 }, 107 prefixDir: { 108 'npm-exec-test': { 109 'package.json': JSON.stringify(manifest), 110 'index.js': `#!/usr/bin/env node 111 require('fs').writeFileSync('npm-exec-test-success', '')`, 112 }, 113 'package.json': JSON.stringify({ 114 name: '@npmcli/npx-workspace-test', 115 workspaces: ['workspace-a'], 116 }), 117 'workspace-a': { 118 'package.json': JSON.stringify({ 119 name: 'workspace-a', 120 }), 121 }, 122 }, 123 }) 124 125 await registry.package({ manifest, 126 tarballs: { 127 '1.0.0': path.join(npm.prefix, 'npm-exec-test'), 128 }, 129 }) 130 await npm.exec('exec', ['@npmcli/npx-test']) 131 const exists = await fs.stat(path.join(npm.prefix, 'workspace-a', 'npm-exec-test-success')) 132 t.ok(exists.isFile(), 'bin ran, creating file inside workspace') 133}) 134 135t.test('finds workspace bin first', async t => { 136 const { npm } = await loadMockNpm(t, { 137 config: { 138 workspace: ['workspace-a'], 139 }, 140 prefixDir: { 141 'package.json': JSON.stringify({ 142 name: '@npmcli/npx-workspace-root-test', 143 bin: { 'npx-test': 'index.js' }, 144 workspaces: ['workspace-a'], 145 }), 146 'index.js': `#!/usr/bin/env node 147 require('fs').writeFileSync('npm-exec-test-fail', '')`, 148 'workspace-a': { 149 'package.json': JSON.stringify({ 150 name: '@npmcli/npx-workspace-test', 151 bin: { 'npx-test': 'index.js' }, 152 }), 153 'index.js': `#!/usr/bin/env node 154 require('fs').writeFileSync('npm-exec-test-success', '')`, 155 }, 156 }, 157 }) 158 159 await npm.exec('install', []) // reify 160 await npm.exec('exec', ['npx-test']) 161 const exists = await fs.stat(path.join(npm.prefix, 'workspace-a', 'npm-exec-test-success')) 162 t.ok(exists.isFile(), 'bin ran, creating file inside workspace') 163 t.rejects(fs.stat(path.join(npm.prefix, 'npm-exec-test-fail'))) 164}) 165 166t.test('finds workspace dep first', async t => { 167 const registry = new MockRegistry({ 168 tap: t, 169 registry: 'https://registry.npmjs.org/', 170 }) 171 172 const manifest = registry.manifest({ name: '@npmcli/subdep', versions: ['1.0.0', '2.0.0'] }) 173 manifest.versions['1.0.0'].bin = { 'npx-test': 'index.js' } 174 manifest.versions['2.0.0'].bin = { 'npx-test': 'index.js' } 175 176 const { npm } = await loadMockNpm(t, { 177 prefixDir: { 178 subdep: { 179 one: { 180 'package.json': JSON.stringify(manifest.versions['1.0.0']), 181 'index.js': `#!/usr/bin/env node 182 require('fs').writeFileSync('npm-exec-test-one', '')`, 183 }, 184 two: { 185 'package.json': JSON.stringify(manifest.versions['2.0.0']), 186 'index.js': `#!/usr/bin/env node 187 require('fs').writeFileSync('npm-exec-test-two', '')`, 188 }, 189 }, 190 'package.json': JSON.stringify({ 191 name: '@npmcli/npx-workspace-root-test', 192 dependencies: { '@npmcli/subdep': '1.0.0' }, 193 bin: { 'npx-test': 'index.js' }, 194 workspaces: ['workspace-a'], 195 }), 196 'index.js': `#!/usr/bin/env node 197 require('fs').writeFileSync('npm-exec-test-fail', '')`, 198 'workspace-a': { 199 'package.json': JSON.stringify({ 200 name: '@npmcli/npx-workspace-test', 201 dependencies: { '@npmcli/subdep': '2.0.0' }, 202 bin: { 'npx-test': 'index.js' }, 203 }), 204 'index.js': `#!/usr/bin/env node 205 require('fs').writeFileSync('npm-exec-test-success', '')`, 206 }, 207 }, 208 }) 209 210 await registry.package({ manifest, 211 tarballs: { 212 '1.0.0': path.join(npm.prefix, 'subdep', 'one'), 213 '2.0.0': path.join(npm.prefix, 'subdep', 'two'), 214 }, 215 }) 216 await npm.exec('install', []) 217 npm.config.set('workspace', ['workspace-a']) 218 await npm.exec('exec', ['npx-test']) 219 const exists = await fs.stat(path.join(npm.prefix, 'workspace-a', 'npm-exec-test-success')) 220 t.ok(exists.isFile(), 'bin ran, creating file') 221}) 222 223t.test('npx --no-install @npmcli/npx-test', async t => { 224 const registry = new MockRegistry({ 225 tap: t, 226 registry: 'https://registry.npmjs.org/', 227 }) 228 229 const manifest = registry.manifest({ name: '@npmcli/npx-test' }) 230 manifest.versions['1.0.0'].bin = { 'npx-test': 'index.js' } 231 232 const { npm } = await loadMockNpm(t, { 233 config: { 234 audit: false, 235 yes: false, 236 }, 237 prefixDir: { 238 'npm-exec-test': { 239 'package.json': JSON.stringify(manifest), 240 'index.js': `#!/usr/bin/env node 241 require('fs').writeFileSync('npm-exec-test-success', '')`, 242 }, 243 }, 244 }) 245 246 try { 247 await npm.exec('exec', ['@npmcli/npx-test']) 248 t.fail('Expected error was not thrown') 249 } catch (error) { 250 t.match( 251 error.message, 252 'npx canceled due to missing packages and no YES option: ', 253 'Expected error message thrown' 254 ) 255 } 256}) 257