Skip to content

Commit ba0fefe

Browse files
fix: support errors with circular dependencies in object values with --parallel (#5212)
* fix: support errors with circular dependencies in object values with --parallel * Also handle nested non-writable getters
1 parent f44f71b commit ba0fefe

File tree

6 files changed

+68
-5
lines changed

6 files changed

+68
-5
lines changed

lib/nodejs/serializer.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,15 @@ class SerializableEvent {
262262
breakCircularDeps(result.error);
263263

264264
const pairs = Object.keys(result).map(key => [result, key]);
265-
265+
const seenPairs = new Set();
266266
let pair;
267+
267268
while ((pair = pairs.shift())) {
269+
if (seenPairs.has(pair[1])) {
270+
continue;
271+
}
272+
273+
seenPairs.add(pair[1]);
268274
SerializableEvent._serialize(pairs, ...pair);
269275
}
270276

lib/utils.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,9 @@ exports.breakCircularDeps = inputObj => {
675675

676676
seen.add(obj);
677677
for (const k in obj) {
678-
if (Object.prototype.hasOwnProperty.call(obj, k)) {
678+
const descriptor = Object.getOwnPropertyDescriptor(obj, k);
679+
680+
if (descriptor && descriptor.writable) {
679681
obj[k] = _breakCircularDeps(obj[k], k);
680682
}
681683
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {describe,it} from "../../../../index.js";
2+
3+
describe('test1', () => {
4+
it('test', () => {
5+
const errorA = {};
6+
const objectB = {toA: errorA};
7+
errorA.toB = objectB;
8+
9+
const error = new Error("Oh no!");
10+
error.error = errorA;
11+
error.values = [errorA];
12+
13+
throw error;
14+
});
15+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {describe, it} from '../../../../index.js';
2+
3+
describe('test1', () => {
4+
it('test', async () => {
5+
const error = new Error('Oh no!');
6+
7+
error.nested = {
8+
get inner() {
9+
return 'abc';
10+
}
11+
};
12+
13+
throw error;
14+
});
15+
});

test/integration/parallel.spec.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ describe('parallel run', () => {
3131
assert.strictEqual(result.stats.passes, 3);
3232
});
3333

34-
it('should correctly handle circular references in an exception', async () => {
35-
const result = await runMochaJSONAsync('parallel/circular-error.mjs', [
34+
it('should correctly handle circular array references in an exception', async () => {
35+
const result = await runMochaJSONAsync('parallel/circular-error-array.mjs', [
3636
'--parallel',
3737
'--jobs',
3838
'2',
@@ -45,7 +45,7 @@ describe('parallel run', () => {
4545
});
4646

4747
it('should correctly handle an exception with retries', async () => {
48-
const result = await runMochaJSONAsync('parallel/circular-error.mjs', [
48+
const result = await runMochaJSONAsync('parallel/circular-error-array.mjs', [
4949
'--parallel',
5050
'--jobs',
5151
'2',
@@ -58,4 +58,29 @@ describe('parallel run', () => {
5858
assert.strictEqual(result.failures[0].err.message, 'Foo');
5959
assert.strictEqual(result.failures[0].err.foo.props[0], '[Circular]');
6060
});
61+
62+
it('should correctly handle circular object references in an exception', async () => {
63+
const result = await runMochaJSONAsync('parallel/circular-error-object.mjs', [
64+
'--parallel',
65+
'--jobs',
66+
'2',
67+
require.resolve('./fixtures/parallel/testworkerid1.mjs')
68+
]);
69+
assert.strictEqual(result.stats.failures, 1);
70+
assert.strictEqual(result.stats.passes, 1);
71+
assert.strictEqual(result.failures[0].err.message, 'Oh no!');
72+
assert.deepStrictEqual(result.failures[0].err.values, [ { toB: { toA: '[Circular]' } } ]);
73+
});
74+
75+
it('should correctly handle a non-writable getter reference in an exception', async () => {
76+
const result = await runMochaJSONAsync('parallel/getter-error-object.mjs', [
77+
'--parallel',
78+
'--jobs',
79+
'2',
80+
require.resolve('./fixtures/parallel/testworkerid1.mjs')
81+
]);
82+
assert.strictEqual(result.stats.failures, 1);
83+
assert.strictEqual(result.stats.passes, 1);
84+
assert.strictEqual(result.failures[0].err.message, 'Oh no!');
85+
});
6186
});

0 commit comments

Comments
 (0)