|
1 |
| -import React from "react"; |
2 |
| -import { act, render, screen, waitFor } from "@testing-library/react"; |
| 1 | +import React, { memo, useEffect } from "react"; |
| 2 | +import { |
| 3 | + act, |
| 4 | + render, |
| 5 | + RenderResult, |
| 6 | + screen, |
| 7 | + waitFor, |
| 8 | +} from "@testing-library/react"; |
3 | 9 | import lazy, { lazyWithPreload as namedExport } from "../index";
|
4 | 10 |
|
5 | 11 | function getTestComponentModule() {
|
6 | 12 | const TestComponent = React.forwardRef<
|
7 | 13 | HTMLDivElement,
|
8 | 14 | { foo: string; children: React.ReactNode }
|
9 | 15 | >(function TestComponent(props, ref) {
|
| 16 | + renders++; |
| 17 | + useEffect(() => { |
| 18 | + mounts++; |
| 19 | + }, []); |
10 | 20 | return <div ref={ref}>{`${props.foo} ${props.children}`}</div>;
|
11 | 21 | });
|
12 | 22 | let loaded = false;
|
13 | 23 | let loadCalls = 0;
|
| 24 | + let renders = 0; |
| 25 | + let mounts = 0; |
14 | 26 |
|
15 | 27 | return {
|
16 | 28 | isLoaded: () => loaded,
|
17 | 29 | loadCalls: () => loadCalls,
|
| 30 | + renders: () => renders, |
| 31 | + mounts: () => mounts, |
18 | 32 | OriginalComponent: TestComponent,
|
19 | 33 | TestComponent: async () => {
|
20 | 34 | loaded = true;
|
21 | 35 | loadCalls++;
|
22 | 36 | return { default: TestComponent };
|
23 | 37 | },
|
| 38 | + TestMemoizedComponent: async () => { |
| 39 | + loaded = true; |
| 40 | + loadCalls++; |
| 41 | + return { default: memo(TestComponent) }; |
| 42 | + }, |
24 | 43 | };
|
25 | 44 | }
|
26 | 45 |
|
@@ -158,4 +177,66 @@ describe("lazy", () => {
|
158 | 177 | it("exports named export as well", () => {
|
159 | 178 | expect(lazy).toBe(namedExport);
|
160 | 179 | });
|
| 180 | + |
| 181 | + it("does not re-render memoized base component when passed same props after preload", async () => { |
| 182 | + const { TestMemoizedComponent, renders } = getTestComponentModule(); |
| 183 | + const LazyTestComponent = lazy(TestMemoizedComponent); |
| 184 | + |
| 185 | + expect(renders()).toBe(0); |
| 186 | + |
| 187 | + let rerender: RenderResult["rerender"] | undefined; |
| 188 | + await act(async () => { |
| 189 | + const result = render( |
| 190 | + <React.Suspense fallback={null}> |
| 191 | + <LazyTestComponent foo="bar">baz</LazyTestComponent> |
| 192 | + </React.Suspense> |
| 193 | + ); |
| 194 | + rerender = result.rerender; |
| 195 | + }); |
| 196 | + |
| 197 | + expect(renders()).toBe(1); |
| 198 | + |
| 199 | + await LazyTestComponent.preload(); |
| 200 | + |
| 201 | + await act(async () => { |
| 202 | + rerender?.( |
| 203 | + <React.Suspense fallback={null}> |
| 204 | + <LazyTestComponent foo="bar">baz</LazyTestComponent> |
| 205 | + </React.Suspense> |
| 206 | + ); |
| 207 | + }); |
| 208 | + |
| 209 | + expect(renders()).toBe(1); |
| 210 | + }); |
| 211 | + |
| 212 | + it("does not re-mount base component after preload", async () => { |
| 213 | + const { TestComponent, mounts } = getTestComponentModule(); |
| 214 | + const LazyTestComponent = lazy(TestComponent); |
| 215 | + |
| 216 | + expect(mounts()).toBe(0); |
| 217 | + |
| 218 | + let rerender: RenderResult["rerender"] | undefined; |
| 219 | + await act(async () => { |
| 220 | + const result = render( |
| 221 | + <React.Suspense fallback={null}> |
| 222 | + <LazyTestComponent foo="bar">baz</LazyTestComponent> |
| 223 | + </React.Suspense> |
| 224 | + ); |
| 225 | + rerender = result.rerender; |
| 226 | + }); |
| 227 | + |
| 228 | + expect(mounts()).toBe(1); |
| 229 | + |
| 230 | + await LazyTestComponent.preload(); |
| 231 | + |
| 232 | + await act(async () => { |
| 233 | + rerender?.( |
| 234 | + <React.Suspense fallback={null}> |
| 235 | + <LazyTestComponent foo="updated">updated</LazyTestComponent> |
| 236 | + </React.Suspense> |
| 237 | + ); |
| 238 | + }); |
| 239 | + |
| 240 | + expect(mounts()).toBe(1); |
| 241 | + }); |
161 | 242 | });
|
0 commit comments