Skip to content

Commit 43f1220

Browse files
committed
fix: Addressed nested router issue and filled gap in storybook testing
1 parent 0120489 commit 43f1220

File tree

8 files changed

+220
-2349
lines changed

8 files changed

+220
-2349
lines changed

client/.storybook/preview.js

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,48 @@ import { ThemeProvider } from '@mui/material/styles';
44
import CssBaseline from '@mui/material/CssBaseline';
55
import { LocalizationProvider } from '@mui/x-date-pickers';
66
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
7-
import { MemoryRouter } from 'react-router-dom';
87
import WebSocketContext from '../src/contexts/WebSocketContext';
98
import { lightTheme, darkTheme } from '../src/theme';
109
import { defaultMswHandlers } from './fixtures/mswHandlers';
1110

11+
/**
12+
* STORYBOOK ROUTER CONFIGURATION
13+
*
14+
* Stories for components that use React Router hooks (useNavigate, useParams, useLocation)
15+
* must explicitly wrap their components with MemoryRouter to avoid runtime errors.
16+
*
17+
* Router-dependent components with stories:
18+
* - ChannelManager (.../ChannelManager.story.tsx)
19+
* - ChannelPage (.../ChannelPage.story.tsx)
20+
* - DownloadManager (.../DownloadManager.story.tsx)
21+
* - ChannelVideos (.../ChannelPage/__tests__/ChannelVideos.story.tsx)
22+
* - DownloadProgress (.../DownloadManager/__tests__/DownloadProgress.story.tsx)
23+
*
24+
* To add routing to a story:
25+
*
26+
* 1. For components that need routing context but no specific routes:
27+
* import { MemoryRouter } from 'react-router-dom';
28+
* const meta: Meta<typeof MyComponent> = {
29+
* // ...
30+
* decorators: [
31+
* (Story) => <MemoryRouter><Story /></MemoryRouter>
32+
* ]
33+
* };
34+
*
35+
* 2. For components that need specific routes/parameters:
36+
* import { MemoryRouter, Routes, Route } from 'react-router-dom';
37+
* const meta: Meta<typeof MyComponent> = {
38+
* // ...
39+
* render: (args) => (
40+
* <MemoryRouter initialEntries={['/path/to/route']}>
41+
* <Routes>
42+
* <Route path="/path/:id" element={<MyComponent {...args} />} />
43+
* </Routes>
44+
* </MemoryRouter>
45+
* )
46+
* };
47+
*/
48+
1249
initialize({
1350
onUnhandledRequest: 'bypass',
1451
});
@@ -81,20 +118,16 @@ const preview = {
81118
const selectedTheme = context.globals.theme === 'dark' ? darkTheme : lightTheme;
82119

83120
return React.createElement(
84-
MemoryRouter,
85-
null,
121+
LocalizationProvider,
122+
{ dateAdapter: AdapterDateFns },
86123
React.createElement(
87-
LocalizationProvider,
88-
{ dateAdapter: AdapterDateFns },
124+
ThemeProvider,
125+
{ theme: selectedTheme },
126+
React.createElement(CssBaseline, null),
89127
React.createElement(
90-
ThemeProvider,
91-
{ theme: selectedTheme },
92-
React.createElement(CssBaseline, null),
93-
React.createElement(
94-
WebSocketContext.Provider,
95-
{ value: mockWebSocketContext },
96-
React.createElement(Story)
97-
)
128+
WebSocketContext.Provider,
129+
{ value: mockWebSocketContext },
130+
React.createElement(Story)
98131
)
99132
)
100133
);

client/jest.setup.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,39 @@ if (typeof globalThis.Request === 'undefined') {
1515
} as any;
1616
}
1717

18+
// Minimal Response polyfill for MSW and other libraries
19+
if (typeof globalThis.Response === 'undefined') {
20+
globalThis.Response = class Response {
21+
body: any;
22+
status: number;
23+
statusText: string;
24+
headers: Map<string, string>;
25+
26+
constructor(body?: any, init?: { status?: number; statusText?: string; headers?: Record<string, string> }) {
27+
this.body = body;
28+
this.status = init?.status ?? 200;
29+
this.statusText = init?.statusText ?? 'OK';
30+
this.headers = new Map(Object.entries(init?.headers ?? {}));
31+
}
32+
33+
async json() {
34+
return JSON.parse(this.body);
35+
}
36+
37+
async text() {
38+
return this.body;
39+
}
40+
41+
clone() {
42+
return new Response(this.body, {
43+
status: this.status,
44+
statusText: this.statusText,
45+
headers: Object.fromEntries(this.headers),
46+
});
47+
}
48+
} as any;
49+
}
50+
1851
// Some libs (and JSDOM) expect these to exist
1952
import { TextDecoder, TextEncoder } from 'util';
2053
import { _testLocationHelpers } from './src/utils/location';

0 commit comments

Comments
 (0)