reactjs - storybook + jest play -metodi epäonnistuu, kun kutsutaan shouldHaveBeenCalled funktiolle
Minulla on tämä komponentti:
import {
FC,
ReactElement,
useState,
MouseEvent as ReactMouseEvent,
ChangeEvent as ReactChangeEvent,
} from 'react';
import { Stack, TablePagination } from '@mui/material';
export const Pagination: FC<IPaginationProps> = ({
total,
page = 1,
rowsPerPage = 25,
position = 'start',
rowsPerPageOptions = [10, 25, 50, 100],
onPageChange,
onRowsPerPageChange,
}): ReactElement => {
const [localPage, setPage] = useState(page);
const [localRowsPerPage, setRowsPerPage] = useState(rowsPerPage);
const handleChangePage = (event: ReactMouseEvent<HTMLButtonElement> | null, newPage: number) => {
setPage(newPage);
onPageChange({ page: newPage, total, rowsPerPage: localRowsPerPage });
};
const handleChangeRowsPerPage = (
event: ReactChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
const perPage = parseInt(event.target.value, 10);
setRowsPerPage(perPage);
setPage(0);
onRowsPerPageChange({ page: 0, total, rowsPerPage: perPage });
};
return (
<Stack direction="row" justifyContent={`flex-${position}`}>
<TablePagination
component="div"
showFirstButton
showLastButton
count={total}
page={localPage}
onPageChange={handleChangePage}
rowsPerPage={localRowsPerPage}
onRowsPerPageChange={handleChangeRowsPerPage}
rowsPerPageOptions={rowsPerPageOptions}
/>
</Stack>
);
};
Kirjoitin sille tarinan:
export default {
title: 'Components/Pagination',
component: Pagination,
parameters: {
actions: {
handles: ['click'],
},
},
args: {
total: 100,
page: 1,
onPageChange: ({ page }) => {
// eslint-disable-next-line no-console
console.log({ page });
},
onRowsPerPageChange: ({ rowsPerPage }) => {
// eslint-disable-next-line no-console
console.log({ rowsPerPage });
},
},
decorators: [
(Story) => (
<div style={{ margin: '3em', boxShadow: '7px 5px 14px -8px rgba(0,0,0,0.55)' }}>
{Story()}
</div>
),
],
} as ComponentMeta<typeof Pagination>;
const Template: ComponentStory<typeof Pagination> = ({ ...args }) => <Pagination {...args} />;
export const Default = Template.bind({});
Default.play = async ({ canvasElement, args }) => {
const onPageChangeSpy = jest.spyOn(args, 'onPageChange');
const canvas = await within(canvasElement);
const prevBtn = canvas.getByLabelText('Go to previous page');
await userEvent.click(prevBtn);
await expect(onPageChangeSpy).toHaveBeenCalled();
};
Näen, että painiketta klikattiin ja onPageChange kutsuttiin, koska sivutus muuttuu sen mukaisesti, mutta testi epäonnistuu:
Odotettavissa oleva puhelujen määrä: >= 1
Vastaanotettujen puheluiden määrä: 0
Ja outoin asia siinä on, että jos klikkaan uudelleen suorita Storybookin vuorovaikutukset-välilehdellä, kaikki toimii.
Vastaus #1
Sen sijaan, että käytät jest.spyOn, etkö voisi käyttää tavallisia storybook-argumentteja? Jotain tällaista:
await waitFor(() => expect(args.onPageChange).toHaveBeenCalledTimes(1));
Jotta yllä oleva toimisi, sinun täytyy varmistaa, että toimintasi rekisteröidään oikein. Liittämässäsi kuvakaappauksessa en näe numeroa Actions-välilehden otsikon vieressä (sen pitäisi näyttää tältä: Actions (1)), mikä saa minut uskomaan, että toimintasi eivät ole rekisteröityneet oikein, eikä niitä siksi näy Actions-välilehdellä.
Toiminnan rekisteröimisestä voit katsoa kuvaukseni toisesta viestistä täällä.
Periaatteessa jotain tällaista:
import { action } from '@storybook/addon-actions';
// ...
args: {
onPageChange: action('onPageChange'),
//...
},
argTypes: {
onPageChange: { action: 'onPageChange' },
//...
},
Vastaus #2
Ongelma on se, että jest.spyOn kutsuttiin liian myöhään, sen jälkeen kun askeleesi olivat suoritetut. Siksi toistokerralla se menee läpi - koska edellinen toiminto on olemassa ja siihen voi päästä käsiksi.
Minulle auttoi, kun siirsin jest.spyOnin Default.playin yläpuolelle:
const onPageChangeSpy = jest.spyOn(args, 'onPageChange'); // replase 'args' with your arguments
Default.play = async ({ canvasElement }) => {
...
onPageChangeSpy.mockClear(); //remember to stop spying
};

