Ant Design & React Testing Library - Testing Form with Select - reactjs

I'm attempting to test a Select input inside an Ant Design Form filled with initialValues and the test is failing because the Select does not receive a value. Is there a best way to test a "custom" rendered select?
Test Output:
Error: expect(element).toHaveValue(chocolate)
Expected the element to have value:
chocolate
Received:
Example Test:
import { render, screen } from '#testing-library/react';
import { Form, Select } from 'antd';
const customRender = (ui: React.ReactElement, options = {}) => render(ui, {
wrapper: ({ children }) => children,
...options,
});
describe('select tests', () => {
it('renders select', () => {
const options = [
{ label: 'Chocolate', value: 'chocolate' },
{ label: 'Strawberry', value: 'strawberry' },
{ label: 'Vanilla', value: 'vanilla' },
];
const { value } = options[0];
customRender(
<Form initialValues={{ formSelectItem: value }}>
<Form.Item label="Form Select Label" name="formSelectItem">
<Select options={options} />
</Form.Item>
</Form>,
);
expect(screen.getByLabelText('Form Select Label')).toHaveValue(value);
});
});

testing a library component may be harsh sometimes because it hides internal complexity.
for testing antd select i suggest to mock it and use normal select in your tests like this:
jest.mock('antd', () => {
const antd = jest.requireActual('antd');
const Select = ({ children, onChange, ...rest }) => {
return <select role='combobox' onChange={e => onChange(e.target.value)}>
{children}
</select>;
};
Select.Option = ({ children, ...otherProps }) => {
return <option role='option' {...otherProps}}>{children}</option>;
}
return {
...antd,
Select,
}
})
this way you can test the select component as a normal select (use screen.debug to check that the antd select is mocked)

I mocked a normal select and was able to get everything working.
The following example utilizes Vitest for a test runner but should apply similar to Jest.
antd-mock.tsx
import React from 'react';
import { vi } from 'vitest';
vi.mock('antd', async () => {
const antd = await vi.importActual('antd');
const Select = props => {
const [text, setText] = React.useState('');
const multiple = ['multiple', 'tags'].includes(props.mode);
const handleOnChange = e => props.onChange(
multiple
? Array.from(e.target.selectedOptions)
.map(option => option.value)
: e.target.value,
);
const handleKeyDown = e => {
if (e.key === 'Enter') {
props.onChange([text]);
setText('');
}
};
return (
<>
<select
// add value in custom attribute to handle async selector,
// where no option exists on load (need to type to fetch option)
className={props.className}
data-testid={props['data-testid']}
data-value={props.value || undefined}
defaultValue={props.defaultValue || undefined}
disabled={props.disabled || undefined}
id={props.id || undefined}
multiple={multiple || undefined}
onChange={handleOnChange}
value={props.value || undefined}
>
{props.children}
</select>
{props.mode === 'tags' && (
<input
data-testid={`${props['data-testid']}Input`}
onChange={e => setText(e.target.value)}
onKeyDown={handleKeyDown}
type="text"
value={text}
/>
)}
</>
);
};
Select.Option = ({ children, ...otherProps }) => (
<option {...otherProps}>{children}</option>
);
Select.OptGroup = ({ children, ...otherProps }) => (
<optgroup {...otherProps}>{children}</optgroup>
);
return { ...antd, Select };
});
utils.tsx
import { render } from '#testing-library/react';
import { ConfigProvider } from 'antd';
const customRender = (ui: React.ReactElement, options = {}) => render(ui, {
wrapper: ({ children }) => <ConfigProvider prefixCls="bingo">{children}</ConfigProvider>,
...options,
});
export * from '#testing-library/react';
export { default as userEvent } from '#testing-library/user-event';
export { customRender as render };
Select.test.tsx
import { Form } from 'antd';
import { render, screen, userEvent } from '../../../test/utils';
import Select from './Select';
const options = [
{ label: 'Chocolate', value: 'chocolate' },
{ label: 'Strawberry', value: 'strawberry' },
{ label: 'Vanilla', value: 'vanilla' },
];
const { value } = options[0];
const initialValues = { selectFormItem: value };
const renderSelect = () => render(
<Form initialValues={initialValues}>
<Form.Item label="Label" name="selectFormItem">
<Select options={options} />
</Form.Item>
</Form>,
);
describe('select tests', () => {
it('renders select', () => {
render(<Select options={options} />);
expect(screen.getByRole('combobox')).toBeInTheDocument();
});
it('renders select with initial values', () => {
renderSelect();
expect(screen.getByLabelText('Label')).toHaveValue(value);
});
it('handles select change', () => {
renderSelect();
expect(screen.getByLabelText('Label')).toHaveValue(value);
userEvent.selectOptions(screen.getByLabelText('Label'), 'vanilla');
expect(screen.getByLabelText('Label')).toHaveValue('vanilla');
});
});

