Skip to content

Commit 4374931

Browse files
JiaLiPassionkara
authored andcommitted
fix(zone.js): zone.js patch jest should handle done correctly (#36022)
`zone.js` supports jest `test.each()` methods, but it introduces a bug, which is the `done()` function will not be handled correctly. ``` it('should work with done', done => { // done will be undefined. }); ``` The reason is the logic of monkey patching `test` method is different from `jasmine` patch // jasmine patch ``` return testBody.length === 0 ? () => testProxyZone.run(testBody, null) : done => testProxyZone.run(testBody, null, [done]); ``` // jest patch ``` return function(...args) { return testProxyZone.run(testBody, null, args); }; ``` the purpose of this change is to handle the following cases. ``` test.each([1, 2])('test.each', (arg1, arg2) => { expect(arg1).toBe(1); expect(arg2).toBe(2); }); ``` so in jest, it is a little complex, because the `testBody`'s parameter may be bigger than 1, so the logic in `jasmine` ``` return testBody.length === 0 ? () => testProxyZone.run(testBody, null) : done => testProxyZone.run(testBody, null, [done]); ``` will not work for `test.each` in jest. So in this PR, I created a dynamic `Function` to return the correct length of paramters (which is required by jest core), to handle 1. normal `test` with or without `done`. 2. each with parameters with or without done. PR Close #36022
1 parent 64022f5 commit 4374931

2 files changed

Lines changed: 85 additions & 18 deletions

File tree

packages/zone.js/lib/jest/jest.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,9 @@ Zone.__load_patch('jest', (context: any, Zone: ZoneType) => {
4343

4444
function wrapTestFactoryInZone(originalJestFn: Function) {
4545
return function(this: unknown, ...tableArgs: any[]) {
46-
const testFn = originalJestFn.apply(this, tableArgs);
4746
return function(this: unknown, ...args: any[]) {
4847
args[1] = wrapTestInZone(args[1]);
49-
return testFn.apply(this, args);
48+
return originalJestFn.apply(this, tableArgs).apply(this, args);
5049
};
5150
};
5251
}
@@ -64,16 +63,21 @@ Zone.__load_patch('jest', (context: any, Zone: ZoneType) => {
6463
/**
6564
* Gets a function wrapping the body of a jest `it/beforeEach/afterEach` block to
6665
* execute in a ProxyZone zone.
67-
* This will run in the `testProxyZone`.
66+
* This will run in the `proxyZone`.
6867
*/
6968
function wrapTestInZone(testBody: Function): Function {
7069
if (typeof testBody !== 'function') {
7170
return testBody;
7271
}
73-
// The `done` callback is only passed through if the function expects at least one argument.
74-
// Note we have to make a function with correct number of arguments, otherwise jest will
75-
// think that all functions are sync or async.
76-
return function(this: unknown, ...args: any[]) { return proxyZone.run(testBody, this, args); };
72+
const wrappedFunc = function() {
73+
return proxyZone.run(testBody, null, arguments as any);
74+
};
75+
// Update the length of wrappedFunc to be the same as the length of the testBody
76+
// So jest core can handle whether the test function has `done()` or not correctly
77+
Object.defineProperty(
78+
wrappedFunc, 'length', {configurable: true, writable: true, enumerable: false});
79+
wrappedFunc.length = testBody.length;
80+
return wrappedFunc;
7781
}
7882

7983
['describe', 'xdescribe', 'fdescribe'].forEach(methodName => {

packages/zone.js/test/jest/jest.spec.js

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,97 @@ function assertInsideSyncDescribeZone() {
66
}
77
describe('describe', () => {
88
assertInsideSyncDescribeZone();
9-
beforeEach(() => { assertInsideProxyZone(); });
10-
beforeAll(() => { assertInsideProxyZone(); });
11-
afterEach(() => { assertInsideProxyZone(); });
12-
afterAll(() => { assertInsideProxyZone(); });
9+
beforeEach(() => {
10+
assertInsideProxyZone();
11+
});
12+
beforeAll(() => {
13+
assertInsideProxyZone();
14+
});
15+
afterEach(() => {
16+
assertInsideProxyZone();
17+
});
18+
afterAll(() => {
19+
assertInsideProxyZone();
20+
});
1321
});
1422
describe.each([[1, 2]])('describe.each', (arg1, arg2) => {
1523
assertInsideSyncDescribeZone();
1624
expect(arg1).toBe(1);
1725
expect(arg2).toBe(2);
1826
});
1927
describe('test', () => {
20-
it('it', () => { assertInsideProxyZone(); });
28+
it('it', () => {
29+
assertInsideProxyZone();
30+
});
2131
it.each([[1, 2]])('it.each', (arg1, arg2) => {
2232
assertInsideProxyZone();
2333
expect(arg1).toBe(1);
2434
expect(arg2).toBe(2);
2535
});
26-
test('test', () => { assertInsideProxyZone(); });
27-
test.each([[]])('test.each', () => { assertInsideProxyZone(); });
36+
test('test', () => {
37+
assertInsideProxyZone();
38+
});
39+
test.each([[]])('test.each', () => {
40+
assertInsideProxyZone();
41+
});
42+
});
43+
44+
it('it', () => {
45+
assertInsideProxyZone();
46+
});
47+
it('it with done', done => {
48+
assertInsideProxyZone();
49+
done();
2850
});
2951

30-
it('it', () => { assertInsideProxyZone(); });
31-
it.each([[1, 2]])('it.each', (arg1, arg2) => {
52+
it.each([[1, 2]])('it.each', (arg1, arg2, done) => {
3253
assertInsideProxyZone();
3354
expect(arg1).toBe(1);
3455
expect(arg2).toBe(2);
56+
done();
57+
});
58+
59+
it.each([2])('it.each with 1D array', arg1 => {
60+
assertInsideProxyZone();
61+
expect(arg1).toBe(2);
62+
});
63+
64+
it.each([2])('it.each with 1D array and done', (arg1, done) => {
65+
assertInsideProxyZone();
66+
expect(arg1).toBe(2);
67+
done();
68+
});
69+
70+
it.each`
71+
foo | bar
72+
${1} | ${2}
73+
`('it.each should work with table as a tagged template literal', ({foo, bar}) => {
74+
expect(foo).toBe(1);
75+
expect(bar).toBe(2);
76+
});
77+
78+
it.each`
79+
foo | bar
80+
${1} | ${2}
81+
`('it.each should work with table as a tagged template literal with done', ({foo, bar}, done) => {
82+
expect(foo).toBe(1);
83+
expect(bar).toBe(2);
84+
done();
85+
});
86+
87+
it.each`
88+
foo | bar
89+
${1} | ${2}
90+
`('(async) it.each should work with table as a tagged template literal', async ({foo, bar}) => {
91+
expect(foo).toBe(1);
92+
expect(bar).toBe(2);
93+
});
94+
95+
test('test', () => {
96+
assertInsideProxyZone();
97+
});
98+
test.each([[]])('test.each', () => {
99+
assertInsideProxyZone();
35100
});
36-
test('test', () => { assertInsideProxyZone(); });
37-
test.each([[]])('test.each', () => { assertInsideProxyZone(); });
38101

39102
test.todo('todo');

0 commit comments

Comments
 (0)