From 45d9e4ce089a3563a5b9895eddb8610c7c8537d4 Mon Sep 17 00:00:00 2001 From: Yaacov Rydzinski Date: Sun, 27 Oct 2024 10:14:03 +0200 Subject: [PATCH] fix: handle default and different types passed to abort method --- src/execution/__tests__/abort-signal-test.ts | 121 +++++++++++++++++-- src/execution/execute.ts | 6 +- 2 files changed, 112 insertions(+), 15 deletions(-) diff --git a/src/execution/__tests__/abort-signal-test.ts b/src/execution/__tests__/abort-signal-test.ts index bf3595298a..6675b5c54d 100644 --- a/src/execution/__tests__/abort-signal-test.ts +++ b/src/execution/__tests__/abort-signal-test.ts @@ -89,7 +89,104 @@ describe('Execute: Cancellation', () => { }, }); - abortController.abort('Aborted'); + abortController.abort(); + + const result = await resultPromise; + + expect(result.errors?.[0].originalError?.name).to.equal('AbortError'); + + expectJSON(result).toDeepEqual({ + data: { + todo: null, + }, + errors: [ + { + message: 'This operation was aborted', + path: ['todo'], + locations: [{ line: 3, column: 9 }], + }, + ], + }); + }); + + it('should stop the execution when aborted during object field completion with a custom error', async () => { + const abortController = new AbortController(); + const document = parse(` + query { + todo { + id + author { + id + } + } + } + `); + + const resultPromise = execute({ + document, + schema, + abortSignal: abortController.signal, + rootValue: { + todo: async () => + Promise.resolve({ + id: '1', + text: 'Hello, World!', + /* c8 ignore next */ + author: () => expect.fail('Should not be called'), + }), + }, + }); + + const customError = new Error('Custom abort error'); + abortController.abort(customError); + + const result = await resultPromise; + + expect(result.errors?.[0].originalError).to.equal(customError); + + expectJSON(result).toDeepEqual({ + data: { + todo: null, + }, + errors: [ + { + message: 'Custom abort error', + path: ['todo'], + locations: [{ line: 3, column: 9 }], + }, + ], + }); + }); + + it('should stop the execution when aborted during object field completion with a custom string', async () => { + const abortController = new AbortController(); + const document = parse(` + query { + todo { + id + author { + id + } + } + } + `); + + const resultPromise = execute({ + document, + schema, + abortSignal: abortController.signal, + rootValue: { + todo: async () => + Promise.resolve({ + id: '1', + text: 'Hello, World!', + /* c8 ignore next */ + author: () => expect.fail('Should not be called'), + }), + }, + }); + + abortController.abort('Custom abort error message'); const result = await resultPromise; @@ -99,7 +196,7 @@ describe('Execute: Cancellation', () => { }, errors: [ { - message: 'Aborted', + message: 'Unexpected error value: "Custom abort error message"', path: ['todo'], locations: [{ line: 3, column: 9 }], }, @@ -135,7 +232,7 @@ describe('Execute: Cancellation', () => { }, }); - abortController.abort('Aborted'); + abortController.abort(); const result = await resultPromise; @@ -148,7 +245,7 @@ describe('Execute: Cancellation', () => { }, errors: [ { - message: 'Aborted', + message: 'This operation was aborted', path: ['todo', 'author'], locations: [{ line: 5, column: 11 }], }, @@ -187,7 +284,7 @@ describe('Execute: Cancellation', () => { abortSignal: abortController.signal, }); - abortController.abort('Aborted'); + abortController.abort(); const result = await resultPromise; @@ -197,7 +294,7 @@ describe('Execute: Cancellation', () => { }, errors: [ { - message: 'Aborted', + message: 'This operation was aborted', path: ['todo'], locations: [{ line: 3, column: 9 }], }, @@ -242,7 +339,7 @@ describe('Execute: Cancellation', () => { await resolveOnNextTick(); await resolveOnNextTick(); - abortController.abort('Aborted'); + abortController.abort(); const result = await resultPromise; @@ -271,7 +368,7 @@ describe('Execute: Cancellation', () => { line: 7, }, ], - message: 'Aborted', + message: 'This operation was aborted', path: ['todo', 'author'], }, ], @@ -304,7 +401,7 @@ describe('Execute: Cancellation', () => { }, }); - abortController.abort('Aborted'); + abortController.abort(); const result = await resultPromise; @@ -315,7 +412,7 @@ describe('Execute: Cancellation', () => { }, errors: [ { - message: 'Aborted', + message: 'This operation was aborted', path: ['bar'], locations: [{ line: 4, column: 9 }], }, @@ -335,7 +432,7 @@ describe('Execute: Cancellation', () => { } } `); - abortController.abort('Aborted'); + abortController.abort(); const result = await execute({ document, schema, @@ -349,7 +446,7 @@ describe('Execute: Cancellation', () => { expectJSON(result).toDeepEqual({ errors: [ { - message: 'Aborted', + message: 'This operation was aborted', }, ], }); diff --git a/src/execution/execute.ts b/src/execution/execute.ts index 427cfc2e1d..855cfcfed4 100644 --- a/src/execution/execute.ts +++ b/src/execution/execute.ts @@ -518,7 +518,7 @@ export function validateExecutionArgs( } = args; if (abortSignal?.aborted) { - return [locatedError(new Error(abortSignal.reason), undefined)]; + return [locatedError(abortSignal.reason, undefined)]; } // If the schema used for execution is invalid, throw an error. @@ -668,7 +668,7 @@ function executeFieldsSerially( const abortSignal = exeContext.validatedExecutionArgs.abortSignal; if (abortSignal?.aborted) { handleFieldError( - new Error(abortSignal.reason), + abortSignal.reason, exeContext, parentType, fieldDetailsList, @@ -1732,7 +1732,7 @@ function completeObjectValue( const abortSignal = validatedExecutionArgs.abortSignal; if (abortSignal?.aborted) { throw locatedError( - new Error(abortSignal.reason), + abortSignal.reason, toNodes(fieldDetailsList), pathToArray(path), );