Stu*_*art 7 jestjs react-testing-library
在我的登录表单中,成功登录会启动一个承诺链,最终用户被重定向到主屏幕。在下面的测试中,我希望通过捕获最后一步来确保我的登录有效。
我在代码中包含日志语句,告诉我承诺链中的每个步骤都按我的预期执行,但断言仍然失败。从我的日志记录可以清楚地看出,测试在承诺链执行之前完成。
我认为这可能会因为我在实际形式中使用的 Formik 的行为而变得复杂。我无法成功查询并等待登录时显示的微调器。
我不知道如何让这个测试等到导航发生。可以触发什么承诺决议waitFor来完成?
import { act, render, screen, waitFor } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import React from "react"
import { AuthProvider } from "context/auth-context"
import { rest } from "msw"
import { setupServer } from "msw/node"
import { MemoryRouter as Router } from "react-router-dom"
import { LoginScreen } from "screens/login"
import { handlers } from "test/auth-handlers"
import { buildLoginForm } from "test/generate/auth"
import { deferred } from "test/test-utils"
const Wrapper = ({ children }) => (
<Router>
<AuthProvider>{children}</AuthProvider>
</Router>
)
const serverURL = process.env.REACT_APP_SERVER_URL
const server = setupServer(...handlers)
const mockNav = jest.fn()
jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"),
useNavigate: () => mockNav,
}))
beforeAll(() => {
server.listen()
})
afterAll(() => server.close())
afterEach(() => {
server.resetHandlers()
jest.clearAllMocks()
})
test("successful login", async () => {
const { promise, resolve } = deferred()
render(
<Wrapper>
<LoginScreen />
</Wrapper>,
)
expect(screen.getByLabelText(/loading/i)).toBeInTheDocument()
await act(() => {
resolve()
return promise
})
const { email, password } = buildLoginForm()
userEvent.type(screen.getByRole("textbox", { name: /email/i }), email)
userEvent.type(screen.getByLabelText(/password/i), password)
userEvent.click(screen.getByRole("button"))
await waitFor(expect(mockNav).toHaveBeenCalledWith("home"))
})
Run Code Online (Sandbox Code Playgroud)
登录表单:
function LoginForm({ onSubmit }) {
const { isError, isLoading, error, run } = useAsync()
function handleSubmit(values) {
// any 400 or 500 is displayed to the user
run(onSubmit(values)).catch(() => {})
}
return (
<Formik
initialValues={{ email: "", password: "" }}
validationSchema={Yup.object({
email: Yup.string().email("Invalid email address").required("A valid email is required"),
password: Yup.string().required("Password is required"),
})}
onSubmit={(values) => handleSubmit(values)}
>
<Form>
<FormGroup name="email" type="text" label="Email" />
<FormGroup name="password" type="password" label="Password" />
<IconSubmitButton loading={isLoading} color="green">
<MdArrowForward style={{ marginTop: ".6rem" }} />
</IconSubmitButton>
{isError ? <ErrorDisplay error={error} /> : null}
</Form>
</Formik>
)
}
Run Code Online (Sandbox Code Playgroud)
waitFor不知道承诺或其他实现细节,它通过在指定的时间间隔内轮询提供的断言来工作,直到断言通过或发生超时。
waitFortoThrow其工作原理与错误处理类似。当断言被指定为参数、被调用一次、抛出错误并导致测试失败时,它不可能捕获expect错误并多次评估断言:
await waitFor(expect(mockNav).toHaveBeenCalledWith("home"))
Run Code Online (Sandbox Code Playgroud)
唯一waitFor可行的方法是为其提供一个可以在try..catch内部包装并多次执行的函数。正确的做法是:
await waitFor(() => expect(mockNav).toHaveBeenCalledWith("home"))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5747 次 |
| 最近记录: |