Asserting function calls in Storybook interaction tests
Asserting how many times a function has been called, and with what arguments, is a common task in unit tests. Despiite this, when I started writing Storybook interaction tests it wasn't immediately obvious how to actually do it.
After trawling the Storybook docs and still not finding an answer, I stumbled upon this solution through trial and error. It appears that the action
argType is using a mock function behind the scenes — which makes sense when you think about it — and you can use Jest's toHaveBeenCalled
matcher to assert on it.
import type { Meta, StoryObj } from '@storybook/react';
import {
within,
userEvent,
} from '@storybook/testing-library';
import { expect } from '@storybook/jest';
import { Button } from './button';
const meta: Meta<typeof Button> = {
component: Button,
title: 'Button',
argTypes: {
// Use the `action` argType to mock a function
onClick: { action: 'clicked' },
},
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Click: Story = {
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
// Jest will see the action as a normal mock
expect(args.onClick).not.toHaveBeenCalled();
await userEvent.click(canvas.getByRole('button'));
expect(args.onClick).toHaveBeenCalledTimes(1);
},
};