-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9d708b5
commit d470e99
Showing
1 changed file
with
85 additions
and
110 deletions.
There are no files selected for viewing
195 changes: 85 additions & 110 deletions
195
packages/react-router-dom/__tests__/use-prompt-test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,151 +1,126 @@ | ||
import * as React from "react"; | ||
import { act, render, screen } from "@testing-library/react"; | ||
import { fireEvent, render, screen, waitFor } from "@testing-library/react"; | ||
import { | ||
Link, | ||
RouterProvider, | ||
createBrowserRouter, | ||
unstable_usePrompt as usePrompt, | ||
} from "../index"; | ||
import "@testing-library/jest-dom"; | ||
|
||
const PromptRoute = ({ when, message }: Parameters<typeof usePrompt>[0]) => { | ||
usePrompt({ when, message }); | ||
|
||
return ( | ||
<> | ||
<h1>Prompt Route</h1> | ||
|
||
<Link to="/arbitrary">Navigate to arbitrary route</Link> | ||
</> | ||
); | ||
}; | ||
|
||
const ArbitraryRoute = () => { | ||
return <h1>Arbitrary Route</h1>; | ||
}; | ||
import { JSDOM } from "jsdom"; | ||
|
||
describe("usePrompt", () => { | ||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
|
||
window.history.pushState({}, "", "/"); | ||
}); | ||
|
||
describe("when navigation is blocked", () => { | ||
it("shows the confirmation prompt and does not navigate when the confirmation prompt is cancelled", () => { | ||
const when = true; | ||
const message = "__MESSAGE__"; | ||
|
||
const router = createBrowserRouter([ | ||
{ | ||
path: "/", | ||
element: <PromptRoute when={when} message={message} />, | ||
}, | ||
{ | ||
path: "/arbitrary", | ||
element: <ArbitraryRoute />, | ||
}, | ||
]); | ||
|
||
render(<RouterProvider router={router} />); | ||
|
||
expect( | ||
screen.getByRole("heading", { name: "Prompt Route" }) | ||
).toBeInTheDocument(); | ||
|
||
it("shows window.confirm and blocks navigation when it returns false", async () => { | ||
let testWindow = getWindowImpl("/"); | ||
const windowConfirmMock = jest | ||
.spyOn(window, "confirm") | ||
.mockImplementationOnce(() => false); | ||
|
||
act(() => { | ||
screen | ||
.getByRole("link", { name: "Navigate to arbitrary route" }) | ||
.click(); | ||
}); | ||
|
||
expect(windowConfirmMock).toHaveBeenNthCalledWith(1, message); | ||
|
||
expect( | ||
screen.getByRole("heading", { name: "Prompt Route" }) | ||
).toBeInTheDocument(); | ||
}); | ||
|
||
it("shows the confirmation prompt and navigates when the confirmation prompt is accepted", () => { | ||
const when = true; | ||
const message = "__MESSAGE__"; | ||
|
||
const router = createBrowserRouter([ | ||
{ | ||
path: "/", | ||
element: <PromptRoute when={when} message={message} />, | ||
}, | ||
{ | ||
path: "/arbitrary", | ||
element: <ArbitraryRoute />, | ||
}, | ||
]); | ||
let router = createBrowserRouter( | ||
[ | ||
{ | ||
path: "/", | ||
Component() { | ||
usePrompt({ when: true, message: "Are you sure??" }); | ||
return <Link to="/arbitrary">Navigate</Link>; | ||
}, | ||
}, | ||
{ | ||
path: "/arbitrary", | ||
Component: () => <h1>Arbitrary</h1>, | ||
}, | ||
], | ||
{ window: testWindow } | ||
); | ||
|
||
render(<RouterProvider router={router} />); | ||
expect(screen.getByText("Navigate")).toBeInTheDocument(); | ||
|
||
expect( | ||
screen.getByRole("heading", { name: "Prompt Route" }) | ||
).toBeInTheDocument(); | ||
fireEvent.click(screen.getByText("Navigate")); | ||
await new Promise((r) => setTimeout(r, 0)); | ||
|
||
expect(windowConfirmMock).toHaveBeenNthCalledWith(1, "Are you sure??"); | ||
expect(screen.getByText("Navigate")).toBeInTheDocument(); | ||
}); | ||
|
||
it("shows window.confirm and navigates when it returns true", async () => { | ||
let testWindow = getWindowImpl("/"); | ||
const windowConfirmMock = jest | ||
.spyOn(window, "confirm") | ||
.mockImplementationOnce(() => true); | ||
|
||
act(() => { | ||
screen | ||
.getByRole("link", { name: "Navigate to arbitrary route" }) | ||
.click(); | ||
}); | ||
let router = createBrowserRouter( | ||
[ | ||
{ | ||
path: "/", | ||
Component() { | ||
usePrompt({ when: true, message: "Are you sure??" }); | ||
return <Link to="/arbitrary">Navigate</Link>; | ||
}, | ||
}, | ||
{ | ||
path: "/arbitrary", | ||
Component: () => <h1>Arbitrary</h1>, | ||
}, | ||
], | ||
{ window: testWindow } | ||
); | ||
|
||
render(<RouterProvider router={router} />); | ||
expect(screen.getByText("Navigate")).toBeInTheDocument(); | ||
|
||
expect(windowConfirmMock).toHaveBeenNthCalledWith(1, message); | ||
fireEvent.click(screen.getByText("Navigate")); | ||
await waitFor(() => screen.getByText("Arbitrary")); | ||
|
||
expect( | ||
screen.getByRole("heading", { name: "Arbitrary Route" }) | ||
).toBeInTheDocument(); | ||
expect(windowConfirmMock).toHaveBeenNthCalledWith(1, "Are you sure??"); | ||
expect(screen.getByText("Arbitrary")).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
describe("when navigation is not blocked", () => { | ||
it("navigates without showing the confirmation prompt", () => { | ||
const when = false; | ||
const message = "__MESSAGE__"; | ||
|
||
const router = createBrowserRouter([ | ||
{ | ||
path: "/", | ||
element: <PromptRoute when={when} message={message} />, | ||
}, | ||
{ | ||
path: "/arbitrary", | ||
element: <ArbitraryRoute />, | ||
}, | ||
]); | ||
|
||
render(<RouterProvider router={router} />); | ||
|
||
expect( | ||
screen.getByRole("heading", { name: "Prompt Route" }) | ||
).toBeInTheDocument(); | ||
|
||
it("navigates without showing window.confirm", async () => { | ||
let testWindow = getWindowImpl("/"); | ||
const windowConfirmMock = jest | ||
.spyOn(window, "confirm") | ||
.mockImplementationOnce(() => false); | ||
.mockImplementation(() => true); | ||
|
||
let router = createBrowserRouter( | ||
[ | ||
{ | ||
path: "/", | ||
Component() { | ||
usePrompt({ when: false, message: "Are you sure??" }); | ||
return <Link to="/arbitrary">Navigate</Link>; | ||
}, | ||
}, | ||
{ | ||
path: "/arbitrary", | ||
Component: () => <h1>Arbitrary</h1>, | ||
}, | ||
], | ||
{ window: testWindow } | ||
); | ||
|
||
render(<RouterProvider router={router} />); | ||
expect(screen.getByText("Navigate")).toBeInTheDocument(); | ||
|
||
act(() => { | ||
screen | ||
.getByRole("link", { name: "Navigate to arbitrary route" }) | ||
.click(); | ||
}); | ||
fireEvent.click(screen.getByText("Navigate")); | ||
await waitFor(() => screen.getByText("Arbitrary")); | ||
|
||
expect(windowConfirmMock).not.toHaveBeenCalled(); | ||
|
||
expect( | ||
screen.getByRole("heading", { name: "Arbitrary Route" }) | ||
).toBeInTheDocument(); | ||
expect(screen.getByText("Arbitrary")).toBeInTheDocument(); | ||
}); | ||
}); | ||
}); | ||
|
||
function getWindowImpl(initialUrl: string, isHash = false): Window { | ||
// Need to use our own custom DOM in order to get a working history | ||
const dom = new JSDOM(`<!DOCTYPE html>`, { url: "http://localhost/" }); | ||
dom.window.history.replaceState(null, "", (isHash ? "#" : "") + initialUrl); | ||
return dom.window as unknown as Window; | ||
} |