|
1 | 1 | const t = require('tap')
|
2 |
| - |
3 |
| -if (process.platform !== 'win32') { |
4 |
| - t.plan(0, 'test only relevant on windows') |
5 |
| - process.exit(0) |
6 |
| -} |
7 |
| - |
8 |
| -const has = path => { |
9 |
| - try { |
10 |
| - // If WSL is installed, it *has* a bash.exe, but it fails if |
11 |
| - // there is no distro installed, so we need to detect that. |
12 |
| - const result = spawnSync(path, ['-l', '-c', 'exit 0']) |
13 |
| - if (result.status === 0) { |
14 |
| - return true |
15 |
| - } else { |
16 |
| - // print whatever error we got |
17 |
| - throw result.error || Object.assign(new Error(String(result.stderr)), { |
18 |
| - code: result.status, |
19 |
| - }) |
20 |
| - } |
21 |
| - } catch (er) { |
22 |
| - t.comment(`not installed: ${path}`, er) |
23 |
| - return false |
24 |
| - } |
25 |
| -} |
26 |
| - |
27 |
| -const { version } = require('../../package.json') |
28 | 2 | const spawn = require('@npmcli/promise-spawn')
|
29 | 3 | const { spawnSync } = require('child_process')
|
30 | 4 | const { resolve } = require('path')
|
31 |
| -const { ProgramFiles, SystemRoot } = process.env |
32 | 5 | const { readFileSync, chmodSync } = require('fs')
|
33 |
| -const gitBash = resolve(ProgramFiles, 'Git', 'bin', 'bash.exe') |
34 |
| -const gitUsrBinBash = resolve(ProgramFiles, 'Git', 'usr', 'bin', 'bash.exe') |
35 |
| -const wslBash = resolve(SystemRoot, 'System32', 'bash.exe') |
36 |
| -const cygwinBash = resolve(SystemRoot, '/', 'cygwin64', 'bin', 'bash.exe') |
37 |
| - |
38 |
| -const bashes = Object.entries({ |
39 |
| - 'wsl bash': wslBash, |
40 |
| - 'git bash': gitBash, |
41 |
| - 'git internal bash': gitUsrBinBash, |
42 |
| - 'cygwin bash': cygwinBash, |
43 |
| -}) |
| 6 | +const Diff = require('diff') |
| 7 | +const { version } = require('../../package.json') |
44 | 8 |
|
45 | 9 | const npmShim = resolve(__dirname, '../../bin/npm')
|
46 | 10 | const npxShim = resolve(__dirname, '../../bin/npx')
|
47 | 11 |
|
48 |
| -const path = t.testdir({ |
49 |
| - 'node.exe': readFileSync(process.execPath), |
50 |
| - npm: readFileSync(npmShim), |
51 |
| - npx: readFileSync(npxShim), |
52 |
| - // simulate the state where one version of npm is installed |
53 |
| - // with node, but we should load the globally installed one |
54 |
| - 'global-prefix': { |
55 |
| - node_modules: { |
56 |
| - npm: t.fixture('symlink', resolve(__dirname, '../..')), |
| 12 | +t.test('npm vs npx', t => { |
| 13 | + // these scripts should be kept in sync so this tests the contents of each |
| 14 | + // and does a diff to ensure the only differences between them are necessary |
| 15 | + const diffFiles = (ext = '') => Diff.diffChars( |
| 16 | + readFileSync(`${npmShim}${ext}`, 'utf8'), |
| 17 | + readFileSync(`${npxShim}${ext}`, 'utf8') |
| 18 | + ).filter(v => v.added || v.removed).map((v, i) => i === 0 ? v.value : v.value.toUpperCase()) |
| 19 | + |
| 20 | + t.test('bash', t => { |
| 21 | + const [npxCli, ...changes] = diffFiles() |
| 22 | + const npxCliLine = npxCli.split('\n').reverse().join('') |
| 23 | + t.match(npxCliLine, /^NPX_CLI_JS=/, 'has NPX_CLI') |
| 24 | + t.equal(changes.length, 20) |
| 25 | + t.strictSame([...new Set(changes)], ['M', 'X'], 'all other changes are m->x') |
| 26 | + t.end() |
| 27 | + }) |
| 28 | + |
| 29 | + t.test('cmd', t => { |
| 30 | + const [npxCli, ...changes] = diffFiles('.cmd') |
| 31 | + t.match(npxCli, /^SET "NPX_CLI_JS=/, 'has NPX_CLI') |
| 32 | + t.equal(changes.length, 12) |
| 33 | + t.strictSame([...new Set(changes)], ['M', 'X'], 'all other changes are m->x') |
| 34 | + t.end() |
| 35 | + }) |
| 36 | + |
| 37 | + t.end() |
| 38 | +}) |
| 39 | + |
| 40 | +t.test('basic', async t => { |
| 41 | + if (process.platform !== 'win32') { |
| 42 | + t.plan(0, 'test only relevant on windows') |
| 43 | + return |
| 44 | + } |
| 45 | + |
| 46 | + const has = path => { |
| 47 | + try { |
| 48 | + // If WSL is installed, it *has* a bash.exe, but it fails if |
| 49 | + // there is no distro installed, so we need to detect that. |
| 50 | + const result = spawnSync(path, ['-l', '-c', 'exit 0']) |
| 51 | + if (result.status === 0) { |
| 52 | + return true |
| 53 | + } else { |
| 54 | + // print whatever error we got |
| 55 | + throw result.error || Object.assign(new Error(String(result.stderr)), { |
| 56 | + code: result.status, |
| 57 | + }) |
| 58 | + } |
| 59 | + } catch (er) { |
| 60 | + t.comment(`not installed: ${path}`, er) |
| 61 | + return false |
| 62 | + } |
| 63 | + } |
| 64 | + |
| 65 | + const { ProgramFiles, SystemRoot } = process.env |
| 66 | + const gitBash = resolve(ProgramFiles, 'Git', 'bin', 'bash.exe') |
| 67 | + const gitUsrBinBash = resolve(ProgramFiles, 'Git', 'usr', 'bin', 'bash.exe') |
| 68 | + const wslBash = resolve(SystemRoot, 'System32', 'bash.exe') |
| 69 | + const cygwinBash = resolve(SystemRoot, '/', 'cygwin64', 'bin', 'bash.exe') |
| 70 | + |
| 71 | + const bashes = Object.entries({ |
| 72 | + 'wsl bash': wslBash, |
| 73 | + 'git bash': gitBash, |
| 74 | + 'git internal bash': gitUsrBinBash, |
| 75 | + 'cygwin bash': cygwinBash, |
| 76 | + }) |
| 77 | + |
| 78 | + const path = t.testdir({ |
| 79 | + 'node.exe': readFileSync(process.execPath), |
| 80 | + npm: readFileSync(npmShim), |
| 81 | + npx: readFileSync(npxShim), |
| 82 | + // simulate the state where one version of npm is installed |
| 83 | + // with node, but we should load the globally installed one |
| 84 | + 'global-prefix': { |
| 85 | + node_modules: { |
| 86 | + npm: t.fixture('symlink', resolve(__dirname, '../..')), |
| 87 | + }, |
57 | 88 | },
|
58 |
| - }, |
59 |
| - // put in a shim that ONLY prints the intended global prefix, |
60 |
| - // and should not be used for anything else. |
61 |
| - node_modules: { |
62 |
| - npm: { |
63 |
| - bin: { |
64 |
| - 'npx-cli.js': ` |
| 89 | + // put in a shim that ONLY prints the intended global prefix, |
| 90 | + // and should not be used for anything else. |
| 91 | + node_modules: { |
| 92 | + npm: { |
| 93 | + bin: { |
| 94 | + 'npx-cli.js': ` |
65 | 95 | throw new Error('this should not be called')
|
66 | 96 | `,
|
67 |
| - 'npm-cli.js': ` |
| 97 | + 'npm-cli.js': ` |
68 | 98 | const assert = require('assert')
|
69 | 99 | const args = process.argv.slice(2)
|
70 | 100 | assert.equal(args[0], 'prefix')
|
71 | 101 | assert.equal(args[1], '-g')
|
72 | 102 | const { resolve } = require('path')
|
73 | 103 | console.log(resolve(__dirname, '../../../global-prefix'))
|
74 | 104 | `,
|
| 105 | + }, |
75 | 106 | },
|
76 | 107 | },
|
77 |
| - }, |
78 |
| -}) |
79 |
| -chmodSync(resolve(path, 'npm'), 0o755) |
80 |
| -chmodSync(resolve(path, 'npx'), 0o755) |
| 108 | + }) |
| 109 | + chmodSync(resolve(path, 'npm'), 0o755) |
| 110 | + chmodSync(resolve(path, 'npx'), 0o755) |
81 | 111 |
|
82 |
| -for (const [name, bash] of bashes) { |
83 |
| - if (!has(bash)) { |
84 |
| - t.skip(`${name} not installed`, { bin: bash, diagnostic: true }) |
85 |
| - continue |
86 |
| - } |
| 112 | + for (const [name, bash] of bashes) { |
| 113 | + if (!has(bash)) { |
| 114 | + t.skip(`${name} not installed`, { bin: bash, diagnostic: true }) |
| 115 | + continue |
| 116 | + } |
87 | 117 |
|
88 |
| - if (bash === cygwinBash && process.env.NYC_CONFIG) { |
89 |
| - t.skip('Cygwin does not play nicely with NYC, run without coverage') |
90 |
| - continue |
91 |
| - } |
| 118 | + if (bash === cygwinBash && process.env.NYC_CONFIG) { |
| 119 | + t.skip('Cygwin does not play nicely with NYC, run without coverage') |
| 120 | + continue |
| 121 | + } |
92 | 122 |
|
93 |
| - t.test(name, async t => { |
94 |
| - t.plan(2) |
95 |
| - t.test('npm', async t => { |
| 123 | + await t.test(name, async t => { |
| 124 | + t.plan(2) |
| 125 | + t.test('npm', async t => { |
96 | 126 | // only cygwin *requires* the -l, but the others are ok with it
|
97 | 127 | // don't hit the registry for the update check
|
98 |
| - const args = ['-l', 'npm', 'help'] |
| 128 | + const args = ['-l', 'npm', 'help'] |
99 | 129 |
|
100 |
| - const result = await spawn(bash, args, { |
101 |
| - env: { PATH: path, npm_config_update_notifier: 'false' }, |
102 |
| - cwd: path, |
| 130 | + const result = await spawn(bash, args, { |
| 131 | + env: { PATH: path, npm_config_update_notifier: 'false' }, |
| 132 | + cwd: path, |
| 133 | + }) |
| 134 | + t.match(result, { |
| 135 | + cmd: bash, |
| 136 | + args: ['-l', 'npm', 'help'], |
| 137 | + code: 0, |
| 138 | + signal: null, |
| 139 | + stderr: String, |
| 140 | + // should have loaded this instance of npm we symlinked in |
| 141 | + stdout: `npm@${version} ${resolve(__dirname, '../..')}`, |
| 142 | + }) |
103 | 143 | })
|
104 |
| - t.match(result, { |
105 |
| - cmd: bash, |
106 |
| - args: ['-l', 'npm', 'help'], |
107 |
| - code: 0, |
108 |
| - signal: null, |
109 |
| - stderr: String, |
110 |
| - // should have loaded this instance of npm we symlinked in |
111 |
| - stdout: `npm@${version} ${resolve(__dirname, '../..')}`, |
112 |
| - }) |
113 |
| - }) |
114 | 144 |
|
115 |
| - t.test('npx', async t => { |
116 |
| - const args = ['-l', 'npx', '--version'] |
| 145 | + t.test('npx', async t => { |
| 146 | + const args = ['-l', 'npx', '--version'] |
117 | 147 |
|
118 |
| - const result = await spawn(bash, args, { |
119 |
| - env: { PATH: path, npm_config_update_notifier: 'false' }, |
120 |
| - cwd: path, |
121 |
| - }) |
122 |
| - t.match(result, { |
123 |
| - cmd: bash, |
124 |
| - args: ['-l', 'npx', '--version'], |
125 |
| - code: 0, |
126 |
| - signal: null, |
127 |
| - stderr: String, |
128 |
| - // should have loaded this instance of npm we symlinked in |
129 |
| - stdout: version, |
| 148 | + const result = await spawn(bash, args, { |
| 149 | + env: { PATH: path, npm_config_update_notifier: 'false' }, |
| 150 | + cwd: path, |
| 151 | + }) |
| 152 | + t.match(result, { |
| 153 | + cmd: bash, |
| 154 | + args: ['-l', 'npx', '--version'], |
| 155 | + code: 0, |
| 156 | + signal: null, |
| 157 | + stderr: String, |
| 158 | + // should have loaded this instance of npm we symlinked in |
| 159 | + stdout: version, |
| 160 | + }) |
130 | 161 | })
|
131 | 162 | })
|
132 |
| - }) |
133 |
| -} |
| 163 | + } |
| 164 | +}) |
0 commit comments