2

I'm having an issue with testing component which is using react hooks. I need to test if after clicking a button the date range inside the ant design range picker is being updated. For testing I'm using Jest and react-testing-library.

At this point it looks like this: (some of these nested components are just styled-components :) )

Parent.jsx:

 const Parent = () => {
  const [dateRange, setDateRange] = useState([moment(), moment()]);
  return (
    <div>
      <Sidebar
        visible={sidebarVisible}
        setSidebarVisible={setSidebarVisible}
        setTableData={setTableData}
        setStatementsLength={setStatementsLength}
        setDateRange={setDateRange}
        dateRange={dateRange}
      />
    </div>
  );
};

export default Parent;

Sidebar.jsx:

const Sidebar = props => {
  return (
    <div>
      <Drawer
        placement="left"
        closable={false}
        onClose={() => props.setSidebarVisible(false)}
        visible={props.visible}
        width={488}
        bodyStyle={drawerStyle}
      >
        <DrawerContent data-test-id="statementsSidebar">
          <DrawerHeader data-test-id="statementsSidebarHeader">
            {t('settlements.statements.sidebar.createQuery')}
          </DrawerHeader>
          <DrawerBody>
            <DateSelect
              dateRange={props.dateRange}
              setDateRange={props.setDateRange}
            />
          </DrawerBody>
          <DrawerFooter/>
        </DrawerContent>
      </Drawer>
    </div>
  );
};

export default Sidebar;

DateSelect.jsx:

const DateSelect = props => {
  const RangePicker = DatePicker.RangePicker;
  const [offset, setOffset] = useState(0);
  const timeUnit = Object.freeze({ day: 'd', week: 'w', month: 'm' });
  const [offsetUnit, setOffsetUnit] = useState(timeUnit.day);

  const setRangeToLastWeek = () => {
    if (offset > 0) {
      props.setDateRange([
        moment().subtract(1, 'w'),
        moment().add(offset, 'd'),
      ]);
    } else if (offset < 0) {
      props.setDateRange([
        moment()
          .subtract(1, 'w')
          .add(offset, 'd'),
        moment(),
      ]);
    } else {
      props.setDateRange([moment().subtract(1, 'w'), moment()]);
    }
    setOffsetUnit('w');
  };

 const manuallySetDate = range => {
    setOffset(0);
    props.setDateRange(range);
  };

  return (
    <div>
      <HeaderRow/>
      <DateSelectorRow>
          <ButtonsColumn>
            <Button
              value="lastWeek"
              onClick={setRangeToLastWeek}
              style={styleButtonPadding}
              data-test-id="setRangeToLastWeek"
              data-testid="lastWeekButton"
            >
              Last 7 days
            </Button>
          </ButtonsColumn>
        <div data-testid="range-picker-value">
        <RangePicker
          value={props.dateRange}
          format={DateFormat}
          onChange={v => manuallySetDate(v)}
        />
        </div>
      </DateSelectorRow>
    </div>
  );
};

export default DateSelect;

DateSelect.test.js:

 it('After clicking last 7 days button date range is changed', () => {
    // const setDateRange = ??????
     const range = [moment(), moment()];
     const { container } = render(<DateSelect setDateRange={setDateRange} dateRange={range}/>);
     const startDate = getByPlaceholderText(container, 'Start date');
     const endDate = getByPlaceholderText(container, 'End date');
     const lastWeekButton = getByTestId(container,'lastWeekButton');
     expect(startDate.value).toBe(moment().format(DateFormat));
     expect(endDate.value).toBe(moment().format(DateFormat));
     fireEvent.click(lastWeekButton);
     expect(startDate).toBe(moment().subtract(1, 'w').format(DateFormat));
     expect(endDate.value).toBe(moment().format(DateFormat));
   });

As expected, since I'm not passing the setDateRange function as a prop to DateSelect component inside the test the range value doesn't change. I've tried to add a hook inside the test like this:

const [dateRange, setDateRange] = [moment(), moment()];

But I'm getting the: Hooks can only be called inside the body of a function component. So I'm guessing I cannot use it there. Is there any solution to this? How to specify the setDateRange function inside the test that would act like a hook?

I found this: https://github.com/mpeyper/react-hooks-testing-library But it looks like this is for custom hooks?

Maybe there is a solution to this test case that is without the use of react-hooks? Any ideas highly appreciated. :)

1 Answer 1

4

You have to render Parent since it contains the logic to update DateSelect. This makes for a better test because you're testing that the integration among components works.

Sign up to request clarification or add additional context in comments.

3 Comments

Oh, that makes sense. But should that be a part of parent test or the DateSelect test than? :)
Probably parent. TBH I stopped testing components, I test features now. Makes more sense to me
I'm a begginer to react as well as testing in it so it might take me a while to work things out, but thank you very much for your help :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.