Skip to content

Commit 2116362

Browse files
committed
test: remove use of global npm installs
1 parent b79b0f0 commit 2116362

File tree

12 files changed

+1990
-163
lines changed

12 files changed

+1990
-163
lines changed

.circleci/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ workflows:
343343
- setup
344344
- e2e-cli:
345345
name: e2e-cli
346-
nodeversion: '14.15'
346+
nodeversion: '14.17'
347347
post-steps:
348348
- store_artifacts:
349349
path: /tmp/dist

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
"minimatch": "5.0.1",
172172
"ng-packagr": "14.0.0-rc.0",
173173
"node-fetch": "^2.2.0",
174+
"npm": "6.14.15",
174175
"npm-package-arg": "9.0.2",
175176
"open": "8.4.0",
176177
"ora": "5.4.1",
@@ -219,6 +220,7 @@
219220
"webpack-subresource-integrity": "5.1.0",
220221
"yargs": "17.5.1",
221222
"yargs-parser": "21.0.1",
223+
"yarn": "^1.22.18",
222224
"zone.js": "^0.11.3"
223225
}
224226
}

tests/legacy-cli/e2e/setup/100-global-cli.ts

-18
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { delimiter, join } from 'path';
2+
import { getGlobalVariable } from '../utils/env';
3+
import { npm } from '../utils/process';
4+
5+
// Tested packages required on the $PATH
6+
const TESTED_BIN_PACKAGES = ['@angular/cli', '@angular-devkit/schematics-cli'];
7+
8+
export default async function () {
9+
const testRegistry: string = getGlobalVariable('package-registry');
10+
11+
// Install the packages being tested
12+
await npm('install', `--registry=${testRegistry}`, ...TESTED_BIN_PACKAGES);
13+
14+
// Ensure the npm .bin for the packages is first on the PATH
15+
process.env.PATH = join(process.cwd(), 'node_modules', '.bin') + delimiter + process.env.PATH;
16+
}

tests/legacy-cli/e2e/tests/misc/npm-7.ts

+28-28
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import * as assert from 'assert';
22
import { execSync } from 'child_process';
33
import { valid as validSemVer } from 'semver';
4+
import { delimiter, join } from 'path';
5+
import * as semver from 'semver';
46
import { rimraf } from '../../utils/fs';
57
import { getActivePackageManager } from '../../utils/packages';
6-
import { ng, npm } from '../../utils/process';
8+
import { exec, execAndWaitForOutputToMatch, ng, npm } from '../../utils/process';
79
import { isPrereleaseCli } from '../../utils/project';
8-
import { expectToFail } from '../../utils/utils';
910

10-
const warningText = 'npm version 7.5.6 or higher is recommended';
11+
const warningTextRe = /npm version 7\.5\.6 or higher is recommended/;
1112

