@salesforce/b2c-dx-mcp 2.0.0 → 2.1.0

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.
Files changed (108) hide show
  1. package/README.md +15 -62
  2. package/dist/commands/mcp.d.ts +1 -0
  3. package/dist/commands/mcp.js +47 -9
  4. package/dist/registry.d.ts +3 -4
  5. package/dist/registry.js +7 -14
  6. package/dist/services.d.ts +21 -1
  7. package/dist/services.js +38 -1
  8. package/dist/tools/adapter.d.ts +19 -2
  9. package/dist/tools/adapter.js +49 -10
  10. package/dist/tools/cartridges/index.js +11 -3
  11. package/dist/tools/diagnostics/config-inspect.js +2 -2
  12. package/dist/tools/diagnostics/debug-list-sessions.js +1 -0
  13. package/dist/tools/diagnostics/debug-start-session.js +13 -2
  14. package/dist/tools/diagnostics/log-watch-registry.d.ts +3 -0
  15. package/dist/tools/diagnostics/log-watch-registry.js +1 -0
  16. package/dist/tools/diagnostics/logs-watch-list.js +1 -0
  17. package/dist/tools/diagnostics/logs-watch-start.js +6 -1
  18. package/dist/tools/diagnostics/mrt-log-watch-registry.d.ts +3 -0
  19. package/dist/tools/diagnostics/mrt-log-watch-registry.js +0 -0
  20. package/dist/tools/diagnostics/mrt-logs-watch-list.js +1 -0
  21. package/dist/tools/diagnostics/mrt-logs-watch-start.js +7 -1
  22. package/dist/tools/diagnostics/session-registry.d.ts +3 -0
  23. package/dist/tools/diagnostics/session-registry.js +2 -1
  24. package/dist/tools/index.d.ts +0 -1
  25. package/dist/tools/index.js +0 -1
  26. package/dist/tools/mrt/index.js +4 -0
  27. package/dist/tools/project-context.d.ts +42 -11
  28. package/dist/tools/project-context.js +48 -15
  29. package/dist/tools/scapi/metrics-get.js +1 -1
  30. package/dist/tools/scapi/scapi-custom-api-generate-scaffold.d.ts +4 -0
  31. package/dist/tools/scapi/scapi-custom-api-generate-scaffold.js +27 -7
  32. package/dist/tools/scapi/scapi-custom-apis-get-status.js +1 -1
  33. package/dist/tools/scapi/scapi-schemas-list.js +1 -0
  34. package/dist/utils/constants.d.ts +2 -13
  35. package/dist/utils/constants.js +1 -20
  36. package/oclif.manifest.json +2 -2
  37. package/package.json +3 -3
  38. package/content/sfnext/auth.md +0 -62
  39. package/content/sfnext/components.md +0 -123
  40. package/content/sfnext/config.md +0 -180
  41. package/content/sfnext/data-fetching.md +0 -323
  42. package/content/sfnext/extensions.md +0 -80
  43. package/content/sfnext/i18n.md +0 -121
  44. package/content/sfnext/page-designer.md +0 -78
  45. package/content/sfnext/performance.md +0 -80
  46. package/content/sfnext/pitfalls.md +0 -141
  47. package/content/sfnext/quick-reference.md +0 -226
  48. package/content/sfnext/state-management.md +0 -75
  49. package/content/sfnext/styling.md +0 -51
  50. package/content/sfnext/testing.md +0 -232
  51. package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.d.ts +0 -24
  52. package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.js +0 -53
  53. package/dist/tools/storefrontnext/figma/figma-to-component/index.d.ts +0 -45
  54. package/dist/tools/storefrontnext/figma/figma-to-component/index.js +0 -332
  55. package/dist/tools/storefrontnext/figma/generate-component/decision.d.ts +0 -40
  56. package/dist/tools/storefrontnext/figma/generate-component/decision.js +0 -312
  57. package/dist/tools/storefrontnext/figma/generate-component/formatter.d.ts +0 -9
  58. package/dist/tools/storefrontnext/figma/generate-component/formatter.js +0 -92
  59. package/dist/tools/storefrontnext/figma/generate-component/index.d.ts +0 -117
  60. package/dist/tools/storefrontnext/figma/generate-component/index.js +0 -102
  61. package/dist/tools/storefrontnext/figma/map-tokens/css-parser.d.ts +0 -71
  62. package/dist/tools/storefrontnext/figma/map-tokens/css-parser.js +0 -260
  63. package/dist/tools/storefrontnext/figma/map-tokens/index.d.ts +0 -64
  64. package/dist/tools/storefrontnext/figma/map-tokens/index.js +0 -242
  65. package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.d.ts +0 -65
  66. package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.js +0 -268
  67. package/dist/tools/storefrontnext/index.d.ts +0 -30
  68. package/dist/tools/storefrontnext/index.js +0 -28
  69. package/dist/tools/storefrontnext/page-designer-decorator/analyzer.d.ts +0 -169
  70. package/dist/tools/storefrontnext/page-designer-decorator/analyzer.js +0 -567
  71. package/dist/tools/storefrontnext/page-designer-decorator/index.d.ts +0 -259
  72. package/dist/tools/storefrontnext/page-designer-decorator/index.js +0 -622
  73. package/dist/tools/storefrontnext/page-designer-decorator/rules/1-mode-selection.d.ts +0 -8
  74. package/dist/tools/storefrontnext/page-designer-decorator/rules/1-mode-selection.js +0 -65
  75. package/dist/tools/storefrontnext/page-designer-decorator/rules/2a-auto-mode.d.ts +0 -13
  76. package/dist/tools/storefrontnext/page-designer-decorator/rules/2a-auto-mode.js +0 -87
  77. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-0-interactive-overview.d.ts +0 -4
  78. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-0-interactive-overview.js +0 -55
  79. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-1-interactive-analyze.d.ts +0 -22
  80. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-1-interactive-analyze.js +0 -109
  81. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-2-interactive-select-props.d.ts +0 -21
  82. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-2-interactive-select-props.js +0 -60
  83. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-3-interactive-configure-attrs.d.ts +0 -27
  84. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-3-interactive-configure-attrs.js +0 -68
  85. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-4-interactive-configure-regions.d.ts +0 -4
  86. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-4-interactive-configure-regions.js +0 -65
  87. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-5-interactive-confirm-generation.d.ts +0 -11
  88. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-5-interactive-confirm-generation.js +0 -92
  89. package/dist/tools/storefrontnext/page-designer-decorator/rules.d.ts +0 -51
  90. package/dist/tools/storefrontnext/page-designer-decorator/rules.js +0 -70
  91. package/dist/tools/storefrontnext/page-designer-decorator/templates/decorator-generator.d.ts +0 -116
  92. package/dist/tools/storefrontnext/page-designer-decorator/templates/decorator-generator.js +0 -350
  93. package/dist/tools/storefrontnext/sfnext-development-guidelines.d.ts +0 -9
  94. package/dist/tools/storefrontnext/sfnext-development-guidelines.js +0 -141
  95. package/dist/tools/storefrontnext/site-theming/color-contrast.d.ts +0 -92
  96. package/dist/tools/storefrontnext/site-theming/color-contrast.js +0 -186
  97. package/dist/tools/storefrontnext/site-theming/color-mapping.d.ts +0 -16
  98. package/dist/tools/storefrontnext/site-theming/color-mapping.js +0 -131
  99. package/dist/tools/storefrontnext/site-theming/guidance-merger.d.ts +0 -11
  100. package/dist/tools/storefrontnext/site-theming/guidance-merger.js +0 -78
  101. package/dist/tools/storefrontnext/site-theming/index.d.ts +0 -14
  102. package/dist/tools/storefrontnext/site-theming/index.js +0 -128
  103. package/dist/tools/storefrontnext/site-theming/response-builder.d.ts +0 -16
  104. package/dist/tools/storefrontnext/site-theming/response-builder.js +0 -316
  105. package/dist/tools/storefrontnext/site-theming/theming-store.d.ts +0 -64
  106. package/dist/tools/storefrontnext/site-theming/theming-store.js +0 -417
  107. package/dist/tools/storefrontnext/site-theming/types.d.ts +0 -36
  108. package/dist/tools/storefrontnext/site-theming/types.js +0 -7
