Skip to content

Commit 269fb87

Browse files
alan-agius4dgp1130
authored andcommitted
test: reject promise when output doesn't match waitForMatch
Previously, when the process output didn't match, the promise was always resolved.
1 parent 1c634cd commit 269fb87

File tree

2 files changed

+100
-74
lines changed

2 files changed

+100
-74
lines changed

tests/legacy-cli/e2e/tests/misc/completion.ts

+28-16
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,61 @@ import { execAndWaitForOutputToMatch } from '../../utils/process';
22

33
export default async function () {
44
// ng build
5-
await execAndWaitForOutputToMatch('ng', ['--get-yargs-completions', 'b', ''], /test-project/);
6-
await execAndWaitForOutputToMatch('ng', ['--get-yargs-completions', 'build', ''], /test-project/);
7-
await execAndWaitForOutputToMatch('ng', ['--get-yargs-completions', 'build', '--a'], /--aot/);
85
await execAndWaitForOutputToMatch(
96
'ng',
10-
['--get-yargs-completions', 'build', '--configuration'],
7+
['--get-yargs-completions', 'ng', 'b', ''],
8+
/test-project/,
9+
);
10+
await execAndWaitForOutputToMatch(
11+
'ng',
12+
['--get-yargs-completions', 'ng', 'build', ''],
13+
/test-project/,
14+
);
15+
await execAndWaitForOutputToMatch(
16+
'ng',
17+
['--get-yargs-completions', 'ng', 'build', '--a'],
18+
/--aot/,
19+
);
20+
await execAndWaitForOutputToMatch(
21+
'ng',
22+
['--get-yargs-completions', 'ng', 'build', '--configuration'],
1123
/production/,
1224
);
1325
await execAndWaitForOutputToMatch(
1426
'ng',
15-
['--get-yargs-completions', 'b', '--configuration'],
27+
['--get-yargs-completions', 'ng', 'b', '--configuration'],
1628
/production/,
1729
);
1830

1931
// ng run
2032
await execAndWaitForOutputToMatch(
2133
'ng',
22-
['--get-yargs-completions', 'run', ''],
23-
/test-project\:build\:development/,
34+
['--get-yargs-completions', 'ng', 'run', ''],
35+
/test-project\\:build\\:development/,
2436
);
2537
await execAndWaitForOutputToMatch(
2638
'ng',
27-
['--get-yargs-completions', 'run', ''],
28-
/test-project\:build/,
39+
['--get-yargs-completions', 'ng', 'run', ''],
40+
/test-project\\:build/,
2941
);
3042
await execAndWaitForOutputToMatch(
3143
'ng',
32-
['--get-yargs-completions', 'run', ''],
33-
/test-project\:test/,
44+
['--get-yargs-completions', 'ng', 'run', ''],
45+
/test-project\\:test/,
3446
);
3547
await execAndWaitForOutputToMatch(
3648
'ng',
37-
['--get-yargs-completions', 'run', 'test-project:build'],
38-
/test-project\:build\:development/,
49+
['--get-yargs-completions', 'ng', 'run', 'test-project:build'],
50+
/test-project\\:build\\:development/,
3951
);
4052
await execAndWaitForOutputToMatch(
4153
'ng',
42-
['--get-yargs-completions', 'run', 'test-project:'],
43-
/test-project\:test/,
54+
['--get-yargs-completions', 'ng', 'run', 'test-project:'],
55+
/test-project\\:test/,
4456
);
4557
await execAndWaitForOutputToMatch(
4658
'ng',
47-
['--get-yargs-completions', 'run', 'test-project:build'],
59+
['--get-yargs-completions', 'ng', 'run', 'test-project:build'],
4860
// does not include 'test-project:serve'
4961
/^((?!:serve).)*$/,
5062
);

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

+72-58
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
import * as ansiColors from 'ansi-colors';
2-
import { SpawnOptions } from "child_process";
2+
import { SpawnOptions } from 'child_process';
33
import * as child_process from 'child_process';
4-
import { concat, defer, EMPTY, from} from 'rxjs';
5-
import {repeat, takeLast} from 'rxjs/operators';
6-
import {getGlobalVariable} from './env';
7-
import {catchError} from 'rxjs/operators';
4+
import { concat, defer, EMPTY, from } from 'rxjs';
5+
import { repeat, takeLast } from 'rxjs/operators';
6+
import { getGlobalVariable } from './env';
7+
import { catchError } from 'rxjs/operators';
88
const treeKill = require('tree-kill');
99

10-
1110
interface ExecOptions {
1211
silent?: boolean;
1312
waitForMatch?: RegExp;
1413
env?: { [varname: string]: string };
1514
}
1615

17-
1816
let _processes: child_process.ChildProcess[] = [];
1917

2018
export type ProcessOutput = {
2119
stdout: string;
2220
stderr: string;
2321
};
2422

25-
26-
function _exec(options: ExecOptions, cmd: string, args: string[]): Promise<ProcessOutput> {
23+
function _exec(options: ExecOptions, cmd: string, args: string[]): Promise<ProcessOutput> {
2724
// Create a separate instance to prevent unintended global changes to the color configuration
2825
// Create function is not defined in the typings. See: https://github.com/doowb/ansi-colors/pull/44
2926
const colors = (ansiColors as typeof ansiColors & { create: () => typeof ansiColors }).create();
@@ -33,24 +30,24 @@ function _exec(options: ExecOptions, cmd: string, args: string[]): Promise<Proc
3330
const cwd = process.cwd();
3431
const env = options.env;
3532
console.log(
36-
`==========================================================================================`
33+
`==========================================================================================`,
3734
);
3835

39-
args = args.filter(x => x !== undefined);
36+
args = args.filter((x) => x !== undefined);
4037
const flags = [
4138
options.silent && 'silent',
42-
options.waitForMatch && `matching(${options.waitForMatch})`
39+
options.waitForMatch && `matching(${options.waitForMatch})`,
4340
]
44-
.filter(x => !!x) // Remove false and undefined.
41+
.filter((x) => !!x) // Remove false and undefined.
4542
.join(', ')
46-
.replace(/^(.+)$/, ' [$1]'); // Proper formatting.
43+
.replace(/^(.+)$/, ' [$1]'); // Proper formatting.
4744

48-
console.log(colors.blue(`Running \`${cmd} ${args.map(x => `"${x}"`).join(' ')}\`${flags}...`));
45+
console.log(colors.blue(`Running \`${cmd} ${args.map((x) => `"${x}"`).join(' ')}\`${flags}...`));
4946
console.log(colors.blue(`CWD: ${cwd}`));
5047
console.log(colors.blue(`ENV: ${JSON.stringify(env)}`));
5148
const spawnOptions: SpawnOptions = {
5249
cwd,
53-
...env ? { env } : {},
50+
...(env ? { env } : {}),
5451
};
5552

5653
if (process.platform.startsWith('win')) {
@@ -65,56 +62,74 @@ function _exec(options: ExecOptions, cmd: string, args: string[]): Promise<Proc
6562
if (options.silent) {
6663
return;
6764
}
68-
data.toString('utf-8')
65+
data
66+
.toString('utf-8')
6967
.split(/[\n\r]+/)
70-
.filter(line => line !== '')
71-
.forEach(line => console.log(' ' + line));
68+
.filter((line) => line !== '')
69+
.forEach((line) => console.log(' ' + line));
7270
});
7371
childProcess.stderr.on('data', (data: Buffer) => {
7472
stderr += data.toString('utf-8');
7573
if (options.silent) {
7674
return;
7775
}
78-
data.toString('utf-8')
76+
data
77+
.toString('utf-8')
7978
.split(/[\n\r]+/)
80-
.filter(line => line !== '')
81-
.forEach(line => console.error(colors.yellow(' ' + line)));
79+
.filter((line) => line !== '')
80+
.forEach((line) => console.error(colors.yellow(' ' + line)));
8281
});
8382

8483
_processes.push(childProcess);
8584

8685
// Create the error here so the stack shows who called this function.
87-
const err = new Error(`Running "${cmd} ${args.join(' ')}" returned error code `);
86+
8887
return new Promise((resolve, reject) => {
88+
let matched = false;
89+
8990
childProcess.on('exit', (error: any) => {
90-
_processes = _processes.filter(p => p !== childProcess);
91+
_processes = _processes.filter((p) => p !== childProcess);
92+
93+
if (options.waitForMatch && !matched) {
94+
error = `Output didn't match '${options.waitForMatch}'.`;
95+
}
9196

9297
if (!error) {
9398
resolve({ stdout, stderr });
94-
} else {
95-
err.message += `${error}...\n\nSTDOUT:\n${stdout}\n\nSTDERR:\n${stderr}\n`;
96-
reject(err);
99+
return;
97100
}
101+
102+
reject(
103+
new Error(
104+
`Running "${cmd} ${args.join(
105+
' ',
106+
)}" returned error. ${error}...\n\nSTDOUT:\n${stdout}\n\nSTDERR:\n${stderr}\n`,
107+
),
108+
);
98109
});
99110

100111
if (options.waitForMatch) {
101112
const match = options.waitForMatch;
102113
childProcess.stdout.on('data', (data: Buffer) => {
103114
if (data.toString().match(match)) {
104115
resolve({ stdout, stderr });
116+
matched = true;
105117
}
106118
});
107119
childProcess.stderr.on('data', (data: Buffer) => {
108120
if (data.toString().match(match)) {
109121
resolve({ stdout, stderr });
122+
matched = true;
110123
}
111124
});
112125
}
113126
});
114127
}
115128

116-
export function waitForAnyProcessOutputToMatch(match: RegExp,
117-
timeout = 30000): Promise<ProcessOutput> {
129+
export function waitForAnyProcessOutputToMatch(
130+
match: RegExp,
131+
timeout = 30000,
132+
): Promise<ProcessOutput> {
118133
// Race between _all_ processes, and the timeout. First one to resolve/reject wins.
119134
const timeoutPromise: Promise<ProcessOutput> = new Promise((_resolve, reject) => {
120135
// Wait for 30 seconds and timeout.
@@ -124,28 +139,30 @@ export function waitForAnyProcessOutputToMatch(match: RegExp,
124139
});
125140

126141
const matchPromises: Promise<ProcessOutput>[] = _processes.map(
127-
childProcess => new Promise(resolve => {
128-
let stdout = '';
129-
let stderr = '';
130-
childProcess.stdout.on('data', (data: Buffer) => {
131-
stdout += data.toString();
132-
if (data.toString().match(match)) {
133-
resolve({ stdout, stderr });
134-
}
135-
});
136-
childProcess.stderr.on('data', (data: Buffer) => {
137-
stderr += data.toString();
138-
if (data.toString().match(match)) {
139-
resolve({ stdout, stderr });
140-
}
141-
});
142-
}));
142+
(childProcess) =>
143+
new Promise((resolve) => {
144+
let stdout = '';
145+
let stderr = '';
146+
childProcess.stdout.on('data', (data: Buffer) => {
147+
stdout += data.toString();
148+
if (data.toString().match(match)) {
149+
resolve({ stdout, stderr });
150+
}
151+
});
152+
childProcess.stderr.on('data', (data: Buffer) => {
153+
stderr += data.toString();
154+
if (data.toString().match(match)) {
155+
resolve({ stdout, stderr });
156+
}
157+
});
158+
}),
159+
);
143160

144161
return Promise.race(matchPromises.concat([timeoutPromise]));
145162
}
146163

147164
export function killAllProcesses(signal = 'SIGTERM') {
148-
_processes.forEach(process => treeKill(process.pid, signal));
165+
_processes.forEach((process) => treeKill(process.pid, signal));
149166
_processes = [];
150167
}
151168

@@ -169,16 +186,14 @@ export function execAndWaitForOutputToMatch(cmd: string, args: string[], match:
169186
// This seems to be due to host file system differences, see
170187
// https://nodejs.org/docs/latest/api/fs.html#fs_caveats
171188
return concat(
172-
from(
173-
_exec({ waitForMatch: match }, cmd, args)
174-
),
189+
from(_exec({ waitForMatch: match }, cmd, args)),
175190
defer(() => waitForAnyProcessOutputToMatch(match, 2500)).pipe(
176191
repeat(20),
177192
catchError(() => EMPTY),
178193
),
179-
).pipe(
180-
takeLast(1),
181-
).toPromise();
194+
)
195+
.pipe(takeLast(1))
196+
.toPromise();
182197
} else {
183198
return _exec({ waitForMatch: match }, cmd, args);
184199
}
@@ -190,8 +205,7 @@ export function ng(...args: string[]) {
190205
if (['build', 'serve', 'test', 'e2e', 'extract-i18n'].indexOf(args[0]) != -1) {
191206
if (args[0] == 'e2e') {
192207
// Wait 1 second before running any end-to-end test.
193-
return new Promise(resolve => setTimeout(resolve, 1000))
194-
.then(() => maybeSilentNg(...args));
208+
return new Promise((resolve) => setTimeout(resolve, 1000)).then(() => maybeSilentNg(...args));
195209
}
196210

197211
return maybeSilentNg(...args);
@@ -205,15 +219,15 @@ export function noSilentNg(...args: string[]) {
205219
}
206220

207221
export function silentNg(...args: string[]) {
208-
return _exec({silent: true}, 'ng', args);
222+
return _exec({ silent: true }, 'ng', args);
209223
}
210224

211225
export function silentNpm(...args: string[]) {
212-
return _exec({silent: true}, 'npm', args);
226+
return _exec({ silent: true }, 'npm', args);
213227
}
214228

215229
export function silentYarn(...args: string[]) {
216-
return _exec({silent: true}, 'yarn', args);
230+
return _exec({ silent: true }, 'yarn', args);
217231
}
218232

219233
export function npm(...args: string[]) {
@@ -229,5 +243,5 @@ export function git(...args: string[]) {
229243
}
230244

231245
export function silentGit(...args: string[]) {
232-
return _exec({silent: true}, 'git', args);
246+
return _exec({ silent: true }, 'git', args);
233247
}

0 commit comments

Comments
 (0)