import {render, screen} from 'sentry-test/reactTestingLibrary';
import LazyLoad from 'sentry/components/lazyLoad';
type TestProps = {
testProp?: boolean;
};
function FooComponent({}: TestProps) {
return
my foo component
;
}
function BarComponent({}: TestProps) {
return my bar component
;
}
type ResolvedComponent = {default: React.ComponentType};
type GetComponent = () => Promise;
describe('LazyLoad', function () {
it('renders with a loading indicator when promise is not resolved yet', function () {
const importTest = new Promise(() => {});
const getComponent = () => importTest;
render();
// Should be loading
expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
});
it('renders when given a promise of a "foo" component', async function () {
let doResolve: (c: ResolvedComponent) => void;
const importFoo = new Promise(resolve => {
doResolve = resolve;
});
render( importFoo} />);
// Should be loading
expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
// resolve with foo
doResolve!({default: FooComponent});
expect(await screen.findByText('my foo component')).toBeInTheDocument();
});
it('renders with error message when promise is rejected', async function () {
// eslint-disable-next-line no-console
jest.spyOn(console, 'error').mockImplementation(jest.fn());
const getComponent = jest.fn(
() =>
new Promise((_resolve, reject) =>
reject(new Error('Could not load component'))
)
);
try {
render();
} catch (err) {
// ignore
}
expect(
await screen.findByText('There was an error loading a component.')
).toBeInTheDocument();
// eslint-disable-next-line no-console
expect(console.error).toHaveBeenCalled();
// @ts-expect-error
// eslint-disable-next-line no-console
console.error.mockRestore();
});
it('refetches only when component changes', async function () {
let doResolve: (c: ResolvedComponent) => void;
const importFoo = new Promise(resolve => {
doResolve = resolve;
});
// First render Foo
const {rerender} = render( importFoo} />);
expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
// resolve with foo
doResolve!({default: FooComponent});
expect(await screen.findByText('my foo component')).toBeInTheDocument();
// Re-render with Bar
const importBar = new Promise(resolve => {
doResolve = resolve;
});
rerender( importBar} />);
expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
// resolve with bar
doResolve!({default: BarComponent});
expect(await screen.findByText('my bar component')).toBeInTheDocument();
// Update component prop to a mock to make sure it isn't re-called
const getComponent2: GetComponent = jest.fn(
() => new Promise(() => {})
);
rerender();
expect(getComponent2).toHaveBeenCalledTimes(1);
// Does not refetch on other prop changes
rerender();
expect(getComponent2).toHaveBeenCalledTimes(1);
});
});