'How to test ant design Select and Option properly using jest?
I am using Ant Design for my select form component and I would like to test the options value because the values will change dynamically based on the different choices that user made while filling.
my-test.spec.js
let questionDropdown
await waitFor(() => {
questionDropdown = screen.getByRole('combobox', { name: 'Question'})
expect(questionDropdown).toBeDefined()
})
fireEvent.click(questionDropdown)
// Hoping to test the options after clicking on the select, but I can't find the options element on screen
// expect(screen.getByText('question 1')).toBeDefined()
// expect(screen.queryAllByRole('option').length).toEqual(2)
I found this issues in antd about how to mock the Select and Options components.
jest.mock('antd', () => {
const antd = jest.requireActual('antd');
const Select = ({ children, onChange }) => {
return <select onChange={e => onChange(e.target.value)}>{children}</select>;
};
Select.Option = ({ children, ...otherProps }) => {
return <option {...otherProps}>{children}</option>;
}
return {
...antd,
Select,
}
}
but still have no luck getting my options tested.
Solution 1:[1]
You can test it without mocking. See this example:
import { Select, SelectProps } from 'antd';
import React from 'react';
const { Option } = Select;
export type Period = 'days' | 'months' | 'years';
const ranges = [
{ name: 'Dia', duration: 'days' },
{ name: 'Mês', duration: 'months' },
{ name: 'Ano', duration: 'years' },
];
export type PeriodRangePickerProps = Pick<SelectProps<Period>, 'value' | 'onChange' | 'style'>;
const PeriodRangePicker = ({ value, onChange, style }: PeriodRangePickerProps) => (
<Select style={style || { width: 90 }} showSearch optionFilterProp="children" {...{ value, onChange }}>
{ranges.map(({ duration, name }) => (
<Option key={duration} value={duration}>
% {name}
</Option>
))}
</Select>
);
export default PeriodRangePicker;
import PeriodRangePicker from '@components/PeriodRangePicker/PeriodRangePicker';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
describe('PeriodRangePicker', () => {
it('should call onChange with correct values', async () => {
const handleChangeStub = jest.fn();
render(<PeriodRangePicker onChange={handleChangeStub} />);
const periodSelect = screen.getByRole('combobox');
await userEvent.click(periodSelect);
await waitFor(() => screen.getByText('% Dia'));
fireEvent.click(screen.getByText('% Dia'));
expect(handleChangeStub).toBeCalledWith('days', expect.anything());
});
});
Solution 2:[2]
I added a more complete example of a mock for the Ant Design Select component which works great so far (in the middle of a 300 unit tests migration mocking antd Select :)). I placed this mock in a setupTests.js file in my project src folder (I'm using CRA).
With this kind of mock, you can test select options like this :
const options = Array.from(mySelect.querySelectorAll('option')).map(o => o.getAttribute('value');
expect(options).toEqual(['value1', 'value2', 'value3'];
expect(mySelect).toHaveValue('selectedValue');
This example only grabs options value attributes, you can also test textContent (displayed values), by modifying the function applied in map.
To interact with the select, as explained by angkiki, you just need to fireEvent.change(mySelect, { target: { value: 'value2' } });, and act() should not be necessary since react-testing-library takes care of that for you. If you still have issues with annoying warnings about using act, see https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning.
Solution 3:[3]
Since you have mocked it as such, your interaction with the Select component should be
const questionDropdown = await screen.getByRole('combobox', { name: 'Question'});
act(() => {
fireEvent.change(questionDropdown, { target: value: { CHANGE_VALUE } });
});
For testing the Select component without mocking, it should be something like this
const questionDropdown = await screen.getByRole('combobox', { name: 'Question' });
act(() => {
fireEvent.click(questionDropdown);
});
// basically, you should be able to find the elements of the
// dropdown after you fire the click even on the select
const questionOneEle = await screen.getByText('question 1');
act(() => {
fireEvent.click(questionOneEle);
});
// you can consider using jest-dom to run an assertion here
// at the top of your test file -> import '@testing-library/jest-dom'
expect(questionDropdown).toHaveValue(YOUR_EXPECTED_VALUE);
The annoying thing with testing this way, however, is that due to the way antd handles their select component, there's quite a bit of opacity to the dropdown items that gets rendered, which might make debugging failing tests a little difficult.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Michael Pacheco |
| Solution 2 | |
| Solution 3 | Alex Lomia |
