Skip to content

Commit 29e145b

Browse files
committed
fix: update MSW plugin configuration in msw-browser; enhance objectStackLoader to manage dynamic handlers in Storybook
1 parent 7d06684 commit 29e145b

4 files changed

Lines changed: 69 additions & 30 deletions

File tree

.storybook/msw-browser.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ import { config as crmConfig } from '@object-ui/example-crm';
1313
import { http, HttpResponse } from 'msw';
1414

1515
let kernel: ObjectKernel | null = null;
16+
let mswPlugin: MSWPlugin | null = null;
1617

1718
export async function startMockServer() {
1819
if (kernel) return kernel;
1920

2021
console.log('[Storybook MSW] Starting ObjectStack Runtime (Browser Mode)...');
22+
2123
console.log('[Storybook MSW] Loaded Config:', crmConfig ? 'Found' : 'Missing', crmConfig?.apps?.length);
2224

2325
if (crmConfig && crmConfig.objects) {
@@ -40,8 +42,8 @@ export async function startMockServer() {
4042
console.error('❌ CRM Config is missing! Skipping AppPlugin.');
4143
}
4244

43-
kernel.use(new MSWPlugin({
44-
enableBrowser: true,
45+
mswPlugin = new MSWPlugin({
46+
enableBrowser: false, // Disable auto-start, let msw-storybook-addon handle it
4547
baseUrl: '/api/v1',
4648
logRequests: true,
4749
customHandlers: [
@@ -70,7 +72,9 @@ export async function startMockServer() {
7072
});
7173
})
7274
]
73-
}));
75+
});
76+
77+
kernel.use(mswPlugin);
7478

7579
console.log('[Storybook MSW] Bootstrapping kernel...');
7680
await kernel.bootstrap();
@@ -105,4 +109,8 @@ async function initializeMockData(driver: InMemoryDriver) {
105109
}
106110
}
107111

112+
export function getHandlers() {
113+
return mswPlugin?.getHandlers() || [];
114+
}
115+
108116
export { kernel };

.storybook/preview.ts

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import type { Preview } from '@storybook/react-vite'
1+
import type { Preview, LoaderFunction } from '@storybook/react-vite'
22
import { initialize, mswLoader } from 'msw-storybook-addon';
33
import { handlers } from './mocks';
4-
import { startMockServer } from './msw-browser';
4+
import { startMockServer, getHandlers } from './msw-browser';
55
import '../packages/components/src/index.css';
6+
67
import { ComponentRegistry } from '@object-ui/core';
78
import * as components from '../packages/components/src/index';
89

@@ -11,17 +12,46 @@ initialize({
1112
onUnhandledRequest: 'bypass'
1213
});
1314

14-
// Start MSW runtime with ObjectStack kernel
15-
// This must be called during Storybook initialization
16-
if (typeof window !== 'undefined') {
17-
startMockServer().catch(err => {
18-
console.error('Failed to start MSW runtime:', err);
19-
});
20-
}
15+
// Custom loader to ensure ObjectStack kernel is ready and handlers are active
16+
const objectStackLoader: LoaderFunction = async (context) => {
17+
// Ensure kernel is started
18+
if (typeof window !== 'undefined') {
19+
await startMockServer().catch(err => {
20+
console.error('Failed to start MSW runtime:', err);
21+
});
22+
}
23+
24+
// Get dynamic handlers from the ObjectStack kernel
25+
const kernelHandlers = getHandlers();
26+
27+
// Inject kernel handlers into parameters for mswLoader to pick up.
28+
// We prepend them so specific story handlers can override them if needed,
29+
// OR we append them if we want kernel to be fallback.
30+
// Generally, specific mocks should win, so kernel handlers should be 'after' or 'fallback'.
31+
// But msw-storybook-addon applies handlers in order.
32+
33+
// If we assume MSW standard: first matching handler wins.
34+
// So specific story handlers (from parameters.msw.handlers) should come FIRST.
35+
// Kernel handlers (generic) should come LAST.
36+
37+
const existingHandlers = context.parameters.msw?.handlers || [];
38+
39+
// Careful: existingHandlers might be a single handler or array.
40+
const existingArray = Array.isArray(existingHandlers) ? existingHandlers : [existingHandlers].filter(Boolean);
41+
42+
context.parameters.msw = {
43+
...context.parameters.msw,
44+
handlers: [...existingArray, ...kernelHandlers]
45+
};
46+
47+
// Now run the standard mswLoader which will use the updated parameters
48+
return mswLoader(context);
49+
};
2150

2251
// Register all base components for Storybook
2352
Object.values(components);
2453

54+
2555
// Import and register all plugin components for Storybook
2656
// This ensures plugin components are available for the plugin stories
2757
import '@object-ui/plugin-aggrid';
@@ -42,7 +72,7 @@ import '@object-ui/layout';
4272
import '@object-ui/fields';
4373

