|
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