当组件使用诸如 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));
});