Skip to content

Commit

Permalink
Add tests with React.lazy
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 committed May 17, 2023
1 parent d539adc commit 5c41962
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as React from "react";

export default function LazyComponent() {
return <h1>Lazy</h1>;
}
218 changes: 140 additions & 78 deletions packages/react-router-dom/__tests__/concurrent-mode-navigations-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
waitFor,
} from "@testing-library/react";
import { JSDOM } from "jsdom";
import LazyComponent from "./components//LazyComponent";

describe("Handles concurrent mode features during navigations", () => {
function getComponents() {
Expand All @@ -28,6 +29,7 @@ describe("Handles concurrent mode features during navigations", () => {
<>
<h1>Home</h1>
<button onClick={() => navigate("/about")}>/about</button>
<button onClick={() => navigate("/lazy")}>/lazy</button>
</>
);
}
Expand All @@ -40,61 +42,79 @@ describe("Handles concurrent mode features during navigations", () => {
}

function About() {
let navigate = useNavigate();
if (!resolved) {
throw dfd.promise;
}
return <h1>About</h1>;
return (
<>
<h1>About</h1>
<button onClick={() => navigate(-1)}>back</button>
</>
);
}

let lazyDfd = createDeferred();

const LazyComponent = React.lazy(async () => {
await lazyDfd.promise;
return import("./components/LazyComponent");
});

return {
Home,
About,
LazyComponent,
resolve,
resolveLazy: lazyDfd.resolve,
};
}

describe("when the destination route suspends with a boundary", () => {
async function assertNavigation(
container: HTMLElement,
resolve: () => void
resolve: () => void,
resolveLazy: () => void
) {
expect(getHtml(container)).toMatchInlineSnapshot(`
"<div>
<h1>
Home
</h1>
<button>
/about
</button>
</div>"
`);

fireEvent.click(screen.getByText("/about"));
await waitFor(() => screen.getByText("Loading..."));
// Start on home
expect(getHtml(container)).toMatch("Home");

expect(getHtml(container)).toMatchInlineSnapshot(`
"<div>
<p>
Loading...
</p>
</div>"
`);
// Click to /about and should see Suspense boundary
await act(() => {
fireEvent.click(screen.getByText("/about"));
});
await waitFor(() => screen.getByText("Loading..."));
expect(getHtml(container)).toMatch("Loading...");

// Resolve the destination UI to clear the boundary
await act(() => resolve());
await waitFor(() => screen.getByText("About"));

expect(getHtml(container)).toMatchInlineSnapshot(`
"<div>
<h1>
About
</h1>
</div>"
`);
expect(getHtml(container)).toMatch("About");

// Back to home
await act(() => {
fireEvent.click(screen.getByText("back"));
});
await waitFor(() => screen.getByText("Home"));
expect(getHtml(container)).toMatch("Home");

// Click to /lazy and should see Suspense boundary
await act(() => {
fireEvent.click(screen.getByText("/lazy"));
});
await waitFor(() => screen.getByText("Loading Lazy Component..."));
expect(getHtml(container)).toMatch("Loading Lazy Component...");

// Resolve the lazy component to clear the boundary
await act(() => resolveLazy());
await waitFor(() => screen.getByText("Lazy"));
expect(getHtml(container)).toMatch("Lazy");
}

// eslint-disable-next-line jest/expect-expect
it("MemoryRouter", async () => {
let { Home, About, resolve } = getComponents();
let { Home, About, LazyComponent, resolve, resolveLazy } =
getComponents();

let { container } = render(
<MemoryRouter>
Expand All @@ -108,16 +128,25 @@ describe("Handles concurrent mode features during navigations", () => {
</React.Suspense>
}
/>
<Route
path="/lazy"
element={
<React.Suspense fallback={<p>Loading Lazy Component...</p>}>
<LazyComponent />
</React.Suspense>
}
/>
</Routes>
</MemoryRouter>
);

await assertNavigation(container, resolve);
await assertNavigation(container, resolve, resolveLazy);
});

// eslint-disable-next-line jest/expect-expect
it("BrowserRouter", async () => {
let { Home, About, resolve } = getComponents();
let { Home, About, LazyComponent, resolve, resolveLazy } =
getComponents();

let { container } = render(
<BrowserRouter window={getWindowImpl("/", false)}>
Expand All @@ -131,16 +160,25 @@ describe("Handles concurrent mode features during navigations", () => {
</React.Suspense>
}
/>
<Route
path="/lazy"
element={
<React.Suspense fallback={<p>Loading Lazy Component...</p>}>
<LazyComponent />
</React.Suspense>
}
/>
</Routes>
</BrowserRouter>
);

await assertNavigation(container, resolve);
await assertNavigation(container, resolve, resolveLazy);
});

// eslint-disable-next-line jest/expect-expect
it("HashRouter", async () => {
let { Home, About, resolve } = getComponents();
let { Home, About, LazyComponent, resolve, resolveLazy } =
getComponents();

let { container } = render(
<HashRouter window={getWindowImpl("/", true)}>
Expand All @@ -154,16 +192,25 @@ describe("Handles concurrent mode features during navigations", () => {
</React.Suspense>
}
/>
<Route
path="/lazy"
element={
<React.Suspense fallback={<p>Loading Lazy Component...</p>}>
<LazyComponent />
</React.Suspense>
}
/>
</Routes>
</HashRouter>
);

await assertNavigation(container, resolve);
await assertNavigation(container, resolve, resolveLazy);
});

// eslint-disable-next-line jest/expect-expect
it("RouterProvider", async () => {
let { Home, About, resolve } = getComponents();
let { Home, About, LazyComponent, resolve, resolveLazy } =
getComponents();

let router = createMemoryRouter(
createRoutesFromElements(
Expand All @@ -177,120 +224,135 @@ describe("Handles concurrent mode features during navigations", () => {
</React.Suspense>
}
/>
<Route
path="/lazy"
element={
<React.Suspense fallback={<p>Loading Lazy Component...</p>}>
<LazyComponent />
</React.Suspense>
}
/>
</>
)
);
let { container } = render(<RouterProvider router={router} />);

await assertNavigation(container, resolve);
await assertNavigation(container, resolve, resolveLazy);
});
});

describe("when the destination route suspends without a boundary", () => {
async function assertNavigation(
container: HTMLElement,
resolve: () => void
resolve: () => void,
resolveLazy: () => void
) {
expect(getHtml(container)).toMatchInlineSnapshot(`
"<div>
<h1>
Home
</h1>
<button>
/about
</button>
</div>"
`);

fireEvent.click(screen.getByText("/about"));
await tick();
// Start on home
expect(getHtml(container)).toMatch("Home");

expect(getHtml(container)).toMatchInlineSnapshot(`
"<div>
<h1>
Home
</h1>
<button>
/about
</button>
</div>"
`);
// Click to /about and should see the frozen current UI
await act(() => {
fireEvent.click(screen.getByText("/about"));
});
await waitFor(() => screen.getByText("Home"));
expect(getHtml(container)).toMatch("Home");

// Resolve the destination UI to clear the boundary
await act(() => resolve());
await waitFor(() => screen.getByText("About"));

expect(getHtml(container)).toMatchInlineSnapshot(`
"<div>
<h1>
About
</h1>
</div>"
`);
expect(getHtml(container)).toMatch("About");

// Back to home
await act(() => {
fireEvent.click(screen.getByText("back"));
});
await waitFor(() => screen.getByText("Home"));
expect(getHtml(container)).toMatch("Home");

// Click to /lazy and should see the frozen current UI
await act(() => {
fireEvent.click(screen.getByText("/lazy"));
});
await waitFor(() => screen.getByText("Home"));
expect(getHtml(container)).toMatch("Home");

// Resolve the lazy component to clear the boundary
await act(() => resolveLazy());
await waitFor(() => screen.getByText("Lazy"));
expect(getHtml(container)).toMatch("Lazy");
}

// eslint-disable-next-line jest/expect-expect
it("MemoryRouter", async () => {
let { Home, About, resolve } = getComponents();
let { Home, About, resolve, LazyComponent, resolveLazy } =
getComponents();

let { container } = render(
<MemoryRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/lazy" element={<LazyComponent />} />
</Routes>
</MemoryRouter>
);

await assertNavigation(container, resolve);
await assertNavigation(container, resolve, resolveLazy);
});

// eslint-disable-next-line jest/expect-expect
it("BrowserRouter", async () => {
let { Home, About, resolve } = getComponents();
let { Home, About, resolve, LazyComponent, resolveLazy } =
getComponents();

let { container } = render(
<BrowserRouter window-={getWindowImpl("/", true)}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/lazy" element={<LazyComponent />} />
</Routes>
</BrowserRouter>
);

await assertNavigation(container, resolve);
await assertNavigation(container, resolve, resolveLazy);
});

// eslint-disable-next-line jest/expect-expect
it("HashRouter", async () => {
let { Home, About, resolve } = getComponents();
let { Home, About, resolve, LazyComponent, resolveLazy } =
getComponents();

let { container } = render(
<HashRouter window-={getWindowImpl("/", true)}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/lazy" element={<LazyComponent />} />
</Routes>
</HashRouter>
);

await assertNavigation(container, resolve);
await assertNavigation(container, resolve, resolveLazy);
});

// eslint-disable-next-line jest/expect-expect
it("RouterProvider", async () => {
let { Home, About, resolve } = getComponents();
let { Home, About, resolve, LazyComponent, resolveLazy } =
getComponents();

let router = createMemoryRouter(
createRoutesFromElements(
<>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/lazy" element={<LazyComponent />} />
</>
)
);
let { container } = render(<RouterProvider router={router} />);

await assertNavigation(container, resolve);
await assertNavigation(container, resolve, resolveLazy);
});
});
});
Expand Down

0 comments on commit 5c41962

Please sign in to comment.