Related

Creating test cases for react components using jest/RTL for RequestPreferencesEdit

Creating test cases for react components using jest/RTL-please i need a guidence for improve my coverage in my test cases ,
My React component is RequestPreferencesEdit.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { FormattedMessage, injectIntl } from 'react-intl';
import { Field } from 'react-final-form';
import {
get,
isEmpty,
difference,
} from 'lodash';
import fp from 'lodash/fp';
import {
Row,
Col,
Select,
Checkbox,
Label,
} from '#folio/stripes/components';
import { deliveryFulfillmentValues } from '../../../../constants';
import { addressTypesShape } from '../../../../shapes';
import { nullOrStringIsRequiredTypeValidator } from '../../../../customTypeValidators';
import styles from './RequestPreferencesEdit.css';
class RequestPreferencesEdit extends Component {
static propTypes = {
deliveryAvailable: PropTypes.bool,
servicePoints: PropTypes.arrayOf(PropTypes.object),
addresses: PropTypes.arrayOf(PropTypes.shape({
addressType: PropTypes.string.isRequired,
})),
addressTypes: addressTypesShape,
setFieldValue: PropTypes.func.isRequired,
defaultDeliveryAddressTypeId: nullOrStringIsRequiredTypeValidator,
intl: PropTypes.object.isRequired,
}
componentDidUpdate(prevProps) {
if (this.isDefaultDeliveryAddressResetNeeded(prevProps.addresses, this.props.addresses)) {
this.resetDefaultDeliveryAddress();
}
if (prevProps.deliveryAvailable !== this.props.deliveryAvailable) {
this.onDeliveryCheckboxChange(this.props.deliveryAvailable);
}
}
isDefaultDeliveryAddressResetNeeded(prevAddresses, currentAddresses) {
const byAddressType = address => get(address, 'addressType');
const prevAddressTypeIds = (prevAddresses ?? []).map(byAddressType);
const currentAddressTypeIds = (currentAddresses ?? []).map(byAddressType);
const addressTypesAreChanged = difference(prevAddressTypeIds, currentAddressTypeIds).length !== 0;
const defaultAddressTypeNotExists = !currentAddressTypeIds
.some(addressTypeId => addressTypeId === this.props.defaultDeliveryAddressTypeId);
return addressTypesAreChanged && defaultAddressTypeNotExists;
}
renderDefaultDeliveryAddressSelect() {
return (
<div data-test-default-delivery-address-field>
<Field
name="requestPreferences.defaultDeliveryAddressTypeId"
label={<FormattedMessage id="ui-users.requests.defaultDeliveryAddress" />}
dataOptions={this.getAddressOptions()}
component={Select}
validate={this.defaultDeliveryAddressValidator}
placeholder={this.props.intl.formatMessage({ id: 'ui-users.requests.selectDeliveryAddress' })}
required
/>
</div>
);
}
renderServicePointSelect() {
const { servicePoints, intl } = this.props;
const options = servicePoints.map(servicePoint => ({
value: servicePoint.id,
label: servicePoint.name,
}));
const defaultOption = { value: '', label: intl.formatMessage({ id: 'ui-users.sp.selectServicePoint' }) };
const resultOptions = [defaultOption, ...options];
return (
<Field
name="requestPreferences.defaultServicePointId"
label={<FormattedMessage id="ui-users.requests.defaultPickupServicePoint" />}
dataOptions={resultOptions}
component={Select}
parse={this.defaultServicePointFieldParser}
/>
);
}
defaultServicePointFieldParser(value) {
return value === '' ? null : value;
}
renderFulfillmentPreferenceSelect() {
const { intl } = this.props;
const options = [
{
value: deliveryFulfillmentValues.HOLD_SHELF,
label: intl.formatMessage({ id: 'ui-users.requests.holdShelf' })
},
{
value: deliveryFulfillmentValues.DELIVERY,
label: intl.formatMessage({ id: 'ui-users.requests.delivery' })
},
];
return (
<Field
data-test-fulfillment-preference
name="requestPreferences.fulfillment"
label={<FormattedMessage id="ui-users.requests.fulfillmentPreference" />}
dataOptions={options}
component={Select}
/>
);
}
getAddressOptions() {
const {
addresses,
addressTypes,
} = this.props;
return addresses.reduce((options, address) => {
const { addressType: addressTypeId } = address;
const relatedAddressType = addressTypes
.find((currentAddressType) => currentAddressType.id === addressTypeId);
return [
...options,
{
value: get(relatedAddressType, 'id'),
label: get(relatedAddressType, 'addressType'),
}
];
}, []);
}
// eslint-disable-next-line consistent-return
defaultDeliveryAddressValidator = (value, formData) => {
const nonEmptyAddresses = get(formData, 'personal.addresses', []).filter(address => !isEmpty(address));
if (nonEmptyAddresses.length === 0) {
return <FormattedMessage id="ui-users.addAddressError" />;
}
if (!value) {
return <FormattedMessage id="ui-users.errors.missingRequiredField" />;
}
}
resetDefaultDeliveryAddress() {
this.props.setFieldValue('requestPreferences.defaultDeliveryAddressTypeId', null);
}
onDeliveryCheckboxChange = (deliveryAvailable) => {
const { setFieldValue } = this.props;
const fulfillmentValue = deliveryAvailable ? deliveryFulfillmentValues.HOLD_SHELF : null;
setFieldValue('requestPreferences.fulfillment', fulfillmentValue);
this.resetDefaultDeliveryAddress();
}
render() {
const {
deliveryAvailable,
} = this.props;
return (
<Col xs={12}>
<Row>
<Col
xs={12}
md={6}
>
<Label tagName="div">
<span className={styles.heading}>
<FormattedMessage id="ui-users.requests.preferences" />
</span>
</Label>
</Col>
</Row>
<Row className={styles.rowMargin}>
<Col xs={12} md={6}>
<Field
data-test-hold-shelf-checkbox
name="requestPreferences.holdShelf"
label={<FormattedMessage id="ui-users.requests.holdShelf" />}
checked
disabled
component={Checkbox}
type="checkbox"
/>
</Col>
<Col xs={12} md={6}>
<Field
data-test-delivery-checkbox
name="requestPreferences.delivery"
label={<FormattedMessage id="ui-users.requests.delivery" />}
component={Checkbox}
type="checkbox"
/>
</Col>
</Row>
<Row>
<Col xs={12} md={6}>
{this.renderServicePointSelect()}
</Col>
<Col xs={12} md={6}>
{ deliveryAvailable && this.renderFulfillmentPreferenceSelect() }
</Col>
</Row>
<Row>
<Col mdOffset={6} xs={12} md={6}>
{ deliveryAvailable && this.renderDefaultDeliveryAddressSelect() }
</Col>
</Row>
</Col>
);
}
}
const selectServicePointsWithPickupLocation = fp.pipe([
fp.getOr([], 'folio_users_service_points.records'),
fp.filter(servicePoint => servicePoint.pickupLocation),
fp.uniqBy('id'),
fp.sortBy('name'),
]);
export default connect(
store => ({
servicePoints: selectServicePointsWithPickupLocation(store),
}),
)(injectIntl(RequestPreferencesEdit));
I'm tried to creating test cases for my react component
My test case is
import { render, screen, fireEvent, waitFor } from '#testing-library/react';
import { Form, Field } from 'react-final-form';
import userEvent from '#testing-library/user-event';
import PropTypes from 'prop-types';
import { StripesContext } from '#folio/stripes-core/src/StripesContext';
import '__mock__/stripesComponents.mock';
import renderWithRouter from 'helpers/renderWithRouter';
import { nullOrStringIsRequiredTypeValidator } from '../../../../customTypeValidators';
import RequestPreferencesEdit from './RequestPreferencesEdit';
jest.mock('react-redux', () => ({
connect: () => (ReactComponent) => ReactComponent,
}));
jest.unmock('#folio/stripes/components');
jest.unmock('#folio/stripes/smart-components');
const onSubmit = jest.fn();
const setFieldMock = jest.fn();
let mockrenderServicePointSelect = jest.fn();
let mockrenderFulfillmentPreferenceSelect = jest.fn();
let mockrenderDefaultDeliveryAddressSelect = jest.fn();
let mockUpdateHobbies;
const renderRequestPreferencesEdit = (props) => {
const component = () => (
<>
<RequestPreferencesEdit {...props} />
</>
);
renderWithRouter(
<Form
id="form-user"
onSubmit={onSubmit}
render={component}
renderServicePointSelect= {mockrenderServicePointSelect}
renderFulfillmentPreferenceSelect = {mockrenderFulfillmentPreferenceSelect}
renderDefaultDeliveryAddressSelect={mockrenderDefaultDeliveryAddressSelect}
/>,
<Field
id="form-user"
onSubmit={onSubmit}
render={component}
renderServicePointSelect= {mockrenderServicePointSelect}
renderFulfillmentPreferenceSelect = {mockrenderFulfillmentPreferenceSelect}
renderDefaultDeliveryAddressSelect={mockrenderDefaultDeliveryAddressSelect}
/>
);
};
const props = {
renderServicePointSelect: {mockrenderServicePointSelect},
renderFulfillmentPreferenceSelect: { mockrenderFulfillmentPreferenceSelect},
renderDefaultDeliveryAddressSelect: {mockrenderDefaultDeliveryAddressSelect},
accordionId: 'EditContactInfo',
expanded: true,
onToggle: jest.fn(),
setFieldValue: setFieldMock,
deliveryAvailable: true,
intl: { formatMessage : jest.fn() },
servicePoints: [
{
name: 'servicePointsName',
id: 'd003c876-90f1-40da-90bc-a5dd3dedb9c6a',
name2: 'servicenameDefault',
id1: ''
}
],
addresses: [{
addressType: 'Industrial Zone'
}],
addressTypes: [{
addressType: 'Home',
id: '123123'
},
{
addressType: 'Work',
id: '123123132'
}]
};
//const renderRequestPreferencesEdit1 = () => renderWithRouter(<RequestPreferencesEdit {...props} />);
describe('request preference point', () => {
it('Must be rendered request preferences', () => {
renderRequestPreferencesEdit(props);
screen.debug(undefined, Infinity);
expect(screen.getByText('ui-users.requests.preferences')).toBeTruthy();
});
it('Must be rendered', () => {
renderRequestPreferencesEdit(props);
expect(screen.getByText('ui-users.requests.selectDeliveryAddress')).toBeInTheDocument();
});
it('Must be rendered request null value', () => {
renderRequestPreferencesEdit(props);
//screen.debug(undefined, Infinity);
expect(document.querySelector('ui-users.errors.missingRequiredField')).toBeNull();
});
it('Checkbox selection', async () => {
renderRequestPreferencesEdit(props);
let options = document.querySelector('[name="requestPreferences.holdShelf"]');
userEvent.click(options);
userEvent.selectOptions(document.querySelector('[data-test-fulfillment-preference="true"]'), 'Hold Shelf');
expect(screen.findByDisplayValue('Hold Shelf')).toBeTruthy();
expect(options).toBeChecked();
});
it('Service PointsWith Pickup Location', () => {
renderRequestPreferencesEdit(props);
expect(screen.findByLabelText('folio_users_service_points.records"')).toBeTruthy();
});
it('text conatain * ', () => {
renderRequestPreferencesEdit(props);
expect(screen.getByText('*')).toBeInTheDocument();
});
it('Checkbox selection delevery', async () => {
renderRequestPreferencesEdit(props);
userEvent.click(document.querySelector('[name="requestPreferences.fulfillment"]'));
userEvent.selectOptions(document.querySelector('[data-test-fulfillment-preference="true"]'), 'Delivery');
expect(screen.findByDisplayValue('Delivery')).toBeTruthy();
});
it('Must have defaultPickupServicePoint text ', () => {
renderRequestPreferencesEdit(props);
expect(screen.getByText('ui-users.requests.defaultPickupServicePoint')).toBeInTheDocument();
});
it('Checkbox selection selectServicePoint', async () => {
renderRequestPreferencesEdit(props);
userEvent.click(document.querySelector('[name="requestPreferences.defaultServicePointId"]'));
userEvent.selectOptions(document.querySelector('[ class="selectControl formControl"]'), '');
expect(screen.findByDisplayValue('')).toBeTruthy();
expect(screen.getByText('ui-users.sp.selectServicePoint')).toBeInTheDocument();
});
it('Checkbox selection selectServicePoint value servicePointsName', async () => {
renderRequestPreferencesEdit(props);
userEvent.click(document.querySelector('[name="requestPreferences.defaultServicePointId"]'));
userEvent.selectOptions(document.querySelector('[class="selectControl formControl"]'), 'd003c876-90f1-40da-90bc-a5dd3dedb9c6a');
expect(screen.findByDisplayValue('d003c876-90f1-40da-90bc-a5dd3dedb9c6a')).toBeTruthy();
expect(screen.getByText('servicePointsName')).toBeInTheDocument();
});
it('Checkbox selection selectServicePoint value fulfillmentPreference', async () => {
renderRequestPreferencesEdit(props);
expect(screen.queryByLabelText('ui-users.requests.fulfillmentPreference')).toBeTruthy();
});
it('label value defaultDeliveryAddress must null', async () => {
renderRequestPreferencesEdit(props);
expect(screen.queryByLabelText('ui-users.requests.defaultDeliveryAddress')).toBeNull();
});
it('Checkbox selection selectDeliveryAddress', async () => {
renderRequestPreferencesEdit(props);
userEvent.click(document.querySelector('[name="requestPreferences.defaultDeliveryAddressTypeId"]'));
userEvent.selectOptions(document.querySelector('[class="selectControl placeholder formControl"]'), '');
expect(screen.findByDisplayValue('')).toBeTruthy();
});
it('Checkbox selection selectDeliveryAddress changing', async () => {
renderRequestPreferencesEdit(props);
fireEvent.change(document.querySelector('[name="requestPreferences.defaultDeliveryAddressTypeId"]', { target: { value: 2 } }))
let options = document.querySelector('[name="requestPreferences.defaultDeliveryAddressTypeId"]');
expect(screen.findByDisplayValue(2)).toBeTruthy();
expect(options[0].selected).toBeTruthy();
expect(options[1].selected).toBeFalsy();
});
});
I got 75% coverage only, can any one guide for improve my test cases

