diff --git a/.changeset/chilled-walls-scream.md b/.changeset/chilled-walls-scream.md new file mode 100644 index 000000000000..e487e31679d0 --- /dev/null +++ b/.changeset/chilled-walls-scream.md @@ -0,0 +1,5 @@ +--- +'@solana/rpc': patch +--- + +Fixed a bug where the RPC would fail to throw errors in the event that you configured it with an `AbortSignal` diff --git a/packages/rpc/src/__tests__/rpc-request-coalescer-test.ts b/packages/rpc/src/__tests__/rpc-request-coalescer-test.ts index a8bca1eb7200..f852d54c505c 100644 --- a/packages/rpc/src/__tests__/rpc-request-coalescer-test.ts +++ b/packages/rpc/src/__tests__/rpc-request-coalescer-test.ts @@ -218,4 +218,25 @@ describe('RPC request coalescer', () => { }); }); }); + // https://github.com/solana-labs/solana-web3.js/pull/2910 + describe('regression test #2910', () => { + beforeEach(() => { + // Necessary to prevent the coalescer from bailing out. + hashFn.mockReturnValue('samehash'); + }); + it('throws an error in the case of failure, if it was not configured with an `AbortSignal`', async () => { + expect.assertions(1); + const mockError = { err: 'bad' }; + mockTransport.mockRejectedValueOnce(mockError); + await expect(coalescedTransport({ payload: null })).rejects.toBe(mockError); + }); + it('throws an error in the case of failure, if it was configured with an `AbortSignal`', async () => { + expect.assertions(1); + const mockError = { err: 'bad' }; + mockTransport.mockRejectedValueOnce(mockError); + await expect(coalescedTransport({ payload: null, signal: new AbortController().signal })).rejects.toBe( + mockError, + ); + }); + }); }); diff --git a/packages/rpc/src/rpc-request-coalescer.ts b/packages/rpc/src/rpc-request-coalescer.ts index 2b6b5d4a5b2c..eb05e7bebe79 100644 --- a/packages/rpc/src/rpc-request-coalescer.ts +++ b/packages/rpc/src/rpc-request-coalescer.ts @@ -83,9 +83,12 @@ export function getRpcTransportWithRequestCoalescing { - signal.removeEventListener('abort', handleAbort); - }); + responsePromise + .then(resolve) + .catch(reject) + .finally(() => { + signal.removeEventListener('abort', handleAbort); + }); }); } else { return (await coalescedRequest.responsePromise) as TResponse;