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 the current (development/test) build', () => {
render();
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();
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();
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();
});
});