Is there a way to access values from the Actions tab in Storybook?

259 Views Asked by At

I'm using Chromatic to run interaction tests. When I click the button for "Mexican" cuisine, it appends to the url params. Storybook reflects this in the "Actions" tab (shown below). How can I access those Actions so that I can run an assertion against them?

  play: async ({canvasElement}) => {
    const canvas = within(canvasElement);
    userEvent.click(await canvas.findByRole('button', {name: 'Mexican'}));
    // expect that nextRouter.push is called with the value "?cuisineOption=MEXICAN"
  },

Actions

2

There are 2 best solutions below

2
On BEST ANSWER

There is currently no first-class way to do this in Storybook. I was able to get this very hacky solution to work for me:

let pushCalls: any[][] = [];
const afterEach = () => {
  pushCalls = [];
};
const channel = addons.getChannel();
channel.on(FORCE_REMOUNT, afterEach);
channel.on(STORY_RENDER_PHASE_CHANGED, ({newPhase}) => {
  if (newPhase === 'loading') afterEach();
});

Then in your component you can mock the router like so:

  parameters: {
    nextjs: {
      router: {
        push: (...args: any[]) => {
          action('nextRouter.push')(...args);
          pushCalls.push(args);
          return Promise.resolve(true);
        },
      },
    },
  },

Then you can create assertions:

expect(pushCalls[0][0]).toEqual('/?cuisineOption=MEXICAN');
3
On

I haven't used Chromatic, so I can't attest to whether or not it exposes the controls, actions, etc... but I think you can get the same results by mocking nextRouter and asserting that some route object matches the value you expect when the button is clicked.

You can probably use next-router-mock for this which can be find here

Here's an example of how that might work:

import { within, userEvent } from '@storybook/testing-library';
import { expect } from '@storybook/jest';
import mockRouter from 'next-router-mock';

jest.mock('next/router', () => require('next-router-mock'));

export const MyTask = {
  play: async ({canvasElement}) => {
    const canvas = within(canvasElement);
    userEvent.click(await canvas.findByRole('button', {name: 'Mexican'}));    

    // router matches the expected value: "?cuisineOption=MEXICAN"
    expect(mockRouter).toMatchObject({ 
      asPath: "/?cuisineOption=MEXICAN",
      pathname: "/",
      query: { cuisineOption: "Mexican" },
    });
  }
}