react-select: Impossible to get value onBlur event

I have a problem with the react-select lib (see here: https://www.npmjs.com/package/react-select). For the validation of my form, I display an error message on the onBlur event. The problem is that no value appears in my logs.
However, onChange works fine.
Handler
const handleBlur = (e: FocusEvent<HTMLInputElement, Element>) => {
//Here, When I select a value and deselect the input, no value exists in this log.
console.log("value Select: ", e.target.value )
}
The return of my component function
<Select
placeholder={`Select ${name}`}
name={name}
id={id}
onBlur={(e) => {
handleBlur(e)
}}
onChange={(e) => {
setValueOnChange(e, name)
}}
options={options}
styles={customStyle}
/>
Anyone have a suggestion?
Thanks !
import "./styles.css";
import Select from "react-select";
import { useState } from "react";
export default function App() {
const options = [
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" }
];
const [value, setValue] = useState();
const [focusValue, setFocusValue] = useState();
const handleChange = (changeValue) => {
setValue(changeValue);
};
const handleFocus = (event) => {
const focusValue = event.target.value;
console.log("Should be focus value", focusValue);
setFocusValue(focusValue);
};
const handleBlur = (event) => {
const blurValue = event.target.value;
console.log("Should be blur value", blurValue);
if (focusValue !== blurValue) {
console.log("Do something");
}
};
return (
<div className="App">
<h1>React Select onFocus & onBlur </h1>
<Select
options={options}
value={value}
onChange={handleChange}
onFocus={handleFocus}
onBlur={handleBlur}
/>
</div>
);
}

React/Jest: Simulate users tampering with the HTML

In a React vanilla form, I need to solve an issue where users edit manually the value of an option to make the form submit bad values.
To reproduce, the users inspect the element, and manually change the value of an option to an invalid value (domain-wise).
The fix is easy, but I want to create a failing unit test before fixing, in a TDD fashion, and cannot figure how to model this in a test. I use jest and react-testing-library.
Here is the form code:
export const CreateTripForm = ({ countries, onSubmit }) => {
const [countryId, setCountryId] = useState()
const submit = async (e) => {
e.preventDefault()
if (countryId === undefined) return
await onSubmit(countryId)
}
return (
<form onSubmit={submit}>
<legend>Choose a country</legend>
<label htmlFor="countryId">Country</label>
<select name="countryId" required value={countryId} onChange={(e) => setCountryId(e.target.value)}>
<option value=""></option>
{countries.map((country) =>
<option key={country.id} value={country.id}>{country.label}</option>
)}
</select>
<input type="submit" value="Create a trip" />
</form>
)
}
Here is what I tried to do, but the test passes instead of failing:
it('keeps previous countryId if the selected one has been tampered with', () => {
const onSubmit = jest.fn(() => Promise.resolve())
const countries = [
{ id: 'fr', label: 'France' },
{ id: 'en', label: 'England' },
]
const { container } = render(
<CreateTripForm countries={countries} onSubmit={onSubmit} />
)
const select = container.querySelector('select[name=countryId]')
const submitButton = container.querySelector('input[type=select]')
// Select the 'fr' option, it works.
fireEvent.change(select, { target: { value: 'fr' } })
submitButton.click()
expect(onSubmit).toHaveBeenCalledWith('fr')
// Edit an option to have an incorrect value, it should keep the previous value.
elements.unitSelect.options[2].value = 'asgard'
fireEvent.change(select, { target: { value: 'asgard' } })
submitButton.click()
expect(onSubmit).toHaveBeenCalledWith('fr')
})
I've had some bad experiences with expect() like this before.
Have you tried to separate the tests? One for success and one for failure?
From what I can see, the first expect() doesn't reset what he have been called already so I guess that's why your test have passed on the second expect().
Try it like this:
it('keeps previous countryId if the selected one has been tampered with', () => {
const onSubmit = jest.fn(() => Promise.resolve())
const countries = [
{ id: 'fr', label: 'France' },
{ id: 'en', label: 'England' },
]
const { container } = render(
<CreateTripForm countries={countries} onSubmit={onSubmit} />
)
const select = container.querySelector('select[name=countryId]')
const submitButton = container.querySelector('input[type=select]')
// Select the 'fr' option, it works.
fireEvent.change(select, { target: { value: 'fr' } })
submitButton.click()
expect(onSubmit).toHaveBeenCalledWith('fr')
})
it('should prevent sending with tampered select', () => {
const onSubmit = jest.fn(() => Promise.resolve())
const countries = [
{ id: 'fr', label: 'France' },
{ id: 'en', label: 'England' },
]
const { container } = render(
<CreateTripForm countries={countries} onSubmit={onSubmit} />
)
const select = container.querySelector('select[name=countryId]')
const submitButton = container.querySelector('input[type=select]')
elements.unitSelect.options[2].value = 'asgard'
fireEvent.change(select, { target: { value: 'asgard' } })
submitButton.click()
expect(onSubmit).not.toHaveBeenCalled()
})

code is not covered by testing-library-react

I want to test a select change function,here is the code :
import React, { useEffect, useState } from 'react';
import Select from 'react-select';
function Component1(props) {
const [content, setContent] = useState('initialized Value');
const [color, setColor] = useState('initialized Value');
const options = [
{ value: 'red', label: 'Red' },
{ value: 'green', label: 'Green' },
{ value: 'blue', label: 'Blue' },
];
useEffect(async () => {
fetchSomeData();
// onclickButton();
}, []);
const fetchSomeData = async () => {
console.log('fetchSomeData');
};
const onclickButton = () => {
console.log('do something here onclickButton');
setContent('updated Value');
};
const resetColor = (value) => {
console.log(value);
setColor(value);
};
return (
<div data-testid='Component1'>
Component1
<button data-testid='button' onClick={onclickButton}>
Button
</button>
<div>Button Test :{content}</div>
<Select aria-label='select-Label' data-testid='select' options={options} value={color} onChange={resetColor} />
<div data-testid='color-value'>Current Color:{color}</div>
</div>
);
}
I did some reasearches , and they said the best way is mocked a select and test it:
beforeEach(() => {
render(<Component1 />);
});
test('should 3', () => {
jest.doMock('react-select', () => ({ options, value, onChange }) => {
function handleChange(event) {
const option = options.find((option) => option.value === event.currentTarget.value);
onChange(option);
}
return (
<select data-testid='custom-select' value={value} onChange={handleChange}>
{options.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</select>
);
});
fireEvent.change(screen.getByTestId('select'), {
target: { value: 'green' },
});
test('should 2', () => {
// screen.debug()
const onclickButton = jest.fn();
// render(<Component1 onclickButton={onclickButton} />);
fireEvent.click(screen.getByTestId('button'), {
// target: { value: 'JavaScript' },
});
});
after I run the test, I got this :
TestingLibraryElementError: Unable to find an element by: [data-testid="select"]
can some one help me? I just want below codes can be covered by unit test
update:
I tried to use queryByLabelText, and it works, but still ,it seems not trigger the onChange event. I got this:
Expected element to have text content:
Current Color:green
Received:
Current Color:red
fireEvent.select(screen.queryByLabelText('select-Label'),{target:{value:'green'}})
expect(screen.queryByTestId('color-value')).toHaveTextContent('Current Color:green');
I resolved it by below code:
const DOWN_ARROW = { keyCode: 40 };
fireEvent.keyDown(screen.getByLabelText('select-Label'), DOWN_ARROW);
fireEvent.click(screen.getByText('Green'));
these code will trigger onChange event.
also refter to:
how to test react-select with react-testing-library

In react hooks form, how to you copy data from one property to other of state?

This is register form, I want to send the value orgTypes>name to orgType of data of same object using onChange of select.
https://codesandbox.io/s/react-typescript-zm1ov?fontsize=14&fbclid=IwAR06ZifrKrDT_JFb0A-d_iu5YaSyuQ9qvLRgqS20JgAcSwLtAyaOFOoj5IQ
When I use onChange of Select, it erases all other data of the inputs.
import React from "react";
import { Select } from "antd";
const { Option } = Select;
const RegisterFinal = () => {
const data = {
orgName: "",
orgRegNo: "",
orgType: "",
orgTypes: [
{ id: "1", name: "Vendor" },
{ id: "2", name: "Supplier" },
{ id: "3", name: "Vendor and Supplier" }
],
errors: {}
};
const [values, setValues] = React.useState(data);
const handleChange = (e: any) => {
e.persist();
setValues((values: any) => ({
...values,
[e.target.name]: e.target.value
}));
};
const handleSubmit = () => {
console.log(values);
};
return (
<React.Fragment>
<input
name="orgName"
onChange={handleChange}
placeholder="Organization Name"
value={values.orgName}
/>
<input
name="orgRegNo"
onChange={handleChange}
placeholder="Registration Number"
value={values.orgRegNo}
/>
<Select //imported from antd
id="select"
defaultValue="Choose"
onChange={(select: any) => {
setValues(select);
console.log(select); //shows Vender/Supplier, I want this value to be sent to orgType above
}}
>
{data.orgTypes.map((option: any) => (
<Option key={option.id} value={option.name}>
{option.name}
</Option>
))}
</Select>
</React.Fragment>
);
};
When I use onChange of Select, it erases all other data of the inputs.
Thank you for your help
setValues function expects to take the values object as an argument. Instead you are passing the select value to it.
Instead, you can do it like this:
const handleSelectChange = (selectValue: any) => {
setValues((values: any) => ({
...values,
orgType: selectValue
}));
}
and use handleSelectChange in the onChange of your select.
Check the solution here: https://codesandbox.io/s/react-typescript-p9bjz

Resources