-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(tracing): Support Apollo/GraphQL with NestJS (#7194)
Co-authored-by: Abhijeet Prasad <[email protected]>
- Loading branch information
1 parent
79babe9
commit a8449de
Showing
2 changed files
with
230 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
packages/tracing/test/integrations/apollo-nestjs.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/* eslint-disable @typescript-eslint/unbound-method */ | ||
import { Hub, Scope } from '@sentry/core'; | ||
import { logger } from '@sentry/utils'; | ||
|
||
import { Apollo } from '../../src/integrations/node/apollo'; | ||
import { Span } from '../../src/span'; | ||
import { getTestClient } from '../testutils'; | ||
|
||
type ApolloResolverGroup = { | ||
[key: string]: () => unknown; | ||
}; | ||
|
||
type ApolloModelResolvers = { | ||
[key: string]: ApolloResolverGroup; | ||
}; | ||
|
||
class GraphQLFactory { | ||
_resolvers: ApolloModelResolvers[]; | ||
resolversExplorerService = { | ||
explore: () => this._resolvers, | ||
}; | ||
constructor() { | ||
this._resolvers = [ | ||
{ | ||
Query: { | ||
res_1(..._args: unknown[]) { | ||
return 'foo'; | ||
}, | ||
}, | ||
Mutation: { | ||
res_2(..._args: unknown[]) { | ||
return 'bar'; | ||
}, | ||
}, | ||
}, | ||
]; | ||
|
||
this.mergeWithSchema(); | ||
} | ||
|
||
public mergeWithSchema(..._args: unknown[]) { | ||
return this.resolversExplorerService.explore(); | ||
} | ||
} | ||
|
||
// mock for @nestjs/graphql package | ||
jest.mock('@sentry/utils', () => { | ||
const actual = jest.requireActual('@sentry/utils'); | ||
return { | ||
...actual, | ||
loadModule() { | ||
return { | ||
GraphQLFactory, | ||
}; | ||
}, | ||
}; | ||
}); | ||
|
||
describe('setupOnce', () => { | ||
let scope = new Scope(); | ||
let parentSpan: Span; | ||
let childSpan: Span; | ||
let GraphQLFactoryInstance: GraphQLFactory; | ||
|
||
beforeAll(() => { | ||
new Apollo({ | ||
useNestjs: true, | ||
}).setupOnce( | ||
() => undefined, | ||
() => new Hub(undefined, scope), | ||
); | ||
|
||
GraphQLFactoryInstance = new GraphQLFactory(); | ||
}); | ||
|
||
beforeEach(() => { | ||
scope = new Scope(); | ||
parentSpan = new Span(); | ||
childSpan = parentSpan.startChild(); | ||
jest.spyOn(scope, 'getSpan').mockReturnValueOnce(parentSpan); | ||
jest.spyOn(scope, 'setSpan'); | ||
jest.spyOn(parentSpan, 'startChild').mockReturnValueOnce(childSpan); | ||
jest.spyOn(childSpan, 'finish'); | ||
}); | ||
|
||
it('should wrap a simple resolver', () => { | ||
GraphQLFactoryInstance._resolvers[0]?.['Query']?.['res_1']?.(); | ||
expect(scope.getSpan).toBeCalled(); | ||
expect(parentSpan.startChild).toBeCalledWith({ | ||
description: 'Query.res_1', | ||
op: 'graphql.resolve', | ||
}); | ||
expect(childSpan.finish).toBeCalled(); | ||
}); | ||
|
||
it('should wrap another simple resolver', () => { | ||
GraphQLFactoryInstance._resolvers[0]?.['Mutation']?.['res_2']?.(); | ||
expect(scope.getSpan).toBeCalled(); | ||
expect(parentSpan.startChild).toBeCalledWith({ | ||
description: 'Mutation.res_2', | ||
op: 'graphql.resolve', | ||
}); | ||
expect(childSpan.finish).toBeCalled(); | ||
}); | ||
|
||
it("doesn't attach when using otel instrumenter", () => { | ||
const loggerLogSpy = jest.spyOn(logger, 'log'); | ||
|
||
const client = getTestClient({ instrumenter: 'otel' }); | ||
const hub = new Hub(client); | ||
|
||
const integration = new Apollo({ useNestjs: true }); | ||
integration.setupOnce( | ||
() => {}, | ||
() => hub, | ||
); | ||
|
||
expect(loggerLogSpy).toBeCalledWith('Apollo Integration is skipped because of instrumenter configuration.'); | ||
}); | ||
}); |