diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml new file mode 100644 index 000000000..4590c897b --- /dev/null +++ b/.github/workflows/storybook.yml @@ -0,0 +1,27 @@ +name: Storybook Build and Test + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + storybook: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'npm' + - name: Install dependencies + run: npm ci + - name: Install Playwright + run: npx playwright install --with-deps chromium + - name: Build Storybook + run: npm run build-storybook + - name: Storybook smoke tests + run: npm run test-storybook diff --git a/.storybook/test-runner.js b/.storybook/test-runner.js new file mode 100644 index 000000000..7d874352b --- /dev/null +++ b/.storybook/test-runner.js @@ -0,0 +1,36 @@ +/** + * Basic smoke tests for Storybook stories. + * + * This configuration runs in CI via the Storybook test runner. It renders each + * story and performs a minimal interaction to surface runtime errors that unit + * tests might miss. + * + * What it covers: + * - Verifies that stories render without throwing. + * - Clicks the first button (if present) to catch simple interaction bugs. + * + * What it doesn't cover: + * - Visual regressions or accessibility checks. + * - Complex workflows that require multiple interactions. + * - Stories that depend on network requests or auth; those may require mocks + * or can be excluded from CI if flaky. + * + * This smoke test is a lightweight safety net and does not replace dedicated + * unit, integration, or visual testing. + */ +// If a button exists, click the first one to ensure the interaction doesn't trigger +// runtime errors. +export const run = async ({ canvasElement }) => { + // Import testing utilities inside the runner so that Storybook's jsdom + // environment is available. Importing at the module level throws because the + // package expects `location` to exist on the global object. + const { within, userEvent } = await import('@storybook/testing-library'); + + const canvas = within(canvasElement); + // Use queryAllByRole so the test runner doesn't throw when multiple buttons + // are present. + const [button] = canvas.queryAllByRole('button'); + if (button) { + await userEvent.click(button); + } +}; diff --git a/package.json b/package.json index bc80bc919..10ebd5523 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "sb": "storybook dev -p 6006", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", + "test-storybook": "npx @storybook/test-runner --index-json ./storybook-static/index.json", "build-css": "rollup -c rollup-css.config.js", "generate-tokens": "tsx ./src/tokenGen/index.js", "bundle-tokens": "rollup --config rollup-tokens.config.js",