當元件使用像是 useLoaderData
、<Link>
等功能時,它們必須在 React Router 應用程式的上下文中渲染。createRoutesStub
函數建立該上下文,以隔離測試元件。
考慮一個依賴 useActionData
的登入表單元件
import { useActionData } from "react-router";
export function LoginForm() {
const errors = useActionData();
return (
<Form method="post">
<label>
<input type="text" name="username" />
{errors?.username && <div>{errors.username}</div>}
</label>
<label>
<input type="password" name="password" />
{errors?.password && <div>{errors.password}</div>}
</label>
<button type="submit">Login</button>
</Form>
);
}
我們可以使用 createRoutesStub
測試此元件。它接受一個物件陣列,這些物件類似於具有載入器、動作和元件的路由模組。
import { createRoutesStub } from "react-router";
import {
render,
screen,
waitFor,
} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { LoginForm } from "./LoginForm";
test("LoginForm renders error messages", async () => {
const USER_MESSAGE = "Username is required";
const PASSWORD_MESSAGE = "Password is required";
const Stub = createRoutesStub([
{
path: "/login",
Component: LoginForm,
action() {
return {
errors: {
username: USER_MESSAGE,
password: PASSWORD_MESSAGE,
},
};
},
},
]);
// render the app stub at "/login"
render(<Stub initialEntries={["/login"]} />);
// simulate interactions
userEvent.click(screen.getByText("Login"));
await waitFor(() => screen.findByText(USER_MESSAGE));
await waitFor(() => screen.findByText(PASSWORD_MESSAGE));
});