Skip to content

Commit

Permalink
fix: Handle unsafe structureClone with functions in matchers whil…
Browse files Browse the repository at this point in the history
…e using workers
  • Loading branch information
dj-stormtrooper committed Aug 21, 2023
1 parent a2a54a0 commit 627031c
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 1 deletion.
34 changes: 34 additions & 0 deletions packages/jest-runner/src/__tests__/helpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import {replaceFunctionsWithStringReferences} from '../helpers';

it('serialize functions inside the nested object', () => {
const obj = {
foo: () => {},
nested: {
fn: function bar() {
return 0;
},
},
nestedArray: [{baz: function baz() {}}, () => {}],
};

expect(replaceFunctionsWithStringReferences(obj)).toEqual({
foo: '[Function foo]',
nested: {
fn: '[Function bar]',
},
nestedArray: [
{
baz: '[Function baz]',
},
'[Function anonymous]',
],
});
});
29 changes: 29 additions & 0 deletions packages/jest-runner/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

export const replaceFunctionsWithStringReferences = <T>(value: T): T => {
if (typeof value === 'function') {
return `[Function ${value.name || 'anonymous'}]` as unknown as T;
}

if (Array.isArray(value)) {
return value.map(replaceFunctionsWithStringReferences) as T;
}

const isObject = value !== null && typeof value === 'object';
if (isObject) {
const oldObject = value as Record<string, unknown>;
const newObject: Record<string, unknown> = {};
for (const key of Object.keys(value)) {
newObject[key] = replaceFunctionsWithStringReferences(oldObject[key]);
}

return newObject as T;
}

return value;
};
24 changes: 23 additions & 1 deletion packages/jest-runner/src/testWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {separateMessageFromStack} from 'jest-message-util';
import type Resolver from 'jest-resolve';
import Runtime from 'jest-runtime';
import {messageParent} from 'jest-worker';
import {replaceFunctionsWithStringReferences} from './helpers';
import runTest from './runTest';
import type {ErrorWithCode, TestRunnerSerializedContext} from './types';

Expand Down Expand Up @@ -92,7 +93,7 @@ export async function worker({
context,
}: WorkerData): Promise<TestResult> {
try {
return await runTest(
const testResult = await runTest(
path,
globalConfig,
config,
Expand All @@ -106,7 +107,28 @@ export async function worker({
},
sendMessageToJest,
);
return makeSerializableTestResults(testResult);
} catch (error: any) {
throw formatError(error);
}
}

function makeSerializableTestResults(result: TestResult): TestResult {
const {testResults} = result;
const serializableResults = testResults.map(resultItem => {
if (resultItem.failureDetails) {
return {
...resultItem,
// Functions cause DataCloneError when passed between workers,
// therefore they are converted to string references
failureDetails: replaceFunctionsWithStringReferences(
resultItem.failureDetails,
),
};
}

return resultItem;
});

return {...result, testResults: serializableResults};
}

0 comments on commit 627031c

Please sign in to comment.