import React from 'react';
import * as Sentry from '@sentry/browser';
import { render } from '@testing-library/react';
import { SentryErrorBoundary } from '../sentryErrorBoundary';

describe('<SentryErrorBoundary>', () => {
    test('renders children', () => {
        const output = 'im behaving';
        const Child = () => <div>{output}</div>;
        const wrapper = render(
            <SentryErrorBoundary>
                <Child />
            </SentryErrorBoundary>
        );

        expect(wrapper.getByText(output)).toBeDefined();
    });

    describe('on error', () => {
        const output = 'im misbehaving';
        const error = new Error(output);
        const Child = () => {
            throw error;
        };

        const setExtras = vi.fn();
        const scope = { setExtras } as unknown as Sentry.Scope;
        const eventId = '1234';

        vi.spyOn(Sentry, 'withScope').mockImplementation((callback: unknown) => {
            if (callback && typeof callback === 'function') callback(scope);
        });
        const captureException = vi.spyOn(Sentry, 'captureException').mockReturnValue(eventId);

        let globalConsoleError: typeof global.console.error;

        beforeEach(() => {
            captureException.mockClear();
            setExtras.mockClear();

            globalConsoleError = global.console.error;
            global.console.error = vi.fn();
        });

        afterEach(() => {
            global.console.error = globalConsoleError;
        });

        test('renders error message', () => {
            const wrapper = render(
                <SentryErrorBoundary>
                    <Child />
                </SentryErrorBoundary>
            );
            const errorMessage = wrapper.container.getElementsByClassName('ErrorMessage').item(0);

            expect(errorMessage).toBeVisible();
        });

        test('sends error to Sentry', () => {
            render(
                <SentryErrorBoundary>
                    <Child />
                </SentryErrorBoundary>
            );

            expect(scope.setExtras).toHaveBeenCalled();
            expect(Sentry.captureException).toHaveBeenCalledWith(error);
        });
    });
});
