diff --git a/.cursor/rules/storybook-testing.mdc b/.cursor/rules/storybook-testing.mdc index ac10988..9ec9b0b 100644 --- a/.cursor/rules/storybook-testing.mdc +++ b/.cursor/rules/storybook-testing.mdc @@ -1,187 +1,121 @@ --- -type: Always -description: Rules for writing Storybook Playwright tests in the lambda-curry/forms repository +description: +globs: **/*.stories.tsx,apps/docs/**/*.mdx +alwaysApply: false --- -You are an expert in Storybook, Playwright testing, React, TypeScript, Remix Hook Form, react-hook-form, @medusajs/ui, Zod validation, and the lambda-curry/forms monorepo architecture. +You are an expert in Storybook, Playwright testing, React, TypeScript, react-hook-form, @medusajs/ui, Zod validation, and the lambda-curry/medusa-forms monorepo architecture. # Project Context -This is a monorepo containing form components with comprehensive Storybook Playwright testing. The testing setup combines Storybook's component isolation with Playwright's browser automation to create real-world testing scenarios. +This is a monorepo containing form components with comprehensive Storybook interaction testing. The testing setup combines Storybook's component isolation with modern interaction testing patterns using play functions and the @storybook/test utilities. ## Key Technologies -- Storybook 8.6.7 with React and Vite +- Storybook 9.0.6 with React and Vite +- @storybook/test for interaction testing utilities (userEvent, expect, canvas) - @storybook/test-runner for Playwright automation -- @storybook/test for testing utilities (userEvent, expect, canvas) -- React Router stub decorator for form handling -- Remix Hook Form + Zod for validation testing (main components) - react-hook-form + @medusajs/ui for Medusa Forms components +- Zod validation for form validation testing - Yarn 4.7.0 with corepack - TypeScript throughout -## Project Structure -``` -lambda-curry/forms/ -├── apps/docs/ # Storybook app -│ ├── .storybook/ # Storybook configuration -│ ├── src/remix-hook-form/ # Remix Hook Form story files with tests -│ ├── src/medusa-forms/ # Medusa Forms story files with tests -│ ├── simple-server.js # Custom static server for testing -│ └── package.json # Test scripts -├── packages/components/ # Main component library (Remix Hook Form) -│ └── src/ -│ ├── remix-hook-form/ # Form components -│ └── ui/ # UI components -├── packages/medusa-forms/ # Medusa Forms component library -│ └── src/ -│ ├── controlled/ # Controlled components using react-hook-form -│ └── ui/ # UI components using @medusajs/ui -└── .cursor/rules/ # Cursor rules directory -``` - -# Environment Setup and Testing Infrastructure - -## Prerequisites -Before running Playwright tests locally, ensure the following setup is complete: - -### 1. System Dependencies -```bash -# Install Node.js dependencies -cd apps/docs -yarn install - -# Install Playwright browsers -npx playwright install - -# Install system dependencies for Playwright -npx playwright install-deps -``` - -### 2. Build Storybook Static Files -```bash -cd apps/docs -yarn build # Creates storybook-static directory -``` - -### 3. Server Setup for Local Testing -Due to common port conflicts in development environments, use the custom static server for local testing: - +### Local Development Workflow ```bash -# Start the custom static server (handles port conflicts) +# Local development commands cd apps/docs -node simple-server.js & # Runs on port 45678 -``` - -The `simple-server.js` file provides: -- Static file serving with proper MIME types -- CORS headers for cross-origin requests -- SPA routing fallback to index.html -- Conflict-free port allocation (45678) +yarn dev # Start Storybook for development +yarn test:local # Run tests against running Storybook (if available) -### 4. Run Tests Locally -```bash -# Run tests against the static server -cd apps/docs -npx test-storybook --url http://127.0.0.1:45678 +# Local testing of built Storybook +yarn build # Build static Storybook +node simple-server.js & # Start custom server +npx test-storybook --url http://127.0.0.1:45678 # Test built version ``` -## Complete Local Testing Workflow +### Codegen Testing Workflow +This setup is optimized for Codegen agents and local development testing: ```bash -# Full local testing workflow from scratch +# Codegen workflow for testing built Storybook cd apps/docs - -# 1. Install dependencies (if needed) yarn install npx playwright install npx playwright install-deps - -# 2. Build Storybook yarn build - -# 3. Start static server node simple-server.js & - -# 4. Run tests npx test-storybook --url http://127.0.0.1:45678 - -# 5. Stop server when done -pkill -f "simple-server.js" ``` -## Troubleshooting Common Issues - -### Port Conflicts -If you encounter "EADDRINUSE" errors: -- **Problem**: Default ports (6006, 6007, 8080, etc.) are occupied -- **Solution**: Use the custom static server on port 45678 -- **Alternative**: Find available ports with `netstat -tulpn | grep :PORT` - -### Browser Installation Issues -If Playwright can't find browsers: -```bash -# Reinstall browsers -npx playwright install chromium - -# Install system dependencies -npx playwright install-deps +## Project Structure ``` - -### Build Issues -If Storybook build fails: -```bash -# Clean and rebuild -rm -rf storybook-static -yarn build +lambda-curry/medusa-forms/ +├── apps/docs/ # Storybook app +│ ├── .storybook/ # Storybook configuration +│ ├── src/medusa-forms/ # Medusa Forms story files with tests +│ ├── simple-server.js # Custom static server for testing +│ └── package.json # Test scripts +├── packages/medusa-forms/ # Medusa Forms component library +│ └── src/ +│ ├── controlled/ # Controlled components using react-hook-form +│ └── ui/ # UI components using @medusajs/ui +└── .cursor/rules/ # Cursor rules directory ``` -### Test Execution Issues -- **Timeout errors**: Increase timeout in test configuration -- **Element not found**: Ensure proper async handling with `findBy*` -- **Server not responding**: Verify static server is running on correct port - -# Core Principles for Storybook Testing +# Modern Storybook Interaction Testing -## Story Structure Pattern -- Follow the three-phase testing pattern: Default state → Invalid submission → Valid submission -- Each story serves dual purposes: documentation AND automated tests -- Use play functions for comprehensive interaction testing -- Test complete user workflows, not isolated units +## Core Principles +- **Stories as Tests**: Every story can be a render test; complex stories include interaction tests +- **Play Functions**: Use play functions to simulate user behavior and assert on results +- **Canvas Queries**: Use Testing Library queries through the canvas parameter +- **User Events**: Simulate real user interactions with userEvent +- **Step Grouping**: Organize complex interactions with the step function +- **Visual Debugging**: Debug tests visually in the Storybook UI -## Essential Code Elements -Always include these in Storybook test stories: - -### Required Imports +## Essential Imports for Interaction Testing ```typescript -import type { Meta, StoryContext, StoryObj } from '@storybook/react'; -import { expect, userEvent } from '@storybook/test'; -import { withReactRouterStubDecorator } from '../lib/storybook/react-router-stub'; +import type { Meta, StoryObj } from '@storybook/react'; +import { expect, userEvent, within } from '@storybook/test'; +import { FormProvider, useForm } from 'react-hook-form'; ``` -### Form Schema Setup +## Story Structure with Play Functions + +### Basic Interaction Test Pattern ```typescript -const formSchema = z.object({ - fieldName: z.string().min(1, 'Field is required'), -}); -type FormData = z.infer; +export const FilledForm: Story = { + play: async ({ canvas, userEvent }) => { + // 👇 Simulate interactions with the component + await userEvent.type(canvas.getByTestId('email'), 'email@provider.com'); + await userEvent.type(canvas.getByTestId('password'), 'a-random-password'); + + // 👇 Trigger form submission + await userEvent.click(canvas.getByRole('button', { name: 'Submit' })); + + // 👇 Assert DOM structure + await expect( + canvas.getByText('Form submitted successfully!') + ).toBeInTheDocument(); + }, +}; ``` -### Component Wrapper Pattern +### Advanced Pattern with Step Grouping ```typescript -const ControlledComponentExample = () => { - const fetcher = useFetcher<{ message: string }>(); - const methods = useRemixForm({ - resolver: zodResolver(formSchema), - defaultValues: { /* defaults */ }, - fetcher, - submitConfig: { action: '/', method: 'post' }, - }); - - return ( - - - {/* Component and form elements */} - - - ); +export const CompleteWorkflow: Story = { + play: async ({ canvas, userEvent, step }) => { + await step('Fill out form fields', async () => { + await userEvent.type(canvas.getByLabelText('Email'), 'user@example.com'); + await userEvent.type(canvas.getByLabelText('Password'), 'securepassword'); + }); + + await step('Submit form', async () => { + await userEvent.click(canvas.getByRole('button', { name: 'Submit' })); + }); + + await step('Verify success state', async () => { + await expect( + canvas.getByText('Welcome! Your account is ready.') + ).toBeInTheDocument(); + }); + }, }; ``` @@ -413,3 +347,109 @@ When creating or modifying Storybook tests, ensure: - Fast feedback loop optimized for developer productivity Remember: Every story should test real user workflows and serve as living documentation. Focus on behavior, not implementation details. The testing infrastructure should be reliable, fast, and easy to maintain for local development and Codegen workflows. + +## Canvas Queries - Testing Library Integration + +### Query Types and When to Use Them +| Query Type | 0 Matches | 1 Match | >1 Matches | Awaited | Use Case | +|------------|-----------|---------|------------|---------|----------| +| `getBy*` | Throw error | Return element | Throw error | No | Elements that should exist | +| `queryBy*` | Return null | Return element | Throw error | No | Elements that may not exist | +| `findBy*` | Throw error | Return element | Throw error | Yes | Async elements | +| `getAllBy*` | Throw error | Return array | Return array | No | Multiple elements | +| `queryAllBy*` | Return [] | Return array | Return array | No | Multiple elements (optional) | +| `findAllBy*` | Throw error | Return array | Return array | Yes | Multiple async elements | + +### Query Priority (Recommended Order) +1. **ByRole** - Find elements by accessible role (most user-like) +2. **ByLabelText** - Find form elements by associated label +3. **ByPlaceholderText** - Find inputs by placeholder +4. **ByText** - Find elements by text content +5. **ByDisplayValue** - Find inputs by current value +6. **ByAltText** - Find images by alt text +7. **ByTitle** - Find elements by title attribute +8. **ByTestId** - Find by data-testid (last resort) + +### Common Query Examples +```typescript +// Semantic queries (preferred) +const submitButton = canvas.getByRole('button', { name: 'Submit' }); +const emailInput = canvas.getByLabelText('Email Address'); +const dropdown = canvas.getByRole('combobox', { name: 'Country' }); + +// Async queries for dynamic content +const successMessage = await canvas.findByText('Form submitted successfully'); +const errorList = await canvas.findAllByRole('alert'); + +// Conditional queries +const optionalField = canvas.queryByLabelText('Optional Field'); +expect(optionalField).not.toBeInTheDocument(); +``` + +## UserEvent Interactions + +### Common UserEvent Methods +```typescript +// Clicking elements +await userEvent.click(element); +await userEvent.dblClick(element); + +// Typing and input +await userEvent.type(input, 'text to type'); +await userEvent.clear(input); +await userEvent.paste(input, 'pasted text'); + +// Keyboard interactions +await userEvent.keyboard('{Enter}'); +await userEvent.tab(); + +// Selection +await userEvent.selectOptions(select, 'option-value'); +await userEvent.deselectOptions(select, 'option-value'); + +// File uploads +await userEvent.upload(fileInput, file); + +// Hover interactions +await userEvent.hover(element); +await userEvent.unhover(element); +``` + +### Form Interaction Best Practices +```typescript +// ✅ ALWAYS click before clearing inputs (for focus) +await userEvent.click(input); +await userEvent.clear(input); +await userEvent.type(input, 'new value'); + +// ✅ Use proper selection for dropdowns +await userEvent.click(canvas.getByRole('combobox')); +await userEvent.click(canvas.getByRole('option', { name: 'Option Text' })); + +// ✅ Handle file uploads properly +const file = new File(['content'], 'test.txt', { type: 'text/plain' }); +await userEvent.upload(canvas.getByLabelText('Upload File'), file); +``` + +## Component Wrapper Pattern for Medusa Forms + +### Controlled Component Setup +```typescript +const ControlledComponentExample = () => { + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: { /* defaults */ }, + }); + + return ( + +
console.log(data))}> + {/* Medusa Forms components */} + + + + +
+ ); +}; +``` diff --git a/apps/docs/package.json b/apps/docs/package.json index de0f074..01f62a4 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -14,16 +14,17 @@ "@hookform/error-message": "^2.0.0", "@hookform/resolvers": "^3.9.1", "@lambdacurry/medusa-forms": "*", - "@storybook/addon-links": "^9.0.1", - "@storybook/react-vite": "^9.0.1", + "@storybook/addon-links": "^9.0.6", + "@storybook/react-vite": "^9.0.6", "react": "^19.0.0", "react-hook-form": "^7.51.0", - "storybook": "^9.0.1", + "storybook": "^9.0.6", "zod": "^3.23.8" }, "devDependencies": { - "@storybook/addon-docs": "^9.0.1", - "@storybook/test-runner": "^0.22.0", + "@storybook/addon-docs": "^9.0.6", + "@storybook/test": "^8.6.14", + "@storybook/test-runner": "^0.22.1", "@storybook/testing-library": "^0.2.2", "@tailwindcss/postcss": "^4.1.8", "@tailwindcss/vite": "^4.0.0", diff --git a/apps/docs/simple-server.js b/apps/docs/simple-server.js index 1b386c3..8483f62 100644 --- a/apps/docs/simple-server.js +++ b/apps/docs/simple-server.js @@ -5,7 +5,7 @@ const path = require('node:path'); const server = http.createServer((req, res) => { // Add CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); let filePath = path.join(__dirname, 'storybook-static', req.url === '/' ? 'index.html' : req.url); @@ -30,16 +30,18 @@ const server = http.createServer((req, res) => { fs.readFile(filePath, (err, content) => { if (err) { - res.writeHead(404); - res.end('Not found'); + console.error('Error reading file:', filePath, err); + res.writeHead(500); + res.end('Server Error'); return; } + res.writeHead(200, { 'Content-Type': contentType }); - res.end(content); + res.end(content, 'utf-8'); }); }); const PORT = 45678; server.listen(PORT, () => { - // Server started successfully + console.log(`Server running on http://127.0.0.1:${PORT}`); }); diff --git a/package.json b/package.json index 2126c8c..fceb7f2 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,10 @@ "name": "medusa-forms", "version": "0.1.1", "private": true, - "workspaces": ["apps/*", "packages/*"], + "workspaces": [ + "apps/*", + "packages/*" + ], "scripts": { "start": "yarn dev", "dev": "turbo run dev", diff --git a/packages/medusa-forms/package.json b/packages/medusa-forms/package.json index cc89ff4..0a08a81 100644 --- a/packages/medusa-forms/package.json +++ b/packages/medusa-forms/package.json @@ -4,7 +4,9 @@ "main": "./dist/cjs/index.cjs", "module": "./dist/esm/index.js", "types": "./dist/types/index.d.ts", - "files": ["dist"], + "files": [ + "dist" + ], "exports": { ".": { "import": { diff --git a/yarn.lock b/yarn.lock index f8dcd7b..d4679a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1644,10 +1644,11 @@ __metadata: "@hookform/error-message": "npm:^2.0.0" "@hookform/resolvers": "npm:^3.9.1" "@lambdacurry/medusa-forms": "npm:*" - "@storybook/addon-docs": "npm:^9.0.1" - "@storybook/addon-links": "npm:^9.0.1" - "@storybook/react-vite": "npm:^9.0.1" - "@storybook/test-runner": "npm:^0.22.0" + "@storybook/addon-docs": "npm:^9.0.6" + "@storybook/addon-links": "npm:^9.0.6" + "@storybook/react-vite": "npm:^9.0.6" + "@storybook/test": "npm:^8.6.14" + "@storybook/test-runner": "npm:^0.22.1" "@storybook/testing-library": "npm:^0.2.2" "@tailwindcss/postcss": "npm:^4.1.8" "@tailwindcss/vite": "npm:^4.0.0" @@ -1659,7 +1660,7 @@ __metadata: react: "npm:^19.0.0" react-hook-form: "npm:^7.51.0" start-server-and-test: "npm:^2.0.11" - storybook: "npm:^9.0.1" + storybook: "npm:^9.0.6" tailwindcss: "npm:^4.0.0" typescript: "npm:^5.7.2" vite: "npm:^6.2.2" @@ -4923,59 +4924,59 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-docs@npm:^9.0.1": - version: 9.0.4 - resolution: "@storybook/addon-docs@npm:9.0.4" +"@storybook/addon-docs@npm:^9.0.6": + version: 9.0.6 + resolution: "@storybook/addon-docs@npm:9.0.6" dependencies: "@mdx-js/react": "npm:^3.0.0" - "@storybook/csf-plugin": "npm:9.0.4" + "@storybook/csf-plugin": "npm:9.0.6" "@storybook/icons": "npm:^1.2.12" - "@storybook/react-dom-shim": "npm:9.0.4" + "@storybook/react-dom-shim": "npm:9.0.6" react: "npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" react-dom: "npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^9.0.4 - checksum: 10c0/c70937abe73ec77e80017f14f459224fcefae457999be7be25cd198d49bdff31d181a99d3ec7b72fa494063e4f229c7c4e324173b416a2710208c8a12882e2bd + storybook: ^9.0.6 + checksum: 10c0/f4b6c133599f60cd3e73901056357eab3a5024f43fef8dac4f46dbb77e7ea3a7d48b0efce58ca2dc8f03afc4fa9c56a5e3fee9e53960193328b1d14e565b71ee languageName: node linkType: hard -"@storybook/addon-links@npm:^9.0.1": - version: 9.0.4 - resolution: "@storybook/addon-links@npm:9.0.4" +"@storybook/addon-links@npm:^9.0.6": + version: 9.0.6 + resolution: "@storybook/addon-links@npm:9.0.6" dependencies: "@storybook/global": "npm:^5.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^9.0.4 + storybook: ^9.0.6 peerDependenciesMeta: react: optional: true - checksum: 10c0/ec12e2e61973e24a69e70447959a0c244a23fcb3707a72aa5cee68f6d355f78effdf8cb50a771476111871848a8bcc798608d781e0a760642eeadfd150af6c55 + checksum: 10c0/6f8530dc3b1ffa84339be8dd7bc27f7406f6223a826070b503b9df6dcc0afa1b05f7aeb1d08bbc23d1d6546170de3da16fec50525a97b8932a18e45ee5e411d2 languageName: node linkType: hard -"@storybook/builder-vite@npm:9.0.4": - version: 9.0.4 - resolution: "@storybook/builder-vite@npm:9.0.4" +"@storybook/builder-vite@npm:9.0.6": + version: 9.0.6 + resolution: "@storybook/builder-vite@npm:9.0.6" dependencies: - "@storybook/csf-plugin": "npm:9.0.4" + "@storybook/csf-plugin": "npm:9.0.6" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^9.0.4 + storybook: ^9.0.6 vite: ^5.0.0 || ^6.0.0 - checksum: 10c0/137c1b114d96f1e12f0d76b38d7d4ec10842b8d8284ead906e56d91d61dfbd9a82b84e7643be7cb226040d5829a72d580b441cb26cfa8d6634a7ebe4eff14071 + checksum: 10c0/5832bed758045294b602dd70e680bd5dd974cd430048fa14c5795f424c31d8820717b190c54eea25c0f271cbcaac8898817642884257b32118384bbd8ed879aa languageName: node linkType: hard -"@storybook/csf-plugin@npm:9.0.4": - version: 9.0.4 - resolution: "@storybook/csf-plugin@npm:9.0.4" +"@storybook/csf-plugin@npm:9.0.6": + version: 9.0.6 + resolution: "@storybook/csf-plugin@npm:9.0.6" dependencies: unplugin: "npm:^1.3.1" peerDependencies: - storybook: ^9.0.4 - checksum: 10c0/3988920c425b5ea8c2fd6d7148ae8d009ec4556fab2e14b6223ea6ae7422a0242a16c2e333f28218f85b7c0781c3540ecefbeaa94a492aaf9132e98a5785b254 + storybook: ^9.0.6 + checksum: 10c0/de866c9bff11f28652354a3ac9a28c472650eecf997951dc4d6318836336e9cdd0dd59c78a91dc5c28608382a262f7f55c153308258ca994522d22213d714b92 languageName: node linkType: hard @@ -5005,25 +5006,37 @@ __metadata: languageName: node linkType: hard -"@storybook/react-dom-shim@npm:9.0.4": - version: 9.0.4 - resolution: "@storybook/react-dom-shim@npm:9.0.4" +"@storybook/instrumenter@npm:8.6.14": + version: 8.6.14 + resolution: "@storybook/instrumenter@npm:8.6.14" + dependencies: + "@storybook/global": "npm:^5.0.0" + "@vitest/utils": "npm:^2.1.1" + peerDependencies: + storybook: ^8.6.14 + checksum: 10c0/6b887e25d11404bb1b0f27eea310529732d9a6222d2581ae9f5d66d28e02b76a4ebe0a31d97322d88d5c9d2d2bd503e5f3da6b6f7dfc4c025eb7f86371db0e23 + languageName: node + linkType: hard + +"@storybook/react-dom-shim@npm:9.0.6": + version: 9.0.6 + resolution: "@storybook/react-dom-shim@npm:9.0.6" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^9.0.4 - checksum: 10c0/abee05aa500c90b15a850163965f6631c1cd95f688eb12f5c629de0b2ce47f340b540e1f76b15bb84219a8961c0389316f39f5cc10cf807f76ae7e8d0c33a1c7 + storybook: ^9.0.6 + checksum: 10c0/e3437cf14cdd425e1a6514535016c53fb560d9da6a55743ea44a21ff13a2d8351f9d8cc181ea7ecda55646507c27c654bdfd91c3470df20c9703faa271f9a7aa languageName: node linkType: hard -"@storybook/react-vite@npm:^9.0.1": - version: 9.0.4 - resolution: "@storybook/react-vite@npm:9.0.4" +"@storybook/react-vite@npm:^9.0.6": + version: 9.0.6 + resolution: "@storybook/react-vite@npm:9.0.6" dependencies: "@joshwooding/vite-plugin-react-docgen-typescript": "npm:0.6.0" "@rollup/pluginutils": "npm:^5.0.2" - "@storybook/builder-vite": "npm:9.0.4" - "@storybook/react": "npm:9.0.4" + "@storybook/builder-vite": "npm:9.0.6" + "@storybook/react": "npm:9.0.6" find-up: "npm:^5.0.0" magic-string: "npm:^0.30.0" react-docgen: "npm:^8.0.0" @@ -5032,33 +5045,33 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^9.0.4 + storybook: ^9.0.6 vite: ^5.0.0 || ^6.0.0 - checksum: 10c0/79031f1d6f07c5830fbc3d21e6483f090b75b20cbfe9ee4d26efa3c6346c70c1c462751ce1d110b100ace383a0adc0e159535d5de0d399980c07be95c21d170a + checksum: 10c0/6568571bdeb3c59c53911c5a4f135e01802cd4296c99a92dad93ddd1850dacf350ebb379cb0c365f4fc0d54a50c96ad6f274d764c004de76a12a4cb38b913d70 languageName: node linkType: hard -"@storybook/react@npm:9.0.4": - version: 9.0.4 - resolution: "@storybook/react@npm:9.0.4" +"@storybook/react@npm:9.0.6": + version: 9.0.6 + resolution: "@storybook/react@npm:9.0.6" dependencies: "@storybook/global": "npm:^5.0.0" - "@storybook/react-dom-shim": "npm:9.0.4" + "@storybook/react-dom-shim": "npm:9.0.6" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^9.0.4 + storybook: ^9.0.6 typescript: ">= 4.9.x" peerDependenciesMeta: typescript: optional: true - checksum: 10c0/d1b7f3c2ccd9d8eeb7fd029a74a0011fb4ddaf7b46ea8d6bbd51a4dedecf9959aed5db44725169e134fb931a3c2d7edfc29d3c6e63a0d1f1535317609bed1a97 + checksum: 10c0/0fe38890e6d7cc1bbe25349f1299077e2d28b564a910aedf0e0d2f1c3c63fb0582c7eea22f0368c6c412418a93867051d0e56ef18b23eeb04c409419087c6131 languageName: node linkType: hard -"@storybook/test-runner@npm:^0.22.0": - version: 0.22.0 - resolution: "@storybook/test-runner@npm:0.22.0" +"@storybook/test-runner@npm:^0.22.1": + version: 0.22.1 + resolution: "@storybook/test-runner@npm:0.22.1" dependencies: "@babel/core": "npm:^7.22.5" "@babel/generator": "npm:^7.22.5" @@ -5083,7 +5096,24 @@ __metadata: storybook: ^0.0.0-0 || ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 || ^9.0.0-0 bin: test-storybook: dist/test-storybook.js - checksum: 10c0/f644ee495298e013f85f57643afbcbd26fe6579890aeb2e7e28a06f1a488e3dbbaf01473a3d961e75c5b9b341a484895eb464cd1b5781abdc6db8dd796eabafd + checksum: 10c0/2f9d3ba4cab137893b77ef1626ed9f328942c38c7dd8d6aa71eaccbfef5eb1afe350e080e6c5c88bc46b795a26749cd2186c64ad9a63b608866da9d3dad1f855 + languageName: node + linkType: hard + +"@storybook/test@npm:^8.6.14": + version: 8.6.14 + resolution: "@storybook/test@npm:8.6.14" + dependencies: + "@storybook/global": "npm:^5.0.0" + "@storybook/instrumenter": "npm:8.6.14" + "@testing-library/dom": "npm:10.4.0" + "@testing-library/jest-dom": "npm:6.5.0" + "@testing-library/user-event": "npm:14.5.2" + "@vitest/expect": "npm:2.0.5" + "@vitest/spy": "npm:2.0.5" + peerDependencies: + storybook: ^8.6.14 + checksum: 10c0/f2808db7d567b03320dbdd4a5e2b8ff8a92860138ff4fc87c7c18c3b2fbfb57158cc5ae936770222d7c3ef0fbed85f5e826762ddbeb7f0399961ab9528dbbcb8 languageName: node linkType: hard @@ -5450,6 +5480,22 @@ __metadata: languageName: node linkType: hard +"@testing-library/dom@npm:10.4.0": + version: 10.4.0 + resolution: "@testing-library/dom@npm:10.4.0" + dependencies: + "@babel/code-frame": "npm:^7.10.4" + "@babel/runtime": "npm:^7.12.5" + "@types/aria-query": "npm:^5.0.1" + aria-query: "npm:5.3.0" + chalk: "npm:^4.1.0" + dom-accessibility-api: "npm:^0.5.9" + lz-string: "npm:^1.5.0" + pretty-format: "npm:^27.0.2" + checksum: 10c0/0352487720ecd433400671e773df0b84b8268fb3fe8e527cdfd7c11b1365b398b4e0eddba6e7e0c85e8d615f48257753283fccec41f6b986fd6c85f15eb5f84f + languageName: node + linkType: hard + "@testing-library/dom@npm:^9.0.0": version: 9.3.4 resolution: "@testing-library/dom@npm:9.3.4" @@ -5466,6 +5512,21 @@ __metadata: languageName: node linkType: hard +"@testing-library/jest-dom@npm:6.5.0": + version: 6.5.0 + resolution: "@testing-library/jest-dom@npm:6.5.0" + dependencies: + "@adobe/css-tools": "npm:^4.4.0" + aria-query: "npm:^5.0.0" + chalk: "npm:^3.0.0" + css.escape: "npm:^1.5.1" + dom-accessibility-api: "npm:^0.6.3" + lodash: "npm:^4.17.21" + redent: "npm:^3.0.0" + checksum: 10c0/fd5936a547f04608d8de15a7de3ae26516f21023f8f45169b10c8c8847015fd20ec259b7309f08aa1031bcbc37c6e5e6f532d1bb85ef8f91bad654193ec66a4c + languageName: node + linkType: hard + "@testing-library/jest-dom@npm:^6.6.3": version: 6.6.3 resolution: "@testing-library/jest-dom@npm:6.6.3" @@ -5481,6 +5542,15 @@ __metadata: languageName: node linkType: hard +"@testing-library/user-event@npm:14.5.2": + version: 14.5.2 + resolution: "@testing-library/user-event@npm:14.5.2" + peerDependencies: + "@testing-library/dom": ">=7.21.4" + checksum: 10c0/68a0c2aa28a3c8e6eb05cafee29705438d7d8a9427423ce5064d44f19c29e89b5636de46dd2f28620fb10abba75c67130185bbc3aa23ac1163a227a5f36641e1 + languageName: node + linkType: hard + "@testing-library/user-event@npm:^14.4.0, @testing-library/user-event@npm:^14.6.1": version: 14.6.1 resolution: "@testing-library/user-event@npm:14.6.1" @@ -5850,6 +5920,18 @@ __metadata: languageName: node linkType: hard +"@vitest/expect@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/expect@npm:2.0.5" + dependencies: + "@vitest/spy": "npm:2.0.5" + "@vitest/utils": "npm:2.0.5" + chai: "npm:^5.1.1" + tinyrainbow: "npm:^1.2.0" + checksum: 10c0/08cb1b0f106d16a5b60db733e3d436fa5eefc68571488eb570dfe4f599f214ab52e4342273b03dbe12331cc6c0cdc325ac6c94f651ad254cd62f3aa0e3d185aa + languageName: node + linkType: hard + "@vitest/expect@npm:3.0.9": version: 3.0.9 resolution: "@vitest/expect@npm:3.0.9" @@ -5862,6 +5944,24 @@ __metadata: languageName: node linkType: hard +"@vitest/pretty-format@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/pretty-format@npm:2.0.5" + dependencies: + tinyrainbow: "npm:^1.2.0" + checksum: 10c0/236c0798c5170a0b5ad5d4bd06118533738e820b4dd30079d8fbcb15baee949d41c60f42a9f769906c4a5ce366d7ef11279546070646c0efc03128c220c31f37 + languageName: node + linkType: hard + +"@vitest/pretty-format@npm:2.1.9": + version: 2.1.9 + resolution: "@vitest/pretty-format@npm:2.1.9" + dependencies: + tinyrainbow: "npm:^1.2.0" + checksum: 10c0/155f9ede5090eabed2a73361094bb35ed4ec6769ae3546d2a2af139166569aec41bb80e031c25ff2da22b71dd4ed51e5468e66a05e6aeda5f14b32e30bc18f00 + languageName: node + linkType: hard + "@vitest/pretty-format@npm:3.0.9": version: 3.0.9 resolution: "@vitest/pretty-format@npm:3.0.9" @@ -5871,6 +5971,15 @@ __metadata: languageName: node linkType: hard +"@vitest/spy@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/spy@npm:2.0.5" + dependencies: + tinyspy: "npm:^3.0.0" + checksum: 10c0/70634c21921eb271b54d2986c21d7ab6896a31c0f4f1d266940c9bafb8ac36237846d6736638cbf18b958bd98e5261b158a6944352742accfde50b7818ff655e + languageName: node + linkType: hard + "@vitest/spy@npm:3.0.9": version: 3.0.9 resolution: "@vitest/spy@npm:3.0.9" @@ -5880,6 +5989,18 @@ __metadata: languageName: node linkType: hard +"@vitest/utils@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/utils@npm:2.0.5" + dependencies: + "@vitest/pretty-format": "npm:2.0.5" + estree-walker: "npm:^3.0.3" + loupe: "npm:^3.1.1" + tinyrainbow: "npm:^1.2.0" + checksum: 10c0/0d1de748298f07a50281e1ba058b05dcd58da3280c14e6f016265e950bd79adab6b97822de8f0ea82d3070f585654801a9b1bcf26db4372e51cf7746bf86d73b + languageName: node + linkType: hard + "@vitest/utils@npm:3.0.9": version: 3.0.9 resolution: "@vitest/utils@npm:3.0.9" @@ -5891,6 +6012,17 @@ __metadata: languageName: node linkType: hard +"@vitest/utils@npm:^2.1.1": + version: 2.1.9 + resolution: "@vitest/utils@npm:2.1.9" + dependencies: + "@vitest/pretty-format": "npm:2.1.9" + loupe: "npm:^3.1.2" + tinyrainbow: "npm:^1.2.0" + checksum: 10c0/81a346cd72b47941f55411f5df4cc230e5f740d1e97e0d3f771b27f007266fc1f28d0438582f6409ea571bc0030ed37f684c64c58d1947d6298d770c21026fdf + languageName: node + linkType: hard + "@volar/language-core@npm:2.4.14, @volar/language-core@npm:~2.4.11": version: 2.4.14 resolution: "@volar/language-core@npm:2.4.14" @@ -6210,6 +6342,15 @@ __metadata: languageName: node linkType: hard +"aria-query@npm:5.3.0": + version: 5.3.0 + resolution: "aria-query@npm:5.3.0" + dependencies: + dequal: "npm:^2.0.3" + checksum: 10c0/2bff0d4eba5852a9dd578ecf47eaef0e82cc52569b48469b0aac2db5145db0b17b7a58d9e01237706d1e14b7a1b0ac9b78e9c97027ad97679dd8f91b85da1469 + languageName: node + linkType: hard + "aria-query@npm:^5.0.0": version: 5.3.2 resolution: "aria-query@npm:5.3.2" @@ -6572,7 +6713,7 @@ __metadata: languageName: node linkType: hard -"chai@npm:^5.2.0": +"chai@npm:^5.1.1, chai@npm:^5.2.0": version: 5.2.0 resolution: "chai@npm:5.2.0" dependencies: @@ -7059,6 +7200,13 @@ __metadata: languageName: node linkType: hard +"dequal@npm:^2.0.3": + version: 2.0.3 + resolution: "dequal@npm:2.0.3" + checksum: 10c0/f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888 + languageName: node + linkType: hard + "detect-indent@npm:^6.0.0": version: 6.1.0 resolution: "detect-indent@npm:6.1.0" @@ -7585,6 +7733,15 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^3.0.3": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d + languageName: node + linkType: hard + "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -9735,7 +9892,7 @@ __metadata: languageName: node linkType: hard -"loupe@npm:^3.1.0, loupe@npm:^3.1.3": +"loupe@npm:^3.1.0, loupe@npm:^3.1.1, loupe@npm:^3.1.2, loupe@npm:^3.1.3": version: 3.1.3 resolution: "loupe@npm:3.1.3" checksum: 10c0/f5dab4144254677de83a35285be1b8aba58b3861439ce4ba65875d0d5f3445a4a496daef63100ccf02b2dbc25bf58c6db84c9cb0b96d6435331e9d0a33b48541 @@ -11753,9 +11910,9 @@ __metadata: languageName: node linkType: hard -"storybook@npm:^9.0.1": - version: 9.0.4 - resolution: "storybook@npm:9.0.4" +"storybook@npm:^9.0.6": + version: 9.0.6 + resolution: "storybook@npm:9.0.6" dependencies: "@storybook/global": "npm:^5.0.0" "@testing-library/jest-dom": "npm:^6.6.3" @@ -11775,7 +11932,7 @@ __metadata: optional: true bin: storybook: ./bin/index.cjs - checksum: 10c0/52aa44ac9ba73bf3ab2718669faa02c515ef91243f7d39bcac815efc1b72ac2f2c3b1ea4586ec37beb8f6044c8c5b1c9e2d46405a8832974f3cee37f4b3c3821 + checksum: 10c0/8e0ff615997b806d6d85f0c6813119cdf1e35a4ef03a31c3355aa6cdc35c12a8c1e2b9e49d1dc0e912769ec417aa73a7def249782d8b2f042dabddc78a44b3f8 languageName: node linkType: hard @@ -12021,6 +12178,13 @@ __metadata: languageName: node linkType: hard +"tinyrainbow@npm:^1.2.0": + version: 1.2.0 + resolution: "tinyrainbow@npm:1.2.0" + checksum: 10c0/7f78a4b997e5ba0f5ecb75e7ed786f30bab9063716e7dff24dd84013fb338802e43d176cb21ed12480561f5649a82184cf31efb296601a29d38145b1cdb4c192 + languageName: node + linkType: hard + "tinyrainbow@npm:^2.0.0": version: 2.0.0 resolution: "tinyrainbow@npm:2.0.0" @@ -12028,7 +12192,7 @@ __metadata: languageName: node linkType: hard -"tinyspy@npm:^3.0.2": +"tinyspy@npm:^3.0.0, tinyspy@npm:^3.0.2": version: 3.0.2 resolution: "tinyspy@npm:3.0.2" checksum: 10c0/55ffad24e346622b59292e097c2ee30a63919d5acb7ceca87fc0d1c223090089890587b426e20054733f97a58f20af2c349fb7cc193697203868ab7ba00bcea0