1213
export default async function () {
1314
// Only relevant with npm as a package manager
@@ -44,61 +45,60 @@ export default async function () {
4445
extraArgs.push('--next');
4546
}
4647

48+
// Add the npmModuleDir to the PATH so the test-installed npm is used
49+
process.env.PATH = join(currentDirectory, 'node_modules', '.bin') + delimiter + process.env.PATH;
50+
4751
try {
48-
// Install version >=7.5.6
49-
await npm('install', '--global', 'npm@>=7.5.6');
52+
// Install and verify npm version >=7.5.6
53+
await npm('install', 'npm@>=7.5.6');
54+
const { stdout: npm75Version } = await exec('npm', '--version');
55+
if (!semver.gte(npm75Version, '7.5.6')) {
56+
throw new Error('npm install >=7.5.6 failed');
57+
}
5058

5159
// Ensure `ng update` does not show npm warning
5260
const { stderr: stderrUpdate1 } = await ng('update', ...extraArgs);
53-
if (stderrUpdate1.includes(warningText)) {
61+
if (stderrUpdate1.match(warningTextRe)) {
5462
throw new Error('ng update expected to not show npm version warning.');
5563
}
5664

57-
// Install version <7.5.6
58-
await npm('install', '--global', '[email protected]');
65+
// Install and verify npm version <7.5.6
66+
await npm('install', '[email protected]');
67+
const { stdout: npm74Version } = await exec('npm', '--version');
68+
if (!semver.eq(npm74Version, '7.4.0')) {
69+
throw new Error('npm install =7.4.0 failed');
70+
}
5971

6072
// Ensure `ng add` shows npm warning
61-
const { stderr: stderrAdd } = await ng('add', '@angular/localize');
62-
if (!stderrAdd.includes(warningText)) {
63-
throw new Error('ng add expected to show npm version warning.');
64-
}
73+
await execAndWaitForOutputToMatch('ng', ['add', '@angular/localize'], warningTextRe);
6574

6675
// Ensure `ng update` shows npm warning
67-
const { stderr: stderrUpdate2 } = await ng('update', ...extraArgs);
68-
if (!stderrUpdate2.includes(warningText)) {
69-
throw new Error('ng update expected to show npm version warning.');
70-
}
76+
await execAndWaitForOutputToMatch('ng', ['update', ...extraArgs], warningTextRe);
7177

7278
// Ensure `ng build` executes successfully
7379
const { stderr: stderrBuild } = await ng('build', '--configuration=development');
74-
if (stderrBuild.includes(warningText)) {
80+
if (stderrBuild.match(warningTextRe)) {
7581
throw new Error('ng build expected to not show npm version warning.');
7682
}
7783

7884
// Ensure `ng new` shows npm warning
7985
// Must be outside the project for `ng new`
8086
process.chdir('..');
81-
const { message: stderrNew } = await expectToFail(() => ng('new'));
82-
if (!stderrNew.includes(warningText)) {
83-
throw new Error('ng new expected to show npm version warning.');
84-
}
87+
await execAndWaitForOutputToMatch('ng', ['new'], warningTextRe);
8588

8689
// Ensure `ng new --package-manager=npm` shows npm warning
87-
const { message: stderrNewNpm } = await expectToFail(() => ng('new', '--package-manager=npm'));
88-
if (!stderrNewNpm.includes(warningText)) {
89-
throw new Error('ng new expected to show npm version warning.');
90-
}
90+
await execAndWaitForOutputToMatch('ng', ['new', '--package-manager=npm'], warningTextRe);
9191

9292
// Ensure `ng new --skip-install` executes successfully
9393
const { stderr: stderrNewSkipInstall } = await ng('new', 'npm-seven-skip', '--skip-install');
94-
if (stderrNewSkipInstall.includes(warningText)) {
94+
if (stderrNewSkipInstall.match(warningTextRe)) {
9595
throw new Error('ng new --skip-install expected to not show npm version warning.');
9696
}
9797

9898
// Ensure `ng new --package-manager=yarn` executes successfully
9999
// Need an additional npmrc file since yarn does not use the NPM registry environment variable
100100
const { stderr: stderrNewYarn } = await ng('new', 'npm-seven-yarn', '--package-manager=yarn');
101-
if (stderrNewYarn.includes(warningText)) {
101+
if (stderrNewYarn.match(warningTextRe)) {
102102
throw new Error('ng new --package-manager=yarn expected to not show npm version warning.');
103103
}
104104
} finally {
@@ -110,6 +110,6 @@ export default async function () {
110110
process.chdir(currentDirectory);
111111

112112
// Reset version back to initial version
113-
await npm('install', '--global', `npm@${initialVersion}`);
113+
await npm('install', `npm@${initialVersion}`);
114114
}
115115
}

tests/legacy-cli/e2e/tests/schematics_cli/basic.ts

+1-11
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
11
import * as path from 'path';
2-
import { getGlobalVariable } from '../../utils/env';
3-
import { exec, execAndWaitForOutputToMatch, silentNpm } from '../../utils/process';
2+
import { exec, execAndWaitForOutputToMatch } from '../../utils/process';
43
import { rimraf } from '../../utils/fs';
54

65
export default async function () {
7-
// setup
8-
const argv = getGlobalVariable('argv');
9-
if (argv.noglobal) {
10-
return;
11-
}
12-
13-
await silentNpm('install', '-g', '@angular-devkit/schematics-cli');
14-
await exec(process.platform.startsWith('win') ? 'where' : 'which', 'schematics');
15-
166
const startCwd = process.cwd();
177
const schematicPath = path.join(startCwd, 'test-schematic');
188

tests/legacy-cli/e2e/tests/schematics_cli/blank-test.ts

-11
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
1-
import * as fs from 'fs';
21
import * as path from 'path';
3-
import { getGlobalVariable } from '../../utils/env';
42
import { exec, silentNpm } from '../../utils/process';
53
import { rimraf } from '../../utils/fs';
64

75
export default async function () {
8-
// setup
9-
const argv = getGlobalVariable('argv');
10-
if (argv.noglobal) {
11-
return;
12-
}
13-
14-
await silentNpm('install', '-g', '@angular-devkit/schematics-cli');
15-
await exec(process.platform.startsWith('win') ? 'where' : 'which', 'schematics');
16-
176
const startCwd = process.cwd();
187
const schematicPath = path.join(startCwd, 'test-schematic');
198

tests/legacy-cli/e2e/tests/schematics_cli/schematic-test.ts

-11
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
1-
import * as fs from 'fs';
21
import * as path from 'path';
3-
import { getGlobalVariable } from '../../utils/env';
42
import { exec, silentNpm } from '../../utils/process';
53
import { rimraf } from '../../utils/fs';
64

75
export default async function () {
8-
// setup
9-
const argv = getGlobalVariable('argv');
10-
if (argv.noglobal) {
11-
return;
12-
}
13-
14-
await silentNpm('install', '-g', '@angular-devkit/schematics-cli');
15-
await exec(process.platform.startsWith('win') ? 'where' : 'which', 'schematics');
16-
176
const startCwd = process.cwd();
187
const schematicPath = path.join(startCwd, 'test-schematic');
198

tests/legacy-cli/e2e/utils/process.ts

+14-5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,17 @@ import { concat, defer, EMPTY, from } from 'rxjs';
55
import { repeat, takeLast } from 'rxjs/operators';
66
import { getGlobalVariable } from './env';
77
import { catchError } from 'rxjs/operators';
8+
import { join } from 'path';
89
const treeKill = require('tree-kill');
910

11+
// The node_modules directory containing non-tested dependencies.
12+
const NODE_MODULES = join(process.cwd(), 'node_modules');
13+
14+
// Do not depend on any global or test-local npm/yarn.
15+
// Always use the NPM + Yarn from the e2e node process node_modules.
16+
const NPM_CLI_JS = join(NODE_MODULES, 'npm/bin/npm-cli.js');
17+
const YARN_CLI_JS = join(NODE_MODULES, 'yarn/bin/yarn.js');
18+
1019
interface ExecOptions {
1120
silent?: boolean;
1221
waitForMatch?: RegExp;
@@ -270,20 +279,20 @@ export function silentNpm(
270279
silent: true,
271280
cwd: (options as { cwd?: string } | undefined)?.cwd,
272281
},
273-
'npm',
274-
params,
282+
'node',
283+
[NPM_CLI_JS, ...params],
275284
);
276285
} else {
277-
return _exec({ silent: true }, 'npm', args as string[]);
286+
return _exec({ silent: true }, 'node', [NPM_CLI_JS, ...(args as string[])]);
278287
}
279288
}
280289

281290
export function silentYarn(...args: string[]) {
282-
return _exec({ silent: true }, 'yarn', args);
291+
return _exec({ silent: true }, 'node', [YARN_CLI_JS, ...args]);
283292
}
284293

285294
export function npm(...args: string[]) {
286-
return _exec({}, 'npm', args);
295+
return _exec({}, 'node', [NPM_CLI_JS, ...args]);
287296
}
288297

289298
export function node(...args: string[]) {

tests/legacy-cli/e2e_runner.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ Error.stackTraceLimit = Infinity;
1919
* Here's a short description of those flags:
2020
* --debug If a test fails, block the thread so the temporary directory isn't deleted.
2121
* --noproject Skip creating a project or using one.
22-
* --nobuild Skip building the packages. Use with --noglobal and --reuse to quickly
23-
* rerun tests.
24-
* --noglobal Skip linking your local @angular/cli directory. Can save a few seconds.
22+
* --nobuild Skip building the packages. Use with --reuse to quickly rerun tests.
2523
* --nosilent Never silence ng commands.
2624
* --ng-tag=TAG Use a specific tag for build snapshots. Similar to ng-snapshots but point to a
2725
* tag instead of using the latest `main`.
@@ -39,7 +37,7 @@ Error.stackTraceLimit = Infinity;
3937
* If unnamed flags are passed in, the list of tests will be filtered to include only those passed.
4038
*/
4139
const argv = yargsParser(process.argv.slice(2), {
42-
boolean: ['debug', 'esbuild', 'ng-snapshots', 'noglobal', 'nosilent', 'noproject', 'verbose'],
40+
boolean: ['debug', 'esbuild', 'ng-snapshots', 'nosilent', 'noproject', 'verbose'],
4341
string: ['devkit', 'glob', 'ignore', 'reuse', 'ng-tag', 'tmpdir', 'ng-version'],
4442
configuration: {
4543
'dot-notation': false,

0 commit comments

Comments
 (0)