import { useState } from "preact/hooks";
import { useMemo } from "preact/hooks";
import { render, screen } from "@testing-library/preact";
import userEvent from "@testing-library/user-event";
import { createMemoryHistory } from "@nano-router/history";
import "@testing-library/jest-dom";
import {
Routes,
Route,
ExternalRoute,
Router,
useRouteName,
useRouter,
usePrompt,
useLink,
} from "./index.js";
const routes = new Routes(
new Route("posts/new", "/posts/new"),
new Route("posts", "/posts"),
new ExternalRoute("external", "https://www.example.com/blog/:id"),
);
const NewView = () => {
const router = useRouter();
const [name, setName] = useState("");
const isDirty = Boolean(name);
const confirmation = usePrompt(isDirty);
const showPosts = useLink("posts");
const showExternal = useLink({ route: "external", params: { id: 42 } });
const onChange = (e: Event) => {
setName((e.currentTarget as HTMLInputElement).value);
};
const onSave = () => {
// Save
// Success
router.navigate({
route: "posts",
state: { skipPrompt: true },
});
};
return (
);
};
const RootView = () => {
const routeName = useRouteName();
switch (routeName) {
case "posts/new":
return ;
default:
return ;
}
};
const App = () => {
const history = useMemo(
() => createMemoryHistory({ initialEntries: ["/posts/new"] }),
[],
);
return (
);
};
describe("usePrompt", () => {
beforeEach(() => {
render();
});
describe("when navigation is blocked", () => {
beforeEach(async () => {
await userEvent.type(screen.getByTestId("name"), "Sune");
await userEvent.click(screen.getByTestId("show-list"));
});
it("shows a confirmation", () => {
expect(screen.getByTestId("approve")).toBeInTheDocument();
});
});
describe("when navigation is blocked to an external route", () => {
beforeEach(async () => {
await userEvent.type(screen.getByTestId("name"), "Sune");
await userEvent.click(screen.getByTestId("external"));
});
it("shows a confirmation", () => {
expect(screen.getByTestId("approve")).toBeInTheDocument();
});
});
describe("when block navigation is confirmed", () => {
beforeEach(async () => {
await userEvent.type(screen.getByTestId("name"), "Sune");
await userEvent.click(screen.getByTestId("show-list"));
await userEvent.click(screen.getByTestId("approve"));
});
it("navigates", () => {
expect(screen.getByTestId("posts-list")).toBeInTheDocument();
});
});
describe("when block navigation is rejected", () => {
beforeEach(async () => {
await userEvent.type(screen.getByTestId("name"), "Sune");
await userEvent.click(screen.getByTestId("show-list"));
await userEvent.click(screen.getByTestId("reject"));
});
it("removes the confirmation but it doesn't navigate", () => {
expect(screen.queryByTestId("approve")).toBe(null);
expect(screen.getByTestId("show-list")).toBeInTheDocument();
expect(screen.queryByTestId("posts-list")).toBe(null);
});
});
describe("when block navigation is rejected multiple times", () => {
beforeEach(async () => {
await userEvent.type(screen.getByTestId("name"), "Sune");
await userEvent.click(screen.getByTestId("show-list"));
await userEvent.click(screen.getByTestId("reject"));
await userEvent.click(screen.getByTestId("show-list"));
await userEvent.click(screen.getByTestId("reject"));
});
it("removes the confirmation but it doesn't navigate", () => {
expect(screen.queryByTestId("approve")).toBe(null);
expect(screen.getByTestId("show-list")).toBeInTheDocument();
expect(screen.queryByTestId("posts-list")).toBe(null);
});
});
describe("when removing a confirmation", () => {
beforeEach(async () => {
await userEvent.type(screen.getByTestId("name"), "Sune");
await userEvent.click(screen.getByTestId("save"));
});
it("won't prompt on navigation", () => {
expect(screen.queryByTestId("posts-list")).toBeInTheDocument();
});
});
});