从外部组件反应测试库触发回调
Trigger callback from external component react testing library
我正在尝试弄清楚如何测试作为 props 给出的回调,以使用 jest 和 React 测试库对功能组件做出反应。
示例场景:我正在测试呈现模式的组件。当用户单击模态框上的 'Close' 按钮时,父组件会隐藏模态框。所以逻辑是这样的:
const ParentComp = () => {
const [openModal, setOpenModal] = useState(false);
return (
<>
<MyModal showModal={openModal} onClose={() => setOpenModal(false)} />
<button data-testid="open-modal-button" onClick={()=> setOpenModal(true)}>Test</button>
</>
}
const MyModal = ({showModal, onClose}) => {
return (
{showModal && <>
<div>This is a modal</div>
<button data-testid="close-modal-button" onClick={onClose}>Close</button>
</>
}
}
我在父组件的测试中模拟模态,因为我不想依赖实际的模态组件。使用 React 测试库,如何在我的父组件中触发 onClose 以便我可以测试 setOpenModal(false)?
jest.mock('../MyModal');
beforeEach(() => {
MyModal.mockImplementation(() => <div data-testid="my-modal" />);
});
it('should close the modal' () => {
const { container, getByTestId } = render(
<MyParentComp />
);
const openModalButton = getByTestId('open-modal-button');
fireEvent.click(openModalButton);
const myModal = getByTestId('my-modal');
expect(myModal).toBeDefined();
//How to test setOpenModal(false) on parent component?
});
对于您的示例,实际上不需要模拟 MyModal
组件,除非 MyModal
组件有很多外部依赖项。参见 testing-recipes.html#mocking-modules。
为了触发onClose
功能,您还需要在MyModal
组件上触发onClick
功能。
此外,您没有正确模拟 MyModal 组件。这是一个工作示例:
ParentComp.tsx
:
import React, { useState } from 'react';
import { MyModal } from './MyModal';
export const ParentComp = () => {
const [openModal, setOpenModal] = useState(false);
return (
<>
<MyModal showModal={openModal} onClose={() => setOpenModal(false)} />
<button data-testid="open-modal-button" onClick={() => setOpenModal(true)}>
Test
</button>
</>
);
};
MyModal.tsx
:
import React from 'react';
export const MyModal = ({ showModal, onClose }) => {
return (
showModal && (
<>
<div>This is a modal</div>
<button data-testid="close-modal-button" onClick={onClose}>
Close
</button>
</>
)
);
};
ParentComp.test.tsx
:
import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import { ParentComp } from './ParentComp';
function MockedMyModal({ onClose, showModal }) {
return (
showModal && (
<>
<div>This is a mocked modal</div>
<button data-testid="my-modal" onClick={onClose}>
Close
</button>
</>
)
);
}
jest.mock('./MyModal', () => {
return { MyModal: MockedMyModal };
});
describe('65038548', () => {
afterAll(() => {
jest.resetAllMocks();
});
it('should open the modal', () => {
const { getByTestId } = render(<ParentComp></ParentComp>);
const openModalButton = getByTestId('open-modal-button');
fireEvent.click(openModalButton);
const myModal = getByTestId('my-modal');
expect(myModal).toBeDefined();
});
it('should close the modal', () => {
const { getByTestId, queryByText } = render(<ParentComp></ParentComp>);
const openModalButton = getByTestId('open-modal-button');
fireEvent.click(openModalButton);
const closeModalButton = getByTestId('my-modal');
expect(closeModalButton).toBeDefined();
fireEvent.click(closeModalButton);
expect(queryByText('This is a mocked modal')).toBeNull();
});
});
为什么使用 queryByText
而不是 getByTestId
,参见
单元测试结果:
PASS examples/65038548/ParentComp.test.tsx
65038548
✓ should pass (34 ms)
----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------|---------|----------|---------|---------|-------------------
All files | 87.5 | 100 | 66.67 | 85.71 |
ParentComp.tsx | 87.5 | 100 | 66.67 | 85.71 | 8
----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 5.848 s
源代码:https://github.com/mrdulin/jest-v26-codelab/tree/main/examples/65038548
我正在尝试弄清楚如何测试作为 props 给出的回调,以使用 jest 和 React 测试库对功能组件做出反应。
示例场景:我正在测试呈现模式的组件。当用户单击模态框上的 'Close' 按钮时,父组件会隐藏模态框。所以逻辑是这样的:
const ParentComp = () => {
const [openModal, setOpenModal] = useState(false);
return (
<>
<MyModal showModal={openModal} onClose={() => setOpenModal(false)} />
<button data-testid="open-modal-button" onClick={()=> setOpenModal(true)}>Test</button>
</>
}
const MyModal = ({showModal, onClose}) => {
return (
{showModal && <>
<div>This is a modal</div>
<button data-testid="close-modal-button" onClick={onClose}>Close</button>
</>
}
}
我在父组件的测试中模拟模态,因为我不想依赖实际的模态组件。使用 React 测试库,如何在我的父组件中触发 onClose 以便我可以测试 setOpenModal(false)?
jest.mock('../MyModal');
beforeEach(() => {
MyModal.mockImplementation(() => <div data-testid="my-modal" />);
});
it('should close the modal' () => {
const { container, getByTestId } = render(
<MyParentComp />
);
const openModalButton = getByTestId('open-modal-button');
fireEvent.click(openModalButton);
const myModal = getByTestId('my-modal');
expect(myModal).toBeDefined();
//How to test setOpenModal(false) on parent component?
});
对于您的示例,实际上不需要模拟 MyModal
组件,除非 MyModal
组件有很多外部依赖项。参见 testing-recipes.html#mocking-modules。
为了触发onClose
功能,您还需要在MyModal
组件上触发onClick
功能。
此外,您没有正确模拟 MyModal 组件。这是一个工作示例:
ParentComp.tsx
:
import React, { useState } from 'react';
import { MyModal } from './MyModal';
export const ParentComp = () => {
const [openModal, setOpenModal] = useState(false);
return (
<>
<MyModal showModal={openModal} onClose={() => setOpenModal(false)} />
<button data-testid="open-modal-button" onClick={() => setOpenModal(true)}>
Test
</button>
</>
);
};
MyModal.tsx
:
import React from 'react';
export const MyModal = ({ showModal, onClose }) => {
return (
showModal && (
<>
<div>This is a modal</div>
<button data-testid="close-modal-button" onClick={onClose}>
Close
</button>
</>
)
);
};
ParentComp.test.tsx
:
import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import { ParentComp } from './ParentComp';
function MockedMyModal({ onClose, showModal }) {
return (
showModal && (
<>
<div>This is a mocked modal</div>
<button data-testid="my-modal" onClick={onClose}>
Close
</button>
</>
)
);
}
jest.mock('./MyModal', () => {
return { MyModal: MockedMyModal };
});
describe('65038548', () => {
afterAll(() => {
jest.resetAllMocks();
});
it('should open the modal', () => {
const { getByTestId } = render(<ParentComp></ParentComp>);
const openModalButton = getByTestId('open-modal-button');
fireEvent.click(openModalButton);
const myModal = getByTestId('my-modal');
expect(myModal).toBeDefined();
});
it('should close the modal', () => {
const { getByTestId, queryByText } = render(<ParentComp></ParentComp>);
const openModalButton = getByTestId('open-modal-button');
fireEvent.click(openModalButton);
const closeModalButton = getByTestId('my-modal');
expect(closeModalButton).toBeDefined();
fireEvent.click(closeModalButton);
expect(queryByText('This is a mocked modal')).toBeNull();
});
});
为什么使用 queryByText
而不是 getByTestId
,参见
单元测试结果:
PASS examples/65038548/ParentComp.test.tsx
65038548
✓ should pass (34 ms)
----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------|---------|----------|---------|---------|-------------------
All files | 87.5 | 100 | 66.67 | 85.71 |
ParentComp.tsx | 87.5 | 100 | 66.67 | 85.71 | 8
----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 5.848 s
源代码:https://github.com/mrdulin/jest-v26-codelab/tree/main/examples/65038548