import { Meta, StoryObj } from '@storybook/react-vite'; import { expect, userEvent, waitFor, within } from 'storybook/test'; import { TokenExplorer } from './TokenExplorer'; function cleanUrlParams() { try { const url = new URL(window.top?.location.href || window.location.href); for (const key of [...url.searchParams.keys()]) { if (key !== 'path' && key !== 'id' && key !== 'viewMode' && key !== 'globals') { url.searchParams.delete(key); } } window.top?.history.replaceState({}, '', url); window.dispatchEvent(new Event('token-explorer-url-change')); } catch { // ignore if cross-origin } } const meta: Meta = { title: 'Conventions/Token Explorer/Tests', component: TokenExplorer, tags: ['!autodocs', '!manifest', 'internal'], parameters: { // Interaction tests only — no visual baseline (the explorer is data-driven). chromatic: { disableSnapshot: true }, }, }; export default meta; type Story = StoryObj; export const FilterByExactName: Story = { args: { category: 'spacing', }, play: async ({ canvas, step }) => { cleanUrlParams(); await step('type exact token name in search', async () => { const input = canvas.getByRole('textbox', { name: 'Filter tokens by name, value, or id', }); await userEvent.clear(input); await userEvent.type(input, 'spacing.32'); }); await step('should show exactly 1 token', async () => { expect(canvas.getByText('1 token')).toBeInTheDocument(); expect(canvas.getByText('spacing.32')).toBeInTheDocument(); }); cleanUrlParams(); }, }; export const SectionHeadersVisibleThenHidden: Story = { args: { category: 'color', groupBySegment: 1, }, play: async ({ canvas, step }) => { cleanUrlParams(); await step('all section headers should be visible initially', async () => { const table = canvas.getByRole('table'); expect(within(table).getByText('text')).toBeInTheDocument(); expect(within(table).getByText('icon')).toBeInTheDocument(); expect(within(table).getByText('background')).toBeInTheDocument(); expect(within(table).getByText('border')).toBeInTheDocument(); }); await step('filter to only text tokens', async () => { const input = canvas.getByRole('textbox', { name: 'Filter tokens by name, value, or id', }); await userEvent.clear(input); await userEvent.type(input, 'color.text.'); }); await step('only text section header should remain, others hidden', async () => { const table = canvas.getByRole('table'); expect(within(table).getByText('text')).toBeInTheDocument(); expect(within(table).queryByText('icon')).not.toBeInTheDocument(); expect(within(table).queryByText('background')).not.toBeInTheDocument(); expect(within(table).queryByText('border')).not.toBeInTheDocument(); }); cleanUrlParams(); }, }; export const UrlStateFilter: Story = { args: { category: 'spacing', }, play: async ({ canvas, step }) => { cleanUrlParams(); await step('type a filter term', async () => { const input = canvas.getByRole('textbox', { name: 'Filter tokens by name, value, or id', }); await userEvent.clear(input); await userEvent.type(input, 'spacing.32'); }); await step('URL should contain filter param', async () => { await waitFor(() => { const url = new URL(window.top?.location.href || window.location.href); expect(url.searchParams.get('filter')).toBe('spacing.32'); }); }); cleanUrlParams(); }, };