Skip to content

Commit 5f49357

Browse files
authored
Fix unittest parallel reporting (#18583)
* Some tests depended on late execution * Emulate mocha execution order * Polyfill a synchronous done to handle that one unittest * Accpept updates tsconfig baselines fixed by #18534
1 parent 1264951 commit 5f49357

File tree

9 files changed

+114
-42
lines changed

9 files changed

+114
-42
lines changed

src/harness/parallel/worker.ts

Lines changed: 106 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,132 @@
11
namespace Harness.Parallel.Worker {
22
let errors: ErrorInfo[] = [];
33
let passing = 0;
4+
let reportedUnitTests = false;
5+
6+
type Executor = {name: string, callback: Function, kind: "suite" | "test"} | never;
7+
48
function resetShimHarnessAndExecute(runner: RunnerBase) {
5-
errors = [];
6-
passing = 0;
9+
if (reportedUnitTests) {
10+
errors = [];
11+
passing = 0;
12+
testList.length = 0;
13+
}
14+
reportedUnitTests = true;
715
runner.initializeTests();
16+
testList.forEach(({ name, callback, kind }) => executeCallback(name, callback, kind));
817
return { errors, passing };
918
}
1019

20+
21+
let beforeEachFunc: Function;
22+
const namestack: string[] = [];
23+
let testList: Executor[] = [];
1124
function shimMochaHarness() {
1225
(global as any).before = undefined;
1326
(global as any).after = undefined;
1427
(global as any).beforeEach = undefined;
15-
let beforeEachFunc: Function;
16-
describe = ((_name, callback) => {
17-
const fakeContext: Mocha.ISuiteCallbackContext = {
18-
retries() { return this; },
19-
slow() { return this; },
20-
timeout() { return this; },
21-
};
22-
(before as any) = (cb: Function) => cb();
23-
let afterFunc: Function;
24-
(after as any) = (cb: Function) => afterFunc = cb;
25-
const savedBeforeEach = beforeEachFunc;
26-
(beforeEach as any) = (cb: Function) => beforeEachFunc = cb;
27-
callback.call(fakeContext);
28-
afterFunc && afterFunc();
29-
afterFunc = undefined;
30-
beforeEachFunc = savedBeforeEach;
28+
describe = ((name, callback) => {
29+
testList.push({ name, callback, kind: "suite" });
3130
}) as Mocha.IContextDefinition;
3231
it = ((name, callback) => {
33-
const fakeContext: Mocha.ITestCallbackContext = {
34-
skip() { return this; },
35-
timeout() { return this; },
36-
retries() { return this; },
37-
slow() { return this; },
38-
};
39-
// TODO: If we ever start using async test completions, polyfill the `done` parameter/promise return handling
40-
if (beforeEachFunc) {
41-
try {
42-
beforeEachFunc();
43-
}
44-
catch (error) {
45-
errors.push({ error: error.message, stack: error.stack, name });
46-
return;
47-
}
32+
if (!testList) {
33+
throw new Error("Tests must occur within a describe block");
4834
}
35+
testList.push({ name, callback, kind: "test" });
36+
}) as Mocha.ITestDefinition;
37+
}
38+
39+
function executeSuiteCallback(name: string, callback: Function) {
40+
const fakeContext: Mocha.ISuiteCallbackContext = {
41+
retries() { return this; },
42+
slow() { return this; },
43+
timeout() { return this; },
44+
};
45+
namestack.push(name);
46+
let beforeFunc: Function;
47+
(before as any) = (cb: Function) => beforeFunc = cb;
48+
let afterFunc: Function;
49+
(after as any) = (cb: Function) => afterFunc = cb;
50+
const savedBeforeEach = beforeEachFunc;
51+
(beforeEach as any) = (cb: Function) => beforeEachFunc = cb;
52+
const savedTestList = testList;
53+
54+
testList = [];
55+
callback.call(fakeContext);
56+
beforeFunc && beforeFunc();
57+
beforeFunc = undefined;
58+
testList.forEach(({ name, callback, kind }) => executeCallback(name, callback, kind));
59+
testList.length = 0;
60+
testList = savedTestList;
61+
62+
afterFunc && afterFunc();
63+
afterFunc = undefined;
64+
beforeEachFunc = savedBeforeEach;
65+
namestack.pop();
66+
}
67+
68+
function executeCallback(name: string, callback: Function, kind: "suite" | "test") {
69+
if (kind === "suite") {
70+
executeSuiteCallback(name, callback);
71+
}
72+
else {
73+
executeTestCallback(name, callback);
74+
}
75+
}
76+
77+
function executeTestCallback(name: string, callback: Function) {
78+
const fakeContext: Mocha.ITestCallbackContext = {
79+
skip() { return this; },
80+
timeout() { return this; },
81+
retries() { return this; },
82+
slow() { return this; },
83+
};
84+
name = [...namestack, name].join(" ");
85+
if (beforeEachFunc) {
4986
try {
87+
beforeEachFunc();
88+
}
89+
catch (error) {
90+
errors.push({ error: error.message, stack: error.stack, name });
91+
return;
92+
}
93+
}
94+
if (callback.length === 0) {
95+
try {
96+
// TODO: If we ever start using async test completions, polyfill promise return handling
5097
callback.call(fakeContext);
5198
}
5299
catch (error) {
53100
errors.push({ error: error.message, stack: error.stack, name });
54101
return;
55102
}
56103
passing++;
57-
}) as Mocha.ITestDefinition;
104+
}
105+
else {
106+
// Uses `done` callback
107+
let completed = false;
108+
try {
109+
callback.call(fakeContext, (err: any) => {
110+
if (completed) {
111+
throw new Error(`done() callback called multiple times; ensure it is only called once.`);
112+
}
113+
if (err) {
114+
errors.push({ error: err.toString(), stack: "", name });
115+
}
116+
else {
117+
passing++;
118+
}
119+
completed = true;
120+
});
121+
}
122+
catch (error) {
123+
errors.push({ error: error.message, stack: error.stack, name });
124+
return;
125+
}
126+
if (!completed) {
127+
errors.push({ error: "Test completes asynchronously, which is unsupported by the parallel harness", stack: "", name });
128+
}
129+
}
58130
}
59131

60132
export function start() {

tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
/* Basic Options */
44
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
5-
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
5+
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
66
// "lib": [], /* Specify library files to be included in the compilation: */
77
// "allowJs": true, /* Allow javascript files to be compiled. */
88
// "checkJs": true, /* Report errors in .js files. */

tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
/* Basic Options */
44
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
5-
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
5+
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
66
// "lib": [], /* Specify library files to be included in the compilation: */
77
// "allowJs": true, /* Allow javascript files to be compiled. */
88
// "checkJs": true, /* Report errors in .js files. */

tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
/* Basic Options */
44
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
5-
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
5+
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
66
// "lib": [], /* Specify library files to be included in the compilation: */
77
// "allowJs": true, /* Allow javascript files to be compiled. */
88
// "checkJs": true, /* Report errors in .js files. */

tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
/* Basic Options */
44
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
5-
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
5+
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
66
// "lib": [], /* Specify library files to be included in the compilation: */
77
// "allowJs": true, /* Allow javascript files to be compiled. */
88
// "checkJs": true, /* Report errors in .js files. */

tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
/* Basic Options */
44
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
5-
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
5+
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
66
"lib": ["es5","es2015.promise"], /* Specify library files to be included in the compilation: */
77
// "allowJs": true, /* Allow javascript files to be compiled. */
88
// "checkJs": true, /* Report errors in .js files. */

tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
/* Basic Options */
44
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
5-
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
5+
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
66
// "lib": [], /* Specify library files to be included in the compilation: */
77
// "allowJs": true, /* Allow javascript files to be compiled. */
88
// "checkJs": true, /* Report errors in .js files. */

tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
/* Basic Options */
44
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
5-
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
5+
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
66
"lib": ["es5","es2015.core"], /* Specify library files to be included in the compilation: */
77
// "allowJs": true, /* Allow javascript files to be compiled. */
88
// "checkJs": true, /* Report errors in .js files. */

tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
/* Basic Options */
44
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
5-
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
5+
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
66
// "lib": [], /* Specify library files to be included in the compilation: */
77
// "allowJs": true, /* Allow javascript files to be compiled. */
88
// "checkJs": true, /* Report errors in .js files. */

0 commit comments

Comments
 (0)