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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy