From a3d929dc19dae5b8b20f3a90177fe496b76bfd8f Mon Sep 17 00:00:00 2001 From: repl-sarath Date: Thu, 16 Dec 2021 16:31:53 +0530 Subject: [PATCH] fix: include partial GraphQL errors in breadcrumbs (#410) Co-authored-by: spawnia --- src/SentryLink.ts | 12 +++++++++ tests/SentryLink.test.ts | 53 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/SentryLink.ts b/src/SentryLink.ts index 45dda9f..880490f 100644 --- a/src/SentryLink.ts +++ b/src/SentryLink.ts @@ -1,4 +1,5 @@ import { + ApolloError, ApolloLink, FetchResult, NextLink, @@ -62,6 +63,17 @@ export class SentryLink extends ApolloLink { // We must have a breadcrumb if attachBreadcrumbs was set (breadcrumb as GraphQLBreadcrumb).data.fetchResult = result; } + + if ( + this.options.attachBreadcrumbs.includeError && + result.errors && + result.errors.length > 1 + ) { + // We must have a breadcrumb if attachBreadcrumbs was set + (breadcrumb as GraphQLBreadcrumb).data.error = new ApolloError({ + graphQLErrors: result.errors, + }); + } } originalObserver.next(result); diff --git a/tests/SentryLink.test.ts b/tests/SentryLink.test.ts index be7d269..e38fa42 100644 --- a/tests/SentryLink.test.ts +++ b/tests/SentryLink.test.ts @@ -1,4 +1,9 @@ -import { ApolloLink, execute, ServerError } from '@apollo/client/core'; +import { + ApolloError, + ApolloLink, + execute, + ServerError, +} from '@apollo/client/core'; import * as Sentry from '@sentry/browser'; import { Severity } from '@sentry/browser'; import { GraphQLError, parse } from 'graphql'; @@ -118,6 +123,52 @@ describe('SentryLink', () => { }); }); + it('should attach a breadcrumb with partial errors', (done) => { + const errors = [ + new GraphQLError('partial failure'), + new GraphQLError('another failure'), + ]; + const result = { + data: { foo: true }, + errors: errors, + }; + const withPartialErrors = ApolloLink.from([ + new SentryLink({ + attachBreadcrumbs: { includeFetchResult: true, includeError: true }, + }), + new ApolloLink( + () => + new Observable((observer) => { + observer.next(result); + observer.complete(); + }), + ), + ]); + + execute(withPartialErrors, { + query: parse(`query PartialErrors { foo }`), + }).subscribe({ + complete() { + Sentry.captureException(new Error()); + + const [report] = testkit.reports(); + expect(report.breadcrumbs).toHaveLength(1); + + const [breadcrumb] = report.breadcrumbs as Array; + + expect(breadcrumb.category).toBe('graphql.query'); + expect(breadcrumb.level).toBe(Severity.Error); + expect(breadcrumb.data.operationName).toBe('PartialErrors'); + expect(breadcrumb.data.fetchResult).toBe(stringify(result)); + expect(breadcrumb.data.error).toBe( + stringify(new ApolloError({ graphQLErrors: errors })), + ); + + done(); + }, + }); + }); + it('should mark results with errors with level error', (done) => { const link = ApolloLink.from([ new SentryLink(),