Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit02c04c4

Browse files
authored
fix: better tracking of seen objects in error serialization (#5032)
* fix:closes#4552Breaks circular references in before objects are serialized to preventcryptic error in parallel mode.* chore: trigger test re-run
1 parent103c56b commit02c04c4

File tree

4 files changed

+62
-10
lines changed

4 files changed

+62
-10
lines changed

‎lib/nodejs/serializer.js‎

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
'use strict';
88

9-
const{type}=require('../utils');
9+
const{type, breakCircularDeps}=require('../utils');
1010
const{createInvalidArgumentTypeError}=require('../errors');
1111
// this is not named `mocha:parallel:serializer` because it's noisy and it's
1212
// helpful to be able to write `DEBUG=mocha:parallel*` and get everything else.
@@ -188,14 +188,9 @@ class SerializableEvent {
188188
*@param {Array<object|string>} pairs - List of parent/key tuples to process; modified in-place. This JSDoc type is an approximation
189189
*@param {object} parent - Some parent object
190190
*@param {string} key - Key to inspect
191-
*@param {WeakSet<Object>} seenObjects - For avoiding circular references
192191
*/
193-
static_serialize(pairs,parent,key,seenObjects){
192+
static_serialize(pairs,parent,key){
194193
letvalue=parent[key];
195-
if(seenObjects.has(value)){
196-
parent[key]=Object.create(null);
197-
return;
198-
}
199194
let_type=type(value);
200195
if(_type==='error'){
201196
// we need to reference the stack prop b/c it's lazily-loaded.
@@ -263,13 +258,14 @@ class SerializableEvent {
263258
error:this.originalError
264259
});
265260

261+
// mutates the object
262+
breakCircularDeps(result);
263+
266264
constpairs=Object.keys(result).map(key=>[result,key]);
267-
constseenObjects=newWeakSet();
268265

269266
letpair;
270267
while((pair=pairs.shift())){
271-
SerializableEvent._serialize(pairs, ...pair,seenObjects);
272-
seenObjects.add(pair[0]);
268+
SerializableEvent._serialize(pairs, ...pair);
273269
}
274270

275271
this.data=result.data;

‎lib/utils.js‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,3 +647,36 @@ exports.assignNewMochaID = obj => {
647647
*/
648648
exports.getMochaID=obj=>
649649
obj&&typeofobj==='object' ?obj[MOCHA_ID_PROP_NAME] :undefined;
650+
651+
/**
652+
* Replaces any detected circular dependency with the string '[Circular]'
653+
* Mutates original object
654+
*@param inputObj {*}
655+
*@returns {*}
656+
*/
657+
exports.breakCircularDeps=inputObj=>{
658+
constseen=newSet();
659+
660+
function_breakCircularDeps(obj){
661+
if(obj&&typeofobj!=='object'){
662+
returnobj;
663+
}
664+
665+
if(seen.has(obj)){
666+
return'[Circular]';
667+
}
668+
669+
seen.add(obj);
670+
for(constkinobj){
671+
if(Object.prototype.hasOwnProperty.call(obj,k)){
672+
obj[k]=_breakCircularDeps(obj[k],k);
673+
}
674+
}
675+
676+
// deleting means only a seen object that is its own child will be detected
677+
seen.delete(obj);
678+
returnobj;
679+
}
680+
681+
return_breakCircularDeps(inputObj);
682+
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import{describe,it}from"../../../../index.js";
2+
3+
describe('test1',()=>{
4+
it('test',()=>{
5+
consterror=newError('Foo');
6+
error.foo={props:[]};
7+
error.foo.props.push(error.foo);
8+
throwerror;
9+
});
10+
});

‎test/integration/parallel.spec.js‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,17 @@ describe('parallel run', () => {
3030
assert.strictEqual(result.stats.failures,0);
3131
assert.strictEqual(result.stats.passes,3);
3232
});
33+
34+
it('should correctly handle circular references in an exception',async()=>{
35+
constresult=awaitrunMochaJSONAsync('parallel/circular-error.mjs',[
36+
'--parallel',
37+
'--jobs',
38+
'2',
39+
require.resolve('./fixtures/parallel/testworkerid1.mjs')
40+
]);
41+
assert.strictEqual(result.stats.failures,1);
42+
assert.strictEqual(result.stats.passes,1);
43+
assert.strictEqual(result.failures[0].err.message,'Foo');
44+
assert.strictEqual(result.failures[0].err.foo.props[0],'[Circular]');
45+
});
3346
});

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp