inspector/clients/web/package.json
cliffhall eae68f2fc6 test(web): await the theme observer instead of a wall-clock budget
The AppRenderer "live theme flip" test had its inner `waitFor` raised twice
(bare assertion -> 1000ms -> 5000ms) and failed a third time at 5032ms under
`local:gate` load. The budget was never the problem.

Root cause: happy-dom 20.11.1's `MutationObserverListener` stores its dispatch
callback as `new WeakRef((record) => this.report(record))` — an arrow function
nothing else holds strongly. A GC between `observe()` and the mutation collects
it, `callback.deref()` returns undefined in `Node[reportMutation]`, and the
mutation is dropped silently and permanently. That is why the failure tracks
machine load rather than any wall-clock value, and why no raise ever fixed it.

Reproduced directly against 20.11.1: an observer on `documentElement`, three
forced `global.gc()` passes, then `setAttribute` — callback count 0. Without
the forced GC, 1. Upstream holds the arrow strongly in a private field from
20.11.2 onward; the same probe against the bumped copy reports 1.

So:

- bump `happy-dom`'s floor to `^20.11.2` (lockfile resolves 20.14.5), which is
  the actual fix;
- replace the 5000ms `waitFor` with `flipThemeAttributeAndAwaitObservers`, an
  awaited condition per AGENTS.md: a probe MutationObserver registered after
  the component's is notified after it, so resolving on the probe's callback
  proves the component's already ran. No polling, no timeout, nothing
  load-sensitive.
- use the same helper in the two negative theme tests, which is what makes
  their "not called" a real gate rather than a vacuous pass on a flip that was
  never delivered.

The file's 52 tests now run in ~120ms.

Closes #2384

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
2026-09-16 08:58:21 -04:00

84 lines
3 KiB
JSON

{
"name": "@modelcontextprotocol/inspector-web",
"private": true,
"type": "module",
"main": "build/index.js",
"bin": {
"mcp-inspector-web": "./build/index.js"
},
"exports": {
".": "./build/index.js"
},
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build && npm run build:runner",
"build:client": "vite build",
"build:runner": "tsup --config tsup.runner.config.ts",
"build:storybook": "storybook build",
"check": "npm run format:check && npm run lint && npm run build",
"validate": "npm run check && npm run test",
"pretest": "npm run test-servers:build",
"test": "vitest run --project=unit",
"test:watch": "vitest --project=unit",
"test:coverage": "npm run test-servers:build && vitest run --project=unit --project=integration --coverage",
"test:storybook": "vitest run --project=storybook",
"test:storybook:watch": "vitest --project=storybook",
"test:integration": "npm run test-servers:build && vitest run --project=integration",
"test:integration:watch": "npm run test-servers:build && vitest --project=integration",
"test-servers:build": "tsc -p ../../test-servers --noCheck",
"lint": "eslint . --max-warnings 0",
"format": "prettier --write src server .storybook \"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}\"",
"format:check": "prettier --check src server .storybook \"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}\"",
"preview": "vite preview",
"storybook": "storybook dev -p 6006"
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@emotion/react": "^11.14.0",
"@mantine/core": "^8.3.17",
"@mantine/form": "^8.3.17",
"@mantine/hooks": "^8.3.17",
"@mantine/notifications": "^8.3.17",
"ace-builds": "^1.44.0",
"papaparse": "^5.5.4",
"react-ace": "^15.0.0",
"react-dom": "^19.2.4",
"react-icons": "^5.6.0",
"react-markdown": "^10.1.0",
"react-syntax-highlighter": "^16.1.1",
"remark-gfm": "^4.0.1"
},
"devDependencies": {
"@chromatic-com/storybook": "^5.2.1",
"@storybook/addon-a11y": "^10.5.5",
"@storybook/addon-docs": "^10.5.5",
"@storybook/addon-onboarding": "^10.5.5",
"@storybook/addon-vitest": "^10.5.5",
"@storybook/react-vite": "^10.5.5",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
"@types/express": "^5.0.6",
"@types/papaparse": "^5.5.2",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@types/react-syntax-highlighter": "^15.5.13",
"@vitejs/plugin-react": "^6.0.0",
"@vitest/browser-playwright": "4.1.11",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"eslint-plugin-storybook": "^10.5.5",
"happy-dom": "^20.11.2",
"playwright": "^1.58.2",
"storybook": "^10.5.5",
"tsup": "^8.5.1",
"vite": "^8.1.5",
"yaml": "^2.9.0"
},
"overrides": {
"esbuild": "^0.28.2",
"vitest": "4.1.11"
}
}