4474
const preview: Preview = {
45-
loaders: [mswLoader],
75+
loaders: [objectStackLoader],
4676
parameters: {
4777
msw: {
4878
handlers: handlers

apps/console/src/__tests__/ObjectGrid.test.tsx

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ describe('ObjectGrid MSW Integration', () => {
4242

4343
// Wait for data to load
4444
await waitFor(() => {
45-
expect(screen.getByText('John Doe')).toBeInTheDocument();
45+
expect(screen.getByText('Alice Johnson')).toBeInTheDocument();
4646
}, { timeout: 5000 });
4747

48-
expect(screen.getByText('jane.smith@example.com')).toBeInTheDocument();
49-
expect(screen.getByText('Tech Solutions')).toBeInTheDocument();
48+
expect(screen.getByText('alice@example.com')).toBeInTheDocument();
49+
expect(screen.getByText('TechCorp')).toBeInTheDocument();
5050
});
5151

5252
it('should render all columns specified in schema', async () => {
@@ -55,20 +55,20 @@ describe('ObjectGrid MSW Integration', () => {
5555
schema={{
5656
type: 'object-grid',
5757
objectName: 'contact',
58-
columns: ['name', 'email', 'phone', 'company', 'priority'],
58+
columns: ['name', 'email', 'phone', 'company', 'status'],
5959
}}
6060
dataSource={dataSource}
6161
/>
6262
);
6363

6464
await waitFor(() => {
65-
expect(screen.getByText('John Doe')).toBeInTheDocument();
65+
expect(screen.getByText('Alice Johnson')).toBeInTheDocument();
6666
}, { timeout: 5000 });
6767

6868
// Check that all specified columns are rendered
69-
expect(screen.getByText('+1234567890')).toBeInTheDocument();
70-
expect(screen.getByText('Acme Corp')).toBeInTheDocument();
71-
expect(screen.getByText('8')).toBeInTheDocument();
69+
expect(screen.getByText('555-0101')).toBeInTheDocument();
70+
expect(screen.getByText('TechCorp')).toBeInTheDocument();
71+
expect(screen.getByText('Active')).toBeInTheDocument();
7272
});
7373

7474
it('should handle empty data gracefully', async () => {
@@ -90,7 +90,7 @@ describe('ObjectGrid MSW Integration', () => {
9090

9191
// Should not show any contact data
9292
await waitFor(() => {
93-
expect(screen.queryByText('John Doe')).not.toBeInTheDocument();
93+
expect(screen.queryByText('Alice Johnson')).not.toBeInTheDocument();
9494
});
9595
});
9696
});
@@ -139,7 +139,7 @@ describe('ObjectGrid MSW Integration', () => {
139139
);
140140

141141
await waitFor(() => {
142-
expect(screen.getByText('John Doe')).toBeInTheDocument();
142+
expect(screen.getByText('Alice Johnson')).toBeInTheDocument();
143143
}, { timeout: 5000 });
144144

145145
// Note: Row selection UI depends on the actual grid implementation
@@ -163,7 +163,7 @@ describe('ObjectGrid MSW Integration', () => {
163163
);
164164

165165
await waitFor(() => {
166-
expect(screen.getByText('John Doe')).toBeInTheDocument();
166+
expect(screen.getByText('Alice Johnson')).toBeInTheDocument();
167167
}, { timeout: 5000 });
168168

169169
// Look for edit buttons (implementation-specific)
@@ -187,7 +187,7 @@ describe('ObjectGrid MSW Integration', () => {
187187
);
188188

189189
await waitFor(() => {
190-
expect(screen.getByText('John Doe')).toBeInTheDocument();
190+
expect(screen.getByText('Alice Johnson')).toBeInTheDocument();
191191
}, { timeout: 5000 });
192192

193193
// Look for delete buttons (implementation-specific)
@@ -211,7 +211,7 @@ describe('ObjectGrid MSW Integration', () => {
211211
// Check for loading indicator (implementation-specific)
212212
// The grid should eventually show data
213213
await waitFor(() => {
214-
expect(screen.getByText('John Doe')).toBeInTheDocument();
214+
expect(screen.getByText('Alice Johnson')).toBeInTheDocument();
215215
}, { timeout: 5000 });
216216
});
217217

@@ -228,9 +228,9 @@ describe('ObjectGrid MSW Integration', () => {
228228
);
229229

230230
await waitFor(() => {
231-
expect(screen.getByText('John Doe')).toBeInTheDocument();
232-
expect(screen.getByText('Jane Smith')).toBeInTheDocument();
233-
expect(screen.getByText('Bob Johnson')).toBeInTheDocument();
231+
expect(screen.getByText('Alice Johnson')).toBeInTheDocument();
232+
expect(screen.getByText('Bob Smith')).toBeInTheDocument();
233+
expect(screen.getByText('Charlie Brown')).toBeInTheDocument();
234234
}, { timeout: 5000 });
235235
});
236236
});

packages/components/src/__tests__/complex-disclosure-renderers.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,11 @@ describe('Complex Renderers - Display Issue Detection', () => {
178178
it('should render scrollable area', () => {
179179
const { container } = renderComponent({
180180
type: 'scroll-area',
181-
content: [{ type: 'text', content: 'Scrollable content' }],
181+
children: [{ type: 'text', content: 'Scrollable content' }],
182182
});
183183

184184
// ScrollArea renders content
185+
185186
expect(container.textContent).toContain('Scrollable content');
186187
});
187188
});

0 commit comments

Comments
 (0)