From d5ad4c734556f7de1e1fe51e625a40207929dc56 Mon Sep 17 00:00:00 2001 From: Ilya Kuznetsov Date: Mon, 21 Aug 2023 23:30:30 +0400 Subject: [PATCH 1/2] fix: Additional error wrapper for `postMessage` to avoid unhandled `DataCloneError` --- .../src/workers/__tests__/threadChild.test.ts | 21 +++++++++++++++++++ .../jest-worker/src/workers/threadChild.ts | 9 +++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/jest-worker/src/workers/__tests__/threadChild.test.ts b/packages/jest-worker/src/workers/__tests__/threadChild.test.ts index 649317919f6f..b7637963969f 100644 --- a/packages/jest-worker/src/workers/__tests__/threadChild.test.ts +++ b/packages/jest-worker/src/workers/__tests__/threadChild.test.ts @@ -365,3 +365,24 @@ it('throws if child is not forked', () => { messagePort.emit('message', [CHILD_MESSAGE_CALL, true, 'fooThrows', []]); }).toThrow('_worker_threads.parentPort.postMessage is not a function'); }); + +it('handle error if `postMessage` throws an error', () => { + messagePort.emit('message', [ + CHILD_MESSAGE_INITIALIZE, + true, + './my-fancy-worker', + ]); + + jest.mocked(messagePort.postMessage).mockImplementationOnce(() => { + throw mockError; + }); + + messagePort.emit('message', [CHILD_MESSAGE_CALL, true, 'fooWorks', []]); + expect(jest.mocked(messagePort.postMessage).mock.calls[1][0]).toEqual([ + PARENT_MESSAGE_CLIENT_ERROR, + 'TypeError', + 'Boo', + mockError.stack, + {}, + ]); +}); diff --git a/packages/jest-worker/src/workers/threadChild.ts b/packages/jest-worker/src/workers/threadChild.ts index 2380e1afd23c..efd31d04ed37 100644 --- a/packages/jest-worker/src/workers/threadChild.ts +++ b/packages/jest-worker/src/workers/threadChild.ts @@ -112,7 +112,14 @@ function reportSuccess(result: unknown) { throw new Error('Child can only be used on a forked process'); } - parentPort!.postMessage([PARENT_MESSAGE_OK, result]); + try { + parentPort!.postMessage([PARENT_MESSAGE_OK, result]); + } catch (err: any) { + // Handling it here to avoid unhandled `DataCloneError` rejection + // which is hard to distinguish on the parent side + // (such error doesn't have any message or stack trace) + reportClientError(err); + } } function reportClientError(error: Error) { From 6b116823209f839485cd70fcc143318eafec5fff Mon Sep 17 00:00:00 2001 From: Ilya Kuznetsov Date: Tue, 22 Aug 2023 11:17:41 +0400 Subject: [PATCH 2/2] chore: Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bbc4accd8ca..1e0bee2c1202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - `[expect]` Remove `@types/node` from dependencies ([#14385](https://github.com/jestjs/jest/pull/14385)) - `[jest-core]` Use workers in watch mode by default to avoid crashes ([#14059](https://github.com/facebook/jest/pull/14059) & [#14085](https://github.com/facebook/jest/pull/14085)). - `[jest-reporters]` Update `istanbul-lib-instrument` dependency to v6. ([#14401](https://github.com/jestjs/jest/pull/14401)) +- `[jest-worker]` Additional error wrapper for `parentPort.postMessage` to fix unhandled `DataCloneError`. ([#14437](https://github.com/jestjs/jest/pull/14437)) ### Chore & Maintenance