Continuous Integration / config (pull_request) Successful in 11s
Continuous Integration / prepare (pull_request) Successful in 1m18s
Continuous Integration / build-production (pull_request) Skipped
Continuous Integration / build (pull_request) Successful in 2m2s
Continuous Integration / test (pull_request) Successful in 1m52s
Continuous Integration / deploy-production (pull_request) Skipped
Deploy / deploy (pull_request) Successful in 37s
Continuous Integration / deploy-test (pull_request) Successful in 36s
De knop was ook zichtbaar op de testomgeving (VITE_APP_ENV=test). Nu uitsluitend zichtbaar bij pnpm dev, zodat de testomgeving een productie-equivalente build draait.
82 lines
2.9 KiB
TypeScript
82 lines
2.9 KiB
TypeScript
import { render, screen, fireEvent, act } from '@testing-library/react';
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
import * as Sentry from '@sentry/react';
|
|
import { SentryTestButton, handleSentryTestErrorClick } from '../SentryTestButton';
|
|
|
|
vi.mock('@sentry/react', () => ({
|
|
captureException: vi.fn(),
|
|
logger: { info: vi.fn() },
|
|
metrics: { count: vi.fn() },
|
|
}));
|
|
|
|
/**
|
|
* De echte fout wordt bewust ongevangen via een `setTimeout` gegooid (zie
|
|
* SentryTestButton.tsx). Om dat in deze fake-timer-tests te simuleren zonder
|
|
* dat de test zelf crasht op die intentionele throw, wordt het "doortikken"
|
|
* van de timers hierin afgevangen.
|
|
*/
|
|
function advanceTimersIgnoringIntentionalThrow(ms: number) {
|
|
try {
|
|
act(() => {
|
|
vi.advanceTimersByTime(ms);
|
|
});
|
|
} catch {
|
|
// verwacht: de intentionele test-fout uit handleSentryTestErrorClick
|
|
}
|
|
}
|
|
|
|
describe('SentryTestButton', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
it('is visible in local development', () => {
|
|
render(<SentryTestButton />);
|
|
expect(screen.getByRole('button', { name: 'Break the world' })).toBeInTheDocument();
|
|
});
|
|
|
|
it('sends a log and a metric to Sentry, then throws an intentional test error', () => {
|
|
expect(() => handleSentryTestErrorClick()).toThrow('This is your first error!');
|
|
|
|
expect(Sentry.logger.info).toHaveBeenCalledWith('User triggered test error', {
|
|
action: 'test_error_button_click',
|
|
});
|
|
expect(Sentry.metrics.count).toHaveBeenCalledWith('test_counter', 1);
|
|
});
|
|
|
|
it('shows a confirmation toast immediately when clicked, before the test error fires', () => {
|
|
render(<SentryTestButton />);
|
|
fireEvent.click(screen.getByRole('button', { name: 'Break the world' }));
|
|
|
|
expect(screen.getByRole('status')).toHaveTextContent('Test error verzonden naar Sentry');
|
|
// De log/metric/throw zijn pas gepland (setTimeout), nog niet uitgevoerd.
|
|
expect(Sentry.logger.info).not.toHaveBeenCalled();
|
|
|
|
advanceTimersIgnoringIntentionalThrow(0);
|
|
|
|
expect(Sentry.logger.info).toHaveBeenCalledWith('User triggered test error', {
|
|
action: 'test_error_button_click',
|
|
});
|
|
expect(Sentry.metrics.count).toHaveBeenCalledWith('test_counter', 1);
|
|
});
|
|
|
|
it('hides the toast again after it has been shown for a while', () => {
|
|
render(<SentryTestButton />);
|
|
fireEvent.click(screen.getByRole('button', { name: 'Break the world' }));
|
|
expect(screen.getByRole('status')).toBeInTheDocument();
|
|
|
|
// De intentionele fout (0ms-timer) stopt het "doortikken" van timers
|
|
// binnen dezelfde advanceTimersByTime-call, dus eerst die apart afhandelen
|
|
// voordat de resterende hide-timer (4000ms) doorgetikt kan worden.
|
|
advanceTimersIgnoringIntentionalThrow(0);
|
|
advanceTimersIgnoringIntentionalThrow(4000);
|
|
|
|
expect(screen.queryByRole('status')).not.toBeInTheDocument();
|
|
});
|
|
});
|