lazyLoad.spec.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import {render, screen} from 'sentry-test/reactTestingLibrary';
  2. import LazyLoad from 'sentry/components/lazyLoad';
  3. type TestProps = {
  4. testProp?: boolean;
  5. };
  6. function FooComponent({}: TestProps) {
  7. return <div>my foo component</div>;
  8. }
  9. function BarComponent({}: TestProps) {
  10. return <div>my bar component</div>;
  11. }
  12. type ResolvedComponent = {default: React.ComponentType<TestProps>};
  13. type GetComponent = () => Promise<ResolvedComponent>;
  14. describe('LazyLoad', function () {
  15. afterEach(() => {
  16. jest.restoreAllMocks();
  17. });
  18. it('renders with a loading indicator when promise is not resolved yet', function () {
  19. const importTest = new Promise<ResolvedComponent>(() => {});
  20. const getComponent = () => importTest;
  21. render(<LazyLoad component={getComponent} />);
  22. // Should be loading
  23. expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
  24. });
  25. it('renders when given a promise of a "foo" component', async function () {
  26. let doResolve: (c: ResolvedComponent) => void;
  27. const importFoo = new Promise<ResolvedComponent>(resolve => {
  28. doResolve = resolve;
  29. });
  30. render(<LazyLoad component={() => importFoo} />);
  31. // Should be loading
  32. expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
  33. // resolve with foo
  34. doResolve!({default: FooComponent});
  35. expect(await screen.findByText('my foo component')).toBeInTheDocument();
  36. });
  37. it('renders with error message when promise is rejected', async function () {
  38. // eslint-disable-next-line no-console
  39. jest.spyOn(console, 'error').mockImplementation(jest.fn());
  40. const getComponent = jest.fn(
  41. () =>
  42. new Promise<ResolvedComponent>((_resolve, reject) =>
  43. reject(new Error('Could not load component'))
  44. )
  45. );
  46. try {
  47. render(<LazyLoad component={getComponent} />);
  48. } catch (err) {
  49. // ignore
  50. }
  51. expect(
  52. await screen.findByText('There was an error loading a component.')
  53. ).toBeInTheDocument();
  54. // eslint-disable-next-line no-console
  55. expect(console.error).toHaveBeenCalled();
  56. });
  57. it('refetches only when component changes', async function () {
  58. let doResolve: (c: ResolvedComponent) => void;
  59. const importFoo = new Promise<ResolvedComponent>(resolve => {
  60. doResolve = resolve;
  61. });
  62. // First render Foo
  63. const {rerender} = render(<LazyLoad component={() => importFoo} />);
  64. expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
  65. // resolve with foo
  66. doResolve!({default: FooComponent});
  67. expect(await screen.findByText('my foo component')).toBeInTheDocument();
  68. // Re-render with Bar
  69. const importBar = new Promise<ResolvedComponent>(resolve => {
  70. doResolve = resolve;
  71. });
  72. rerender(<LazyLoad component={() => importBar} />);
  73. expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
  74. // resolve with bar
  75. doResolve!({default: BarComponent});
  76. expect(await screen.findByText('my bar component')).toBeInTheDocument();
  77. // Update component prop to a mock to make sure it isn't re-called
  78. const getComponent2: GetComponent = jest.fn(
  79. () => new Promise<ResolvedComponent>(() => {})
  80. );
  81. rerender(<LazyLoad component={getComponent2} />);
  82. expect(getComponent2).toHaveBeenCalledTimes(1);
  83. // Does not refetch on other prop changes
  84. rerender(<LazyLoad component={getComponent2} testProp />);
  85. expect(getComponent2).toHaveBeenCalledTimes(1);
  86. });
  87. });