如何在 Jest 和 react-testing-library 中使用 react-hooks
How to use react-hooks with Jest and react-testing-library
我在测试使用反应挂钩的组件时遇到问题。
我需要测试单击按钮后是否正在更新 ant 设计范围选择器内的日期范围。为了进行测试,我使用 Jest 和 react-testing-library。
此时它看起来像这样:(其中一些嵌套组件只是样式化组件 :))
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));
});
正如预期的那样,由于我没有将 setDateRange 函数作为 prop 传递给测试中的 DateSelect 组件,因此范围值不会改变。我试图像这样在测试中添加一个钩子:
const [dateRange, setDateRange] = [moment(), moment()];
但我得到了:
挂钩只能在函数组件的内部调用。
所以我猜我不能在那里使用它。有什么解决办法吗?
如何在测试中指定像钩子一样的 setDateRange
函数?
我发现了这个:https://github.com/mpeyper/react-hooks-testing-library
但看起来这是针对自定义挂钩的?
也许这个测试用例有一个不使用 react-hooks 的解决方案?任何想法高度赞赏。 :)
您必须渲染 Parent
,因为它包含更新 DateSelect
的逻辑。这有助于进行更好的测试,因为您正在测试组件之间的集成是否有效。
我在测试使用反应挂钩的组件时遇到问题。 我需要测试单击按钮后是否正在更新 ant 设计范围选择器内的日期范围。为了进行测试,我使用 Jest 和 react-testing-library。
此时它看起来像这样:(其中一些嵌套组件只是样式化组件 :))
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));
});
正如预期的那样,由于我没有将 setDateRange 函数作为 prop 传递给测试中的 DateSelect 组件,因此范围值不会改变。我试图像这样在测试中添加一个钩子:
const [dateRange, setDateRange] = [moment(), moment()];
但我得到了:
挂钩只能在函数组件的内部调用。
所以我猜我不能在那里使用它。有什么解决办法吗?
如何在测试中指定像钩子一样的 setDateRange
函数?
我发现了这个:https://github.com/mpeyper/react-hooks-testing-library 但看起来这是针对自定义挂钩的?
也许这个测试用例有一个不使用 react-hooks 的解决方案?任何想法高度赞赏。 :)
您必须渲染 Parent
,因为它包含更新 DateSelect
的逻辑。这有助于进行更好的测试,因为您正在测试组件之间的集成是否有效。