Files
Nitro-V3/src/common/error-boundary/WidgetErrorBoundary.test.tsx
T
simoleo89 803de20dfe tests: flatten renderer mock to src/nitro-renderer.mock.ts (drop __mocks__/)
The Jest-style __mocks__/ folder added one indirection for a single
file. Move the stub to src/nitro-renderer.mock.ts at src/ root next to
test-setup.ts, drop the folder, repoint the vitest alias, and update
the lone test that imports the helpers directly (useDoorbellState).

Same behaviour, one fewer directory.
2026-05-16 11:37:33 +02:00

97 lines
2.9 KiB
TypeScript

/* @vitest-environment jsdom */
import { NitroLogger } from '@nitrots/nitro-renderer';
import { cleanup, render, screen } from '@testing-library/react';
import { FC } from 'react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { WidgetErrorBoundary } from './WidgetErrorBoundary';
// `import { NitroLogger } from '@nitrots/nitro-renderer'` resolves to
// `src/nitro-renderer.mock.ts` via the alias in vitest.config.mts.
// The SUT imports the same path, so both reach the same vi.fn instance.
describe('WidgetErrorBoundary', () =>
{
beforeEach(() =>
{
vi.clearAllMocks();
// react-error-boundary lets React's "uncaught error" log through
// by default — silence it so jsdom doesn't dump a stack trace
// every time we deliberately throw below.
vi.spyOn(console, 'error').mockImplementation(() => {});
});
afterEach(() =>
{
cleanup();
vi.restoreAllMocks();
});
it('renders its children when nothing throws', () =>
{
render(
<WidgetErrorBoundary name="HappyPath">
<span data-testid="child">visible</span>
</WidgetErrorBoundary>
);
expect(screen.getByTestId('child')).toHaveTextContent('visible');
});
it('swallows a render-time error to a silent fallback and logs it', () =>
{
const Boom: FC = () =>
{
throw new Error('kaboom');
};
const { container } = render(
<WidgetErrorBoundary name="Boom">
<Boom />
</WidgetErrorBoundary>
);
// Default fallback is `() => null` → boundary subtree is empty.
expect(container).toBeEmptyDOMElement();
expect(NitroLogger.error).toHaveBeenCalledTimes(1);
const [ message, err ] = (NitroLogger.error as ReturnType<typeof vi.fn>).mock.calls[0];
expect(message).toBe('[Widget:Boom] crashed');
expect(err).toBeInstanceOf(Error);
expect((err as Error).message).toBe('kaboom');
});
it('renders a custom fallback node when provided', () =>
{
const Boom: FC = () =>
{
throw new Error('explode');
};
render(
<WidgetErrorBoundary name="WithFallback" fallback={ <div data-testid="fb">offline</div> }>
<Boom />
</WidgetErrorBoundary>
);
expect(screen.getByTestId('fb')).toHaveTextContent('offline');
});
it('uses "unknown" as the widget name when the prop is omitted', () =>
{
const Boom: FC = () =>
{
throw new Error('anonymous');
};
render(
<WidgetErrorBoundary>
<Boom />
</WidgetErrorBoundary>
);
expect(NitroLogger.error).toHaveBeenCalledTimes(1);
expect((NitroLogger.error as ReturnType<typeof vi.fn>).mock.calls[0][0]).toBe('[Widget:unknown] crashed');
});
});