Skip to content

Commit 4a9b020

Browse files
committed
feat: enhance Storybook integration with caching, add MSW handlers, and improve test accessibility
1 parent e34e0f5 commit 4a9b020

File tree

14 files changed

+114
-427
lines changed

14 files changed

+114
-427
lines changed

.github/workflows/ci.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,17 @@ jobs:
200200
cd client
201201
npm ci
202202
203+
- name: Cache Storybook build
204+
id: cache-storybook
205+
uses: actions/cache@v3
206+
with:
207+
path: client/storybook-static
208+
key: ${{ runner.os }}-storybook-${{ hashFiles('client/src/**', 'client/.storybook/**', 'client/package-lock.json') }}
209+
restore-keys: |
210+
${{ runner.os }}-storybook-
211+
203212
- name: Build Storybook for validation
213+
if: steps.cache-storybook.outputs.cache-hit != 'true'
204214
run: cd client && npm run build-storybook
205215

206216
- name: Run Jest story validation tests

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,13 @@ backups/
5858

5959
# Storybook outputs and caches
6060
storybook-static/
61-
client/storybook-static/
6261
build-storybook/
6362
client/build-storybook/
6463
.cache/storybook/
6564

6665
# Storybook test artifacts
6766
.out_storybook_
6867
.storyshots
68+
69+
# MSW service worker - regenerate with: cd client && npx msw init public/ --save
70+
client/public/mockServiceWorker.js
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* Default MSW request handlers shared across all Storybook stories.
3+
*
4+
* These provide baseline API responses so stories render without real network
5+
* requests. Individual stories can override handlers via `parameters.msw`.
6+
*
7+
* Regenerate mockServiceWorker.js if it goes missing:
8+
* cd client && npx msw init public/ --save
9+
*/
10+
import { http, HttpResponse } from 'msw';
11+
import { DEFAULT_CONFIG } from '../src/config/configSchema';
12+
13+
export const defaultMswHandlers = [
14+
http.get('/getconfig', () =>
15+
HttpResponse.json({
16+
...DEFAULT_CONFIG,
17+
preferredResolution: '1080',
18+
channelFilesToDownload: 3,
19+
youtubeOutputDirectory: '/downloads/youtube',
20+
isPlatformManaged: {
21+
plexUrl: false,
22+
authEnabled: true,
23+
useTmpForDownloads: false,
24+
},
25+
deploymentEnvironment: {
26+
platform: null,
27+
isWsl: false,
28+
},
29+
})
30+
),
31+
http.get('/storage-status', () =>
32+
HttpResponse.json({
33+
availableGB: '100',
34+
percentFree: 50,
35+
totalGB: '200',
36+
})
37+
),
38+
http.get('/api/channels/subfolders', () => HttpResponse.json(['Movies', 'Shows'])),
39+
http.get('/api/cookies/status', () =>
40+
HttpResponse.json({
41+
cookiesEnabled: false,
42+
customCookiesUploaded: false,
43+
customFileExists: false,
44+
})
45+
),
46+
http.get('/api/keys', () => HttpResponse.json({ keys: [] })),
47+
http.get('/api/db-status', () => HttpResponse.json({ status: 'healthy' })),
48+
http.get('/setup/status', () =>
49+
HttpResponse.json({
50+
requiresSetup: false,
51+
isLocalhost: true,
52+
platformManaged: false,
53+
})
54+
),
55+
http.get('/getCurrentReleaseVersion', () =>
56+
HttpResponse.json({
57+
version: '1.0.0',
58+
ytDlpVersion: '2024.01.01',
59+
})
60+
),
61+
http.get('/get-running-jobs', () => HttpResponse.json([])),
62+
http.get('/runningjobs', () => HttpResponse.json([])),
63+
];

client/.storybook/main.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ const config = {
1515
plugins: [tsconfigPaths()],
1616
define: {
1717
...(config.define ?? {}),
18-
'process.env': {},
18+
// Explicitly define NODE_ENV rather than wiping all of process.env,
19+
// which would conflict with envPrefix env-var injection.
20+
'process.env.NODE_ENV': JSON.stringify('development'),
1921
},
2022
envPrefix: ['VITE_', 'REACT_APP_'],
2123
});
2224
},
2325
};
2426

