Мне нужно смоделировать функцию useAxios
, но она вызывается в двух разных компонентах, и один из этих компонентов используется внутри другого. Это мой код:
import React, { useEffect, useState } from 'react'
import useAxios from 'axios-hooks'
import { Table, Space } from 'antd'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faEdit, faCalendar, faUserPlus, faTimes } from '@fortawesome/free-solid-svg-icons'
export const RemoveProjectButton = ({ project, updateProjects }) => {
const [, execute] = useAxios(
{
url: `${process.env.REACT_APP_API_URL}/projects/${project.key}/`,
method: 'delete'
},
{
manual: true
}
)
const removeProject = async (project) => {
await execute()
updateProjects(project)
}
return <a data-testid={`project-${project.key}`} onClick={() => { removeProject(project) }}><FontAwesomeIcon icon={faTimes} /></a>
}
export const Projects = () => {
const [projects, setProjects] = useState([])
const [{ data, loading, error }] = useAxios(
`${process.env.REACT_APP_API_URL}/projects/`
)
useEffect(() => {
setProjects(data)
}, [data])
useEffect(() => {}, [projects])
const updateProjects = (projectToDelete) => {
setProjects(() => projects.filter(project => project.key !== projectToDelete.key))
}
if (loading) return <p data-testid='loading'>Loading...</p>
if (error) return <p data-testid='error'>Error!</p>
const columns = [
{
title: 'Title',
dataIndex: 'title',
key: 'title',
render: title => <a>{title}</a>
},
{
title: 'Start Date',
dataIndex: 'startDate',
key: 'startDate'
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
render: description => `${description.substring(0, 50)}...`
},
{
title: 'Team',
dataIndex: 'team',
key: 'team'
},
{
title: 'Action',
key: 'action',
render: (text, record, index) => (
<Space size='middle'>
<FontAwesomeIcon icon={faEdit} />
<FontAwesomeIcon icon={faCalendar} />
<FontAwesomeIcon icon={faUserPlus} />
<RemoveProjectButton project={record} updateProjects={updateProjects} />
</Space>
)
}
]
return (
<Table
data-testid='project-table'
columns={columns}
dataSource={projects}
pagination={false}
/>
)
}
и это мой тест:
import React from 'react'
import { render, cleanup, fireEvent } from '@testing-library/react'
import { Projects, RemoveProjectButton } from '../Projects'
import useAxios from 'axios-hooks'
jest.mock('axios-hooks')
const TABLE_TEST_ID = 'project-table'
const fakeData = [
{
key: 1,
title: 'Testing Project Alpha',
startDate: '2020-04-18',
description: 'This is just for testing',
team: 'A, B, C'
},
{
key: 2,
title: 'Testing Project Beta',
startDate: '2020-04-19',
description: 'This is just for testing too',
team: 'X, Y, Z'
}
]
describe('projects table', () => {
let projects
beforeEach(() => {
projects = JSON.parse(JSON.stringify(fakeData))
useAxios.mockReturnValue([{
data: projects,
loading: false,
error: null
}])
})
it('removes project when clicking on X button in row', async () => {
const { getByTestId, queryByTestId } = render(<Projects />)
const executeMock = jest.fn()
useAxios.mockReturnValue([{
data: projects,
loading: false,
error: null
}])
.mockReturnValue([{}, executeMock])
.mockReturnValue([{}, executeMock])
expect(getByTestId(TABLE_TEST_ID)).toHaveTextContent('Testing Project Alpha')
await fireEvent.click(getByTestId('project-1'))
expect(queryByTestId('project-1')).toBeNull()
expect(getByTestId(TABLE_TEST_ID)).not.toHaveTextContent('Testing Project Alpha')
})
})
Однако я получаю следующую ошибку:
TypeError: execute is not a function
16 | )
17 | const removeProject = async (project) => {
> 18 | await execute()
| ^
19 | updateProjects(project)
20 | }
21 |
Я понимаю, что проблема в том, что я не передаю правильный макет для компонента RemoveProjectButton
. Однако я понятия не имею, как мне этого добиться, потому что useAxios
вызывается в разных компонентах и должно иметь разные возвращаемые значения. Я также пытался использовать mockImplementationOnce
, но кажется, что компонент Projects
визуализируется несколько раз перед рендерингом компонента RemoveProjectButton
, поэтому я чувствую, что мне нужно угадать, сколько раз мне придется использовать mockImplementationOnce
.