mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
803de20dfe
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.
97 lines
2.9 KiB
TypeScript
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');
|
|
});
|
|
});
|