25-
export default config;
27+
export default config;

client/.storybook/preview.js

Lines changed: 6 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,28 @@
11
import React from 'react';
22
import { initialize, mswLoader } from 'msw-storybook-addon';
3-
import { http, HttpResponse } from 'msw';
43
import { ThemeProvider } from '@mui/material/styles';
54
import CssBaseline from '@mui/material/CssBaseline';
65
import { LocalizationProvider } from '@mui/x-date-pickers';
76
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
87
import { MemoryRouter } from 'react-router-dom';
98
import WebSocketContext from '../src/contexts/WebSocketContext';
109
import { lightTheme, darkTheme } from '../src/theme';
11-
import { DEFAULT_CONFIG } from '../src/config/configSchema';
10+
import { defaultMswHandlers } from './fixtures/mswHandlers';
1211

1312
initialize({
1413
onUnhandledRequest: 'bypass',
1514
});
1615

16+
/**
17+
* Stub WebSocket context for stories. subscribe/unsubscribe are no-ops since
18+
* stories don't need live socket events. Override via story decorators if needed.
19+
*/
1720
const mockWebSocketContext = {
1821
socket: null,
1922
subscribe: () => {},
2023
unsubscribe: () => {},
2124
};
2225

23-
const defaultMswHandlers = [
24-
http.get('/getconfig', () =>
25-
HttpResponse.json({
26-
...DEFAULT_CONFIG,
27-
preferredResolution: '1080',
28-
channelFilesToDownload: 3,
29-
youtubeOutputDirectory: '/downloads/youtube',
30-
isPlatformManaged: {
31-
plexUrl: false,
32-
authEnabled: true,
33-
useTmpForDownloads: false,
34-
},
35-
deploymentEnvironment: {
36-
platform: null,
37-
isWsl: false,
38-
},
39-
})
40-
),
41-
http.get('/storage-status', () =>
42-
HttpResponse.json({
43-
availableGB: '100',
44-
percentFree: 50,
45-
totalGB: '200',
46-
})
47-
),
48-
http.get('/api/channels/subfolders', () => HttpResponse.json(['Movies', 'Shows'])),
49-
http.get('/api/cookies/status', () =>
50-
HttpResponse.json({
51-
cookiesEnabled: false,
52-
customCookiesUploaded: false,
53-
customFileExists: false,
54-
})
55-
),
56-
http.get('/api/keys', () => HttpResponse.json({ keys: [] })),
57-
http.get('/api/db-status', () => HttpResponse.json({ status: 'healthy' })),
58-
http.get('/setup/status', () =>
59-
HttpResponse.json({
60-
requiresSetup: false,
61-
isLocalhost: true,
62-
platformManaged: false,
63-
})
64-
),
65-
http.get('/getCurrentReleaseVersion', () =>
66-
HttpResponse.json({
67-
version: '1.0.0',
68-
ytDlpVersion: '2024.01.01',
69-
})
70-
),
71-
http.get('/get-running-jobs', () => HttpResponse.json([])),
72-
http.get('/runningjobs', () => HttpResponse.json([])),
73-
];
74-
7526
const normalizeHandlers = (value) => {
7627
if (!value) return [];
7728
if (Array.isArray(value)) return value;
@@ -151,4 +102,4 @@ const preview = {
151102
],
152103
};
153104

154-
export default preview;
105+
export default preview;

client/.storybook/test-runner.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
/**
2+
* Storybook test-runner configuration (Playwright-based).
3+
*
4+
* Used for LOCAL development testing via `npm run test-storybook`.
5+
* NOT used in CI — the CI workflow validates stories through Jest
6+
* (see client/src/tests/storybook_coverage.test.js and the
7+
* test-storybook job in .github/workflows/ci.yml).
8+
*
9+
* Enable debug output with: STORYBOOK_TEST_RUNNER_DEBUG=1 npm run test-storybook
10+
*/
111
const DEBUG = process.env.STORYBOOK_TEST_RUNNER_DEBUG === '1';
212

313
function logLine(line) {
@@ -88,4 +98,4 @@ const config = {
8898
},
8999
};
90100

91-
export default config;
101+
export default config;

0 commit comments

Comments
 (0)