@@ -1,226 +0,0 @@
1
- # Storefront Next - Development Guidelines (Quick Reference)
2
-
3
- ⚠️ **READ THESE CRITICAL RULES BEFORE WRITING ANY CODE** ⚠️
4
-
5
- ## 🏗️ Architecture Overview
6
-
7
- **Server-rendered SPA** built on React Server Components:
8
- - **React Router 7** in framework mode
9
- - **Managed Runtime (MRT)** as data orchestration layer
10
- - **All SCAPI requests execute on MRT server** (both SSR and client-side navigation)
11
-
12
- **Key Point**: Client-side routing does NOT mean client-side data fetching. Loaders always run on the server.
13
-
14
- ---
15
-
16
- ## 🚨 Non-Negotiable Rules
17
-
18
- ### 1. Server-Only Data Loading
19
-
20
- ✅ **REQUIRED**: Use server `loader` for all SCAPI data fetching
21
-
22
- ```typescript
23
- export function loader({ context }: LoaderFunctionArgs): PageData {
24
- const clients = createApiClients(context);
25
- return {
26
- product: clients.shopperProducts.getProduct({...}), // Promise - streams
27
- reviews: clients.shopperProducts.getReviews({...}), // Promise - streams
28
- };
29
- }
30
- ```
31
-
32
- **Why?** Keeps SCAPI requests on MRT server for security, performance, and bundle size.
33
-
34
- ### 2. Synchronous Loaders (Not Async)
35
-
36
- ✅ **CRITICAL**: Loaders must be **synchronous functions that return promises**, NOT async functions.
37
-
38
- ```typescript
39
- // ✅ CORRECT - Enables streaming
40
- export function loader({ context }: LoaderFunctionArgs): PageData {
41
- const clients = createApiClients(context);
42
- return {
43
- product: clients.shopperProducts.getProduct({...}), // Promise - streams
44
- };
45
- }
46
-
47
- // ❌ AVOID - Blocks page transitions
48
- export async function loader({ context }: LoaderFunctionArgs) {
49
- const product = await clients.shopperProducts.getProduct({...}); // Blocks!
50
- return { product };
51
- }
52
- ```
53
-
54
- **Why?** Async loaders block page transitions. Synchronous loaders enable progressive streaming.
55
-
56
- ### 3. TypeScript-Only
57
-
58
- ✅ **REQUIRED**: Use `.ts` and `.tsx` file extensions
59
- ❌ **BLOCKED**: `.js`, `.jsx`, `.mjs`, `.cjs` files are forbidden by ESLint
60
-
61
- ### 4. Use createPage() HOC
62
-
63
- ✅ **RECOMMENDED**: Use `createPage()` for standardized page patterns
64
-
65
- ```typescript
66
- import { createPage } from '@/components/create-page';
67
-
68
- const ProductPage = createPage({
69
- component: ProductView,
70
- fallback: <ProductSkeleton />
71
- });
72
-
73
- export default ProductPage;
74
- ```
75
-
76
- ### 5. Tailwind CSS 4 Only
77
-
78
- ✅ **REQUIRED**: Use Tailwind utility classes only
79
- ❌ **BLOCKED**: No inline styles (`style={{...}}`), no CSS modules, no separate CSS files
80
-
81
- ```typescript
82
- // ✅ CORRECT - Tailwind utilities
83
- <div className="rounded-lg border border-border bg-card p-4">
84
- <h2 className="text-lg font-semibold text-card-foreground">
85
- {product.name}
86
- </h2>
87
- </div>
88
-
89
- // ❌ AVOID - Inline styles
90
- <div style={{ padding: '1rem' }}>
91
-
92
- // ❌ AVOID - CSS modules
93
- import styles from './product-card.module.css';
94
- ```
95
-
96
- **Why?** Consistent styling approach, better performance, automatic dark mode support via theme variables.
97
-
98
- ---
99
-
100
- ## 📋 Quick Patterns
101
-
102
- ### Data Fetching
103
-
104
- ```typescript
105
- import { createApiClients } from '@/lib/api-clients';
106
-
107
- export function loader({ context }: LoaderFunctionArgs): PageData {
108
- const clients = createApiClients(context);
109
- return {
110
- product: clients.shopperProducts.getProduct({...}),
111
- reviews: clients.shopperProducts.getReviews({...}),
112
- };
113
- }
114
- ```
115
-
116
- **See `data-fetching` section for:** loaders, actions, useScapiFetcher, parallel requests, data flow
117
-
118
- ### Authentication
119
-
120
- ```typescript
121
- import { getAuth } from '@/middlewares/auth.server';
122
-
123
- export function loader({ context }: LoaderFunctionArgs) {
124
- const auth = getAuth(context);
125
- return {
126
- isGuest: auth.userType === 'guest',
127
- customerId: auth.customer_id
128
- };
129
- }
130
- ```
131
-
132
- **See `auth` section for:** cookie architecture, client usage, token management
133
-
134
- ### Configuration
135
-
136
- ```typescript
137
- // Components
138
- import { useConfig } from '@/config';
139
- const config = useConfig();
140
-
141
- // Loaders/Actions
142
- import { getConfig } from '@/config';
143
- const config = getConfig(context);
144
- ```
145
-
146
- **See `config` section for:** adding config, environment variables, security
147
-
148
- ### Internationalization
149
-
150
- ```typescript
151
- // Components
152
- import { useTranslation } from 'react-i18next';
153
- const { t } = useTranslation('product');
154
-
155
- // Loaders/Actions
156
- import { getTranslation } from '@/lib/i18next';
157
- const { t } = getTranslation(context);
158
- ```
159
-
160
- **See `i18n` section for:** validation schemas (factory pattern), language switching, extensions
161
-
162
- ### Components
163
-
164
- ```typescript
165
- // Suspense boundaries
166
- import { Suspense } from 'react';
167
- import { Await } from 'react-router';
168
-
169
- <Suspense fallback={<ProductSkeleton />}>
170
- <Await resolve={product}>
171
- {(data) => <ProductHeader product={data} />}
172
- </Await>
173
- </Suspense>
174
- ```
175
-
176
- **See `components` section for:** createPage HOC, file organization, best practices
177
-
178
- ### Styling
179
-
180
- ```typescript
181
- // Tailwind utility classes
182
- <div className="bg-background text-foreground border-border">
183
- <button className="bg-primary text-primary-foreground rounded-md px-4 py-2">
184
- Click me
185
- </button>
186
- </div>
187
-
188
- // shadcn/ui: Add via npx shadcn@latest add <component-name>
189
- import { Button } from '@/components/ui/button';
190
- import { Card } from '@/components/ui/card';
191
- ```
192
-
193
- **See `styling` section for:** Tailwind CSS 4 rules, Shadcn/ui components, dark mode, responsive design
194
-
195
- ---
196
-
197
- ## 🔍 Get Detailed Guidelines
198
-
199
- Use the `sfnext_get_guidelines` MCP tool with specific sections:
200
-
201
- ```json
202
- {
203
- "sections": ["data-fetching", "components", "testing"]
204
- }
205
- ```
206
-
207
- **Available sections:**
208
- - `data-fetching` - Loaders, actions, useScapiFetcher, data flow
209
- - `components` - createPage HOC, Suspense, file organization
210
- - `styling` - Tailwind CSS 4, Shadcn/ui, styling guidelines
211
- - `testing` - Vitest, Storybook, coverage requirements
212
- - `auth` - Authentication and session management
213
- - `config` - Configuration system
214
- - `i18n` - Internationalization patterns
215
- - `state-management` - Client-side state with Zustand
216
- - `page-designer` - Page Designer integration
217
- - `performance` - Optimization techniques
218
- - `extensions` - Extension development
219
- - `pitfalls` - Common mistakes to avoid
220
-
221
- ---
222
-
223
- **When in doubt:**
224
- 1. Check existing code for similar examples
225
- 2. Use the MCP tool to get detailed section guidance
226
- 3. Follow architectural principles: server-only, streaming, TypeScript
@@ -1,75 +0,0 @@
1
- # Client-Side State Management
2
-
3
- ## Zustand Store Pattern
4
-
5
- Storefront Next uses Zustand for client-side state (basket, wishlist):
6
-
7
- ```typescript
8
- // src/middlewares/basket.client.ts
9
- import {create} from 'zustand';
10
-
11
- interface BasketStore {
12
- basket: Basket | null;
13
- setBasket: (basket: Basket | null) => void;
14
- clearBasket: () => void;
15
- }
16
-
17
- export const useBasketStore = create<BasketStore>((set) => ({
18
- basket: null,
19
- setBasket: (basket) => set({basket}),
20
- clearBasket: () => set({basket: null}),
21
- }));
22
- ```
23
-
24
- ## Context Integration
25
-
26
- Access Zustand state via context helpers:
27
-
28
- ```typescript
29
- import { getBasket, updateBasket } from '@/middlewares/basket.client';
30
-
31
- // In clientLoader
32
- export const clientLoader: ClientLoaderFunction = ({ context }) => {
33
- const basket = getBasket(context);
34
- return { basket, itemCount: basket?.productItems?.length ?? 0 };
35
- };
36
-
37
- // In components
38
- function CartIcon() {
39
- const basket = getBasket(context);
40
- return <Badge count={basket?.productItems?.length ?? 0} />;
41
- }
42
- ```
43
-
44
- ## Update Pattern
45
-
46
- After mutations, update the store:
47
-
48
- ```typescript
49
- export async function clientAction({request, context}: ActionFunctionArgs) {
50
- const formData = await request.formData();
51
- const productId = formData.get('productId') as string;
52
-
53
- const basket = getBasket(context);
54
- const clients = createApiClients(context);
55
-
56
- const {data: updatedBasket} = await clients.shopperBasketsV2.addItemToBasket({
57
- params: {path: {basketId: basket.basketId}},
58
- body: [{productId, quantity: 1}],
59
- });
60
-
61
- // Update Zustand store
62
- updateBasket(context, updatedBasket);
63
-
64
- return Response.json({success: true, basket: updatedBasket});
65
- }
66
- ```
67
-
68
- ## Best Practices
69
-
70
- 1. **Use for ephemeral client state**: Shopping cart, UI state, temporary selections
71
- 2. **Don't duplicate server state**: Prefer React Router loaders for server data
72
- 3. **Keep stores focused**: Separate stores for basket, wishlist, etc.
73
- 4. **Sync with server**: Update store after successful mutations
74
-
75
- For full documentation on client-side state management patterns, see the Zustand documentation and React Router state management patterns.
@@ -1,51 +0,0 @@
1
- # Styling Guidelines
2
-
3
- ## Rules
4
-
5
- - ✅ **Use Tailwind utility classes** in component JSX
6
- - ✅ **Use `cn()` utility** for conditional classes (`import { cn } from '@/lib/utils'`)
7
- - ✅ **Follow mobile-first** responsive patterns (`md:`, `lg:` breakpoints)
8
- - ❌ **NO inline styles** (`style={{...}}`)
9
- - ❌ **NO CSS modules** (`.module.css` files)
10
- - ❌ **NO separate CSS files** for component styles
11
- - ✅ **Custom CSS** only in `src/app.css` for global styles and theme configuration
12
-
13
- ## Shadcn/ui Components
14
-
15
- **Adding components:**
16
-
17
- ```bash
18
- npx shadcn@latest add <component-name>
19
- ```
20
-
21
- **Rules:**
22
-
23
- - ✅ **DO** customize components by editing files in `src/components/ui/`
24
- - ❌ **DON'T** create custom components inside `src/components/ui/`
25
- - ❌ **DON'T** manually copy components (use CLI instead)
26
-
27
- ## Dark Mode
28
-
29
- Dark mode is supported via CSS variables and the `.dark` class. Theme variables automatically adapt:
30
-
31
- ```typescript
32
- <div className="bg-background text-foreground border-border">
33
- <button className="bg-primary text-primary-foreground">
34
- Click me
35
- </button>
36
- </div>
37
- ```
38
-
39
- ## Responsive Design
40
-
41
- Follow mobile-first responsive design:
42
-
43
- ```typescript
44
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
45
- {/* Content */}
46
- </div>
47
- ```
48
-
49
- ---
50
-
51
- **Reference:** See [README-UI-STYLING.md](docs/README-UI-STYLING.md) in your project for complete UI and styling documentation.
@@ -1,232 +0,0 @@
1
- # Testing Strategy
2
-
3
- ## Unit Tests (Vitest)
4
-
5
- This project uses **Vitest** for unit tests, running under Vite with jsdom as the default test environment.
6
-
7
- ### Test File Organization
8
-
9
- Tests live alongside source files with `.test.ts` or `.test.tsx` extension:
10
-
11
- ```typescript
12
- // src/components/product-card/product-card.test.tsx
13
- import { describe, it, expect, vi } from 'vitest';
14
- import { render, screen } from '@testing-library/react';
15
- import { ProductCard } from './product-card';
16
- import { mockProduct } from '@/test-utils/mocks';
17
-
18
- describe('ProductCard', () => {
19
- it('renders product name', () => {
20
- render(<ProductCard product={mockProduct} />);
21
- expect(screen.getByText(mockProduct.productName)).toBeInTheDocument();
22
- });
23
- });
24
- ```
25
-
26
- ### Test Utilities
27
-
28
- Test utilities are available in `src/test-utils/`:
29
- - `config.ts` - Mock configuration objects and ConfigProvider wrappers
30
- - `context-provider-utils.ts` - Context provider helpers for testing
31
- - `context-provider.tsx` - Test context providers
32
-
33
- ### Running Tests
34
-
35
- ```bash
36
- # Run all tests with coverage
37
- pnpm test
38
-
39
- # Open Vitest UI (interactive test runner)
40
- pnpm test:ui
41
-
42
- # Watch mode (re-run on file changes)
43
- pnpm test:watch
44
-
45
- # Generate coverage report
46
- pnpm test
47
- # Coverage report outputs to console and coverage/ directory
48
- ```
49
-
50
- ### Coverage Requirements
51
-
52
- Coverage thresholds are enforced in `vitest.thresholds.ts`:
53
- - Lines: 73%
54
- - Statements: 73%
55
- - Functions: 86%
56
- - Branches: 87%
57
-
58
- These thresholds represent minimum values that must not be undershot. They should be raised regularly to reflect current status.
59
-
60
- ### Testing Libraries
61
-
62
- - **@testing-library/react** - React component testing
63
- - **@testing-library/jest-dom** - Custom Jest DOM matchers
64
- - **@testing-library/user-event** - User interaction simulation
65
- - **@vitest/coverage-v8** - Code coverage
66
- - **@vitest/ui** - Interactive test UI
67
-
68
- ## Storybook Testing
69
-
70
- Every reusable component should have a Storybook story file (`.stories.tsx`).
71
-
72
- ### Story Structure
73
-
74
- ```typescript
75
- // src/components/product-card/product-card.stories.tsx
76
- import type { Meta, StoryObj } from '@storybook/react-vite';
77
- import { within, expect } from 'storybook/test';
78
- import { waitForStorybookReady } from '@storybook/test-utils';
79
- import { ProductCard } from './product-card';
80
- import { ConfigProvider } from '@/config/context';
81
- import { mockConfig } from '@/test-utils/config';
82
- import { mockProduct } from '@/test-utils/mocks';
83
-
84
- const meta: Meta<typeof ProductCard> = {
85
- title: 'Components/ProductCard',
86
- component: ProductCard,
87
- tags: ['autodocs', 'interaction'],
88
- decorators: [
89
- (Story) => (
90
- <ConfigProvider config={mockConfig}>
91
- <Story />
92
- </ConfigProvider>
93
- ),
94
- ],
95
- };
96
-
97
- export default meta;
98
- type Story = StoryObj<typeof ProductCard>;
99
-
100
- export const Default: Story = {
101
- args: {
102
- product: mockProduct,
103
- },
104
- play: async ({ canvasElement }) => {
105
- await waitForStorybookReady(canvasElement);
106
- const canvas = within(canvasElement);
107
- await expect(canvas.getByText(mockProduct.productName)).toBeInTheDocument();
108
- },
109
- };
110
- ```
111
-
112
- ### Storybook Commands
113
-
114
- ```bash
115
- # Development server (port 6006)
116
- pnpm storybook
117
-
118
- # Build static Storybook
119
- pnpm build-storybook
120
-
121
- # Snapshot tests (visual regression)
122
- pnpm test-storybook:snapshot
123
- pnpm test-storybook:snapshot:update # Update snapshots
124
-
125
- # Interaction tests (play functions)
126
- pnpm test-storybook:interaction
127
- pnpm test-storybook:static:interaction # Against static build
128
-
129
- # Accessibility tests
130
- pnpm test-storybook:a11y
131
- pnpm test-storybook:static:a11y # Against static build
132
-
133
- # Generate story tests with coverage
134
- pnpm generate:story-tests:coverage
135
- ```
136
-
137
- ### Storybook Features
138
-
139
- - **@storybook/addon-docs** - Automatic documentation generation
140
- - **@storybook/addon-a11y** - Accessibility testing and validation
141
- - **@storybook/addon-vitest** - Integration with Vitest
142
- - **@storybook/test-runner** - Automated testing (interaction, a11y)
143
- - **Viewport Toolbar** - Built-in toolbar for testing different screen sizes
144
-
145
- > **Important**: Use Storybook's built-in viewport toolbar instead of creating separate Mobile/Tablet/Desktop stories. Use the viewport selector in the Storybook toolbar to test components at different screen sizes.
146
-
147
- ### Story Tags
148
-
149
- - `autodocs` - Enable automatic documentation
150
- - `interaction` - Include in interaction test runs
151
- - `skip-a11y` - Exclude from a11y tests (use sparingly)
152
-
153
- ## Testing Best Practices
154
-
155
- ### Component Testing
156
-
157
- 1. **Colocate tests** - Keep test files next to source files
158
- 2. **Use test utilities** - Leverage `@/test-utils` for mocks and providers
159
- 3. **Mock external dependencies** - Use `vi.mock()` for API clients, context providers, etc.
160
- 4. **Test user interactions** - Use `@testing-library/user-event` for realistic interactions
161
- 5. **Test accessibility** - Use Storybook a11y addon and test-runner
162
-
163
- ### Storybook Stories
164
-
165
- 1. **Multiple variants** - Create stories for different states (Default, Loading, Error, etc.)
166
- 2. **Play functions** - Use `play` functions for interaction testing
167
- 3. **Decorators** - Wrap stories with necessary providers (ConfigProvider, etc.)
168
- 4. **Documentation** - Include component descriptions and prop documentation
169
- 5. **Viewport testing** - Use built-in viewport toolbar, not separate stories
170
-
171
- ### Route Testing
172
-
173
- Route tests should mock:
174
- - Loader functions and their return values
175
- - Action functions
176
- - React Router context
177
- - API clients
178
-
179
- Example:
180
-
181
- ```typescript
182
- // src/routes/_app.product.$productId.test.tsx
183
- import { describe, test, expect, vi } from 'vitest';
184
- import { render } from '@testing-library/react';
185
-
186
- vi.mock('@/components/product-view', () => ({
187
- default: ({ product }: any) => (
188
- <div data-testid="product-view">
189
- <div data-testid="product-name">{product?.name}</div>
190
- </div>
191
- ),
192
- }));
193
-
194
- // Test route component...
195
- ```
196
-
197
- ## Testing Recommendations
198
-
199
- ### SEO Crawler Emulation
200
-
201
- - Use **Googlebot user agent** in network conditions to emulate SEO crawler behavior
202
- - This changes React Router's streaming strategy and shows what crawlers see for SSR
203
- - Helps verify server-side rendering works correctly for search engines
204
-
205
- ### Coverage Goals
206
-
207
- - Maintain coverage above thresholds defined in `vitest.thresholds.ts`
208
- - Raise thresholds regularly as coverage improves
209
- - Focus on testing critical paths and user-facing functionality
210
-
211
- ### Test Organization
212
-
213
- ```
214
- src/
215
- ├── components/
216
- │ ├── product-card/
217
- │ │ ├── index.tsx # Component
218
- │ │ ├── index.test.tsx # Unit tests
219
- │ │ └── index.stories.tsx # Storybook stories
220
- ├── routes/
221
- │ ├── _app.product.$productId.tsx
222
- │ └── _app.product.$productId.test.tsx
223
- └── test-utils/ # Shared test utilities
224
- ├── config.ts
225
- └── context-provider-utils.ts
226
- ```
227
-
228
- ## References
229
-
230
- - **README-TESTS.md** - Complete testing documentation
231
- - **.storybook/README-STORYBOOK.md** - Storybook setup and usage guide
232
- - **vitest.thresholds.ts** - Coverage threshold definitions
@@ -1,24 +0,0 @@
1
- /**
2
- * Extracted parameters from a Figma design URL.
3
- *
4
- * @property {string} fileKey - Figma file identifier from URL path
5
- * @property {string} nodeId - Node identifier (colon format for Figma MCP)
6
- */
7
- export interface FigmaParams {
8
- fileKey: string;
9
- nodeId: string;
10
- }
11
- /**
12
- * Parses a Figma URL to extract fileKey and nodeId.
13
- *
14
- * Supported URL formats:
15
- * - https://figma.com/design/:fileKey/:fileName?node-id=1-2
16
- * - https://www.figma.com/design/:fileKey/:fileName?node-id=1-2
17
- * - https://figma.com/file/:fileKey/:fileName?node-id=1-2
18
- *
19
- * @param figmaUrl - The Figma URL to parse
20
- * @returns Object with fileKey and nodeId
21
- * @throws {Error} When URL is not from figma.com, fileKey cannot be extracted, or node-id is missing
22
- * @throws {TypeError} When URL format is invalid
23
- */
24
- export declare function parseFigmaUrl(figmaUrl: string): FigmaParams;
@@ -1,53 +0,0 @@
1
- /*
2
- * Copyright (c) 2025, Salesforce, Inc.
3
- * SPDX-License-Identifier: Apache-2
4
- * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
5
- */
6
- /**
7
- * Parses a Figma URL to extract fileKey and nodeId.
8
- *
9
- * Supported URL formats:
10
- * - https://figma.com/design/:fileKey/:fileName?node-id=1-2
11
- * - https://www.figma.com/design/:fileKey/:fileName?node-id=1-2
12
- * - https://figma.com/file/:fileKey/:fileName?node-id=1-2
13
- *
14
- * @param figmaUrl - The Figma URL to parse
15
- * @returns Object with fileKey and nodeId
16
- * @throws {Error} When URL is not from figma.com, fileKey cannot be extracted, or node-id is missing
17
- * @throws {TypeError} When URL format is invalid
18
- */
19
- export function parseFigmaUrl(figmaUrl) {
20
- try {
21
- const url = new URL(figmaUrl);
22
- // Validate it's a Figma URL
23
- if (!url.hostname.includes('figma.com')) {
24
- throw new Error('URL must be from figma.com');
25
- }
26
- // Extract fileKey from pathname
27
- // Pattern: /design/:fileKey/:fileName or /file/:fileKey/:fileName
28
- const pathMatch = url.pathname.match(/\/(design|file)\/([^/]+)/);
29
- if (!pathMatch || !pathMatch[2]) {
30
- throw new Error('Could not extract fileKey from URL. Expected format: https://figma.com/design/:fileKey/:fileName');
31
- }
32
- const fileKey = pathMatch[2];
33
- // Extract nodeId from query params
34
- // Pattern: ?node-id=1-2 or ?node-id=1:2
35
- const nodeIdParam = url.searchParams.get('node-id');
36
- if (!nodeIdParam) {
37
- throw new Error('Could not extract node-id from URL. Expected query parameter: ?node-id=1-2');
38
- }
39
- // Convert node-id format from "1-2" to "1:2" (Figma MCP expects colon format)
40
- const nodeId = nodeIdParam.replaceAll('-', ':');
41
- return {
42
- fileKey,
43
- nodeId,
44
- };
45
- }
46
- catch (error) {
47
- if (error instanceof TypeError) {
48
- throw new TypeError(`Invalid URL format: ${figmaUrl}`);
49
- }
50
- throw error;
51
- }
52
- }
53
- //# sourceMappingURL=figma-url-parser.js.map