Skip to content

Commit 979097e

Browse files
committed
test: remove use of global npm installs
1 parent 4be7cdc commit 979097e

File tree

13 files changed

+1986
-168
lines changed

13 files changed

+1986
-168
lines changed

.circleci/config.yml

+1-3
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,8 @@ jobs:
204204
- browser-tools/install-chrome
205205
- run:
206206
name: Initialize Environment
207-
# npm 7 currently does not properly publish the packages locally
208207
command: |
209208
./.circleci/env.sh
210-
sudo npm install --global npm@6
211209
- run:
212210
name: Execute CLI E2E Tests
213211
command: |
@@ -345,7 +343,7 @@ workflows:
345343
- setup
346344
- e2e-cli:
347345
name: e2e-cli
348-
nodeversion: '14.15'
346+
nodeversion: '14.17'
349347
post-steps:
350348
- store_artifacts:
351349
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.0",
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 = 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+
}
+32-29
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import { mkdtempSync, realpathSync } from 'fs';
2+
import { tmpdir } from 'os';
3+
import { delimiter, join } from 'path';
4+
import * as semver from 'semver';
15
import { rimraf } from '../../utils/fs';
26
import { getActivePackageManager } from '../../utils/packages';
3-
import { ng, npm } from '../../utils/process';
7+
import { exec, execAndWaitForOutputToMatch, ng, npm } from '../../utils/process';
48
import { isPrereleaseCli } from '../../utils/project';
5-
import { expectToFail } from '../../utils/utils';
69

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

912
export default async function () {
1013
// Only relevant with npm as a package manager
@@ -25,60 +28,60 @@ export default async function () {
2528
}
2629

2730
try {
28-
// Install version >=7.5.6
29-
await npm('install', '--global', 'npm@>=7.5.6');
31+
// Add the npmModuleDir to the PATH so the test-installed npm is used
32+
process.env.PATH =
33+
join(currentDirectory, 'node_modules', '.bin') + delimiter + process.env.PATH;
34+
35+
// Install and verify npm version >=7.5.6
36+
await npm('install', 'npm@>=7.5.6');
37+
const { stdout: npm75Version } = await exec('npm', '--version');
38+
if (!semver.gte(npm75Version, '7.5.6')) {
39+
throw new Error('npm install >=7.5.6 failed');
40+
}
3041

3142
// Ensure `ng update` does not show npm warning
3243
const { stderr: stderrUpdate1 } = await ng('update', ...extraArgs);
33-
if (stderrUpdate1.includes(warningText)) {
44+
if (stderrUpdate1.match(warningTextRe)) {
3445
throw new Error('ng update expected to not show npm version warning.');
3546
}
3647

37-
// Install version <7.5.6
38-
await npm('install', '--global', '[email protected]');
48+
// Install and verify npm version <7.5.6
49+
await npm('install', '[email protected]');
50+
const { stdout: npm74Version } = await exec('npm', '--version');
51+
if (!semver.eq(npm74Version, '7.4.0')) {
52+
throw new Error('npm install =7.4.0 failed');
53+
}
3954

4055
// Ensure `ng add` shows npm warning
41-
const { stderr: stderrAdd } = await ng('add', '@angular/localize');
42-
if (!stderrAdd.includes(warningText)) {
43-
throw new Error('ng add expected to show npm version warning.');
44-
}
56+
await execAndWaitForOutputToMatch('ng', ['add', '@angular/localize'], warningTextRe);
4557

4658
// Ensure `ng update` shows npm warning
47-
const { stderr: stderrUpdate2 } = await ng('update', ...extraArgs);
48-
if (!stderrUpdate2.includes(warningText)) {
49-
throw new Error('ng update expected to show npm version warning.');
50-
}
59+
await execAndWaitForOutputToMatch('ng', ['update', ...extraArgs], warningTextRe);
5160

5261
// Ensure `ng build` executes successfully
5362
const { stderr: stderrBuild } = await ng('build', '--configuration=development');
54-
if (stderrBuild.includes(warningText)) {
63+
if (stderrBuild.match(warningTextRe)) {
5564
throw new Error('ng build expected to not show npm version warning.');
5665
}
5766

5867
// Ensure `ng new` shows npm warning
5968
// Must be outside the project for `ng new`
6069
process.chdir('..');
61-
const { message: stderrNew } = await expectToFail(() => ng('new'));
62-
if (!stderrNew.includes(warningText)) {
63-
throw new Error('ng new expected to show npm version warning.');
64-
}
70+
await execAndWaitForOutputToMatch('ng', ['new'], warningTextRe);
6571

6672
// Ensure `ng new --package-manager=npm` shows npm warning
67-
const { message: stderrNewNpm } = await expectToFail(() => ng('new', '--package-manager=npm'));
68-
if (!stderrNewNpm.includes(warningText)) {
69-
throw new Error('ng new expected to show npm version warning.');
70-
}
73+
await execAndWaitForOutputToMatch('ng', ['new', '--package-manager=npm'], warningTextRe);
7174

7275
// Ensure `ng new --skip-install` executes successfully
7376
const { stderr: stderrNewSkipInstall } = await ng('new', 'npm-seven-skip', '--skip-install');
74-
if (stderrNewSkipInstall.includes(warningText)) {
77+
if (stderrNewSkipInstall.match(warningTextRe)) {
7578
throw new Error('ng new --skip-install expected to not show npm version warning.');
7679
}
7780

7881
// Ensure `ng new --package-manager=yarn` executes successfully
7982
// Need an additional npmrc file since yarn does not use the NPM registry environment variable
8083
const { stderr: stderrNewYarn } = await ng('new', 'npm-seven-yarn', '--package-manager=yarn');
81-
if (stderrNewYarn.includes(warningText)) {
84+
if (stderrNewYarn.match(warningTextRe)) {
8285
throw new Error('ng new --package-manager=yarn expected to not show npm version warning.');
8386
}
8487
} finally {
@@ -89,7 +92,7 @@ export default async function () {
8992
// Change directory back
9093
process.chdir(currentDirectory);
9194

92-
// Reset version back to 6.x
93-
await npm('install', '--global', 'npm@6');
95+
// Remove the locally installed npm
96+
await npm('uninstall', 'npm');
9497
}
9598
}

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

+12-3
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;
@@ -258,15 +267,15 @@ export function silentNg(...args: string[]) {
258267
}
259268

260269
export function silentNpm(...args: string[]) {
261-
return _exec({ silent: true }, 'npm', args);
270+
return _exec({ silent: true }, 'node', [NPM_CLI_JS, ...args]);
262271
}
263272

264273
export function silentYarn(...args: string[]) {
265-
return _exec({ silent: true }, 'yarn', args);
274+
return _exec({ silent: true }, 'node', [YARN_CLI_JS, ...args]);
266275
}
267276

268277
export function npm(...args: string[]) {
269-
return _exec({}, 'npm', args);
278+
return _exec({}, 'node', [NPM_CLI_JS, ...args]);
270279
}
271280

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

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export function expectToFail(fn: () => Promise<any>, errorMessage?: string): Promise<any> {
1+
export function expectToFail(fn: () => Promise<any>, errorMessage?: string): Promise<Error> {
22
return fn().then(
33
() => {
44
const functionSource = fn.name || (<any>fn).source || fn.toString();

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)