【发布时间】:2022-01-03 18:05:33
【问题描述】:
我正在尝试在我的 React 组件上运行一些开玩笑的测试,更具体地说是针对我的 LoginForm 组件。
我有一个调用 auth api 进行登录的函数:
import axios from 'axios'
const doLogin = (username: string, password: string) => {
return axios.post('api/auth', {
username,
password
})
}
export default { doLogin }
很简单,只是返回一个 axios 响应的 Promise。
我已经在我的LoginPage.tsx 中实现了它:(submitLogin):
import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import SwitchLogo from '../assets/switch-logo.png'
import { Button, TextBox } from '../components/Form'
import userApi from '../api/user'
const LoginPage = () => {
const { doLogin } = userApi
const [username, setUsername] = useState<string>('')
const [password, setPassword] = useState<string>('')
const [loading, setLoading] = useState<boolean>(false)
const [error, setError] = useState<string | undefined>(undefined)
const onUsernameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUsername(e.currentTarget.value)
}
const onPasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setPassword(e.currentTarget.value)
}
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
if (!username || !password) {
setError('Please fill in login details.')
return
}
submitLogin()
}
const submitLogin = () => {
setError(undefined)
setLoading(true)
doLogin(username, password).then((response) => {
console.log(JSON.stringify(response))
}).catch((err) => {
setError(err.response.data.error)
}).finally(() => setLoading(false))
}
return (
<div className="flex h-screen bg-gray-50">
<div className="m-auto w-full sm:w-5/6 lg:w-2/4 xl:w-1/3">
<div className="flex justify-center"><img src={SwitchLogo} className="w-32 h-32" alt="switch-logo" /></div>
<form onSubmit={onSubmit} data-testid='form'>
<div className="bg-white shadow-lg drop-shadow-lg rounded px-8 pt-6 pb-8 mb-4 flex flex-col gap-4">
<div className='flex flex-col gap-2 text-center'>
<p className="text-4xl font-bold">Sign in</p>
<p className='text-sm'>Please sign in to access all features.</p>
</div>
<div className="divider m-0" />
<div>
<TextBox id="username" type="text" placeholder="Username" required value={username} onChange={onUsernameChange} data-testid='username' />
</div>
<div>
<TextBox id="password" type="password" placeholder="Password" required value={password} onChange={onPasswordChange} data-testid='password' />
</div>
<Button colour='red' loading={loading} data-testid='submit'>{!loading && 'Sign in'}</Button>
<Button colour='sky' type='button' outline><Link to='/register'>Register new account</Link></Button>
</div>
{error && (<div className="alert alert-error">
<div className='mx-auto'>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" className="w-6 h-6 mx-2 stroke-current">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"></path>
</svg>
<label>{error}</label>
</div>
</div>)}
</form>
</div>
</div>
)
}
export default LoginPage
注意doLogin 被调用,然后用.then 处理。当我运行应用程序时,这一切正常。
问题是当我尝试测试我的登录页面时。
我有登录页面的规范文件,我在其中模拟 axios 中的 post 函数,然后返回具有最少数据 (LoginPage.spec.tsx) 的基本 AxiosResponse 对象:
import { fireEvent, getByTestId, getByText, render } from '@testing-library/react'
import { BrowserRouter } from 'react-router-dom'
import LoginPage from './LoginPage'
import axios, { AxiosResponse } from 'axios'
jest.mock('axios')
const mockedAxios = axios as jest.Mocked<typeof axios>
const base: AxiosResponse<any, any> = {
data: { test: 123 },
status: 200,
statusText: 'OK',
headers: {},
config: {}
}
mockedAxios.post.mockResolvedValue(base)
describe('Sign in form', () => {
beforeEach(() => {
render(
<BrowserRouter>
<LoginPage />
</BrowserRouter >
)
})
it('Renders', () => {
expect(getByText(document.body, /Please sign in to access all features./i)).toBeInTheDocument()
})
it('Does not submit when no data filled in', () => {
fireEvent.click(getByTestId(document.body, 'submit'))
expect(getByText(document.body, /Please fill in login details/i)).toBeInTheDocument()
expect(mockedAxios.post).not.toHaveBeenCalled()
})
it('Submits when data filled in', () => {
fireEvent.change(getByTestId(document.body, 'username'), { target: { value: 'testUser' } })
fireEvent.change(getByTestId(document.body, 'password'), { target: { value: 'testPassword' } })
fireEvent.click(getByTestId(document.body, 'submit'))
expect(mockedAxios.post).toHaveBeenCalledTimes(1)
})
})
发生的情况是,当测试运行时,它调用submitLogin,然后尝试调用doLogin().then,但显然.then 不存在:
Error: Uncaught [TypeError: Cannot read properties of undefined (reading 'then')]
【问题讨论】:
-
只要确保
doLogin返回一个带有 then 方法的对象。 jestjs.io/docs/manual-mocks 可能会有所帮助 -
@evolutionxbox 我不明白。确实如此。一个promise 应该包含一个
.then方法,这就是doLogin 返回的……一个Promise。 -
不按错误。它认为
doLogin正在返回未定义。 -
是的,我知道,我只是不明白为什么。好几个小时我都在摸不着头脑。
标签: javascript reactjs typescript jestjs