Skip to content

Commit 223d330

Browse files
feat(gatsby): Support user integrations as a function (getsentry#4050)
The goal is to make the Gatsby SDK support non-serializable options, which means supporting the definition of integrations as a function.
1 parent 1d8c500 commit 223d330

File tree

3 files changed

+100
-16
lines changed

3 files changed

+100
-16
lines changed

packages/gatsby/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from '@sentry/react';
2+
export { Integrations } from '@sentry/tracing';
23

34
export { init } from './sdk';

packages/gatsby/src/utils/integrations.ts

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,54 @@ import { Integration } from '@sentry/types';
33

44
import { GatsbyOptions } from './types';
55

6+
type UserFnIntegrations = (integrations: Integration[]) => Integration[];
7+
export type UserIntegrations = Integration[] | UserFnIntegrations;
8+
69
/**
710
* Returns the integrations to add to the SDK.
811
* If tracing is enabled, `BrowserTracing` is always present.
912
*
1013
* @param options The options users have defined.
1114
*/
12-
export function getIntegrationsFromOptions(options: GatsbyOptions): Integration[] {
13-
const integrations = [...(options.integrations || [])];
15+
export function getIntegrationsFromOptions(options: GatsbyOptions): UserIntegrations {
16+
const isTracingEnabled = Tracing.hasTracingEnabled(options);
17+
if (options.integrations === undefined) {
18+
return getIntegrationsFromArray([], isTracingEnabled);
19+
} else if (Array.isArray(options.integrations)) {
20+
return getIntegrationsFromArray(options.integrations, isTracingEnabled);
21+
} else {
22+
return getIntegrationsFromFunction(options.integrations, isTracingEnabled);
23+
}
24+
}
25+
26+
/**
27+
* Returns the integrations to add to the SDK, from the given integrations array.
28+
*
29+
* @param userIntegrations Array of user's integrations.
30+
* @param isTracingEnabled Whether the user has enabled tracing.
31+
*/
32+
function getIntegrationsFromArray(userIntegrations: Integration[], isTracingEnabled: boolean): Integration[] {
1433
if (
15-
Tracing.hasTracingEnabled(options) &&
16-
!integrations.some(integration => integration.name === Tracing.Integrations.BrowserTracing.name)
34+
isTracingEnabled &&
35+
!userIntegrations.some(integration => integration.name === Tracing.Integrations.BrowserTracing.name)
1736
) {
18-
integrations.push(new Tracing.Integrations.BrowserTracing());
37+
userIntegrations.push(new Tracing.Integrations.BrowserTracing());
1938
}
20-
return integrations;
39+
return userIntegrations;
40+
}
41+
42+
/**
43+
* Returns the integrations to add to the SDK, from the given function.
44+
*
45+
* @param userIntegrations Function returning the user's integrations.
46+
* @param isTracingEnabled Whether the user has enabled tracing.
47+
*/
48+
function getIntegrationsFromFunction(
49+
userIntegrations: UserFnIntegrations,
50+
isTracingEnabled: boolean,
51+
): UserFnIntegrations {
52+
const wrapper: UserFnIntegrations = (defaultIntegrations: Integration[]) => {
53+
return getIntegrationsFromArray(userIntegrations(defaultIntegrations), isTracingEnabled);
54+
};
55+
return wrapper;
2156
}

packages/gatsby/test/sdk.test.ts

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Integrations } from '@sentry/tracing';
33
import { Integration, Package } from '@sentry/types';
44

55
import { defaultOptions, init as gatsbyInit } from '../src/sdk';
6+
import { UserIntegrations } from '../src/utils/integrations';
67
import { GatsbyOptions } from '../src/utils/types';
78

89
const reactInit = reactInitRaw as jest.Mock;
@@ -65,28 +66,75 @@ describe('Integrations from options', () => {
6566
afterEach(() => reactInit.mockClear());
6667

6768
test.each([
68-
['tracing disabled, no integrations', {}, []],
69-
['tracing enabled, no integrations', { tracesSampleRate: 1 }, ['BrowserTracing']],
69+
['tracing disabled, no integrations', [], {}, []],
70+
['tracing enabled, no integrations', [], { tracesSampleRate: 1 }, ['BrowserTracing']],
7071
[
71-
'tracing disabled, with Integrations.BrowserTracing',
72+
'tracing disabled, with Integrations.BrowserTracing as an array',
73+
[],
7274
{ integrations: [new Integrations.BrowserTracing()] },
7375
['BrowserTracing'],
7476
],
7577
[
76-
'tracing enabled, with Integrations.BrowserTracing',
78+
'tracing disabled, with Integrations.BrowserTracing as a function',
79+
[],
80+
{
81+
integrations: () => [new Integrations.BrowserTracing()],
82+
},
83+
['BrowserTracing'],
84+
],
85+
[
86+
'tracing enabled, with Integrations.BrowserTracing as an array',
87+
[],
7788
{ tracesSampleRate: 1, integrations: [new Integrations.BrowserTracing()] },
7889
['BrowserTracing'],
7990
],
8091
[
81-
'tracing enabled, with another integration',
92+
'tracing enabled, with Integrations.BrowserTracing as a function',
93+
[],
94+
{ tracesSampleRate: 1, integrations: () => [new Integrations.BrowserTracing()] },
95+
['BrowserTracing'],
96+
],
97+
[
98+
'tracing enabled, with another integration as an array',
99+
[],
82100
{ tracesSampleRate: 1, integrations: [new Integrations.Express()] },
83101
['Express', 'BrowserTracing'],
84102
],
85-
['tracing disabled, with another integration', { integrations: [new Integrations.Express()] }, ['Express']],
86-
])('%s', (_testName, options: GatsbyOptions, expectedIntNames: string[]) => {
103+
[
104+
'tracing enabled, with another integration as a function',
105+
[],
106+
{ tracesSampleRate: 1, integrations: () => [new Integrations.Express()] },
107+
['Express', 'BrowserTracing'],
108+
],
109+
[
110+
'tracing disabled, with another integration as an array',
111+
[],
112+
{ integrations: [new Integrations.Express()] },
113+
['Express'],
114+
],
115+
[
116+
'tracing disabled, with another integration as a function',
117+
[],
118+
{ integrations: () => [new Integrations.Express()] },
119+
['Express'],
120+
],
121+
[
122+
'merges integrations with user integrations as a function',
123+
[new Integrations.Mongo()],
124+
{
125+
tracesSampleRate: 1,
126+
integrations: (defaultIntegrations: Integration[]): Integration[] => [
127+
...defaultIntegrations,
128+
new Integrations.Express(),
129+
],
130+
},
131+
['Mongo', 'Express', 'BrowserTracing'],
132+
],
133+
])('%s', (_testName, defaultIntegrations: Integration[], options: GatsbyOptions, expectedIntNames: string[]) => {
87134
gatsbyInit(options);
88-
const integrations: Integration[] = reactInit.mock.calls[0][0].integrations;
89-
expect(integrations).toHaveLength(expectedIntNames.length);
90-
integrations.map((integration, idx) => expect(integration.name).toStrictEqual(expectedIntNames[idx]));
135+
const integrations: UserIntegrations = reactInit.mock.calls[0][0].integrations;
136+
const arrIntegrations = Array.isArray(integrations) ? integrations : integrations(defaultIntegrations);
137+
expect(arrIntegrations).toHaveLength(expectedIntNames.length);
138+
arrIntegrations.map((integration, idx) => expect(integration.name).toStrictEqual(expectedIntNames[idx]));
91139
});
92140
});

0 commit comments

Comments
 (0)