测试 API 调用
在第二部分中,我们将学习如何测试从 API 获取数据并在 UI 中渲染该数据的组件。
这是一个简单的Users组件。
import React, { useEffect, useState } from 'react'
import { User } from 'types/users'
import { getUsers } from 'services/users'
const Users: React.FC = () => {
let [users, setUsers] = useState<User[]>([])
let [loading, setLoading] = useState(false)
useEffect(() => {
setLoading(true)
getUsers()
.then(users => setUsers(users))
.catch(console.error)
.then(() => setLoading(false))
}, [])
return loading ? (
<p aria-label="loading">Loading ...</p>
) : (
<ul style={{ listStyle: 'none' }}>
{users.map(user => (
<li key={user.id}>
{user.name} ({user.email})
</li>
))}
</ul>
)
}
export default Users
在useEffect钩子函数中,我调用了该方法,并根据从 API 接收到的数据getUsers设置了loading状态。根据状态,我们设置加载指示器,并在获取用户数据后,在一个列表中渲染一些用户详细信息。users
注意:如果您不熟悉 hooks,则可以将调用替换useState为您通常在类组件中定义的初始状态,并将useEffect方法替换为componentDidMount。
这就是getUsers方法。
export const getUsers = () => {
return fetch('https://jsonplaceholder.typicode.com/users').then(res =>
res.json()
)
}
我只是用JSONPlaceholder来获取一些虚拟用户。在这个测试中,我们会检查加载文本是否出现,以及 API 调用完成后用户是否可见。
现在,你的测试应该是隔离的,因此,无论何时运行测试,从服务器或任何第三方服务调用实际的 API 都会造成依赖性且效率低下,这不符合隔离原则。所以,我们应该模拟 API 请求并返回我们自己的示例响应。
因此,我使用了react-mock包,它提供了一个方便的 API 来模拟 fetch 请求。
首先,我们添加所需的导入并创建一个要返回的示例用户数组。
import React from 'react'
import { render } from '@testing-library/react'
import { FetchMock } from '@react-mock/fetch'
import Users from './Users'
import { User } from 'types/users'
const users: Partial<User>[] = [
{
id: 1,
name: 'Leanne Graham',
email: 'Sincere@april.biz',
},
{
id: 2,
name: 'Ervin Howell',
email: 'Shanna@melissa.tv',
},
]
注意:除了 render 函数之外,还导入了一些其他函数,即waitForElement. 这只是我们需要用来断言元素在任何异步操作后是否存在于 DOM 中的方法。
其次,我们创建了一个辅助方法,该方法使用该FetchMock组件来模拟我们的 API。
const renderUsers = () => {
return render(
<FetchMock
matcher="https://jsonplaceholder.typicode.com/users"
response={users}
>
<Users />
</FetchMock>
)
}
这里我们在 prop 中提供了 API 的 URL matcher,该responseprop 包含我们正在模拟的用户数据。
注意:我没有包含 API 返回的所有字段,而只包含了其中的一部分字段,特别是那些在组件中渲染的字段。
最后,我们test按如下方式编写代码块。
test(`should render the users list`, async () => {
const { getByLabelText, findByRole } = renderUsers()
expect(getByLabelText('loading')).toBeInTheDocument()
let userList = await findByRole('list')
expect(userList.children.length).toEqual(users.length)
})
现在,精彩的部分来了。
第一行很简单,渲染 Users 组件,并使用FetchMock包装器获取getByLabelText查询组件元素的方法。
第二行代码判断加载文本是否显示在用户界面中。这是通过toBeInTheDocument匹配器实现的,匹配条件aria-label是我们添加到p标签中的值。
注意: toBeInTheDocument这不是 Jest 原生的匹配器,而是来自jest-domsetupTests.ts库。我们通过在创建一个src并添加以下代码import '@testing-library/jest-dom/extend-expect'。这将自动添加我们可以与 一起使用的 DOM 匹配器expect。
第三行是我们使用该findByRole方法获取列表的地方。
let userList = await findByRole('list')
我们之所以在这里使用await这种方法,是因为它返回一个 Promise 对象,并接受一个匹配器(以角色形式),该匹配器会返回一个 HTML 元素。在我们的模拟 API 返回我们提供的响应之前,它会一直等待指定的 DOM 元素,也就是ul我们渲染用户列表的标签。
在我们的组件中,API 成功返回响应后,加载内容会被替换为用户列表。因此,findByRole它会检查 DOM 中是否存在该元素,如果不存在,则会抛出错误。
由于我们的模拟 API 测试成功,findByRole将获取所需的元素,即ul标签。
在测试的第四行(也是最后一行),我们断言渲染的列表长度是否等于我们传递给模拟 API 的示例数据的长度。
expect(userList.children.length).toEqual(users.length)
如果你运行`pip install --test`yarn test或 ` npm testpip install --test`,你会看到测试通过了!现在,请在浏览器中使用 `pip install --test`yarn start或 `pip install --test` 运行你的应用程序npm start,你会看到加载指示器短暂出现,然后用户界面就会渲染出来。
上述示例的代码仓库位于此处。它包含了本系列上一篇文章中的示例,并且还将包含其他用例的示例。
注意:正如 Kent 在评论中提到的,我们可以在测试中添加另一行,以确保ul正确渲染用户及其电子邮件,从而保证我们传递的用户列表中的任何内容都能被渲染出来。
为此,Jest 提供了一种快照类型:内联快照!与外部快照不同,内联快照会将正在渲染的内容直接写入测试,而不是创建外部.snap文件。为此,您只需在测试中添加以下代码行即可。
expect(userList.textContent).toMatchInlineSnapshot()
ulJest 会自动填充方法中标签的内容toMatchInlineSnapshot。因此,保存测试后,它应该会更新为已通过的列表。很棒吧!
请修改我们传递的示例用户列表,保存文件,并注意此方法中反映的更改。
如果测试失败,请按u更新快照,以便获取您对用户列表所做的最新更改。
感谢阅读!
文章来源:https://dev.to/ryands17/testing-api-calls-88i