Jest / React 测试库:是否可以像 Cypress 一样监视和等待 GraphQL 查询?
Jest / React Testing Library: Is it Possible to Spy on and Wait GraphQL Queries as with Cypress?
我的大部分测试经验都来自 Cypress。我正在尝试使用 React 测试库(以下简称 "RTL")测试一些 React 组件。我想知道我是否可以应用我在 Cypress 中使用的一些技术。
我的(网络)应用程序有一部分显示来自数据库的 table 搜索结果。搜索 API 是在 GraphQL 中实现的。我们在前端使用 Apollo。可以针对 <FilterCheckbox/>
组件过滤搜索。它包括四个复选框和一个 "Clear All" 按钮。复选框状态存储在 Apollo 缓存中。
我正在为此组件编写规范。我想测试前两个复选框是否默认选中,单击 "Clear Filters" 会取消选中它们。我有以下内容:
import React from 'react'
import FilterCheckboxes from './FilterCheckboxes'
import { render, fireEvent } from 'Utils/test-utils'
import {
getByText,
getByTestId
} from '@testing-library/dom'
const props = {
options: [
{ label: 'new', value: 'FRESH' },
{ label: 'active', value: 'ACTIVE' },
{ label: 'closed', value: 'CLOSED' },
{ label: 'removed', value: 'ARCHIVED' },
],
statusArray: [
'FRESH',
'ACTIVE',
],
cacheKey: 'status',
}
describe('FilterCheckboxes component', () => {
const { container } = render(<FilterCheckboxes {...props} />)
const checkNew = getByTestId(container,'checkbox_new')
.querySelector('input[type="checkbox"]')
const checkActive = getByTestId(container, 'checkbox_active')
.querySelector('input[type="checkbox"]')
const checkClosed = getByTestId(container,'checkbox_closed' )
.querySelector('input[type="checkbox"]')
const checkRemoved = getByTestId(container, 'checkbox_removed')
.querySelector('input[type="checkbox"]')
const clearButton = getByText(container, 'clear status filters')
it('should render the checkboxes with the correct default state', () => {
expect(checkNew).toHaveProperty('checked', true)
expect(checkActive).toHaveProperty('checked', true)
expect(checkClosed).toHaveProperty('checked', false)
expect(checkRemoved).toHaveProperty('checked', false)
})
it('Should clear all checkboxes when clear filters is clicked', () => {
fireEvent.click(clearButton)
setTimeout(() => {
expect(checkNew).toHaveProperty('checked', false)
expect(checkActive).toHaveProperty('checked', false)
expect(checkClosed).toHaveProperty('checked', false)
expect(checkRemoved).toHaveProperty('checked', false)
}, 500)
})
})
测试通过,但第二个测试只有在我任意延迟 500 毫秒后才能通过。没有它,当 expect()
调用触发时,复选框仍处于默认状态。
如果这是 Cypress 测试并且 onClick 调用了 REST API,我会这样做:
cy.server()
cy.route('POST', '/foo/bar/v2', '@someAliasedFixture').as('fooBar')
cy.get('.my-button')
.click()
.then(() => {
cy.wait('@fooBar')
// continue test here as we know that the call completed
})
是否可以用 Jest / RTL / GraphQL / Apollo 做这样的事情?
更新:
今天早上又看了一眼。 waitFor()
似乎是打算在异步场景中使用的功能。但是,如果我这样做
it('should deselect checkboxes when Clear Filters is clicked', async () => {
fireEvent.click(clearButton)
waitFor(expect(checkNew).toHaveProperty('checked', false))
})
它只是失败了,因为复选框仍然被选中。肯定有办法用 RTL 测试这个吗?
根据我看过的示例,正统的方法似乎是将点击处理程序函数作为道具传递,然后 expect()
它 .toHaveBeenCalled()
调用。
对吗?这对我来说似乎是错误的。我的组件不是让 onClick 处理程序触发以响应单击事件的原因。 React.js 让这成为现实。检查 foo()
在单击 <MyComponent onClick={foo}/>
时是否被调用并不是测试 my 代码是否有效。它正在测试 React.js 是否有效。
已解决!
感谢@flo:
it('should render the checkboxes with the correct default state', () => {
expect(checkNew).toBeChecked()
expect(checkActive).toBeChecked()
expect(checkClosed).not.toBeChecked()
expect(checkRemoved).not.toBeChecked()
})
it('should deselect checkboxes when Clear Filters is clicked', async () => {
fireEvent.click(clearButton)
waitFor(() => {
expect(checkNew).not.toBeChecked()
expect(checkActive).not.toBeChecked()
expect(checkClosed).not.toBeChecked()
expect(checkRemoved).not.toBeChecked()
})
})
我同意,您应该像真实用户一样进行测试,因此您绝对应该测试复选框是否处于正确状态,而不是测试是否调用了点击处理程序。这就是推广 react-testing-library 的原因。
你确定吗?
expect(checkNew).toHaveProperty('checked', false);
我从未使用过它,但阅读文档后我不确定这是否能完成工作 (https://jestjs.io/docs/en/expect#tohavepropertykeypath-value)。事实上,我不知道它是如何工作的。
您考虑过使用 https://github.com/testing-library/jest-dom, and in particular https://github.com/testing-library/jest-dom#tobechecked 吗?
我的大部分测试经验都来自 Cypress。我正在尝试使用 React 测试库(以下简称 "RTL")测试一些 React 组件。我想知道我是否可以应用我在 Cypress 中使用的一些技术。
我的(网络)应用程序有一部分显示来自数据库的 table 搜索结果。搜索 API 是在 GraphQL 中实现的。我们在前端使用 Apollo。可以针对 <FilterCheckbox/>
组件过滤搜索。它包括四个复选框和一个 "Clear All" 按钮。复选框状态存储在 Apollo 缓存中。
我正在为此组件编写规范。我想测试前两个复选框是否默认选中,单击 "Clear Filters" 会取消选中它们。我有以下内容:
import React from 'react'
import FilterCheckboxes from './FilterCheckboxes'
import { render, fireEvent } from 'Utils/test-utils'
import {
getByText,
getByTestId
} from '@testing-library/dom'
const props = {
options: [
{ label: 'new', value: 'FRESH' },
{ label: 'active', value: 'ACTIVE' },
{ label: 'closed', value: 'CLOSED' },
{ label: 'removed', value: 'ARCHIVED' },
],
statusArray: [
'FRESH',
'ACTIVE',
],
cacheKey: 'status',
}
describe('FilterCheckboxes component', () => {
const { container } = render(<FilterCheckboxes {...props} />)
const checkNew = getByTestId(container,'checkbox_new')
.querySelector('input[type="checkbox"]')
const checkActive = getByTestId(container, 'checkbox_active')
.querySelector('input[type="checkbox"]')
const checkClosed = getByTestId(container,'checkbox_closed' )
.querySelector('input[type="checkbox"]')
const checkRemoved = getByTestId(container, 'checkbox_removed')
.querySelector('input[type="checkbox"]')
const clearButton = getByText(container, 'clear status filters')
it('should render the checkboxes with the correct default state', () => {
expect(checkNew).toHaveProperty('checked', true)
expect(checkActive).toHaveProperty('checked', true)
expect(checkClosed).toHaveProperty('checked', false)
expect(checkRemoved).toHaveProperty('checked', false)
})
it('Should clear all checkboxes when clear filters is clicked', () => {
fireEvent.click(clearButton)
setTimeout(() => {
expect(checkNew).toHaveProperty('checked', false)
expect(checkActive).toHaveProperty('checked', false)
expect(checkClosed).toHaveProperty('checked', false)
expect(checkRemoved).toHaveProperty('checked', false)
}, 500)
})
})
测试通过,但第二个测试只有在我任意延迟 500 毫秒后才能通过。没有它,当 expect()
调用触发时,复选框仍处于默认状态。
如果这是 Cypress 测试并且 onClick 调用了 REST API,我会这样做:
cy.server()
cy.route('POST', '/foo/bar/v2', '@someAliasedFixture').as('fooBar')
cy.get('.my-button')
.click()
.then(() => {
cy.wait('@fooBar')
// continue test here as we know that the call completed
})
是否可以用 Jest / RTL / GraphQL / Apollo 做这样的事情?
更新:
今天早上又看了一眼。 waitFor()
似乎是打算在异步场景中使用的功能。但是,如果我这样做
it('should deselect checkboxes when Clear Filters is clicked', async () => {
fireEvent.click(clearButton)
waitFor(expect(checkNew).toHaveProperty('checked', false))
})
它只是失败了,因为复选框仍然被选中。肯定有办法用 RTL 测试这个吗?
根据我看过的示例,正统的方法似乎是将点击处理程序函数作为道具传递,然后 expect()
它 .toHaveBeenCalled()
调用。
对吗?这对我来说似乎是错误的。我的组件不是让 onClick 处理程序触发以响应单击事件的原因。 React.js 让这成为现实。检查 foo()
在单击 <MyComponent onClick={foo}/>
时是否被调用并不是测试 my 代码是否有效。它正在测试 React.js 是否有效。
已解决! 感谢@flo:
it('should render the checkboxes with the correct default state', () => {
expect(checkNew).toBeChecked()
expect(checkActive).toBeChecked()
expect(checkClosed).not.toBeChecked()
expect(checkRemoved).not.toBeChecked()
})
it('should deselect checkboxes when Clear Filters is clicked', async () => {
fireEvent.click(clearButton)
waitFor(() => {
expect(checkNew).not.toBeChecked()
expect(checkActive).not.toBeChecked()
expect(checkClosed).not.toBeChecked()
expect(checkRemoved).not.toBeChecked()
})
})
我同意,您应该像真实用户一样进行测试,因此您绝对应该测试复选框是否处于正确状态,而不是测试是否调用了点击处理程序。这就是推广 react-testing-library 的原因。
你确定吗?
expect(checkNew).toHaveProperty('checked', false);
我从未使用过它,但阅读文档后我不确定这是否能完成工作 (https://jestjs.io/docs/en/expect#tohavepropertykeypath-value)。事实上,我不知道它是如何工作的。
您考虑过使用 https://github.com/testing-library/jest-dom, and in particular https://github.com/testing-library/jest-dom#tobechecked 吗?