MongChangHsi
MongChangHsi

Reputation: 133

React-testing: unable to detect DatePicker field to initiate change

I have a component which uses the react-datepicker package.

I am writing to write a unit test which will edits the dates and thereafter run some logic. However, i am unable to detect the field which for me to change using userEvent.type(). I have tried to use getByText, getByRole, getAllByText.

Form.tsx

import React, { useState } from 'react';
import DatePicker from "react-datepicker";
import { Form } from 'react-bootstrap';
import "react-datepicker/dist/react-datepicker.css";

const Form = () => {
    const [data, setData] = useState({ date1: new Date(), date2: new Date() })
    return (
        <div>
            <Form>
                ...some other fields
                <Form.Group controlId="date1">
                    <Form.Label>Date1</Form.Label>
                    <DatePicker name='date1'selected={data.date1} onChange={(date: Date) => setData({...data, date1: date})}
                </Form.Group>

                <Form.Group controlId="date2">
                    <Form.Label>Date2</Form.Label>
                    <DatePicker name='date2' selected={data.date2} onChange={(date: Date) => setData({...data, date2: date})}
                </Form.Group>
                <Button variant="primary" type="submit">
                    Submit
                </Button>
            </Form>
        </div>
    )
}

export default Form

Form.test.tsx

import React from 'react';
import Form from './Form';
import {render} from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('Form Component', () => {
    it('able to change the date', () => {
        const { getByRole } = render(<Form/>)
        const date1Field = getByRole('textbox', { name: /date1/i })

        act(() => userEvent.type(date1Field, '01/01/1990'))

        ... any other action to submit the form
    })
})

However, my terminal showed me, which is the same for both date, which it was unable to detect the input field:

TestingLibraryElementError: Unable to find an accessible element with the role"textbox" and name "/date1/i"

textbox: 

Name=""
<input
    class=''
    name='date1'
    type='text'
    value='05/23/2021'
/>

Name=""
<input
    class=''
    name='date2'
    type='text'
    value='05/23/2021'
/>

Upvotes: 3

Views: 15365

Answers (7)

DanielM
DanielM

Reputation: 4033

I used for attribute on the label tag and then used getByLabelText.

<div>
   <label for="date-picker">Delivery date:</label>
   <DatePicker
            id="date-picker"
            dateFormat="yyyy-MM-dd"
            selected={selectedDate}
            onChange={(date) => {
              ...
            }}
          />
</div>
it('fireEvent onchange of Date of Birth', async () => {
    const datepicker = screen.getByLabelText("Delivery date:");
    fireEvent.change(datepicker, {
        target: {
          value: "2021-10-01",
        },
      });
}

Upvotes: 0

user22286262
user22286262

Reputation: 1

I found a solution that works perfectly for me.

React Code:

 <DatePicker
    id="dob"
    placeholderText='Date of Birth'
    selected={dateofBirth}
    onChange={(date: Date): void => {setDateofBirth(date)}}
    popperProps={{ strategy: 'fixed' }}
    dateFormat="dd-MM-yyyy"
   />

Test Case Code:

it('fireEvent onchange of Date of Birth', async () => {
    const props: LoginProps = {
        dateofBirth: new Date(),
        setDateofBirth: () => { },
        setUniqueRefNumber: () => { },
        showErrorMessage: "yes",
    }
    render(<LoginScreen {...props} />);
    const dob = screen.getByPlaceholderText('Date of Birth')
    fireEvent.change(dob, { target: { value: new Date() } })
    await waitFor(() => {
        expect(dob).toBeEnabled();
});

Upvotes: 0

Coder
Coder

Reputation: 102

After Trying many solution, and trying and error.

I found a solution that work perfectly fine for me.

describe('Date Picker Test', () => {
  let wrapper;
  beforeEach(() => {
    wrapper = mount(
      <Provider store={store}>
        <Router>
          <DatePikerFunction />
        </Router>
      </Provider>,
    );
  });
  it('Date Picker Change', async () => {
    const datePicker = await wrapper.find('.ant-picker-input input').first();
    await datePicker.simulate('mousedown');

    await waitFor(async () => {
      await wrapper.update();
      const today = await wrapper.find('.ant-picker-cell-today'); // put classname that is used to select the perticular date
      const next = today.nextElementSibling;
      await next.click();
    });
  });
});

Here I have find the today's date and then selected tomorrow date. You can find base on class or any thing you want and use it.

Hope It will work for you too. Thanks

Upvotes: 1

Jitendra Soni
Jitendra Soni

Reputation: 1

try this solution, this perfectly works for me

 const startDate = await container.find('.ant-picker-input input').first();
 await startDate.simulate('mousedown');

 await waitFor(async () => {
    await container.update();
    const dateChart = await container.find('.ant-picker-today-btn');
    await dateChart.simulate('click');
 });

Upvotes: 0

J Akhtar
J Akhtar

Reputation: 667

It might not be needed but in case, you can pass a prop placeholderText='some text' and then get the input using screen.getByPlaceholderText('some text');

Upvotes: 0

Jonathan Southern
Jonathan Southern

Reputation: 1395

There is an issue with the library itself and not being able to pass in any ARIA props into the datepicker in react-datepicker.

With using the other library you mentioned react-day-picker it is possible to pass props into the input and set aria labels.

import DayPickerInput from 'react-day-picker/DayPickerInput';

<DayPickerInput  inputProps={{'aria-label':'Date input 2'}} />

Sandbox: https://codesandbox.io/s/react-day-picker-examplesinput-forked-lj8pp

Upvotes: 1

MongChangHsi
MongChangHsi

Reputation: 133

For anyone who is looking for a solution which I have adopted Jonathan S. answer,

Form.tsx

import React, { useState } from 'react';
import DayPickerInput from "react-datepicker/DayPickerInput";
import { Form } from 'react-bootstrap';
import "react-day-picker/lib/style.css";

const Form = () => {
    const [data, setData] = useState({ date1: new Date(), date2: new Date() })
    return (
        <div>
            <Form>
                ...some other fields
                <Form.Group controlId="date1">
                    <Form.Label>Date1</Form.Label>
                    <DayPickerInput inputProps={{ 'aria-label': 'date1' }} value={data.date1} onChange={(date: Date) => setData({...data, date1: date})}/>
                </Form.Group>

                <Form.Group controlId="date2">
                    <Form.Label>Date2</Form.Label>
                    <DayPickerInput inputProps={{ 'aria-label': 'date2' }} value={data.date2} onChange={(date: Date) => setData({...data, date2: date})}/>
                </Form.Group>
                <Button variant="primary" type="submit">
                    Submit
                </Button>
            </Form>
        </div>
    )
}

export default Form

Form.test.tsx

import React from 'react';
import Form from './Form';
import {render} from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('Form Component', () => {
    it('able to change the date', () => {
        const { getByLabelText } = render(<Form/>)
        let date1Field = getByLabelText('date1') as HTMLInputElement
        
        // Selects your default value of the date field
        date1Field.setSelectRange(0, date1Field.value.length)
        // Replaces it
        userEvent.type(date1Field, '1990-01-01')
       
        ... any other action to submit the form
    })
})

Upvotes: 1

Related Questions