✨(frontend) add sentry
In order to monitor the frontend, we are adding sentry.
This commit is contained in:
@@ -17,6 +17,7 @@ and this project adheres to
|
||||
- ✨(backend) whitelist pod's IP address #443
|
||||
- ✨(backend) config endpoint #425
|
||||
- ✨(frontend) config endpoint #424
|
||||
- ✨(frontend) add sentry #424
|
||||
|
||||
## Changed
|
||||
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
const config = {
|
||||
COLLABORATION_SERVER_URL: 'ws://localhost:4444',
|
||||
ENVIRONMENT: 'development',
|
||||
FRONTEND_THEME: 'dsfr',
|
||||
MEDIA_BASE_URL: 'http://localhost:8083',
|
||||
LANGUAGES: [
|
||||
['en-us', 'English'],
|
||||
['fr-fr', 'French'],
|
||||
['de-de', 'German'],
|
||||
],
|
||||
LANGUAGE_CODE: 'en-us',
|
||||
SENTRY_DSN: null,
|
||||
};
|
||||
|
||||
test.describe('Config', () => {
|
||||
test('it checks the config api is called', async ({ page }) => {
|
||||
const responsePromise = page.waitForResponse(
|
||||
@@ -12,18 +26,34 @@ test.describe('Config', () => {
|
||||
const response = await responsePromise;
|
||||
expect(response.ok()).toBeTruthy();
|
||||
|
||||
expect(await response.json()).toStrictEqual({
|
||||
COLLABORATION_SERVER_URL: 'ws://localhost:4444',
|
||||
ENVIRONMENT: 'development',
|
||||
FRONTEND_THEME: 'dsfr',
|
||||
MEDIA_BASE_URL: 'http://localhost:8083',
|
||||
LANGUAGES: [
|
||||
['en-us', 'English'],
|
||||
['fr-fr', 'French'],
|
||||
['de-de', 'German'],
|
||||
],
|
||||
LANGUAGE_CODE: 'en-us',
|
||||
SENTRY_DSN: null,
|
||||
expect(await response.json()).toStrictEqual(config);
|
||||
});
|
||||
|
||||
test('it checks that sentry is trying to init from config endpoint', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.route('**/api/v1.0/config/', async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET')) {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
...config,
|
||||
SENTRY_DSN: 'https://sentry.io/123',
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await route.continue();
|
||||
}
|
||||
});
|
||||
|
||||
const invalidMsg = 'Invalid Sentry Dsn: https://sentry.io/123';
|
||||
const consoleMessage = page.waitForEvent('console', {
|
||||
timeout: 5000,
|
||||
predicate: (msg) => msg.text().includes(invalidMsg),
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
expect((await consoleMessage).text()).toContain(invalidMsg);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"@gouvfr-lasuite/integration": "1.0.2",
|
||||
"@hocuspocus/provider": "2.13.7",
|
||||
"@openfun/cunningham-react": "2.9.4",
|
||||
"@sentry/nextjs": "8.39.0",
|
||||
"@tanstack/react-query": "5.60.5",
|
||||
"i18next": "23.16.5",
|
||||
"i18next-browser-languagedetector": "8.0.0",
|
||||
|
||||
@@ -13,6 +13,12 @@ jest.mock('next/router', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('@sentry/nextjs', () => ({
|
||||
captureException: jest.fn(),
|
||||
captureMessage: jest.fn(),
|
||||
setUser: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('Page', () => {
|
||||
it('checks Page rendering', () => {
|
||||
render(<Page />, { wrapper: AppWrapper });
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
import { PropsWithChildren } from 'react';
|
||||
import { PropsWithChildren, useEffect } from 'react';
|
||||
|
||||
import { useSentryStore } from '@/stores/useSentryStore';
|
||||
|
||||
import { useConfig } from './api/useConfig';
|
||||
|
||||
export const ConfigProvider = ({ children }: PropsWithChildren) => {
|
||||
useConfig();
|
||||
const { data: conf } = useConfig();
|
||||
const { setSentry } = useSentryStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (!conf?.SENTRY_DSN) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSentry(conf.SENTRY_DSN, conf.ENVIRONMENT);
|
||||
}, [conf?.SENTRY_DSN, conf?.ENVIRONMENT, setSentry]);
|
||||
|
||||
return children;
|
||||
};
|
||||
|
||||
32
src/frontend/apps/impress/src/stores/useSentryStore.tsx
Normal file
32
src/frontend/apps/impress/src/stores/useSentryStore.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
import type { Client } from '@sentry/types';
|
||||
import { create } from 'zustand';
|
||||
|
||||
import packageJson from '../../package.json';
|
||||
|
||||
interface SentryState {
|
||||
sentry?: Client;
|
||||
setSentry: (dsn?: string, environment?: string) => void;
|
||||
}
|
||||
|
||||
export const useSentryStore = create<SentryState>((set, get) => ({
|
||||
sentry: undefined,
|
||||
setSentry: (dsn, environment) => {
|
||||
const sentry = get().sentry;
|
||||
if (sentry) {
|
||||
return;
|
||||
}
|
||||
|
||||
set({
|
||||
sentry: Sentry.init({
|
||||
dsn,
|
||||
environment,
|
||||
integrations: [Sentry.replayIntegration()],
|
||||
release: packageJson.version,
|
||||
replaysSessionSampleRate: 0.1,
|
||||
replaysOnErrorSampleRate: 1.0,
|
||||
tracesSampleRate: 1.0,
|
||||
}),
|
||||
});
|
||||
},
|
||||
}));
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user