8000 ref(gatsby): Make `@sentry/tracing` mandatory + add tests (#2841) · ebeloded/sentry-javascript@f070384 · GitHub
[go: up one dir, main page]

Skip to content

Commit f070384

Browse files
authored
ref(gatsby): Make @sentry/tracing mandatory + add tests (getsentry#2841)
* test: Add gatsby-browser, gatsby-node and integration tests * ref: Make `@sentry/tracing` required dependency * fix: Remove require.ensure call to prevent delay in Sentry init
1 parent 0df3981 commit f070384

14 files changed

+329
-102
lines changed

packages/gatsby/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module.exports = {
77
},
88
parserOptions: {
99
ecmaVersion: 2018,
10+
jsx: true,
1011
},
1112
extends: ['@sentry-internal/sdk'],
1213
ignorePatterns: ['build/**', 'dist/**', 'esm/**', 'examples/**', 'scripts/**'],

packages/gatsby/README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ To automatically capture the `release` value on Vercel you will need to register
4040

4141
## Sentry Performance
4242

43-
To enable Tracing support, supply the `tracesSampleRate` to the options and make sure you have installed the `@sentry/tracing` package.
43+
To enable Tracing support, supply the `tracesSampleRate` to the options and make sure you have installed the `@sentry/tracing` package. This will also turn on the `BrowserTracing` integration for automatic instrumentation of the browser.
4444

4545
```javascript
4646
{
@@ -58,6 +58,28 @@ To enable Tracing support, supply the `tracesSampleRate` to the options and make
5858
}
5959
```
6060

61+
If you want to supply options to the `BrowserTracing` integration, use the `browserTracingOptions` parameter.
62+
63+
```javascript
64+
{
65+
// ...
66+
plugins: [
67+
{
68+
resolve: "@sentry/gatsby",
69+
options: {
70+
dsn: process.env.SENTRY_DSN, // this is the default
71+
tracesSampleRate: 1, // this is just to test, you should lower this in production
72+
browserTracingOptions: {
73+
// disable creating spans for XHR requests
74+
traceXHR: false,
75+
}
76+
}
77+
},
78+
// ...
79+
]
80+
}
81+
```
82+
6183
## Links
6284

6385
- [Official SDK Docs](https://docs.sentry.io/quickstart/)

packages/gatsby/gatsby-browser.js

Lines changed: 37 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,45 @@
1+
const Sentry = require('@sentry/react');
2+
const Tracing = require('@sentry/tracing');
3+
14
exports.onClientEntry = function(_, pluginParams) {
2-
require.ensure(['@sentry/react'], function(require) {
3-
const Sentry = require('@sentry/react');
5+
if (pluginParams === undefined) {
6+
return;
7+
}
48

5-
let TracingIntegration = undefined;
6-
let BrowserTracingIntegration = undefined;
7-
try {
8-
BrowserTracingIntegration = require('@sentry/tracing').Integrations.BrowserTracing;
9-
} catch (_) {
10-
/* no-empty */
11-
}
12-
try {
13-
/** @deprecated Remove when @sentry/apm is no longer used */
14-
TracingIntegration = require('@sentry/apm').Integrations.Tracing;
15-
} catch (_) {
16-
/* no-empty */
17-
}
9+
const tracesSampleRate = pluginParams.tracesSampleRate !== undefined ? pluginParams.tracesSampleRate : 0;
10+
const integrations = [...(pluginParams.integrations || [])];
1811

19-
const tracesSampleRate = pluginParams.tracesSampleRate !== undefined ? pluginParams.tracesSampleRate : 0;
20-
const integrations = [...(pluginParams.integrations || [])];
12+
if (tracesSampleRate && !integrations.some(ele => ele.name === 'BrowserTracing')) {
13+
integrations.push(new Tracing.Integrations.BrowserTracing(pluginParams.browserTracingOptions));
14+
}
2115

22-
if (tracesSampleRate) {
23-
if (BrowserTracingIntegration) {
24-
integrations.push(new BrowserTracingIntegration());
25-
} else if (TracingIntegration) {
26-
integrations.push(new TracingIntegration());
27-
}
28-
}
16+
Tracing.addExtensionMethods();
2917

30-
Sentry.init({
31-
environment: process.env.NODE_ENV || 'development',
32-
// eslint-disable-next-line no-undef
33-
release: __SENTRY_RELEASE__,
34-
// eslint-disable-next-line no-undef
35-
dsn: __SENTRY_DSN__,
36-
...pluginParams,
37-
tracesSampleRate,
38-
integrations,
39-
});
18+
Sentry.init({
19+
environment: process.env.NODE_ENV || 'development',
20+
// eslint-disable-next-line no-undef
21+
release: __SENTRY_RELEASE__,
22+
// eslint-disable-next-line no-undef
23+
dsn: __SENTRY_DSN__,
24+
...pluginParams,
25+
tracesSampleRate,
26+
integrations,
27+
});
4028

41-
Sentry.addGlobalEventProcessor(event => {
42-
event.sdk = {
43-
...event.sdk,
44-
name: 'sentry.javascript.gatsby',
45-
packages: [
46-
...((event.sdk && event.sdk.packages) || []),
47-
{
48-
name: 'npm:@sentry/gatsby',
49-
version: Sentry.SDK_VERSION,
50-
},
51-
],
52-
version: Sentry.SDK_VERSION,
53-
};
54-
return event;
55-
});
56-
window.Sentry = Sentry;
29+
Sentry.addGlobalEventProcessor(event => {
30+
event.sdk = {
31+
...event.sdk,
32+
name: 'sentry.javascript.gatsby',
33+
packages: [
34+
...((event.sdk && event.sdk.packages) || []),
35+
{
36+
name: 'npm:@sentry/gatsby',
37+
version: Sentry.SDK_VERSION,
38+
},
39+
],
40+
version: Sentry.SDK_VERSION,
41+
};
42+
return event;
5743
});
44+
window.Sentry = Sentry;
5845
};

packages/gatsby/gatsby-node.js

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
1+
const sentryRelease = JSON.stringify(
2+
// Always read first as Sentry takes this as precedence
3+
process.env.SENTRY_RELEASE ||
4+
// GitHub Actions - https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables#default-environment-variables
5+
process.env.GITHUB_SHA ||
6+
// Netlify - https://docs.netlify.com/configure-builds/environment-variables/#build-metadata
7+
process.env.COMMIT_REF ||
8+
// Vercel - https://vercel.com/docs/v2/build-step#system-environment-variables
9+
process.env.VERCEL_GITHUB_COMMIT_SHA ||
10+
process.env.VERCEL_GITLAB_COMMIT_SHA ||
11+
process.env.VERCEL_BITBUCKET_COMMIT_SHA ||
12+
// Zeit (now known as Vercel)
13+
process.env.ZEIT_GITHUB_COMMIT_SHA ||
14+
process.env.ZEIT_GITLAB_COMMIT_SHA ||
15+
process.env.ZEIT_BITBUCKET_COMMIT_SHA ||
16+
'',
17+
);
18+
19+
const sentryDsn = JSON.stringify(process.env.SENTRY_DSN || '');
20+
121
exports.onCreateWebpackConfig = ({ plugins, actions }) => {
222
actions.setWebpackConfig({
323
plugins: [
424
plugins.define({
5-
__SENTRY_RELEASE__: JSON.stringify(
6-
process.env.SENTRY_RELEASE ||
7-
// GitHub Actions - https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables#default-environment-variables
8-
process.env.GITHUB_SHA ||
9-
// Netlify - https://docs.netlify.com/configure-builds/environment-variables/#build-metadata
10-
process.env.COMMIT_REF ||
11-
// Vercel - https://vercel.com/docs/v2/build-step#system-environment-variables
12-
process.env.VERCEL_GITHUB_COMMIT_SHA ||
13-
process.env.VERCEL_GITLAB_COMMIT_SHA ||
14-
process.env.VERCEL_BITBUCKET_COMMIT_SHA ||
15-
// Zeit (now known as Vercel)
16-
process.env.ZEIT_GITHUB_COMMIT_SHA ||
17-
process.env.ZEIT_GITLAB_COMMIT_SHA ||
18-
process.env.ZEIT_BITBUCKET_COMMIT_SHA ||
19-
'',
20-
),
21-
__SENTRY_DSN__: JSON.stringify(process.env.SENTRY_DSN || ''),
25+
__SENTRY_RELEASE__: sentryRelease,
26+
__SENTRY_DSN__: sentryDsn,
2227
}),
2328
],
2429
});

packages/gatsby/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,19 @@
2727
},
2828
"dependencies": {
2929
"@sentry/react": "5.21.4",
30-
"@sentry/types": "5.21.4"
30+
"@sentry/tracing": "5.21.4"
3131
},
3232
"peerDependencies": {
3333
"gatsby": "*"
3434
},
3535
"devDependencies": {
3636
"@sentry-internal/eslint-config-sdk": "5.21.4",
37+
"@testing-library/react": "^10.4.9",
3738
"eslint": "7.6.0",
3839
"jest": "^24.7.1",
3940
"npm-run-all": "^4.1.2",
4041
"prettier": "1.17.0",
42+
"react": "^16.13.1",
4143
"rimraf": "^2.6.3",
4244
"typescript": "3.9.7"
4345
},
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/* eslint-disable @typescript-eslint/no-var-requires */
2+
/* eslint-disable @typescript-eslint/no-explicit-any */
3+
4+
const { onClientEntry } = require('../gatsby-browser');
5+
6+
(global as any).__SENTRY_RELEASE__ = '683f3a6ab819d47d23abfca9a914c81f0524d35b';
7+
(global as any).__SENTRY_DSN__ = 'https://examplePublicKey@o0.ingest.sentry.io/0';
8+
9+
let sentryInit = jest.fn();
10+
let sentryProcessEvent: <T>(event: T) => T;
11+
jest.mock('@sentry/react', () => {
12+
const original = jest.requireActual('@sentry/react');
13+
return {
14+
...original,
15+
init: (...args: any[]) => {
16+
sentryInit(...args);
17+
},
18+
addGlobalEventProcessor: (callback: any) => {
19+
sentryProcessEvent = callback;
20+
},
21+
};
22+
});
23+
24+
let tracingAddExtensionMethods = jest.fn();
25+
jest.mock('@sentry/tracing', () => {
26+
const original = jest.requireActual('@sentry/tracing');
27+
return {
28+
...original,
29+
addExtensionMethods: (...args: any[]) => {
30+
tracingAddExtensionMethods(...args);
31+
},
32+
};
33+
});
34+
35+
describe('onClientEntry', () => {
36+
beforeEach(() => {
37+
sentryInit = jest.fn();
38+
tracingAddExtensionMethods = jest.fn();
39+
40+
// @ts-ignore need to set as undefined
41+
sentryProcessEvent = undefined;
42+
});
43+
44+
afterEach(() => {
45+
(window as any).Sentry = undefined;
46+
});
47+
48+
it('inits Sentry by default', () => {
49+
onClientEntry(undefined, {});
50+
expect(sentryInit).toHaveBeenCalledTimes(1);
51+
expect(sentryInit).toHaveBeenLastCalledWith({
52+
dsn: (global as any).__SENTRY_DSN__,
53+
environment: process.env.NODE_ENV,
54+
integrations: [],
55+
release: (global as any).__SENTRY_RELEASE__,
56+
tracesSampleRate: 0,
57+
});
58+
});
59+
60+
it('sets window.Sentry', () => {
61+
onClientEntry(undefined, {});
62+
expect((window as any).Sentry).not.toBeUndefined();
63+
});
64+
65+
it('adds a global event processor', () => {
66+
onClientEntry(undefined, {});
67+
if (sentryProcessEvent) {
68+
const changedEvent = sentryProcessEvent({});
69+
70+
expect(changedEvent).toEqual({
71+
sdk: {
72+
name: 'sentry.javascript.gatsby',
73+
packages: [
74+
{
75+
name: 'npm:@sentry/gatsby',
76+
version: expect.any(String),
77+
},
78+
],
79+
version: expect.any(String),
80+
},
81+
});
82+
} else {
83+
fail('process event not defined');
84+
}
85+
});
86+
87+
it('adds Tracing extension methods', () => {
88+
onClientEntry(undefined, {});
89+
90+
expect(tracingAddExtensionMethods).toHaveBeenCalledTimes(1);
91+
expect(tracingAddExtensionMethods).toHaveBeenLastCalledWith();
92+
});
93+
94+
it('sets a tracesSampleRate if defined as option', () => {
95+
onClientEntry(undefined, { tracesSampleRate: 0.5 });
96+
expect(sentryInit).toHaveBeenLastCalledWith(
97+
expect.objectContaining({
98+
tracesSampleRate: 0.5,
99+
}),
100+
);
101+
});
102+
103+
it('adds `BrowserTracing` integration if tracesSampleRate is defined', () => {
104+
onClientEntry(undefined, { tracesSampleRate: 0.5 });
105+
expect(sentryInit).toHaveBeenLastCalledWith(
106+
expect.objectContaining({
107+
integrations: [expect.objectContaining({ name: 'BrowserTracing' })],
108+
}),
109+
);
110+
});
111+
112+
it('only defines a single `BrowserTracing` integration', () => {
113+
const Tracing = jest.requireActual('@sentry/tracing');
114+
const integrations = [new Tracing.Integrations.BrowserTracing()];
115+
onClientEntry(undefined, { tracesSampleRate: 0.5, integrations });
116+
117+
expect(sentryInit).toHaveBeenLastCalledWith(
118+
expect.objectContaining({
119+
integrations: [expect.objectContaining({ name: 'BrowserTracing' })],
120+
}),
121+
);
122+
});
123+
124+
// Run this last to check for any test side effects
125+
it('does not run if plugin params are undefined', () => {
126+
onClientEntry();
127+
expect(sentryInit).toHaveBeenCalledTimes(0);
128+
expect((window as any).Sentry).toBeUndefined();
129+
expect(sentryProcessEvent).toBeUndefined();
130+
expect(tracingAddExtensionMethods).toHaveBeenCalledTimes(0);
131+
});
132+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* eslint-disable @typescript-eslint/no-var-requires */
2+
/* eslint-disable @typescript-eslint/no-explicit-any */
3+
4+
const { onCreateWebpackConfig } = require('../gatsby-node');
5+
6+
describe('onCreateWebpackConfig', () => {
7+
it('sets a webpack config', () => {
8+
const plugins = {
9+
define: jest.fn(),
10+
};
11+
12+
const actions = {
13+
setWebpackConfig: jest.fn(),
14+
};
15+
16+
onCreateWebpackConfig({ plugins, actions });
17+
18+
expect(plugins.define).toHaveBeenCalledTimes(1);
19+
expect(plugins.define).toHaveBeenLastCalledWith({
20+
__SENTRY_DSN__: expect.any(String),
21+
__SENTRY_RELEASE__: expect.any(String),
22+
});
23+
24+
expect(actions.setWebpackConfig).toHaveBeenCalledTimes(1);
25+
expect(actions.setWebpackConfig).toHaveBeenLastCalledWith({ plugins: expect.any(Array) });
26+
});
27+
});

0 commit comments

Comments
 (0)
0