From ce06b5ae5372dabdb37f0c67ce765c9af5884b2d Mon Sep 17 00:00:00 2001 From: Daniel Gee Date: Mon, 10 Aug 2026 22:56:51 +0100 Subject: [PATCH 1/2] Upgrade msw-storybook-addon to v3 and msw to 2.15.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps msw-storybook-addon 2.0.6 -> 3.0.0 and msw 2.12.14 -> 2.15.0 (these move together; msw-storybook-addon@2.0.6 is incompatible with msw's newer worker internals, which is why Group 1 pinned msw down via a pnpm override). Removes that override now that the addon supports current msw. msw-storybook-addon v3 removes `initialize()`/`mswLoader` in favor of a `definePreview`-style `addons: [addonMsw(setupFn)]` call, and drops `parameters.msw` support for CSF Next (this project's story format) in favor of a `beforeEach({ msw }) { msw.use(handler) }` hook per story. Updated .storybook/preview.ts and the three story files that registered handlers accordingly. This also surfaced and fixed two pre-existing, MSW-adjacent problems that AGENTS.md had documented as "not currently reliable": - MSW genuinely wasn't intercepting requests under `vitest --project=storybook` before (confirmed by probing — a stricter assertion against a previously "passing" story failed until the beforeEach migration). It works correctly now; updated AGENTS.md's component-testing guidance to match and removed the workaround comments in the affected story files. - .storybook/msw-handlers.ts's recipe list fixtures used `name` instead of the real API's `title` field, which had gone unnoticed because MSW wasn't actually serving the response before. Verified: lint, build, unit tests (57/57), storybook interaction tests (78/78, now genuinely exercising mocked responses rather than incidentally matching a fallback UI state), and a dev-server smoke check. Playwright e2e (`pnpm run test:e2e`) fails, but on an unrelated pre-existing stale scaffold assertion ("You did it!") that doesn't match this app's actual content and is unmodified from main. Co-authored-by: Claude --- AGENTS.md | 2 +- ui/menu-website/.storybook/msw-handlers.ts | 8 +- ui/menu-website/.storybook/preview.ts | 38 ++-- ui/menu-website/package.json | 4 +- ui/menu-website/pnpm-lock.yaml | 212 +++++++++--------- ui/menu-website/pnpm-workspace.yaml | 11 - ui/menu-website/public/mockServiceWorker.js | 30 ++- .../recipe/new-recipe-form.stories.ts | 33 +-- .../src/pages/RecipeDetail.stories.ts | 35 +-- .../src/pages/RecipeList.stories.ts | 38 +--- ui/menu-website/tsconfig.storybook.json | 3 +- 11 files changed, 183 insertions(+), 231 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 46af0fff..6626c68e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -181,7 +181,7 @@ Every Vue component that is added or changed must come with both: Split the two by what each can verify reliably: -- Stories cover rendering, props and validation messages. Note that MSW request mocking is **not** currently reliable under `vitest --project=storybook` — handlers registered for `*/api/recipe` are not served, so the request fails at the network layer. Do not write a story that asserts on a mocked response body. +- Stories cover rendering, props and validation messages, including MSW-mocked response bodies — register handlers per-story via the `beforeEach({ msw }) { msw.use(handler); }` hook (not the legacy `parameters.msw` object, which `msw-storybook-addon`'s CSF-Next API silently ignores). See `RecipeList.stories.ts` and `RecipeDetail.stories.ts` for examples. - Unit tests cover request payloads, success/error branches and routing, by mocking `@/services/recipe-api` (the API layer) so the real service/TanStack Query wiring is still exercised. See `src/components/organisms/recipe/new-recipe-form.test.ts`. ### Style & Linting diff --git a/ui/menu-website/.storybook/msw-handlers.ts b/ui/menu-website/.storybook/msw-handlers.ts index edd4771b..dce956ab 100644 --- a/ui/menu-website/.storybook/msw-handlers.ts +++ b/ui/menu-website/.storybook/msw-handlers.ts @@ -54,8 +54,8 @@ export const recipeDetailLoadingHandler = http.get(recipeDetailPath, async () => export const recipesSuccessHandler = http.get(recipePath, async () => { await delay(150); return HttpResponse.json([ - { id: '1', name: 'Chocolate Cake' }, - { id: '2', name: 'Tomato Soup' }, + { id: 1, title: 'Chocolate Cake' }, + { id: 2, title: 'Tomato Soup' }, ]); }); @@ -72,8 +72,8 @@ export const recipesErrorHandler = http.get(recipePath, async () => { export const recipesLoadingHandler = http.get(recipePath, async () => { await delay(3000); return HttpResponse.json([ - { id: '1', name: 'Chocolate Cake' }, - { id: '2', name: 'Tomato Soup' }, + { id: 1, title: 'Chocolate Cake' }, + { id: 2, title: 'Tomato Soup' }, ]); }); diff --git a/ui/menu-website/.storybook/preview.ts b/ui/menu-website/.storybook/preview.ts index 02a56dbb..eb3e4075 100644 --- a/ui/menu-website/.storybook/preview.ts +++ b/ui/menu-website/.storybook/preview.ts @@ -4,7 +4,8 @@ import addonLinks from '@storybook/addon-links'; import { setup, definePreview } from '@storybook/vue3-vite'; import { QLayout, QPageContainer, Quasar } from 'quasar'; import { VueQueryPlugin, QueryClient } from '@tanstack/vue-query'; -import { initialize, mswLoader } from 'msw-storybook-addon'; +import { setupWorker } from 'msw/browser'; +import addonMsw from 'msw-storybook-addon'; import { router } from './router'; import { ingredientUnitsHandler } from './msw-handlers'; @@ -14,14 +15,6 @@ import '@quasar/extras/material-icons/material-icons.css'; import 'quasar/src/css/index.sass'; // as suggested in https://quasar.dev/start/vite-plugin import '../src/css/app.scss'; -initialize({ - serviceWorker: { - url: '/mockServiceWorker.js', - }, - onUnhandledRequest: 'bypass', - quiet: true, -}); - export const queryClient = new QueryClient({ defaultOptions: { queries: { @@ -56,8 +49,6 @@ export const withPageLayout = () => ({ }); export default definePreview({ - loaders: [mswLoader], - initialGlobals: { backgrounds: { value: 'light' }, }, @@ -72,6 +63,10 @@ export default definePreview({ }), ], + beforeEach({ msw }) { + msw.use(ingredientUnitsHandler); + }, + parameters: { controls: { matchers: { @@ -104,10 +99,6 @@ export default definePreview({ }, }, - msw: { - handlers: [ingredientUnitsHandler], - }, - a11y: { // 'todo' - show a11y violations in the test UI only // 'error' - fail CI on a11y violations @@ -116,6 +107,21 @@ export default definePreview({ }, }, - addons: [addonLinks(), addonDocs(), addonA11y()], + addons: [ + addonLinks(), + addonDocs(), + addonA11y(), + addonMsw(async () => { + const worker = setupWorker(); + await worker.start({ + serviceWorker: { + url: '/mockServiceWorker.js', + }, + onUnhandledRequest: 'bypass', + quiet: true, + }); + return worker; + }), + ], }); diff --git a/ui/menu-website/package.json b/ui/menu-website/package.json index e192b5eb..7aa08e69 100644 --- a/ui/menu-website/package.json +++ b/ui/menu-website/package.json @@ -65,8 +65,8 @@ "globals": "^17.9.0", "jiti": "^2.7.0", "jsdom": "^30.0.1", - "msw": "^2.12.14", - "msw-storybook-addon": "^2.0.6", + "msw": "^2.15.0", + "msw-storybook-addon": "^3.0.0", "npm-run-all2": "^8.0.4", "openapi-typescript": "^7.13.0", "playwright": "^1.62.1", diff --git a/ui/menu-website/pnpm-lock.yaml b/ui/menu-website/pnpm-lock.yaml index ebd601bf..81e24f86 100644 --- a/ui/menu-website/pnpm-lock.yaml +++ b/ui/menu-website/pnpm-lock.yaml @@ -6,7 +6,6 @@ settings: overrides: vue: ^3.5.41 - msw: 2.12.14 importers: @@ -87,7 +86,7 @@ importers: version: 6.0.8(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) '@vitest/browser-playwright': specifier: 4.1.10 - version: 4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(playwright@1.62.1)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) + version: 4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(playwright@1.62.1)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) '@vitest/coverage-v8': specifier: 4.1.10 version: 4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10) @@ -131,11 +130,11 @@ importers: specifier: ^30.0.1 version: 30.0.1 msw: - specifier: 2.12.14 - version: 2.12.14(@types/node@24.13.3)(typescript@6.0.3) + specifier: ^2.15.0 + version: 2.15.0(@types/node@24.13.3)(typescript@6.0.3) msw-storybook-addon: - specifier: ^2.0.6 - version: 2.0.6(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3)) + specifier: ^3.0.0 + version: 3.0.0(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(storybook@10.5.7(@types/react@19.1.6)(prettier@3.9.6)(react@19.2.4)) npm-run-all2: specifier: ^8.0.4 version: 8.0.4 @@ -165,7 +164,7 @@ importers: version: 8.2.1(supports-color@10.2.2)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vue@3.5.41(typescript@6.0.3)) vitest: specifier: ^4.1.10 - version: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) + version: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) vue-tsc: specifier: ^3.3.9 version: 3.3.9(typescript@6.0.3) @@ -691,35 +690,35 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@inquirer/ansi@1.0.2': - resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} - engines: {node: '>=18'} + '@inquirer/ansi@2.0.7': + resolution: {integrity: sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - '@inquirer/confirm@5.1.21': - resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} - engines: {node: '>=18'} + '@inquirer/confirm@6.1.1': + resolution: {integrity: sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/core@10.3.2': - resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} - engines: {node: '>=18'} + '@inquirer/core@11.2.1': + resolution: {integrity: sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/figures@1.0.15': - resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} - engines: {node: '>=18'} + '@inquirer/figures@2.0.7': + resolution: {integrity: sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - '@inquirer/type@3.0.10': - resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} - engines: {node: '>=18'} + '@inquirer/type@4.0.7': + resolution: {integrity: sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: @@ -794,6 +793,9 @@ packages: '@open-draft/deferred-promise@2.2.0': resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + '@open-draft/deferred-promise@3.0.0': + resolution: {integrity: sha512-XW375UK8/9SqUVNVa6M0yEy8+iTi4QN5VZ7aZuRFQmy76LRwI9wy5F4YIBU6T+eTe2/DNDo8tqu8RHlwLHM6RA==} + '@open-draft/logger@0.3.0': resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} @@ -1679,9 +1681,15 @@ packages: '@types/node@24.13.3': resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} + '@types/node@25.6.0': + resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} + '@types/react@19.1.6': resolution: {integrity: sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q==} + '@types/set-cookie-parser@2.4.10': + resolution: {integrity: sha512-GGmQVGpQWUe5qglJozEjZV/5dyxbOOZ0LHe/lqyWssB88Y4svNfst0uqBVscdDeIKl5Jy5+aPSvy7mI9tYRguw==} + '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} @@ -1833,7 +1841,7 @@ packages: '@vitest/mocker@4.1.10': resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} peerDependencies: - msw: 2.12.14 + msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: msw: @@ -2737,8 +2745,8 @@ packages: resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} engines: {node: '>= 0.4'} - headers-polyfill@4.0.3: - resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + headers-polyfill@5.0.1: + resolution: {integrity: sha512-1TJ6Fih/b8h5TIcv+1+Hw0PDQWJTKDKzFZzcKOiW1wJza3XoAQlkCuXLbymPYB8+ZQyw8mHvdw560e8zVFIWyA==} hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} @@ -3151,13 +3159,15 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - msw-storybook-addon@2.0.6: - resolution: {integrity: sha512-ExCwDbcJoM2V3iQU+fZNp+axVfNc7DWMRh4lyTXebDO8IbpUNYKGFUrA8UqaeWiRGKVuS7+fU+KXEa9b0OP6uA==} + msw-storybook-addon@3.0.0: + resolution: {integrity: sha512-tyYmYAwSGcfFSHhrE5yzun/OXuVIkBGOt4YTsH5IR94N38F+hzZhvGqe5scu1ENJh/hOApI/8ZRQkWdFNFsKcw==} + hasBin: true peerDependencies: - msw: 2.12.14 + msw: '>=2' + storybook: '>=9' - msw@2.12.14: - resolution: {integrity: sha512-4KXa4nVBIBjbDbd7vfQNuQ25eFxug0aropCQFoI0JdOBuJWamkT1yLVIWReFI8SiTRc+H1hKzaNk+cLk2N9rtQ==} + msw@2.15.0: + resolution: {integrity: sha512-2wQAmKkQKxRuXvYJxVhPGG0wZNBQyD06oJvxqw90XqLvptdqxdlHrFUfEteKkpaNORX3Xzc+HtEl/q0nfmN2wQ==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -3169,9 +3179,9 @@ packages: muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - mute-stream@2.0.0: - resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} - engines: {node: ^18.17.0 || >=20.5.0} + mute-stream@3.0.0: + resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} + engines: {node: ^20.17.0 || >=22.9.0} nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} @@ -3544,8 +3554,8 @@ packages: engines: {node: '>= 0.4'} hasBin: true - rettime@0.10.1: - resolution: {integrity: sha512-uyDrIlUEH37cinabq0AX4QbgV4HbFZ/gqoiunWQ1UqBtRvTTytwhNYjE++pO/MjPTZL5KQCf2bEoJ/BJNVQ5Kw==} + rettime@0.11.11: + resolution: {integrity: sha512-ILJRqVWBCTlg9r42fFgwVZx1gnFAcQF8mRoMkbgQfIrjEDf9nbBFDFx00oloOa+Q869FUtaYDXZvEfnecQSCoQ==} reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} @@ -3736,6 +3746,9 @@ packages: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} + set-cookie-parser@3.1.2: + resolution: {integrity: sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -3924,10 +3937,6 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tough-cookie@6.0.1: - resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} - engines: {node: '>=16'} - tough-cookie@6.0.2: resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==} engines: {node: '>=16'} @@ -4013,6 +4022,9 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@7.19.2: + resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} + undici@8.10.0: resolution: {integrity: sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ==} engines: {node: '>=22.19.0'} @@ -4352,10 +4364,6 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -4418,10 +4426,6 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yoctocolors-cjs@2.1.3: - resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} - engines: {node: '>=18'} - snapshots: '@adobe/css-tools@4.4.4': {} @@ -4902,31 +4906,30 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@inquirer/ansi@1.0.2': {} + '@inquirer/ansi@2.0.7': {} - '@inquirer/confirm@5.1.21(@types/node@24.13.3)': + '@inquirer/confirm@6.1.1(@types/node@24.13.3)': dependencies: - '@inquirer/core': 10.3.2(@types/node@24.13.3) - '@inquirer/type': 3.0.10(@types/node@24.13.3) + '@inquirer/core': 11.2.1(@types/node@24.13.3) + '@inquirer/type': 4.0.7(@types/node@24.13.3) optionalDependencies: '@types/node': 24.13.3 - '@inquirer/core@10.3.2(@types/node@24.13.3)': + '@inquirer/core@11.2.1(@types/node@24.13.3)': dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@24.13.3) + '@inquirer/ansi': 2.0.7 + '@inquirer/figures': 2.0.7 + '@inquirer/type': 4.0.7(@types/node@24.13.3) cli-width: 4.1.0 - mute-stream: 2.0.0 + fast-wrap-ansi: 0.2.0 + mute-stream: 3.0.0 signal-exit: 4.1.0 - wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.3 optionalDependencies: '@types/node': 24.13.3 - '@inquirer/figures@1.0.15': {} + '@inquirer/figures@2.0.7': {} - '@inquirer/type@3.0.10(@types/node@24.13.3)': + '@inquirer/type@4.0.7(@types/node@24.13.3)': optionalDependencies: '@types/node': 24.13.3 @@ -5010,6 +5013,8 @@ snapshots: '@open-draft/deferred-promise@2.2.0': {} + '@open-draft/deferred-promise@3.0.0': {} + '@open-draft/logger@0.3.0': dependencies: is-node-process: 1.2.0 @@ -5565,10 +5570,10 @@ snapshots: '@storybook/icons': 2.1.0(react@19.2.4) storybook: 10.5.7(@types/react@19.1.6)(prettier@3.9.6)(react@19.2.4) optionalDependencies: - '@vitest/browser': 4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) - '@vitest/browser-playwright': 4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(playwright@1.62.1)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/browser': 4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/browser-playwright': 4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(playwright@1.62.1)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) '@vitest/runner': 4.1.10 - vitest: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) + vitest: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) transitivePeerDependencies: - react @@ -5741,10 +5746,18 @@ snapshots: dependencies: undici-types: 7.18.2 + '@types/node@25.6.0': + dependencies: + undici-types: 7.19.2 + '@types/react@19.1.6': dependencies: csstype: 3.2.3 + '@types/set-cookie-parser@2.4.10': + dependencies: + '@types/node': 25.6.0 + '@types/statuses@2.0.6': {} '@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': @@ -5895,29 +5908,29 @@ snapshots: vite: 8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0) vue: 3.5.41(typescript@6.0.3) - '@vitest/browser-playwright@4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(playwright@1.62.1)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10)': + '@vitest/browser-playwright@4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(playwright@1.62.1)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10)': dependencies: - '@vitest/browser': 4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) - '@vitest/mocker': 4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) + '@vitest/browser': 4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) playwright: 1.62.1 tinyrainbow: 3.1.0 - vitest: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) + vitest: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/browser@4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10)': + '@vitest/browser@4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10)': dependencies: '@blazediff/core': 1.9.1 - '@vitest/mocker': 4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) '@vitest/utils': 4.1.10 magic-string: 0.30.21 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.0 - vitest: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) + vitest: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) ws: 8.21.3 transitivePeerDependencies: - bufferutil @@ -5937,9 +5950,9 @@ snapshots: obug: 2.1.1 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) + vitest: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) optionalDependencies: - '@vitest/browser': 4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/browser': 4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) '@vitest/eslint-plugin@1.6.26(@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)(vitest@4.1.10)': dependencies: @@ -5949,7 +5962,7 @@ snapshots: optionalDependencies: '@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) typescript: 6.0.3 - vitest: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) + vitest: 4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) transitivePeerDependencies: - supports-color @@ -5970,13 +5983,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))': + '@vitest/mocker@4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.12.14(@types/node@24.13.3)(typescript@6.0.3) + msw: 2.15.0(@types/node@24.13.3)(typescript@6.0.3) vite: 8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0) '@vitest/pretty-format@3.2.4': @@ -6918,7 +6931,10 @@ snapshots: dependencies: function-bind: 1.1.2 - headers-polyfill@4.0.3: {} + headers-polyfill@5.0.1: + dependencies: + '@types/set-cookie-parser': 2.4.10 + set-cookie-parser: 3.1.2 hookable@5.5.3: {} @@ -7285,28 +7301,28 @@ snapshots: ms@2.1.3: {} - msw-storybook-addon@2.0.6(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3)): + msw-storybook-addon@3.0.0(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(storybook@10.5.7(@types/react@19.1.6)(prettier@3.9.6)(react@19.2.4)): dependencies: - is-node-process: 1.2.0 - msw: 2.12.14(@types/node@24.13.3)(typescript@6.0.3) + msw: 2.15.0(@types/node@24.13.3)(typescript@6.0.3) + storybook: 10.5.7(@types/react@19.1.6)(prettier@3.9.6)(react@19.2.4) - msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3): + msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3): dependencies: - '@inquirer/confirm': 5.1.21(@types/node@24.13.3) + '@inquirer/confirm': 6.1.1(@types/node@24.13.3) '@mswjs/interceptors': 0.41.7 - '@open-draft/deferred-promise': 2.2.0 + '@open-draft/deferred-promise': 3.0.0 '@types/statuses': 2.0.6 cookie: 1.1.1 graphql: 16.13.2 - headers-polyfill: 4.0.3 + headers-polyfill: 5.0.1 is-node-process: 1.2.0 outvariant: 1.4.3 path-to-regexp: 6.3.0 picocolors: 1.1.1 - rettime: 0.10.1 + rettime: 0.11.11 statuses: 2.0.2 strict-event-emitter: 0.5.1 - tough-cookie: 6.0.1 + tough-cookie: 6.0.2 type-fest: 5.6.0 until-async: 3.0.2 yargs: 17.7.2 @@ -7317,7 +7333,7 @@ snapshots: muggle-string@0.4.1: {} - mute-stream@2.0.0: {} + mute-stream@3.0.0: {} nanoid@3.3.11: {} @@ -7740,7 +7756,7 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - rettime@0.10.1: {} + rettime@0.11.11: {} reusify@1.1.0: {} @@ -7950,6 +7966,8 @@ snapshots: transitivePeerDependencies: - supports-color + set-cookie-parser@3.1.2: {} + setprototypeof@1.2.0: {} shallow-clone@3.0.1: @@ -8117,10 +8135,6 @@ snapshots: totalist@3.0.1: {} - tough-cookie@6.0.1: - dependencies: - tldts: 7.0.29 - tough-cookie@6.0.2: dependencies: tldts: 7.0.29 @@ -8182,6 +8196,8 @@ snapshots: undici-types@7.18.2: {} + undici-types@7.19.2: {} + undici@8.10.0: {} universalify@2.0.1: {} @@ -8323,10 +8339,10 @@ snapshots: terser: 5.46.2 yaml: 2.9.0 - vitest@4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)): + vitest@4.1.10(@types/node@24.13.3)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.1)(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) + '@vitest/mocker': 4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -8347,7 +8363,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.13.3 - '@vitest/browser-playwright': 4.1.10(msw@2.12.14(@types/node@24.13.3)(typescript@6.0.3))(playwright@1.62.1)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/browser-playwright': 4.1.10(msw@2.15.0(@types/node@24.13.3)(typescript@6.0.3))(playwright@1.62.1)(vite@8.2.1(@types/node@24.13.3)(esbuild@0.27.7)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.46.2)(yaml@2.9.0))(vitest@4.1.10) '@vitest/coverage-v8': 4.1.10(@vitest/browser@4.1.10)(vitest@4.1.10) jsdom: 30.0.1 transitivePeerDependencies: @@ -8512,12 +8528,6 @@ snapshots: word-wrap@1.2.5: {} - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -8566,5 +8576,3 @@ snapshots: yargs-parser: 21.1.1 yocto-queue@0.1.0: {} - - yoctocolors-cjs@2.1.3: {} diff --git a/ui/menu-website/pnpm-workspace.yaml b/ui/menu-website/pnpm-workspace.yaml index d37e8cfd..48581423 100644 --- a/ui/menu-website/pnpm-workspace.yaml +++ b/ui/menu-website/pnpm-workspace.yaml @@ -23,14 +23,3 @@ overrides: # installs means two structurally-incompatible `App`/`Plugin` types, which # breaks `app.use(createAuth0())` under vue-tsc. Force a single instance. vue: ^3.5.41 - # @vitest/mocker (pulled in by @storybook/addon-vitest's browser mode) only - # peer-requires msw ^2.4.9, but pnpm's dedup picks the newest version that - # satisfies every range in the graph — which silently pulled in msw 2.15.x - # even though our own package.json still asks for ^2.12.14. msw 2.15's - # `setupWorker()` no longer exposes `worker.context`, which - # msw-storybook-addon@2.0.6 depends on, breaking every Storybook - # interaction test with "Cannot set properties of undefined (setting - # 'activationPromise')". Pin msw to the version msw-storybook-addon@2.0.6 - # was actually built against until the addon is upgraded to v3 (which - # supports newer msw), so it stops floating up on unrelated bumps. - msw: 2.12.14 diff --git a/ui/menu-website/public/mockServiceWorker.js b/ui/menu-website/public/mockServiceWorker.js index b17fcd65..0c970efc 100644 --- a/ui/menu-website/public/mockServiceWorker.js +++ b/ui/menu-website/public/mockServiceWorker.js @@ -7,8 +7,8 @@ * - Please do NOT modify this file. */ -const PACKAGE_VERSION = '2.12.14' -const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82' +const PACKAGE_VERSION = '2.15.0' +const INTEGRITY_CHECKSUM = '03cb67ac84128e63d7cd722a6e5b7f1e' const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') const activeClientIds = new Set() @@ -137,8 +137,18 @@ async function handleRequest(event, requestId, requestInterceptedAt) { if (client && activeClientIds.has(client.id)) { const serializedRequest = await serializeRequest(requestCloneForEvents) + // Omit the body of server-sent event stream responses. + // Cloning such responses would prevent client-side stream cancelations + // from reaching the original stream (a teed stream only cancels its + // source once both of its branches cancel) and would buffer the + // entire stream into the unconsumed clone indefinitely. + const isEventStreamResponse = response.headers + .get('content-type') + ?.toLowerCase() + .startsWith('text/event-stream') + // Clone the response so both the client and the library could consume it. - const responseClone = response.clone() + const responseClone = isEventStreamResponse ? null : response.clone() sendToClient( client, @@ -151,15 +161,17 @@ async function handleRequest(event, requestId, requestInterceptedAt) { ...serializedRequest, }, response: { - type: responseClone.type, - status: responseClone.status, - statusText: responseClone.statusText, - headers: Object.fromEntries(responseClone.headers.entries()), - body: responseClone.body, + type: response.type, + status: response.status, + statusText: response.statusText, + headers: Object.fromEntries(response.headers.entries()), + body: responseClone ? responseClone.body : null, }, }, }, - responseClone.body ? [serializedRequest.body, responseClone.body] : [], + responseClone && responseClone.body + ? [serializedRequest.body, responseClone.body] + : [], ) } diff --git a/ui/menu-website/src/components/organisms/recipe/new-recipe-form.stories.ts b/ui/menu-website/src/components/organisms/recipe/new-recipe-form.stories.ts index 022f1be7..13db1620 100644 --- a/ui/menu-website/src/components/organisms/recipe/new-recipe-form.stories.ts +++ b/ui/menu-website/src/components/organisms/recipe/new-recipe-form.stories.ts @@ -99,18 +99,9 @@ export const NonIntegerServingsBlocksSubmit = meta.story({ }, }); -// A fully populated form wired to a successful create. In the interactive -// Storybook dev server (where the MSW service worker is active) submitting this -// story navigates to the new recipe's detail page. The story therefore asserts -// only that a fully populated form clears validation and reaches submit — see -// the NOTE below for why the response itself is not asserted here. export const FullyPopulated = meta.story({ - parameters: { - msw: { - handlers: { - recipe: recipeCreateSuccessHandler, - }, - }, + beforeEach({ msw }) { + msw.use(recipeCreateSuccessHandler); }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -275,25 +266,9 @@ export const ZeroStepDurationBlocksSubmit = meta.story({ }, }); -// NOTE: this story exercises the failed-submit UI, but not specifically a 500. -// Under `vitest --project=storybook`, MSW does not serve the `*/api/recipe` -// handler registered below — the POST fails at the network layer instead, which -// drives the component down the same failure path. (Verified by probing: a POST -// to a sub-path such as `*/api/recipe/probe-ok` is served correctly with its -// body, while `*/api/recipe` is not, so this is a handler-registration gap in the -// Storybook/Vitest MSW setup rather than anything specific to POST. It equally -// affects the RecipeList and RecipeDetail stories.) The story keeps passing -// unchanged once that gap is closed, since the handler below also returns 500. -// The response-specific behaviour — the exact request payload, the 500 → banner -// mapping, and the success path navigating to the new recipe — is covered -// deterministically in new-recipe-form.test.ts, which mocks the API layer. export const SubmitFailureShowsError = meta.story({ - parameters: { - msw: { - handlers: { - recipe: recipeCreateErrorHandler, - }, - }, + beforeEach({ msw }) { + msw.use(recipeCreateErrorHandler); }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); diff --git a/ui/menu-website/src/pages/RecipeDetail.stories.ts b/ui/menu-website/src/pages/RecipeDetail.stories.ts index 38774c48..285137f5 100644 --- a/ui/menu-website/src/pages/RecipeDetail.stories.ts +++ b/ui/menu-website/src/pages/RecipeDetail.stories.ts @@ -18,35 +18,18 @@ const meta = preview.meta({ }); export const Success = meta.story({ - parameters: { - msw: { - handlers: { - recipe: recipeDetailSuccessHandler, - }, - }, + beforeEach({ msw }) { + msw.use(recipeDetailSuccessHandler); }, play: async ({ canvasElement }) => { - // NOTE: MSW isn't intercepting this path-parameterized route - // (`/api/recipe/:recipeId`) under `vitest --project=storybook` today, even - // though the handler pattern matches correctly in isolation (verified - // directly against MSW's own `matchRequestUrl`) and the non-parameterized - // `/api/recipe` route works fine. This looks like a narrow, pre-existing gap - // between `msw-storybook-addon` and this project's Storybook 10 CSF-factory - // setup for parameterized paths specifically — flagged separately for a - // dedicated fix rather than worked around here. Asserting the reliably - // reachable state until then. const canvas = within(canvasElement); - await expect(canvas.getByText('Loading recipe...')).toBeInTheDocument(); + await expect(await canvas.findByText('Chocolate Cake')).toBeInTheDocument(); }, }); export const NotFound = meta.story({ - parameters: { - msw: { - handlers: { - recipe: recipeDetailNotFoundHandler, - }, - }, + beforeEach({ msw }) { + msw.use(recipeDetailNotFoundHandler); }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -55,12 +38,8 @@ export const NotFound = meta.story({ }); export const Loading = meta.story({ - parameters: { - msw: { - handlers: { - recipe: recipeDetailLoadingHandler, - }, - }, + beforeEach({ msw }) { + msw.use(recipeDetailLoadingHandler); }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); diff --git a/ui/menu-website/src/pages/RecipeList.stories.ts b/ui/menu-website/src/pages/RecipeList.stories.ts index f8b62424..8c7a0fb6 100644 --- a/ui/menu-website/src/pages/RecipeList.stories.ts +++ b/ui/menu-website/src/pages/RecipeList.stories.ts @@ -15,30 +15,20 @@ const meta = preview.meta({ decorators: [withPageLayout], }); -const successParameters = { - msw: { - handlers: { - recipes: recipesSuccessHandler, - }, - }, -}; - export const Success = meta.story({ - parameters: successParameters, + beforeEach({ msw }) { + msw.use(recipesSuccessHandler); + }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); await expect(canvas.getByText('My Recipes')).toBeInTheDocument(); - await expect(successParameters.msw.handlers.recipes).toBe(recipesSuccessHandler); + await expect(await canvas.findByText('Chocolate Cake')).toBeInTheDocument(); }, }); export const Empty = meta.story({ - parameters: { - msw: { - handlers: { - recipes: recipesEmptyHandler, - }, - }, + beforeEach({ msw }) { + msw.use(recipesEmptyHandler); }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -48,12 +38,8 @@ export const Empty = meta.story({ export const ErrorStory = meta.story({ name: 'Error', - parameters: { - msw: { - handlers: { - recipes: recipesErrorHandler, - }, - }, + beforeEach({ msw }) { + msw.use(recipesErrorHandler); }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -62,12 +48,8 @@ export const ErrorStory = meta.story({ }); export const Loading = meta.story({ - parameters: { - msw: { - handlers: { - recipes: recipesLoadingHandler, - }, - }, + beforeEach({ msw }) { + msw.use(recipesLoadingHandler); }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); diff --git a/ui/menu-website/tsconfig.storybook.json b/ui/menu-website/tsconfig.storybook.json index 6b54d517..5357bc1d 100644 --- a/ui/menu-website/tsconfig.storybook.json +++ b/ui/menu-website/tsconfig.storybook.json @@ -1,7 +1,8 @@ { "extends": "./tsconfig.node.json", - "include": ["env.d.ts", ".storybook/**/*.ts"], + "include": [".storybook/preview.ts", "env.d.ts", ".storybook/**/*.ts"], "compilerOptions": { + "types": ["msw-storybook-addon/types"], "tsBuildInfoFile": "./build/tsconfig.storybook.tsbuildinfo" } } From b4133dfcb70a63fd5963ce5eccbbd95ed98e4166 Mon Sep 17 00:00:00 2001 From: Daniel Gee Date: Fri, 14 Aug 2026 23:02:30 +0100 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- ui/menu-website/tsconfig.storybook.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/menu-website/tsconfig.storybook.json b/ui/menu-website/tsconfig.storybook.json index 5357bc1d..9a1339a7 100644 --- a/ui/menu-website/tsconfig.storybook.json +++ b/ui/menu-website/tsconfig.storybook.json @@ -2,7 +2,7 @@ "extends": "./tsconfig.node.json", "include": [".storybook/preview.ts", "env.d.ts", ".storybook/**/*.ts"], "compilerOptions": { - "types": ["msw-storybook-addon/types"], + "types": ["node", "msw-storybook-addon/types"], "tsBuildInfoFile": "./build/tsconfig.storybook.tsbuildinfo" } }