Skip to content

Commit e9ac393

Browse files
committed
✨(frontend) add sentry
In order to monitor the frontend, we are adding sentry.
1 parent 5b1745f commit e9ac393

File tree

7 files changed

+1114
-138
lines changed

7 files changed

+1114
-138
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to
1717
- ✨(backend) whitelist pod's IP address #443
1818
- ✨(backend) config endpoint #425
1919
- ✨(frontend) config endpoint #424
20+
- ✨(frontend) add sentry #424
2021

2122
## Changed
2223

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
import { expect, test } from '@playwright/test';
22

3+
const config = {
4+
COLLABORATION_SERVER_URL: 'ws://localhost:4444',
5+
ENVIRONMENT: 'development',
6+
FRONTEND_THEME: 'dsfr',
7+
MEDIA_BASE_URL: 'http://localhost:8083',
8+
LANGUAGES: [
9+
['en-us', 'English'],
10+
['fr-fr', 'French'],
11+
['de-de', 'German'],
12+
],
13+
LANGUAGE_CODE: 'en-us',
14+
SENTRY_DSN: null,
15+
};
16+
317
test.describe('Config', () => {
418
test('it checks the config api is called', async ({ page }) => {
519
const responsePromise = page.waitForResponse(
@@ -12,18 +26,34 @@ test.describe('Config', () => {
1226
const response = await responsePromise;
1327
expect(response.ok()).toBeTruthy();
1428

15-
expect(await response.json()).toStrictEqual({
16-
COLLABORATION_SERVER_URL: 'ws://localhost:4444',
17-
ENVIRONMENT: 'development',
18-
FRONTEND_THEME: 'dsfr',
19-
MEDIA_BASE_URL: 'http://localhost:8083',
20-
LANGUAGES: [
21-
['en-us', 'English'],
22-
['fr-fr', 'French'],
23-
['de-de', 'German'],
24-
],
25-
LANGUAGE_CODE: 'en-us',
26-
SENTRY_DSN: null,
29+
expect(await response.json()).toStrictEqual(config);
30+
});
31+
32+
test('it checks that sentry is trying to init from config endpoint', async ({
33+
page,
34+
}) => {
35+
await page.route('**/api/v1.0/config/', async (route) => {
36+
const request = route.request();
37+
if (request.method().includes('GET')) {
38+
await route.fulfill({
39+
json: {
40+
...config,
41+
SENTRY_DSN: 'https://sentry.io/123',
42+
},
43+
});
44+
} else {
45+
await route.continue();
46+
}
47+
});
48+
49+
const invalidMsg = 'Invalid Sentry Dsn: https://sentry.io/123';
50+
const consoleMessage = page.waitForEvent('console', {
51+
timeout: 5000,
52+
predicate: (msg) => msg.text().includes(invalidMsg),
2753
});
54+
55+
await page.goto('/');
56+
57+
expect((await consoleMessage).text()).toContain(invalidMsg);
2858
});
2959
});

src/frontend/apps/impress/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"@gouvfr-lasuite/integration": "1.0.2",
2222
"@hocuspocus/provider": "2.13.7",
2323
"@openfun/cunningham-react": "2.9.4",
24+
"@sentry/nextjs": "8.39.0",
2425
"@tanstack/react-query": "5.60.5",
2526
"i18next": "23.16.5",
2627
"i18next-browser-languagedetector": "8.0.0",

src/frontend/apps/impress/src/__tests__/pages.test.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ jest.mock('next/router', () => ({
1313
},
1414
}));
1515

16+
jest.mock('@sentry/nextjs', () => ({
17+
captureException: jest.fn(),
18+
captureMessage: jest.fn(),
19+
setUser: jest.fn(),
20+
}));
21+
1622
describe('Page', () => {
1723
it('checks Page rendering', () => {
1824
render(<Page />, { wrapper: AppWrapper });
Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
1-
import { PropsWithChildren } from 'react';
1+
import { PropsWithChildren, useEffect } from 'react';
2+
3+
import { useSentryStore } from '@/stores/useSentryStore';
24

35
import { useConfig } from './api/useConfig';
46

57
export const ConfigProvider = ({ children }: PropsWithChildren) => {
6-
useConfig();
8+
const { data: conf } = useConfig();
9+
const { setSentry } = useSentryStore();
10+
11+
useEffect(() => {
12+
if (!conf?.SENTRY_DSN) {
13+
return;
14+
}
15+
16+
setSentry(conf.SENTRY_DSN, conf.ENVIRONMENT);
17+
}, [conf?.SENTRY_DSN, conf?.ENVIRONMENT, setSentry]);
718

819
return children;
920
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as Sentry from '@sentry/nextjs';
2+
import type { Client } from '@sentry/types';
3+
import { create } from 'zustand';
4+
5+
import packageJson from '../../package.json';
6+
7+
interface SentryState {
8+
sentry?: Client;
9+
setSentry: (dsn?: string, environment?: string) => void;
10+
}
11+
12+
export const useSentryStore = create<SentryState>((set, get) => ({
13+
sentry: undefined,
14+
setSentry: (dsn, environment) => {
15+
const sentry = get().sentry;
16+
if (sentry) {
17+
return;
18+
}
19+
20+
set({
21+
sentry: Sentry.init({
22+
dsn,
23+
environment,
24+
integrations: [Sentry.replayIntegration()],
25+
release: packageJson.version,
26+
replaysSessionSampleRate: 0.1,
27+
replaysOnErrorSampleRate: 1.0,
28+
tracesSampleRate: 1.0,
29+
}),
30+
});
31+
},
32+
}));

0 commit comments

Comments
 (0)