Skip to content

Instantly share code, notes, and snippets.

@jasikpark
Last active April 11, 2025 21:11
Show Gist options
  • Save jasikpark/f0e1d1407173a746731eb1cbeb80732c to your computer and use it in GitHub Desktop.
Save jasikpark/f0e1d1407173a746731eb1cbeb80732c to your computer and use it in GitHub Desktop.
import type { Meta, StoryObj } from "@storybook/react";
import { expect, userEvent, waitFor, within } from "@storybook/test";
import fc from "fast-check";
import { useState } from "react";
import { SMORGASBORD_OPTIONS } from "./contants";
import { OptionSelector } from "./OptionSelector";
const meta = {
title: "components/OptionSelector",
component: OptionSelector,
} satisfies Meta<typeof OptionSelector>;
export default meta;
type Story = StoryObj<typeof meta>;
function StoryHelper() {
const [value, setValue] = useState<string | number | null>(null);
return (
<>
<OptionSelector
className="mb-8"
label="Being vulnerable"
options={SMORGASBORD_OPTIONS}
value={value ? String(value) : undefined}
setValue={setValue}
/>
<div>
Value: <span data-testid="value">{JSON.stringify(value)}</span>
</div>
</>
);
}
export const Smorgasbord: Story = {
render: () => <StoryHelper />,
// @ts-expect-error -- The args are passed in the story helper
args: {},
async play({ canvasElement }) {
const { findByRole, findByTestId } = within(canvasElement);
await expect(await findByTestId("value")).toHaveTextContent("null");
await userEvent.click(await findByRole("radio", { name: "Maybe" }));
await expect(await findByTestId("value")).toHaveTextContent("maybe");
},
};
const ShouldSelectOptionOnClickOptions = Array.from({ length: 10 }, (_, idx) => ({ label: `${idx}`, value: `${idx}` }));
function ShouldSelectOptionOnClickStoryHelper() {
const [value, setValue] = useState<string | number | null>(null);
return (
<>
<OptionSelector
className="mb-8"
label="Being vulnerable"
options={ShouldSelectOptionOnClickOptions}
value={value ? String(value) : undefined}
setValue={setValue}
/>
<div>
Value: <span data-testid="value">{JSON.stringify(value)}</span>
</div>
</>
);
}
export const ShouldSelectOptionOnClick: Story = {
render: () => <ShouldSelectOptionOnClickStoryHelper />,
// @ts-expect-error -- The args are passed in the story helper
args: {},
async play({ canvasElement }) {
const { findByRole, findByTestId } = within(canvasElement);
await expect(await findByTestId("value")).toHaveTextContent("null");
type Model = { radio: string };
class ClickRadioCommand implements fc.AsyncCommand<Model, object> {
constructor(readonly radio: string) {}
check() {
return true;
}
async run(m: Model) {
await userEvent.click(await findByRole("radio", { name: this.radio }));
await waitFor(async () => {
await expect(await findByTestId("value")).toHaveTextContent(this.radio);
});
m.radio = this.radio;
}
}
// define the possible commands and their inputs
const allCommands = [fc.integer({ min: 0, max: 9 }).map((r) => new ClickRadioCommand(`${r}`))];
// run everything
await fc.assert(
fc.asyncProperty(fc.scheduler(), fc.commands(allCommands, { size: "+1" }), async (scheduler, cmds) => {
const setup = () => ({ model: { radio: "0" }, real: {} });
await fc.scheduledModelRun(scheduler, setup, cmds);
}),
);
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment