@lifeonlars/prime-yggdrasil 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/radius.css +3 -3
- package/package.json +1 -4
- package/docs/STORYBOOK-TESTING.md +0 -352
package/dist/radius.css
CHANGED
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
--radius-charts-medium: 8px; /* donut charts, tree maps */
|
|
28
28
|
--radius-charts-small: 2px; /* segments of stacked charts */
|
|
29
29
|
|
|
30
|
-
/* Special radius */
|
|
31
|
-
--radius-full: 9999px; /* fully rounded elements (pills, avatars) */
|
|
32
30
|
|
|
33
31
|
/* ==================== Generic Radius Scale ==================== */
|
|
34
|
-
|
|
32
|
+
|
|
33
|
+
/* Generally not used, however included for edge cases for direct use in
|
|
34
|
+
custom coponents, blocks or compositions to ensure 4px grid adherence */
|
|
35
35
|
|
|
36
36
|
--radius-none: 0;
|
|
37
37
|
--radius-sm: 4px; /* Small elements, tight corners */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifeonlars/prime-yggdrasil",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI-agent-friendly PrimeReact design system for component-driven development with semantic tokens and dark mode support",
|
|
6
6
|
"keywords": [
|
|
@@ -54,8 +54,6 @@
|
|
|
54
54
|
"preview": "vite preview",
|
|
55
55
|
"test": "vitest run",
|
|
56
56
|
"test:watch": "vitest",
|
|
57
|
-
"test:storybook": "test-storybook",
|
|
58
|
-
"test:storybook:watch": "test-storybook --watch",
|
|
59
57
|
"test:contrast": "node scripts/test-contrast.js",
|
|
60
58
|
"test:contrast:vitest": "vitest run tests/contrast.test.ts",
|
|
61
59
|
"test:contrast:watch": "vitest tests/contrast.test.ts",
|
|
@@ -83,7 +81,6 @@
|
|
|
83
81
|
"@storybook/addon-onboarding": "^10.1.11",
|
|
84
82
|
"@storybook/addon-vitest": "^10.1.11",
|
|
85
83
|
"@storybook/react-vite": "^10.1.11",
|
|
86
|
-
"@storybook/test-runner": "^0.24.2",
|
|
87
84
|
"@testing-library/jest-dom": "^6.9.1",
|
|
88
85
|
"@testing-library/react": "^16.3.1",
|
|
89
86
|
"@testing-library/user-event": "^14.6.1",
|
|
@@ -1,352 +0,0 @@
|
|
|
1
|
-
# Storybook Testing Guide
|
|
2
|
-
|
|
3
|
-
This guide explains how to test components in Prime Yggdrasil using Storybook's Vitest addon.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
Prime Yggdrasil uses `@storybook/addon-vitest` for component testing. This allows you to:
|
|
8
|
-
- Write tests alongside your stories
|
|
9
|
-
- Test components in a real browser environment
|
|
10
|
-
- Use Vitest's familiar testing API
|
|
11
|
-
- Run tests in watch mode for development
|
|
12
|
-
|
|
13
|
-
## Setup
|
|
14
|
-
|
|
15
|
-
The testing infrastructure is already configured:
|
|
16
|
-
|
|
17
|
-
### Files
|
|
18
|
-
- `.storybook/vitest.config.ts` - Vitest configuration for Storybook
|
|
19
|
-
- `.storybook/vitest.setup.ts` - Test setup and Storybook project annotations
|
|
20
|
-
- `package.json` - Test scripts
|
|
21
|
-
|
|
22
|
-
### Scripts
|
|
23
|
-
```bash
|
|
24
|
-
# Run all Storybook tests once
|
|
25
|
-
npm run test:storybook
|
|
26
|
-
|
|
27
|
-
# Run tests in watch mode (auto-rerun on changes)
|
|
28
|
-
npm run test:storybook:watch
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Writing Tests
|
|
32
|
-
|
|
33
|
-
### Basic Test Structure
|
|
34
|
-
|
|
35
|
-
Tests are written using Vitest's `expect` API inside your story files:
|
|
36
|
-
|
|
37
|
-
```tsx
|
|
38
|
-
import { test, expect } from '@storybook/test';
|
|
39
|
-
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
40
|
-
import { Button } from 'primereact/button';
|
|
41
|
-
|
|
42
|
-
const meta = {
|
|
43
|
-
title: 'Button/Button',
|
|
44
|
-
component: Button,
|
|
45
|
-
} satisfies Meta<typeof Button>;
|
|
46
|
-
|
|
47
|
-
export default meta;
|
|
48
|
-
type Story = StoryObj<typeof meta>;
|
|
49
|
-
|
|
50
|
-
export const Primary: Story = {
|
|
51
|
-
args: {
|
|
52
|
-
label: 'Click me',
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// Test the Primary story
|
|
57
|
-
test('Primary button renders correctly', async ({ mount }) => {
|
|
58
|
-
const component = await mount(<Primary.component {...Primary.args} />);
|
|
59
|
-
const button = await component.getByRole('button');
|
|
60
|
-
|
|
61
|
-
await expect(button).toBeInTheDocument();
|
|
62
|
-
await expect(button).toHaveTextContent('Click me');
|
|
63
|
-
});
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Testing Interactive Components
|
|
67
|
-
|
|
68
|
-
For components with state (like Checkbox, RadioButton, etc.):
|
|
69
|
-
|
|
70
|
-
```tsx
|
|
71
|
-
import { test, expect } from '@storybook/test';
|
|
72
|
-
import { userEvent } from '@storybook/test';
|
|
73
|
-
|
|
74
|
-
export const Default: Story = {
|
|
75
|
-
render: () => {
|
|
76
|
-
const [checked, setChecked] = useState(false);
|
|
77
|
-
return (
|
|
78
|
-
<Checkbox checked={checked} onChange={(e) => setChecked(e.checked)} />
|
|
79
|
-
);
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
test('Checkbox toggles on click', async ({ mount, page }) => {
|
|
84
|
-
await mount(<Default.component />);
|
|
85
|
-
|
|
86
|
-
const checkbox = page.getByRole('checkbox');
|
|
87
|
-
|
|
88
|
-
// Initially unchecked
|
|
89
|
-
await expect(checkbox).not.toBeChecked();
|
|
90
|
-
|
|
91
|
-
// Click to check
|
|
92
|
-
await userEvent.click(checkbox);
|
|
93
|
-
await expect(checkbox).toBeChecked();
|
|
94
|
-
|
|
95
|
-
// Click again to uncheck
|
|
96
|
-
await userEvent.click(checkbox);
|
|
97
|
-
await expect(checkbox).not.toBeChecked();
|
|
98
|
-
});
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### Testing Theme Switching
|
|
102
|
-
|
|
103
|
-
Test components in both light and dark modes:
|
|
104
|
-
|
|
105
|
-
```tsx
|
|
106
|
-
test('Button renders in dark mode', async ({ mount, page }) => {
|
|
107
|
-
// Set dark mode
|
|
108
|
-
await page.evaluate(() => {
|
|
109
|
-
document.documentElement.setAttribute('data-theme', 'dark');
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
await mount(<Primary.component {...Primary.args} />);
|
|
113
|
-
|
|
114
|
-
const button = page.getByRole('button');
|
|
115
|
-
const bgColor = await button.evaluate((el) =>
|
|
116
|
-
getComputedStyle(el).backgroundColor
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
// Dark mode should have darker background
|
|
120
|
-
await expect(bgColor).toBeTruthy();
|
|
121
|
-
});
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### Testing Accessibility
|
|
125
|
-
|
|
126
|
-
Use built-in a11y assertions:
|
|
127
|
-
|
|
128
|
-
```tsx
|
|
129
|
-
import { test, expect } from '@storybook/test';
|
|
130
|
-
|
|
131
|
-
test('Button is accessible', async ({ mount, page }) => {
|
|
132
|
-
await mount(<Primary.component {...Primary.args} />);
|
|
133
|
-
|
|
134
|
-
const button = page.getByRole('button');
|
|
135
|
-
|
|
136
|
-
// Check ARIA attributes
|
|
137
|
-
await expect(button).toBeEnabled();
|
|
138
|
-
await expect(button).toBeVisible();
|
|
139
|
-
await expect(button).toHaveAccessibleName('Click me');
|
|
140
|
-
});
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Best Practices
|
|
144
|
-
|
|
145
|
-
### 1. Test One Concern Per Test
|
|
146
|
-
```tsx
|
|
147
|
-
// Good
|
|
148
|
-
test('renders with label', async ({ mount }) => { /* ... */ });
|
|
149
|
-
test('responds to click', async ({ mount }) => { /* ... */ });
|
|
150
|
-
|
|
151
|
-
// Avoid
|
|
152
|
-
test('renders and clicks', async ({ mount }) => { /* ... */ });
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### 2. Use Semantic Queries
|
|
156
|
-
```tsx
|
|
157
|
-
// Good - semantic and accessible
|
|
158
|
-
const button = page.getByRole('button', { name: 'Submit' });
|
|
159
|
-
const heading = page.getByRole('heading', { level: 1 });
|
|
160
|
-
|
|
161
|
-
// Avoid - fragile
|
|
162
|
-
const button = page.locator('.p-button');
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### 3. Test User Behavior, Not Implementation
|
|
166
|
-
```tsx
|
|
167
|
-
// Good - tests what user sees/does
|
|
168
|
-
test('shows error message on invalid input', async ({ mount, page }) => {
|
|
169
|
-
await mount(<Form />);
|
|
170
|
-
await page.getByRole('button', { name: 'Submit' }).click();
|
|
171
|
-
await expect(page.getByText('Required field')).toBeVisible();
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
// Avoid - tests implementation details
|
|
175
|
-
test('sets error state to true', async ({ mount }) => {
|
|
176
|
-
const { rerender } = await mount(<Form />);
|
|
177
|
-
// Don't test internal state
|
|
178
|
-
});
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
### 4. Keep Tests Fast
|
|
182
|
-
- Use `mount` instead of full page loads
|
|
183
|
-
- Mock external API calls
|
|
184
|
-
- Avoid unnecessary `waitFor` delays
|
|
185
|
-
|
|
186
|
-
### 5. Test Across Themes
|
|
187
|
-
```tsx
|
|
188
|
-
test.each(['light', 'dark'])('renders in %s mode', async (theme, { mount, page }) => {
|
|
189
|
-
await page.evaluate((t) => {
|
|
190
|
-
document.documentElement.setAttribute('data-theme', t);
|
|
191
|
-
}, theme);
|
|
192
|
-
|
|
193
|
-
await mount(<Component />);
|
|
194
|
-
// Test rendering...
|
|
195
|
-
});
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
## Common Patterns
|
|
199
|
-
|
|
200
|
-
### Testing Forms
|
|
201
|
-
|
|
202
|
-
```tsx
|
|
203
|
-
test('form submission', async ({ mount, page }) => {
|
|
204
|
-
await mount(<FormStory />);
|
|
205
|
-
|
|
206
|
-
// Fill in fields
|
|
207
|
-
await page.getByLabel('Email').fill('user@example.com');
|
|
208
|
-
await page.getByLabel('Password').fill('password123');
|
|
209
|
-
|
|
210
|
-
// Submit
|
|
211
|
-
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
212
|
-
|
|
213
|
-
// Verify result
|
|
214
|
-
await expect(page.getByText('Welcome!')).toBeVisible();
|
|
215
|
-
});
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Testing Dropdowns
|
|
219
|
-
|
|
220
|
-
```tsx
|
|
221
|
-
test('dropdown selection', async ({ mount, page }) => {
|
|
222
|
-
await mount(<DropdownStory />);
|
|
223
|
-
|
|
224
|
-
const dropdown = page.getByRole('combobox');
|
|
225
|
-
await dropdown.click();
|
|
226
|
-
|
|
227
|
-
// Select option
|
|
228
|
-
await page.getByRole('option', { name: 'New York' }).click();
|
|
229
|
-
|
|
230
|
-
// Verify selection
|
|
231
|
-
await expect(dropdown).toHaveValue('NY');
|
|
232
|
-
});
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Testing Modals/Dialogs
|
|
236
|
-
|
|
237
|
-
```tsx
|
|
238
|
-
test('dialog opens and closes', async ({ mount, page }) => {
|
|
239
|
-
await mount(<DialogStory />);
|
|
240
|
-
|
|
241
|
-
// Open dialog
|
|
242
|
-
await page.getByRole('button', { name: 'Open' }).click();
|
|
243
|
-
|
|
244
|
-
const dialog = page.getByRole('dialog');
|
|
245
|
-
await expect(dialog).toBeVisible();
|
|
246
|
-
|
|
247
|
-
// Close dialog
|
|
248
|
-
await dialog.getByRole('button', { name: 'Close' }).click();
|
|
249
|
-
await expect(dialog).not.toBeVisible();
|
|
250
|
-
});
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
## Debugging Tests
|
|
254
|
-
|
|
255
|
-
### Run in headed mode
|
|
256
|
-
```bash
|
|
257
|
-
# See the browser while tests run
|
|
258
|
-
npm run test:storybook:watch
|
|
259
|
-
# Then in the Vitest UI, enable "headed" mode
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### Use page.pause()
|
|
263
|
-
```tsx
|
|
264
|
-
test('debug test', async ({ mount, page }) => {
|
|
265
|
-
await mount(<Component />);
|
|
266
|
-
|
|
267
|
-
await page.pause(); // Opens Playwright Inspector
|
|
268
|
-
|
|
269
|
-
// Test continues...
|
|
270
|
-
});
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
### Screenshot on failure
|
|
274
|
-
```tsx
|
|
275
|
-
test('visual test', async ({ mount, page }) => {
|
|
276
|
-
await mount(<Component />);
|
|
277
|
-
|
|
278
|
-
try {
|
|
279
|
-
await expect(page.getByRole('button')).toBeVisible();
|
|
280
|
-
} catch (error) {
|
|
281
|
-
await page.screenshot({ path: 'test-failure.png' });
|
|
282
|
-
throw error;
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
## Continuous Integration
|
|
288
|
-
|
|
289
|
-
For CI/CD pipelines:
|
|
290
|
-
|
|
291
|
-
```yaml
|
|
292
|
-
# .github/workflows/test.yml
|
|
293
|
-
- name: Install dependencies
|
|
294
|
-
run: npm ci
|
|
295
|
-
|
|
296
|
-
- name: Install Playwright browsers
|
|
297
|
-
run: npx playwright install --with-deps chromium
|
|
298
|
-
|
|
299
|
-
- name: Run Storybook tests
|
|
300
|
-
run: npm run test:storybook
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
## Troubleshooting
|
|
304
|
-
|
|
305
|
-
### "Failed to start test runner process"
|
|
306
|
-
|
|
307
|
-
This usually means:
|
|
308
|
-
1. Playwright browsers aren't installed: `npx playwright install chromium`
|
|
309
|
-
2. Port conflict: Close other Storybook instances
|
|
310
|
-
3. Timeout: Increase timeout in vitest.config.ts
|
|
311
|
-
|
|
312
|
-
### Tests timing out
|
|
313
|
-
|
|
314
|
-
Increase test timeout:
|
|
315
|
-
```ts
|
|
316
|
-
// .storybook/vitest.config.ts
|
|
317
|
-
export default defineConfig({
|
|
318
|
-
test: {
|
|
319
|
-
testTimeout: 30000, // 30 seconds
|
|
320
|
-
},
|
|
321
|
-
});
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### Theme styles not applying
|
|
325
|
-
|
|
326
|
-
Ensure YggdrasilProvider is wrapping your component:
|
|
327
|
-
```tsx
|
|
328
|
-
// In your story
|
|
329
|
-
export const Default: Story = {
|
|
330
|
-
decorators: [
|
|
331
|
-
(Story) => (
|
|
332
|
-
<YggdrasilProvider ripple={true}>
|
|
333
|
-
<Story />
|
|
334
|
-
</YggdrasilProvider>
|
|
335
|
-
),
|
|
336
|
-
],
|
|
337
|
-
};
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
## Resources
|
|
341
|
-
|
|
342
|
-
- [Storybook Test Addon Docs](https://storybook.js.org/docs/writing-tests/test-addon)
|
|
343
|
-
- [Vitest API](https://vitest.dev/api/)
|
|
344
|
-
- [Playwright Test API](https://playwright.dev/docs/api/class-test)
|
|
345
|
-
- [Testing Library Queries](https://testing-library.com/docs/queries/about)
|
|
346
|
-
|
|
347
|
-
## Next Steps
|
|
348
|
-
|
|
349
|
-
1. Add tests to existing stories
|
|
350
|
-
2. Set up CI pipeline to run tests
|
|
351
|
-
3. Add visual regression testing with Chromatic
|
|
352
|
-
4. Configure test coverage reporting
|