Skip to content

Commit bb37b4e

Browse files
committed
test_runner: add missing coverage for assertion prototype metadata
1 parent 8c53105 commit bb37b4e

2 files changed

Lines changed: 87 additions & 11 deletions

File tree

test/parallel/test-runner-v8-deserializer.mjs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { DefaultSerializer } from 'node:v8';
88
import serializer from 'internal/test_runner/reporter/v8-serializer';
99
import runner from 'internal/test_runner/runner';
1010

11+
class ExtendedArray extends Array {}
12+
1113
async function toArray(chunks) {
1214
const arr = [];
1315
for await (const i of chunks) arr.push(i);
@@ -77,6 +79,26 @@ describe('v8 deserializer', common.mustCall(() => {
7779
]);
7880
});
7981

82+
it('should restore assertion metadata without leaking internal transport fields', async () => {
83+
let assertionError;
84+
try {
85+
assert.deepStrictEqual(new ExtendedArray('hello'), ['hello']);
86+
} catch (error) {
87+
assertionError = error;
88+
}
89+
assert(assertionError);
90+
91+
const [chunk] = await toArray(serializer([{
92+
type: 'test:diagnostic',
93+
data: { nesting: 0, details: { error: assertionError }, message: 'diagnostic' },
94+
}]));
95+
96+
const reported = await collectReported([chunk]);
97+
const detailError = reported[0].data.details.error;
98+
assert.strictEqual(detailError.actual.constructor.name, 'ExtendedArray');
99+
assert.strictEqual(Object.hasOwn(reported[0].data.details, 'assertionPrototypeMetadata'), false);
100+
});
101+
80102
const headerPosition = headerLength * 2 + 4;
81103
for (let i = 0; i < headerPosition + 5; i++) {
82104
const message = `should deserialize a serialized message split into two chunks {...${i},${i + 1}...}`;

test/sequential/test-runner-assertion-error-prototype.js

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,79 @@ const {
1313
} = require('internal/test_runner/assertion_error_prototype');
1414

1515
class ExtendedArray extends Array {}
16+
class ExtendedObject {
17+
constructor(value) {
18+
this.value = value;
19+
}
20+
}
1621

17-
function createAssertionError() {
22+
function createAssertionError(actual, expected) {
1823
try {
19-
assert.deepStrictEqual(new ExtendedArray('hello'), ['hello']);
24+
assert.deepStrictEqual(actual, expected);
2025
} catch (error) {
2126
return error;
2227
}
2328
assert.fail('Expected AssertionError');
2429
}
2530

26-
const assertionError = createAssertionError();
27-
const assertionPrototypeMetadata = collectAssertionPrototypeMetadata(assertionError);
28-
assert.ok(assertionPrototypeMetadata);
29-
assert.strictEqual(assertionPrototypeMetadata.actual.constructorName, 'ExtendedArray');
31+
const arrayAssertionError = createAssertionError(new ExtendedArray('hello'), ['hello']);
32+
const arrayPrototypeMetadata = collectAssertionPrototypeMetadata(arrayAssertionError);
33+
assert.ok(arrayPrototypeMetadata);
34+
assert.strictEqual(arrayPrototypeMetadata.actual.constructorName, 'ExtendedArray');
3035

31-
const defaultSerializedError = deserializeError(serializeError(assertionError));
32-
assert.strictEqual(defaultSerializedError.actual.constructor.name, 'Array');
36+
const defaultSerializedArrayError = deserializeError(serializeError(arrayAssertionError));
37+
assert.strictEqual(defaultSerializedArrayError.actual.constructor.name, 'Array');
3338

34-
applyAssertionPrototypeMetadata(defaultSerializedError, assertionPrototypeMetadata);
39+
applyAssertionPrototypeMetadata(defaultSerializedArrayError, arrayPrototypeMetadata);
3540
// Must be idempotent when metadata application is triggered more than once.
36-
applyAssertionPrototypeMetadata(defaultSerializedError, assertionPrototypeMetadata);
37-
assert.strictEqual(defaultSerializedError.actual.constructor.name, 'ExtendedArray');
41+
applyAssertionPrototypeMetadata(defaultSerializedArrayError, arrayPrototypeMetadata);
42+
assert.strictEqual(defaultSerializedArrayError.actual.constructor.name, 'ExtendedArray');
43+
44+
const objectAssertionError = createAssertionError(new ExtendedObject(42), { value: 42 });
45+
const objectPrototypeMetadata = collectAssertionPrototypeMetadata(objectAssertionError);
46+
assert.ok(objectPrototypeMetadata);
47+
assert.strictEqual(objectPrototypeMetadata.actual.constructorName, 'ExtendedObject');
48+
49+
const defaultSerializedObjectError = deserializeError(serializeError(objectAssertionError));
50+
assert.strictEqual(defaultSerializedObjectError.actual.constructor.name, 'Object');
51+
52+
applyAssertionPrototypeMetadata(defaultSerializedObjectError, objectPrototypeMetadata);
53+
assert.strictEqual(defaultSerializedObjectError.actual.constructor.name, 'ExtendedObject');
54+
55+
const expectedArrayAssertionError = createAssertionError(['hello'], new ExtendedArray('hello'));
56+
const expectedArrayPrototypeMetadata = collectAssertionPrototypeMetadata(expectedArrayAssertionError);
57+
assert.ok(expectedArrayPrototypeMetadata);
58+
assert.strictEqual(expectedArrayPrototypeMetadata.actual, undefined);
59+
assert.strictEqual(expectedArrayPrototypeMetadata.expected.constructorName, 'ExtendedArray');
60+
61+
const defaultSerializedExpectedArrayError = deserializeError(serializeError(expectedArrayAssertionError));
62+
assert.strictEqual(defaultSerializedExpectedArrayError.actual.constructor.name, 'Array');
63+
assert.strictEqual(defaultSerializedExpectedArrayError.expected.constructor.name, 'Array');
64+
65+
applyAssertionPrototypeMetadata(defaultSerializedExpectedArrayError, expectedArrayPrototypeMetadata);
66+
assert.strictEqual(defaultSerializedExpectedArrayError.actual.constructor.name, 'Array');
67+
assert.strictEqual(defaultSerializedExpectedArrayError.expected.constructor.name, 'ExtendedArray');
68+
69+
// AssertionError wrapped in ERR_TEST_FAILURE should still be supported.
70+
const wrappedMetadata = collectAssertionPrototypeMetadata({
71+
code: 'ERR_TEST_FAILURE',
72+
cause: arrayAssertionError,
73+
});
74+
assert.deepStrictEqual(wrappedMetadata, arrayPrototypeMetadata);
75+
76+
// Unsupported metadata shapes must be ignored safely.
77+
assert.doesNotThrow(() => applyAssertionPrototypeMetadata(arrayAssertionError, null));
78+
assert.doesNotThrow(() => applyAssertionPrototypeMetadata(arrayAssertionError, {
79+
actual: { baseType: 'map', constructorName: 'ExtendedMap' },
80+
}));
81+
82+
// Base type mismatch should not rewrite the value prototype.
83+
const mismatchError = deserializeError(serializeError(objectAssertionError));
84+
applyAssertionPrototypeMetadata(mismatchError, {
85+
actual: {
86+
__proto__: null,
87+
baseType: 'array',
88+
constructorName: 'ExtendedArray',
89+
},
90+
});
91+
assert.strictEqual(mismatchError.actual.constructor.name, 'Object');

0 commit comments

Comments
 (0)