mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-07-09 16:08:31 +00:00
test(frontend): migrate unit tests to rstest (#3703)
* test(frontend): migrate unit tests to rstest * docs: updates AGENTS.md * test(frontend): fix rstest lint formatting
This commit is contained in:
parent
9535a4f1c2
commit
6fb22bb311
41 changed files with 500 additions and 439 deletions
|
|
@ -38,7 +38,7 @@ DeerFlow is built on a sophisticated agent-based architecture using the [LangGra
|
|||
```
|
||||
tests/
|
||||
├── e2e/ # E2E tests (Playwright, Chromium, mocked backend)
|
||||
└── unit/ # Unit tests (mirrors src/ layout, powered by Vitest)
|
||||
└── unit/ # Unit tests (mirrors src/ layout, powered by Rstest)
|
||||
src/
|
||||
├── app/ # Next.js App Router pages
|
||||
│ ├── api/ # API routes
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ DeerFlow Frontend is a Next.js 16 web interface for an AI agent system. It commu
|
|||
| `pnpm check` | Lint + type check (run before committing) |
|
||||
| `pnpm lint` | ESLint only |
|
||||
| `pnpm lint:fix` | ESLint with auto-fix |
|
||||
| `pnpm test` | Run unit tests with Vitest |
|
||||
| `pnpm test` | Run unit tests with Rstest |
|
||||
| `pnpm test:e2e` | Run E2E tests with Playwright (Chromium) |
|
||||
| `pnpm typecheck` | TypeScript type check (`tsc --noEmit`) |
|
||||
| `pnpm start` | Start production server |
|
||||
|
||||
Unit tests live under `tests/unit/` and mirror the `src/` layout (e.g., `tests/unit/core/api/stream-mode.test.ts` tests `src/core/api/stream-mode.ts`). Powered by Vitest; import source modules via the `@/` path alias.
|
||||
Unit tests live under `tests/unit/` and mirror the `src/` layout (e.g., `tests/unit/core/api/stream-mode.test.ts` tests `src/core/api/stream-mode.ts`). Powered by Rstest; import source modules via the `@/` path alias.
|
||||
|
||||
E2E tests live under `tests/e2e/` and use Playwright with Chromium. They mock all backend APIs via `page.route()` network interception and test real page interactions (navigation, chat input, streaming responses). Config: `playwright.config.ts`.
|
||||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ src/
|
|||
| `pnpm dev` | Start development server with Turbopack |
|
||||
| `pnpm build` | Build for production |
|
||||
| `pnpm start` | Start production server |
|
||||
| `pnpm test` | Run unit tests with Vitest |
|
||||
| `pnpm test` | Run unit tests with Rstest |
|
||||
| `pnpm test:e2e` | Run E2E tests with Playwright |
|
||||
| `pnpm format` | Check formatting with Prettier |
|
||||
| `pnpm format:write` | Apply formatting with Prettier |
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
||||
"preview": "next build && next start",
|
||||
"start": "next start",
|
||||
"test": "vitest run",
|
||||
"test": "rstest",
|
||||
"test:e2e": "playwright test",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
|
|
@ -94,6 +94,8 @@
|
|||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@playwright/test": "^1.59.1",
|
||||
"@rsbuild/plugin-react": "^2.1.0",
|
||||
"@rstest/core": "^0.10.6",
|
||||
"@tailwindcss/postcss": "^4.0.15",
|
||||
"@types/gsap": "^3.0.0",
|
||||
"@types/node": "^20.14.10",
|
||||
|
|
@ -107,8 +109,7 @@
|
|||
"tailwindcss": "^4.0.15",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5.8.2",
|
||||
"typescript-eslint": "^8.27.0",
|
||||
"vitest": "^4.1.4"
|
||||
"typescript-eslint": "^8.27.0"
|
||||
},
|
||||
"ct3aMetadata": {
|
||||
"initVersion": "7.40.0"
|
||||
|
|
|
|||
441
frontend/pnpm-lock.yaml
generated
441
frontend/pnpm-lock.yaml
generated
|
|
@ -228,6 +228,12 @@ importers:
|
|||
'@playwright/test':
|
||||
specifier: ^1.59.1
|
||||
version: 1.59.1
|
||||
'@rsbuild/plugin-react':
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0(@rsbuild/core@2.0.15)(@rspack/core@2.0.8(@swc/helpers@0.5.23))
|
||||
'@rstest/core':
|
||||
specifier: ^0.10.6
|
||||
version: 0.10.6
|
||||
'@tailwindcss/postcss':
|
||||
specifier: ^4.0.15
|
||||
version: 4.1.18
|
||||
|
|
@ -270,9 +276,6 @@ importers:
|
|||
typescript-eslint:
|
||||
specifier: ^8.27.0
|
||||
version: 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
|
||||
vitest:
|
||||
specifier: ^4.1.4
|
||||
version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@20.19.33)(vite@7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3))
|
||||
|
||||
packages:
|
||||
|
||||
|
|
@ -434,6 +437,9 @@ packages:
|
|||
'@codemirror/view@6.39.13':
|
||||
resolution: {integrity: sha512-QBO8ZsgJLCbI28KdY0/oDy5NQLqOQVZCozBknxc2/7L98V+TVYFHnfaCsnGh1U+alpd2LOkStVwYY7nW2R1xbw==}
|
||||
|
||||
'@emnapi/core@1.10.0':
|
||||
resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==}
|
||||
|
||||
'@emnapi/core@1.8.1':
|
||||
resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==}
|
||||
|
||||
|
|
@ -443,6 +449,9 @@ packages:
|
|||
'@emnapi/wasi-threads@1.1.0':
|
||||
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
|
||||
|
||||
'@emnapi/wasi-threads@1.2.1':
|
||||
resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==}
|
||||
engines: {node: '>=18'}
|
||||
|
|
@ -1018,6 +1027,12 @@ packages:
|
|||
'@napi-rs/wasm-runtime@0.2.12':
|
||||
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
|
||||
|
||||
'@napi-rs/wasm-runtime@1.1.4':
|
||||
resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==}
|
||||
peerDependencies:
|
||||
'@emnapi/core': ^1.7.1
|
||||
'@emnapi/runtime': ^1.7.1
|
||||
|
||||
'@next/env@16.2.6':
|
||||
resolution: {integrity: sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==}
|
||||
|
||||
|
|
@ -1856,6 +1871,110 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rsbuild/core@2.0.15':
|
||||
resolution: {integrity: sha512-O8vmMhZu1YImO6jOqt/K/vlJSvkq7UtSq5YM1DIlcEd9LW8Gf6/dkQ1B2KPI6F+hSMFBnTTTumdcIowSLCw97g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
core-js: '>= 3.0.0'
|
||||
peerDependenciesMeta:
|
||||
core-js:
|
||||
optional: true
|
||||
|
||||
'@rsbuild/plugin-react@2.1.0':
|
||||
resolution: {integrity: sha512-RQTIAWB/CwPjoWt9iAl+8HixeQVgZ7kEIBrWPCixfITyHdiD84h0YpUTpEUuz6kGHw1KXT9mHZ3Rwy6WG7aRDA==}
|
||||
peerDependencies:
|
||||
'@rsbuild/core': ^2.0.0
|
||||
peerDependenciesMeta:
|
||||
'@rsbuild/core':
|
||||
optional: true
|
||||
|
||||
'@rspack/binding-darwin-arm64@2.0.8':
|
||||
resolution: {integrity: sha512-vCgbgH7B7qom+uID+RCZsTCOYFb9wC4/4+1U6rMfytrXGVJ72eNQs2tbdjOl0lb18CT3N/n+VkWynUiLk84GwA==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rspack/binding-darwin-x64@2.0.8':
|
||||
resolution: {integrity: sha512-satPm2PD4B7jDTVlVAdvMVdUszwLvWUEnUDzLb77mvVkezKNDZmuhb+e8s+FfKs8hJpNbZ9VAejuA2rr8o985w==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rspack/binding-linux-arm64-gnu@2.0.8':
|
||||
resolution: {integrity: sha512-pSI+npPQE/uDtiboqvcOIRJbEV2+B+H1xffmko/gw50la92oTUW60kVULFwsb6L0+GVCzIcwX3yq60GtYIn+Ug==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rspack/binding-linux-arm64-musl@2.0.8':
|
||||
resolution: {integrity: sha512-igjJ43yxWQ72GZqjDDZSSHax9/Vg+6rLMmOvFglTJUkQpB4Tyvu/YjW+WRjYj2xRw6blOjLxUSJWASvuSqqlvg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rspack/binding-linux-x64-gnu@2.0.8':
|
||||
resolution: {integrity: sha512-zrkoEOnqj1hOEBO5T2I/2Ts2HSJsYFh1qXwMpK4dMJFGGNWDfNeUa6/LF5uq3VINF3JUl7RL47AgrucoSZJXPA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rspack/binding-linux-x64-musl@2.0.8':
|
||||
resolution: {integrity: sha512-6CtDaGZjNDvJd9TBp7a9zABbrPORO21W96+3ZcGBn0YNUPUk4ARxIxrTTpeJ/1F41QDM8AYIkGDdqEYMqTYBsA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rspack/binding-wasm32-wasi@2.0.8':
|
||||
resolution: {integrity: sha512-Yf4SiqTUroT5Ju+te0YAY2xxKOb35tECsO21v7hYyGa705wrgoAK/MmF7enOvs9GR1iZIqgiLD/wxsIxl8GjJw==}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@rspack/binding-win32-arm64-msvc@2.0.8':
|
||||
resolution: {integrity: sha512-8NCuiQsAhXrwRBy57QZoypqrws/zLBkaQVGiB8hksr6v++8hNigNjqpQARLbd0iyMuHsQQ++8+auGk6xlDXmzw==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rspack/binding-win32-ia32-msvc@2.0.8':
|
||||
resolution: {integrity: sha512-bxiekytbX7V9KFAra+HkwtNWC6pYfHEBBZFpiT0xUs3mCFOmAAFVBsBSQsoCP9AdCEXoMAvNdnrHNw3iov4OZw==}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rspack/binding-win32-x64-msvc@2.0.8':
|
||||
resolution: {integrity: sha512-7zPs8YCe/ZVJTwd+5lpB0CP0tkn2pONf/T1ycmVY76u21Nrwt8mXQGc/2yH2eWP4B7fikYBr3hGr7mpR2fajqQ==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rspack/binding@2.0.8':
|
||||
resolution: {integrity: sha512-3uZ+y8aQxq33ty2srMxg2Nu0XuBI6vVrG50rkDaXqwWqOohfgGUSfFuQK7EnSUNy4aFUQlCG6NHialQHJov0wg==}
|
||||
|
||||
'@rspack/core@2.0.8':
|
||||
resolution: {integrity: sha512-+NLGJf8gZxihDmMFzjlly3toc2SMjeDmuvz0/Cai9AMdV4F+Pqcnt2BA9V4e3SY2jmhJQtPwgyyLtR1RiJO77g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
peerDependencies:
|
||||
'@module-federation/runtime-tools': ^0.24.1 || ^2.0.0
|
||||
'@swc/helpers': ^0.5.23
|
||||
peerDependenciesMeta:
|
||||
'@module-federation/runtime-tools':
|
||||
optional: true
|
||||
'@swc/helpers':
|
||||
optional: true
|
||||
|
||||
'@rspack/plugin-react-refresh@2.0.2':
|
||||
resolution: {integrity: sha512-dGNZiCxQxgAUI9sah7gd8u+O7OJZRCmqtEJNDOd8xW5RqcieC86F7p5qcShyw6onH5pKf57evpr2VjGbaFGkZg==}
|
||||
peerDependencies:
|
||||
'@rspack/core': ^2.0.0
|
||||
react-refresh: '>=0.10.0 <1.0.0'
|
||||
peerDependenciesMeta:
|
||||
'@rspack/core':
|
||||
optional: true
|
||||
|
||||
'@rstest/core@0.10.6':
|
||||
resolution: {integrity: sha512-nX61dw2Tnxfwy/jGZEuNbh2tzapgaH6Iwj4Aw5d2wxUwxptUL3ddUxFF5M1ZSWoLEVG30VaPg3ITzrSo5sdbTg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
happy-dom: ^20.8.3
|
||||
jsdom: '*'
|
||||
peerDependenciesMeta:
|
||||
happy-dom:
|
||||
optional: true
|
||||
jsdom:
|
||||
optional: true
|
||||
|
||||
'@rtsao/scc@1.1.0':
|
||||
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
|
||||
|
||||
|
|
@ -1915,6 +2034,9 @@ packages:
|
|||
'@swc/helpers@0.5.21':
|
||||
resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==}
|
||||
|
||||
'@swc/helpers@0.5.23':
|
||||
resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==}
|
||||
|
||||
'@t3-oss/env-core@0.12.0':
|
||||
resolution: {integrity: sha512-lOPj8d9nJJTt81mMuN9GMk8x5veOt7q9m11OSnCBJhwp1QrL/qR+M8Y467ULBSm9SunosryWNbmQQbgoiMgcdw==}
|
||||
peerDependencies:
|
||||
|
|
@ -2459,35 +2581,6 @@ packages:
|
|||
resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==}
|
||||
engines: {node: '>= 20'}
|
||||
|
||||
'@vitest/expect@4.1.4':
|
||||
resolution: {integrity: sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==}
|
||||
|
||||
'@vitest/mocker@4.1.4':
|
||||
resolution: {integrity: sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==}
|
||||
peerDependencies:
|
||||
msw: ^2.4.9
|
||||
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
peerDependenciesMeta:
|
||||
msw:
|
||||
optional: true
|
||||
vite:
|
||||
optional: true
|
||||
|
||||
'@vitest/pretty-format@4.1.4':
|
||||
resolution: {integrity: sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==}
|
||||
|
||||
'@vitest/runner@4.1.4':
|
||||
resolution: {integrity: sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==}
|
||||
|
||||
'@vitest/snapshot@4.1.4':
|
||||
resolution: {integrity: sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==}
|
||||
|
||||
'@vitest/spy@4.1.4':
|
||||
resolution: {integrity: sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==}
|
||||
|
||||
'@vitest/utils@4.1.4':
|
||||
resolution: {integrity: sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==}
|
||||
|
||||
'@vue/compiler-core@3.5.28':
|
||||
resolution: {integrity: sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==}
|
||||
|
||||
|
|
@ -2722,10 +2815,6 @@ packages:
|
|||
ccount@2.0.1:
|
||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||
|
||||
chai@6.2.2:
|
||||
resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
chalk@4.1.2:
|
||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -2842,9 +2931,6 @@ packages:
|
|||
console-table-printer@2.15.0:
|
||||
resolution: {integrity: sha512-SrhBq4hYVjLCkBVOWaTzceJalvn5K1Zq5aQA6wXC/cYjI3frKWNPEMK3sZsJfNNQApvCQmgBcc13ZKmFj8qExw==}
|
||||
|
||||
convert-source-map@2.0.0:
|
||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||
|
||||
cookie-es@1.2.2:
|
||||
resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==}
|
||||
|
||||
|
|
@ -3191,9 +3277,6 @@ packages:
|
|||
resolution: {integrity: sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-module-lexer@2.0.0:
|
||||
resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==}
|
||||
|
||||
es-object-atoms@1.1.1:
|
||||
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -3397,10 +3480,6 @@ packages:
|
|||
resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==}
|
||||
engines: {node: ^18.19.0 || >=20.5.0}
|
||||
|
||||
expect-type@1.3.0:
|
||||
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
exsolve@1.0.8:
|
||||
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
|
||||
|
||||
|
|
@ -4504,9 +4583,6 @@ packages:
|
|||
resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
obug@2.1.1:
|
||||
resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
|
||||
|
||||
ofetch@1.5.1:
|
||||
resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
|
||||
|
||||
|
|
@ -4800,6 +4876,10 @@ packages:
|
|||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
react-refresh@0.18.0:
|
||||
resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
react-remove-scroll-bar@2.3.8:
|
||||
resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -5067,9 +5147,6 @@ packages:
|
|||
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
siginfo@2.0.0:
|
||||
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
|
||||
|
||||
signal-exit@4.1.0:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
|
|
@ -5114,15 +5191,9 @@ packages:
|
|||
stable-hash@0.0.5:
|
||||
resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
|
||||
|
||||
stackback@0.0.2:
|
||||
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
|
||||
|
||||
std-env@3.10.0:
|
||||
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
|
||||
|
||||
std-env@4.0.0:
|
||||
resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==}
|
||||
|
||||
stop-iteration-iterator@1.1.0:
|
||||
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -5233,9 +5304,6 @@ packages:
|
|||
tiny-inflate@1.0.3:
|
||||
resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
|
||||
|
||||
tinybench@2.9.0:
|
||||
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
|
||||
|
||||
tinyexec@1.0.2:
|
||||
resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
|
||||
engines: {node: '>=18'}
|
||||
|
|
@ -5248,10 +5316,6 @@ packages:
|
|||
resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
tinyrainbow@3.1.0:
|
||||
resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
title@4.0.1:
|
||||
resolution: {integrity: sha512-xRnPkJx9nvE5MF6LkB5e8QJjE2FW8269wTu/LQdf7zZqBgPly0QJPf/CWAo7srj5so4yXfoLEdCFgurlpi47zg==}
|
||||
hasBin: true
|
||||
|
|
@ -5578,47 +5642,6 @@ packages:
|
|||
yaml:
|
||||
optional: true
|
||||
|
||||
vitest@4.1.4:
|
||||
resolution: {integrity: sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==}
|
||||
engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@edge-runtime/vm': '*'
|
||||
'@opentelemetry/api': ^1.9.0
|
||||
'@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
|
||||
'@vitest/browser-playwright': 4.1.4
|
||||
'@vitest/browser-preview': 4.1.4
|
||||
'@vitest/browser-webdriverio': 4.1.4
|
||||
'@vitest/coverage-istanbul': 4.1.4
|
||||
'@vitest/coverage-v8': 4.1.4
|
||||
'@vitest/ui': 4.1.4
|
||||
happy-dom: '*'
|
||||
jsdom: '*'
|
||||
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
peerDependenciesMeta:
|
||||
'@edge-runtime/vm':
|
||||
optional: true
|
||||
'@opentelemetry/api':
|
||||
optional: true
|
||||
'@types/node':
|
||||
optional: true
|
||||
'@vitest/browser-playwright':
|
||||
optional: true
|
||||
'@vitest/browser-preview':
|
||||
optional: true
|
||||
'@vitest/browser-webdriverio':
|
||||
optional: true
|
||||
'@vitest/coverage-istanbul':
|
||||
optional: true
|
||||
'@vitest/coverage-v8':
|
||||
optional: true
|
||||
'@vitest/ui':
|
||||
optional: true
|
||||
happy-dom:
|
||||
optional: true
|
||||
jsdom:
|
||||
optional: true
|
||||
|
||||
vscode-jsonrpc@8.2.0:
|
||||
resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
|
@ -5677,11 +5700,6 @@ packages:
|
|||
engines: {node: '>= 8'}
|
||||
hasBin: true
|
||||
|
||||
why-is-node-running@2.3.0:
|
||||
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
|
||||
engines: {node: '>=8'}
|
||||
hasBin: true
|
||||
|
||||
wicked-good-xpath@1.3.0:
|
||||
resolution: {integrity: sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==}
|
||||
|
||||
|
|
@ -6068,6 +6086,12 @@ snapshots:
|
|||
style-mod: 4.1.3
|
||||
w3c-keyname: 2.2.8
|
||||
|
||||
'@emnapi/core@1.10.0':
|
||||
dependencies:
|
||||
'@emnapi/wasi-threads': 1.2.1
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@emnapi/core@1.8.1':
|
||||
dependencies:
|
||||
'@emnapi/wasi-threads': 1.1.0
|
||||
|
|
@ -6084,6 +6108,11 @@ snapshots:
|
|||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@emnapi/wasi-threads@1.2.1':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
optional: true
|
||||
|
||||
|
|
@ -6610,6 +6639,13 @@ snapshots:
|
|||
'@tybys/wasm-util': 0.10.1
|
||||
optional: true
|
||||
|
||||
'@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
|
||||
dependencies:
|
||||
'@emnapi/core': 1.10.0
|
||||
'@emnapi/runtime': 1.10.0
|
||||
'@tybys/wasm-util': 0.10.1
|
||||
optional: true
|
||||
|
||||
'@next/env@16.2.6': {}
|
||||
|
||||
'@next/eslint-plugin-next@15.5.12':
|
||||
|
|
@ -7372,6 +7408,89 @@ snapshots:
|
|||
'@rollup/rollup-win32-x64-msvc@4.60.4':
|
||||
optional: true
|
||||
|
||||
'@rsbuild/core@2.0.15':
|
||||
dependencies:
|
||||
'@rspack/core': 2.0.8(@swc/helpers@0.5.23)
|
||||
'@swc/helpers': 0.5.23
|
||||
transitivePeerDependencies:
|
||||
- '@module-federation/runtime-tools'
|
||||
|
||||
'@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.0.15)(@rspack/core@2.0.8(@swc/helpers@0.5.23))':
|
||||
dependencies:
|
||||
'@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.0.8(@swc/helpers@0.5.23))(react-refresh@0.18.0)
|
||||
react-refresh: 0.18.0
|
||||
optionalDependencies:
|
||||
'@rsbuild/core': 2.0.15
|
||||
transitivePeerDependencies:
|
||||
- '@rspack/core'
|
||||
|
||||
'@rspack/binding-darwin-arm64@2.0.8':
|
||||
optional: true
|
||||
|
||||
'@rspack/binding-darwin-x64@2.0.8':
|
||||
optional: true
|
||||
|
||||
'@rspack/binding-linux-arm64-gnu@2.0.8':
|
||||
optional: true
|
||||
|
||||
'@rspack/binding-linux-arm64-musl@2.0.8':
|
||||
optional: true
|
||||
|
||||
'@rspack/binding-linux-x64-gnu@2.0.8':
|
||||
optional: true
|
||||
|
||||
'@rspack/binding-linux-x64-musl@2.0.8':
|
||||
optional: true
|
||||
|
||||
'@rspack/binding-wasm32-wasi@2.0.8':
|
||||
dependencies:
|
||||
'@emnapi/core': 1.10.0
|
||||
'@emnapi/runtime': 1.10.0
|
||||
'@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
|
||||
optional: true
|
||||
|
||||
'@rspack/binding-win32-arm64-msvc@2.0.8':
|
||||
optional: true
|
||||
|
||||
'@rspack/binding-win32-ia32-msvc@2.0.8':
|
||||
optional: true
|
||||
|
||||
'@rspack/binding-win32-x64-msvc@2.0.8':
|
||||
optional: true
|
||||
|
||||
'@rspack/binding@2.0.8':
|
||||
optionalDependencies:
|
||||
'@rspack/binding-darwin-arm64': 2.0.8
|
||||
'@rspack/binding-darwin-x64': 2.0.8
|
||||
'@rspack/binding-linux-arm64-gnu': 2.0.8
|
||||
'@rspack/binding-linux-arm64-musl': 2.0.8
|
||||
'@rspack/binding-linux-x64-gnu': 2.0.8
|
||||
'@rspack/binding-linux-x64-musl': 2.0.8
|
||||
'@rspack/binding-wasm32-wasi': 2.0.8
|
||||
'@rspack/binding-win32-arm64-msvc': 2.0.8
|
||||
'@rspack/binding-win32-ia32-msvc': 2.0.8
|
||||
'@rspack/binding-win32-x64-msvc': 2.0.8
|
||||
|
||||
'@rspack/core@2.0.8(@swc/helpers@0.5.23)':
|
||||
dependencies:
|
||||
'@rspack/binding': 2.0.8
|
||||
optionalDependencies:
|
||||
'@swc/helpers': 0.5.23
|
||||
|
||||
'@rspack/plugin-react-refresh@2.0.2(@rspack/core@2.0.8(@swc/helpers@0.5.23))(react-refresh@0.18.0)':
|
||||
dependencies:
|
||||
react-refresh: 0.18.0
|
||||
optionalDependencies:
|
||||
'@rspack/core': 2.0.8(@swc/helpers@0.5.23)
|
||||
|
||||
'@rstest/core@0.10.6':
|
||||
dependencies:
|
||||
'@rsbuild/core': 2.0.15
|
||||
'@types/chai': 5.2.3
|
||||
transitivePeerDependencies:
|
||||
- '@module-federation/runtime-tools'
|
||||
- core-js
|
||||
|
||||
'@rtsao/scc@1.1.0': {}
|
||||
|
||||
'@rushstack/eslint-patch@1.15.0': {}
|
||||
|
|
@ -7449,6 +7568,10 @@ snapshots:
|
|||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@swc/helpers@0.5.23':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@t3-oss/env-core@0.12.0(typescript@5.9.3)(zod@3.25.76)':
|
||||
optionalDependencies:
|
||||
typescript: 5.9.3
|
||||
|
|
@ -8004,47 +8127,6 @@ snapshots:
|
|||
|
||||
'@vercel/oidc@3.1.0': {}
|
||||
|
||||
'@vitest/expect@4.1.4':
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.1.0
|
||||
'@types/chai': 5.2.3
|
||||
'@vitest/spy': 4.1.4
|
||||
'@vitest/utils': 4.1.4
|
||||
chai: 6.2.2
|
||||
tinyrainbow: 3.1.0
|
||||
|
||||
'@vitest/mocker@4.1.4(vite@7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3))':
|
||||
dependencies:
|
||||
'@vitest/spy': 4.1.4
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3)
|
||||
|
||||
'@vitest/pretty-format@4.1.4':
|
||||
dependencies:
|
||||
tinyrainbow: 3.1.0
|
||||
|
||||
'@vitest/runner@4.1.4':
|
||||
dependencies:
|
||||
'@vitest/utils': 4.1.4
|
||||
pathe: 2.0.3
|
||||
|
||||
'@vitest/snapshot@4.1.4':
|
||||
dependencies:
|
||||
'@vitest/pretty-format': 4.1.4
|
||||
'@vitest/utils': 4.1.4
|
||||
magic-string: 0.30.21
|
||||
pathe: 2.0.3
|
||||
|
||||
'@vitest/spy@4.1.4': {}
|
||||
|
||||
'@vitest/utils@4.1.4':
|
||||
dependencies:
|
||||
'@vitest/pretty-format': 4.1.4
|
||||
convert-source-map: 2.0.0
|
||||
tinyrainbow: 3.1.0
|
||||
|
||||
'@vue/compiler-core@3.5.28':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.7
|
||||
|
|
@ -8331,8 +8413,6 @@ snapshots:
|
|||
|
||||
ccount@2.0.1: {}
|
||||
|
||||
chai@6.2.2: {}
|
||||
|
||||
chalk@4.1.2:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
|
|
@ -8451,8 +8531,6 @@ snapshots:
|
|||
dependencies:
|
||||
simple-wcswidth: 1.1.2
|
||||
|
||||
convert-source-map@2.0.0: {}
|
||||
|
||||
cookie-es@1.2.2: {}
|
||||
|
||||
cookie-es@1.2.3: {}
|
||||
|
|
@ -8872,8 +8950,6 @@ snapshots:
|
|||
iterator.prototype: 1.1.5
|
||||
safe-array-concat: 1.1.3
|
||||
|
||||
es-module-lexer@2.0.0: {}
|
||||
|
||||
es-object-atoms@1.1.1:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
|
|
@ -9214,8 +9290,6 @@ snapshots:
|
|||
strip-final-newline: 4.0.0
|
||||
yoctocolors: 2.1.2
|
||||
|
||||
expect-type@1.3.0: {}
|
||||
|
||||
exsolve@1.0.8: {}
|
||||
|
||||
extend@3.0.2: {}
|
||||
|
|
@ -10771,8 +10845,6 @@ snapshots:
|
|||
define-properties: 1.2.1
|
||||
es-object-atoms: 1.1.1
|
||||
|
||||
obug@2.1.1: {}
|
||||
|
||||
ofetch@1.5.1:
|
||||
dependencies:
|
||||
destr: 2.0.5
|
||||
|
|
@ -11023,6 +11095,8 @@ snapshots:
|
|||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
|
||||
react-refresh@0.18.0: {}
|
||||
|
||||
react-remove-scroll-bar@2.3.8(@types/react@19.2.13)(react@19.2.4):
|
||||
dependencies:
|
||||
react: 19.2.4
|
||||
|
|
@ -11480,8 +11554,6 @@ snapshots:
|
|||
side-channel-map: 1.0.1
|
||||
side-channel-weakmap: 1.0.2
|
||||
|
||||
siginfo@2.0.0: {}
|
||||
|
||||
signal-exit@4.1.0: {}
|
||||
|
||||
simple-wcswidth@1.1.2: {}
|
||||
|
|
@ -11518,12 +11590,8 @@ snapshots:
|
|||
|
||||
stable-hash@0.0.5: {}
|
||||
|
||||
stackback@0.0.2: {}
|
||||
|
||||
std-env@3.10.0: {}
|
||||
|
||||
std-env@4.0.0: {}
|
||||
|
||||
stop-iteration-iterator@1.1.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
|
|
@ -11653,8 +11721,6 @@ snapshots:
|
|||
|
||||
tiny-inflate@1.0.3: {}
|
||||
|
||||
tinybench@2.9.0: {}
|
||||
|
||||
tinyexec@1.0.2: {}
|
||||
|
||||
tinyglobby@0.2.15:
|
||||
|
|
@ -11667,8 +11733,6 @@ snapshots:
|
|||
fdir: 6.5.0(picomatch@4.0.4)
|
||||
picomatch: 4.0.4
|
||||
|
||||
tinyrainbow@3.1.0: {}
|
||||
|
||||
title@4.0.1:
|
||||
dependencies:
|
||||
arg: 5.0.2
|
||||
|
|
@ -11995,34 +12059,6 @@ snapshots:
|
|||
lightningcss: 1.30.2
|
||||
yaml: 2.8.3
|
||||
|
||||
vitest@4.1.4(@opentelemetry/api@1.9.0)(@types/node@20.19.33)(vite@7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3)):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.1.4
|
||||
'@vitest/mocker': 4.1.4(vite@7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3))
|
||||
'@vitest/pretty-format': 4.1.4
|
||||
'@vitest/runner': 4.1.4
|
||||
'@vitest/snapshot': 4.1.4
|
||||
'@vitest/spy': 4.1.4
|
||||
'@vitest/utils': 4.1.4
|
||||
es-module-lexer: 2.0.0
|
||||
expect-type: 1.3.0
|
||||
magic-string: 0.30.21
|
||||
obug: 2.1.1
|
||||
pathe: 2.0.3
|
||||
picomatch: 4.0.4
|
||||
std-env: 4.0.0
|
||||
tinybench: 2.9.0
|
||||
tinyexec: 1.0.2
|
||||
tinyglobby: 0.2.16
|
||||
tinyrainbow: 3.1.0
|
||||
vite: 7.3.1(@types/node@20.19.33)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.3)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@types/node': 20.19.33
|
||||
transitivePeerDependencies:
|
||||
- msw
|
||||
|
||||
vscode-jsonrpc@8.2.0: {}
|
||||
|
||||
vscode-languageserver-protocol@3.17.5:
|
||||
|
|
@ -12101,11 +12137,6 @@ snapshots:
|
|||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
why-is-node-running@2.3.0:
|
||||
dependencies:
|
||||
siginfo: 2.0.0
|
||||
stackback: 0.0.2
|
||||
|
||||
wicked-good-xpath@1.3.0: {}
|
||||
|
||||
word-wrap@1.2.5: {}
|
||||
|
|
|
|||
19
frontend/rstest.config.ts
Normal file
19
frontend/rstest.config.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { resolve } from "path";
|
||||
|
||||
import { pluginReact } from "@rsbuild/plugin-react";
|
||||
import { defineConfig } from "@rstest/core";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [pluginReact()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": resolve(__dirname, "src"),
|
||||
},
|
||||
},
|
||||
output: {
|
||||
// Streamdown imports KaTeX CSS as a side effect. Bundle these packages so
|
||||
// Rsbuild processes that CSS import instead of Node trying to load it.
|
||||
bundleDependencies: ["streamdown", "katex"],
|
||||
},
|
||||
include: ["tests/unit/**/*.test.ts"],
|
||||
});
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, it } from "@rstest/core";
|
||||
|
||||
import {
|
||||
OFFLINE_BANNER_AUTH_FAILURE_THRESHOLD,
|
||||
|
|
|
|||
|
|
@ -16,20 +16,20 @@
|
|||
* These tests pin both halves of the contract so a future refactor doesn't
|
||||
* silently drop the detail or leak the generated fallback into the UI.
|
||||
*/
|
||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, test, rs } from "@rstest/core";
|
||||
|
||||
vi.mock("@/core/api/fetcher", () => ({
|
||||
fetch: vi.fn(),
|
||||
rs.mock("@/core/api/fetcher", () => ({
|
||||
fetch: rs.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/core/config", () => ({
|
||||
rs.mock("@/core/config", () => ({
|
||||
getBackendBaseURL: () => "",
|
||||
}));
|
||||
|
||||
import { AgentsApiDisabledError, checkAgentName } from "@/core/agents/api";
|
||||
import { fetch as fetcher } from "@/core/api/fetcher";
|
||||
|
||||
const mockedFetch = vi.mocked(fetcher);
|
||||
const mockedFetch = rs.mocked(fetcher);
|
||||
|
||||
function jsonResponse(status: number, body: unknown): Response {
|
||||
return new Response(JSON.stringify(body), {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { afterEach, expect, test, vi } from "vitest";
|
||||
import { afterEach, expect, test, rs } from "@rstest/core";
|
||||
|
||||
import {
|
||||
clearReconnectRun,
|
||||
|
|
@ -9,18 +9,18 @@ import {
|
|||
function makeSessionStorage() {
|
||||
const values = new Map<string, string>();
|
||||
return {
|
||||
getItem: vi.fn((key: string) => values.get(key) ?? null),
|
||||
removeItem: vi.fn((key: string) => {
|
||||
getItem: rs.fn((key: string) => values.get(key) ?? null),
|
||||
removeItem: rs.fn((key: string) => {
|
||||
values.delete(key);
|
||||
}),
|
||||
setItem: vi.fn((key: string, value: string) => {
|
||||
setItem: rs.fn((key: string, value: string) => {
|
||||
values.set(key, value);
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
rs.unstubAllGlobals();
|
||||
});
|
||||
|
||||
test("identifies inactive run stream errors", () => {
|
||||
|
|
@ -45,7 +45,7 @@ test("does not classify unrelated conflict errors as inactive streams", () => {
|
|||
test("clears matching reconnect metadata", () => {
|
||||
const sessionStorage = makeSessionStorage();
|
||||
sessionStorage.setItem("lg:stream:thread-1", "run-1");
|
||||
vi.stubGlobal("window", { sessionStorage });
|
||||
rs.stubGlobal("window", { sessionStorage });
|
||||
|
||||
clearReconnectRun("thread-1", "run-1");
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ test("clears matching reconnect metadata", () => {
|
|||
test("keeps newer reconnect metadata", () => {
|
||||
const sessionStorage = makeSessionStorage();
|
||||
sessionStorage.setItem("lg:stream:thread-1", "newer-run");
|
||||
vi.stubGlobal("window", { sessionStorage });
|
||||
rs.stubGlobal("window", { sessionStorage });
|
||||
|
||||
clearReconnectRun("thread-1", "stale-run");
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ test("keeps newer reconnect metadata", () => {
|
|||
});
|
||||
|
||||
test("ignores reconnect metadata storage access failures", () => {
|
||||
vi.stubGlobal("window", {
|
||||
rs.stubGlobal("window", {
|
||||
get sessionStorage() {
|
||||
throw new DOMException("Blocked", "SecurityError");
|
||||
},
|
||||
|
|
@ -75,13 +75,13 @@ test("ignores reconnect metadata storage access failures", () => {
|
|||
test("clears stale reconnect metadata when join stream cannot be resumed", async () => {
|
||||
const sessionStorage = makeSessionStorage();
|
||||
sessionStorage.setItem("lg:stream:thread-1", "run-1");
|
||||
vi.stubGlobal("window", {
|
||||
rs.stubGlobal("window", {
|
||||
location: { origin: "http://localhost:2026" },
|
||||
sessionStorage,
|
||||
});
|
||||
vi.stubGlobal(
|
||||
rs.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn(async () => {
|
||||
rs.fn(async () => {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
detail:
|
||||
|
|
@ -102,13 +102,13 @@ test("clears stale reconnect metadata when join stream cannot be resumed", async
|
|||
test("rethrows unrelated streaming errors", async () => {
|
||||
const sessionStorage = makeSessionStorage();
|
||||
sessionStorage.setItem("lg:stream:thread-1", "run-1");
|
||||
vi.stubGlobal("window", {
|
||||
rs.stubGlobal("window", {
|
||||
location: { origin: "http://localhost:2026" },
|
||||
sessionStorage,
|
||||
});
|
||||
vi.stubGlobal(
|
||||
rs.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn(async () => {
|
||||
rs.fn(async () => {
|
||||
return new Response(JSON.stringify({ detail: "run is still active" }), {
|
||||
status: 409,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { expect, test } from "vitest";
|
||||
import { expect, test } from "@rstest/core";
|
||||
|
||||
import { sanitizeRunStreamOptions } from "@/core/api/stream-mode";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { expect, test } from "vitest";
|
||||
import { expect, test } from "@rstest/core";
|
||||
|
||||
import {
|
||||
appendHtmlPreviewBaseHref,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
test,
|
||||
rs,
|
||||
} from "@rstest/core";
|
||||
|
||||
const ENV_KEYS = [
|
||||
"NEXT_PUBLIC_BACKEND_BASE_URL",
|
||||
|
|
@ -33,7 +40,7 @@ function restoreEnv(snapshot: EnvSnapshot) {
|
|||
}
|
||||
|
||||
async function loadFreshArtifactUtils() {
|
||||
vi.resetModules();
|
||||
rs.resetModules();
|
||||
return await import("@/core/artifacts/utils");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
test,
|
||||
rs,
|
||||
} from "@rstest/core";
|
||||
|
||||
const ENV_KEYS = [
|
||||
"NODE_ENV",
|
||||
|
|
@ -36,7 +43,7 @@ function restoreEnv(snapshot: EnvSnapshot) {
|
|||
}
|
||||
|
||||
async function loadFreshConfig() {
|
||||
vi.resetModules();
|
||||
rs.resetModules();
|
||||
return await import("@/core/auth/gateway-config");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
test,
|
||||
rs,
|
||||
} from "@rstest/core";
|
||||
|
||||
import { AUTH_DISABLED_USER } from "@/core/auth/auth-disabled-user";
|
||||
import { STATIC_WEBSITE_USER } from "@/core/auth/static-user";
|
||||
|
||||
vi.mock("next/headers", () => ({
|
||||
cookies: vi.fn(() => {
|
||||
rs.mock("next/headers", () => ({
|
||||
cookies: rs.fn(() => {
|
||||
throw new Error("cookies should not be read in static website mode");
|
||||
}),
|
||||
}));
|
||||
|
|
@ -44,7 +51,7 @@ function restoreEnv(snapshot: EnvSnapshot) {
|
|||
}
|
||||
|
||||
async function loadFreshServerAuth() {
|
||||
vi.resetModules();
|
||||
rs.resetModules();
|
||||
return await import("@/core/auth/server");
|
||||
}
|
||||
|
||||
|
|
@ -61,15 +68,15 @@ describe("getServerSideUser", () => {
|
|||
|
||||
afterEach(() => {
|
||||
restoreEnv(saved);
|
||||
vi.unstubAllGlobals();
|
||||
rs.unstubAllGlobals();
|
||||
});
|
||||
|
||||
test("bypasses gateway auth in static website mode", async () => {
|
||||
setEnv("NEXT_PUBLIC_STATIC_WEBSITE_ONLY", "true");
|
||||
const fetchSpy = vi.fn(() => {
|
||||
const fetchSpy = rs.fn(() => {
|
||||
throw new Error("fetch should not be called in static website mode");
|
||||
});
|
||||
vi.stubGlobal("fetch", fetchSpy);
|
||||
rs.stubGlobal("fetch", fetchSpy);
|
||||
|
||||
const { getServerSideUser } = await loadFreshServerAuth();
|
||||
|
||||
|
|
@ -82,10 +89,10 @@ describe("getServerSideUser", () => {
|
|||
|
||||
test("bypasses gateway auth in auth-disabled mode", async () => {
|
||||
setEnv("DEER_FLOW_AUTH_DISABLED", "1");
|
||||
const fetchSpy = vi.fn(() => {
|
||||
const fetchSpy = rs.fn(() => {
|
||||
throw new Error("fetch should not be called in auth-disabled mode");
|
||||
});
|
||||
vi.stubGlobal("fetch", fetchSpy);
|
||||
rs.stubGlobal("fetch", fetchSpy);
|
||||
|
||||
const { getServerSideUser } = await loadFreshServerAuth();
|
||||
|
||||
|
|
@ -118,21 +125,21 @@ describe("getServerSideUser — gateway_unavailable contract (issue #3493)", ()
|
|||
|
||||
afterEach(() => {
|
||||
restoreEnv(saved);
|
||||
vi.unstubAllGlobals();
|
||||
vi.doUnmock("next/headers");
|
||||
rs.unstubAllGlobals();
|
||||
rs.doUnmock("next/headers");
|
||||
});
|
||||
|
||||
test("returns gateway_unavailable when /auth/me fetch rejects (e.g. AbortError)", async () => {
|
||||
vi.doMock("next/headers", () => ({
|
||||
cookies: vi.fn(async () => ({
|
||||
rs.doMock("next/headers", () => ({
|
||||
cookies: rs.fn(async () => ({
|
||||
get: (name: string) =>
|
||||
name === "access_token" ? { value: "stub-token" } : undefined,
|
||||
})),
|
||||
}));
|
||||
const abortErr = new DOMException("Aborted", "AbortError");
|
||||
vi.stubGlobal(
|
||||
rs.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn(() => Promise.reject(abortErr)),
|
||||
rs.fn(() => Promise.reject(abortErr)),
|
||||
);
|
||||
|
||||
const { getServerSideUser } = await loadFreshServerAuth();
|
||||
|
|
@ -143,15 +150,15 @@ describe("getServerSideUser — gateway_unavailable contract (issue #3493)", ()
|
|||
});
|
||||
|
||||
test("returns gateway_unavailable when /auth/me responds with a 5xx", async () => {
|
||||
vi.doMock("next/headers", () => ({
|
||||
cookies: vi.fn(async () => ({
|
||||
rs.doMock("next/headers", () => ({
|
||||
cookies: rs.fn(async () => ({
|
||||
get: (name: string) =>
|
||||
name === "access_token" ? { value: "stub-token" } : undefined,
|
||||
})),
|
||||
}));
|
||||
vi.stubGlobal(
|
||||
rs.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn(() =>
|
||||
rs.fn(() =>
|
||||
Promise.resolve(
|
||||
new Response("upstream error", {
|
||||
status: 503,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, test, rs } from "@rstest/core";
|
||||
|
||||
vi.mock("@/core/api/fetcher", () => ({
|
||||
fetch: vi.fn(),
|
||||
rs.mock("@/core/api/fetcher", () => ({
|
||||
fetch: rs.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/core/config", () => ({
|
||||
rs.mock("@/core/config", () => ({
|
||||
getBackendBaseURL: () => "/backend",
|
||||
}));
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ import {
|
|||
listChannelProviders,
|
||||
} from "@/core/channels/api";
|
||||
|
||||
const mockedFetch = vi.mocked(fetcher);
|
||||
const mockedFetch = rs.mocked(fetcher);
|
||||
|
||||
function jsonResponse(status: number, body: unknown): Response {
|
||||
return new Response(JSON.stringify(body), {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
test,
|
||||
rs,
|
||||
} from "@rstest/core";
|
||||
|
||||
import { startConnectionPoll } from "@/core/channels/connect-poll";
|
||||
import type { ChannelConnection } from "@/core/channels/types";
|
||||
|
|
@ -14,11 +21,11 @@ function connection(provider: string, status: string): ChannelConnection {
|
|||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
rs.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
rs.useRealTimers();
|
||||
});
|
||||
|
||||
describe("startConnectionPoll", () => {
|
||||
|
|
@ -27,8 +34,8 @@ describe("startConnectionPoll", () => {
|
|||
[connection("telegram", "pending")],
|
||||
[connection("telegram", "connected")],
|
||||
];
|
||||
const fetchConnections = vi.fn(async () => responses.shift() ?? []);
|
||||
const onConnected = vi.fn();
|
||||
const fetchConnections = rs.fn(async () => responses.shift() ?? []);
|
||||
const onConnected = rs.fn();
|
||||
|
||||
startConnectionPoll({
|
||||
provider: "telegram",
|
||||
|
|
@ -38,41 +45,41 @@ describe("startConnectionPoll", () => {
|
|||
intervalMs: 1000,
|
||||
});
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1000);
|
||||
await rs.advanceTimersByTimeAsync(1000);
|
||||
expect(fetchConnections).toHaveBeenCalledTimes(1);
|
||||
expect(onConnected).not.toHaveBeenCalled();
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1000);
|
||||
await rs.advanceTimersByTimeAsync(1000);
|
||||
expect(fetchConnections).toHaveBeenCalledTimes(2);
|
||||
expect(onConnected).toHaveBeenCalledTimes(1);
|
||||
|
||||
// No further polling after the connection resolves.
|
||||
await vi.advanceTimersByTimeAsync(5000);
|
||||
await rs.advanceTimersByTimeAsync(5000);
|
||||
expect(fetchConnections).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test("cancel() stops scheduled polling and fires no further fetches", async () => {
|
||||
const fetchConnections = vi.fn(async () => [
|
||||
const fetchConnections = rs.fn(async () => [
|
||||
connection("telegram", "pending"),
|
||||
]);
|
||||
const handle = startConnectionPoll({
|
||||
provider: "telegram",
|
||||
expiresInSeconds: 600,
|
||||
fetchConnections,
|
||||
onConnected: vi.fn(),
|
||||
onConnected: rs.fn(),
|
||||
intervalMs: 1000,
|
||||
});
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1000);
|
||||
await rs.advanceTimersByTimeAsync(1000);
|
||||
expect(fetchConnections).toHaveBeenCalledTimes(1);
|
||||
|
||||
handle.cancel();
|
||||
await vi.advanceTimersByTimeAsync(10000);
|
||||
await rs.advanceTimersByTimeAsync(10000);
|
||||
expect(fetchConnections).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("a non-finite expires_in falls back to a finite deadline and terminates", async () => {
|
||||
const fetchConnections = vi.fn(async () => [
|
||||
const fetchConnections = rs.fn(async () => [
|
||||
connection("telegram", "pending"),
|
||||
]);
|
||||
let nowValue = 0;
|
||||
|
|
@ -80,22 +87,22 @@ describe("startConnectionPoll", () => {
|
|||
provider: "telegram",
|
||||
expiresInSeconds: Number.NaN,
|
||||
fetchConnections,
|
||||
onConnected: vi.fn(),
|
||||
onConnected: rs.fn(),
|
||||
intervalMs: 1000,
|
||||
now: () => nowValue,
|
||||
});
|
||||
|
||||
nowValue = 1;
|
||||
await vi.advanceTimersByTimeAsync(1000);
|
||||
await rs.advanceTimersByTimeAsync(1000);
|
||||
expect(fetchConnections).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Jump past the fallback expiry window: the loop must stop instead of
|
||||
// running forever (Date.now() >= NaN would otherwise never be true).
|
||||
nowValue = 10_000_000;
|
||||
await vi.advanceTimersByTimeAsync(1000);
|
||||
await rs.advanceTimersByTimeAsync(1000);
|
||||
expect(fetchConnections).toHaveBeenCalledTimes(2);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(10000);
|
||||
await rs.advanceTimersByTimeAsync(10000);
|
||||
expect(fetchConnections).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { afterEach, describe, expect, test, vi } from "vitest";
|
||||
import { afterEach, describe, expect, test, rs } from "@rstest/core";
|
||||
|
||||
import {
|
||||
closeConnectWindow,
|
||||
|
|
@ -8,17 +8,17 @@ import {
|
|||
|
||||
type PopupStub = {
|
||||
closed: boolean;
|
||||
close: ReturnType<typeof vi.fn>;
|
||||
close: ReturnType<typeof rs.fn>;
|
||||
location: {
|
||||
replace: ReturnType<typeof vi.fn>;
|
||||
replace: ReturnType<typeof rs.fn>;
|
||||
};
|
||||
opener: unknown;
|
||||
};
|
||||
|
||||
function stubWindow(openResult: PopupStub | null) {
|
||||
const assign = vi.fn();
|
||||
const open = vi.fn(() => openResult);
|
||||
vi.stubGlobal("window", {
|
||||
const assign = rs.fn();
|
||||
const open = rs.fn(() => openResult);
|
||||
rs.stubGlobal("window", {
|
||||
open,
|
||||
location: { assign },
|
||||
});
|
||||
|
|
@ -28,14 +28,14 @@ function stubWindow(openResult: PopupStub | null) {
|
|||
function makePopup(): PopupStub {
|
||||
return {
|
||||
closed: false,
|
||||
close: vi.fn(),
|
||||
location: { replace: vi.fn() },
|
||||
close: rs.fn(),
|
||||
location: { replace: rs.fn() },
|
||||
opener: {},
|
||||
};
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
rs.unstubAllGlobals();
|
||||
});
|
||||
|
||||
describe("channel connect window helpers", () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, it } from "@rstest/core";
|
||||
|
||||
import {
|
||||
providerCanConnect,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { afterEach, expect, test, vi } from "vitest";
|
||||
import { afterEach, expect, test, rs } from "@rstest/core";
|
||||
|
||||
import {
|
||||
installClipboardFallback,
|
||||
|
|
@ -15,7 +15,7 @@ const originalClipboardItemDescriptor = Object.getOwnPropertyDescriptor(
|
|||
);
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
rs.restoreAllMocks();
|
||||
if (!hadOriginalNavigator) {
|
||||
Reflect.deleteProperty(globalThis, "navigator");
|
||||
} else {
|
||||
|
|
@ -46,7 +46,7 @@ afterEach(() => {
|
|||
});
|
||||
|
||||
test("writes text with the Clipboard API when available", async () => {
|
||||
const writeText = vi.fn().mockResolvedValue(undefined);
|
||||
const writeText = rs.fn().mockResolvedValue(undefined);
|
||||
Object.defineProperty(globalThis, "navigator", {
|
||||
configurable: true,
|
||||
value: {
|
||||
|
|
@ -75,14 +75,14 @@ test("returns false when Clipboard API is unavailable", async () => {
|
|||
|
||||
test("falls back to execCommand when Clipboard API is unavailable", async () => {
|
||||
const textarea = {
|
||||
remove: vi.fn(),
|
||||
select: vi.fn(),
|
||||
setAttribute: vi.fn(),
|
||||
remove: rs.fn(),
|
||||
select: rs.fn(),
|
||||
setAttribute: rs.fn(),
|
||||
style: {},
|
||||
value: "",
|
||||
};
|
||||
const appendChild = vi.fn();
|
||||
const execCommand = vi.fn().mockReturnValue(true);
|
||||
const appendChild = rs.fn();
|
||||
const execCommand = rs.fn().mockReturnValue(true);
|
||||
|
||||
Object.defineProperty(globalThis, "navigator", {
|
||||
configurable: true,
|
||||
|
|
@ -94,7 +94,7 @@ test("falls back to execCommand when Clipboard API is unavailable", async () =>
|
|||
body: {
|
||||
appendChild,
|
||||
},
|
||||
createElement: vi.fn().mockReturnValue(textarea),
|
||||
createElement: rs.fn().mockReturnValue(textarea),
|
||||
execCommand,
|
||||
},
|
||||
});
|
||||
|
|
@ -109,16 +109,16 @@ test("falls back to execCommand when Clipboard API is unavailable", async () =>
|
|||
|
||||
test("falls back to parent removal when textarea.remove is unavailable", async () => {
|
||||
const parentNode = {
|
||||
removeChild: vi.fn(),
|
||||
removeChild: rs.fn(),
|
||||
};
|
||||
const textarea = {
|
||||
parentNode,
|
||||
select: vi.fn(),
|
||||
setAttribute: vi.fn(),
|
||||
select: rs.fn(),
|
||||
setAttribute: rs.fn(),
|
||||
style: {},
|
||||
value: "",
|
||||
};
|
||||
const execCommand = vi.fn().mockReturnValue(true);
|
||||
const execCommand = rs.fn().mockReturnValue(true);
|
||||
|
||||
Object.defineProperty(globalThis, "navigator", {
|
||||
configurable: true,
|
||||
|
|
@ -128,9 +128,9 @@ test("falls back to parent removal when textarea.remove is unavailable", async (
|
|||
configurable: true,
|
||||
value: {
|
||||
body: {
|
||||
appendChild: vi.fn(),
|
||||
appendChild: rs.fn(),
|
||||
},
|
||||
createElement: vi.fn().mockReturnValue(textarea),
|
||||
createElement: rs.fn().mockReturnValue(textarea),
|
||||
execCommand,
|
||||
},
|
||||
});
|
||||
|
|
@ -142,8 +142,8 @@ test("falls back to parent removal when textarea.remove is unavailable", async (
|
|||
test("does not fail cleanup when textarea removal APIs are unavailable", async () => {
|
||||
const textarea = {
|
||||
parentNode: {},
|
||||
select: vi.fn(),
|
||||
setAttribute: vi.fn(),
|
||||
select: rs.fn(),
|
||||
setAttribute: rs.fn(),
|
||||
style: {},
|
||||
value: "",
|
||||
};
|
||||
|
|
@ -156,10 +156,10 @@ test("does not fail cleanup when textarea removal APIs are unavailable", async (
|
|||
configurable: true,
|
||||
value: {
|
||||
body: {
|
||||
appendChild: vi.fn(),
|
||||
appendChild: rs.fn(),
|
||||
},
|
||||
createElement: vi.fn().mockReturnValue(textarea),
|
||||
execCommand: vi.fn().mockReturnValue(true),
|
||||
createElement: rs.fn().mockReturnValue(textarea),
|
||||
execCommand: rs.fn().mockReturnValue(true),
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -168,11 +168,11 @@ test("does not fail cleanup when textarea removal APIs are unavailable", async (
|
|||
|
||||
test("cleans up the textarea when selecting text fails", async () => {
|
||||
const textarea = {
|
||||
remove: vi.fn(),
|
||||
select: vi.fn(() => {
|
||||
remove: rs.fn(),
|
||||
select: rs.fn(() => {
|
||||
throw new Error("selection failed");
|
||||
}),
|
||||
setAttribute: vi.fn(),
|
||||
setAttribute: rs.fn(),
|
||||
style: {},
|
||||
value: "",
|
||||
};
|
||||
|
|
@ -185,10 +185,10 @@ test("cleans up the textarea when selecting text fails", async () => {
|
|||
configurable: true,
|
||||
value: {
|
||||
body: {
|
||||
appendChild: vi.fn(),
|
||||
appendChild: rs.fn(),
|
||||
},
|
||||
createElement: vi.fn().mockReturnValue(textarea),
|
||||
execCommand: vi.fn(),
|
||||
createElement: rs.fn().mockReturnValue(textarea),
|
||||
execCommand: rs.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -198,9 +198,9 @@ test("cleans up the textarea when selecting text fails", async () => {
|
|||
|
||||
test("returns false when execCommand fallback fails", async () => {
|
||||
const textarea = {
|
||||
remove: vi.fn(),
|
||||
select: vi.fn(),
|
||||
setAttribute: vi.fn(),
|
||||
remove: rs.fn(),
|
||||
select: rs.fn(),
|
||||
setAttribute: rs.fn(),
|
||||
style: {},
|
||||
value: "",
|
||||
};
|
||||
|
|
@ -213,10 +213,10 @@ test("returns false when execCommand fallback fails", async () => {
|
|||
configurable: true,
|
||||
value: {
|
||||
body: {
|
||||
appendChild: vi.fn(),
|
||||
appendChild: rs.fn(),
|
||||
},
|
||||
createElement: vi.fn().mockReturnValue(textarea),
|
||||
execCommand: vi.fn().mockReturnValue(false),
|
||||
createElement: rs.fn().mockReturnValue(textarea),
|
||||
execCommand: rs.fn().mockReturnValue(false),
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -233,9 +233,9 @@ test("returns false when execCommand fallback cannot create an element", async (
|
|||
configurable: true,
|
||||
value: {
|
||||
body: {
|
||||
appendChild: vi.fn(),
|
||||
appendChild: rs.fn(),
|
||||
},
|
||||
execCommand: vi.fn(),
|
||||
execCommand: rs.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -256,7 +256,7 @@ test("returns false when navigator is unavailable", async () => {
|
|||
});
|
||||
|
||||
test("returns false when Clipboard API rejects", async () => {
|
||||
const writeText = vi.fn().mockRejectedValue(new Error("denied"));
|
||||
const writeText = rs.fn().mockRejectedValue(new Error("denied"));
|
||||
Object.defineProperty(globalThis, "navigator", {
|
||||
configurable: true,
|
||||
value: {
|
||||
|
|
@ -271,14 +271,14 @@ test("returns false when Clipboard API rejects", async () => {
|
|||
|
||||
test("installs a writeText fallback when Clipboard API is unavailable", async () => {
|
||||
const textarea = {
|
||||
remove: vi.fn(),
|
||||
select: vi.fn(),
|
||||
setAttribute: vi.fn(),
|
||||
remove: rs.fn(),
|
||||
select: rs.fn(),
|
||||
setAttribute: rs.fn(),
|
||||
style: {},
|
||||
value: "",
|
||||
};
|
||||
const appendChild = vi.fn();
|
||||
const execCommand = vi.fn().mockReturnValue(true);
|
||||
const appendChild = rs.fn();
|
||||
const execCommand = rs.fn().mockReturnValue(true);
|
||||
|
||||
Object.defineProperty(globalThis, "navigator", {
|
||||
configurable: true,
|
||||
|
|
@ -290,7 +290,7 @@ test("installs a writeText fallback when Clipboard API is unavailable", async ()
|
|||
body: {
|
||||
appendChild,
|
||||
},
|
||||
createElement: vi.fn().mockReturnValue(textarea),
|
||||
createElement: rs.fn().mockReturnValue(textarea),
|
||||
execCommand,
|
||||
},
|
||||
});
|
||||
|
|
@ -333,12 +333,12 @@ test("installed writeText fallback converts thrown DOM failures to rejections",
|
|||
configurable: true,
|
||||
value: {
|
||||
body: {
|
||||
appendChild: vi.fn(),
|
||||
appendChild: rs.fn(),
|
||||
},
|
||||
createElement: vi.fn(() => {
|
||||
createElement: rs.fn(() => {
|
||||
throw new Error("dom unavailable");
|
||||
}),
|
||||
execCommand: vi.fn(),
|
||||
execCommand: rs.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -358,16 +358,16 @@ test("installed writeText fallback distinguishes copy command failure", async ()
|
|||
configurable: true,
|
||||
value: {
|
||||
body: {
|
||||
appendChild: vi.fn(),
|
||||
appendChild: rs.fn(),
|
||||
},
|
||||
createElement: vi.fn().mockReturnValue({
|
||||
remove: vi.fn(),
|
||||
select: vi.fn(),
|
||||
setAttribute: vi.fn(),
|
||||
createElement: rs.fn().mockReturnValue({
|
||||
remove: rs.fn(),
|
||||
select: rs.fn(),
|
||||
setAttribute: rs.fn(),
|
||||
style: {},
|
||||
value: "",
|
||||
}),
|
||||
execCommand: vi.fn().mockReturnValue(false),
|
||||
execCommand: rs.fn().mockReturnValue(false),
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -380,13 +380,13 @@ test("installed writeText fallback distinguishes copy command failure", async ()
|
|||
|
||||
test("installs a write fallback for ClipboardItem text/plain payloads", async () => {
|
||||
const textarea = {
|
||||
remove: vi.fn(),
|
||||
select: vi.fn(),
|
||||
setAttribute: vi.fn(),
|
||||
remove: rs.fn(),
|
||||
select: rs.fn(),
|
||||
setAttribute: rs.fn(),
|
||||
style: {},
|
||||
value: "",
|
||||
};
|
||||
const execCommand = vi.fn().mockReturnValue(true);
|
||||
const execCommand = rs.fn().mockReturnValue(true);
|
||||
|
||||
Object.defineProperty(globalThis, "navigator", {
|
||||
configurable: true,
|
||||
|
|
@ -396,9 +396,9 @@ test("installs a write fallback for ClipboardItem text/plain payloads", async ()
|
|||
configurable: true,
|
||||
value: {
|
||||
body: {
|
||||
appendChild: vi.fn(),
|
||||
appendChild: rs.fn(),
|
||||
},
|
||||
createElement: vi.fn().mockReturnValue(textarea),
|
||||
createElement: rs.fn().mockReturnValue(textarea),
|
||||
execCommand,
|
||||
},
|
||||
});
|
||||
|
|
@ -418,7 +418,7 @@ test("installs a write fallback for ClipboardItem text/plain payloads", async ()
|
|||
});
|
||||
|
||||
test("installed write fallback rejects when ClipboardItem lacks text/plain", async () => {
|
||||
const execCommand = vi.fn().mockReturnValue(true);
|
||||
const execCommand = rs.fn().mockReturnValue(true);
|
||||
|
||||
Object.defineProperty(globalThis, "navigator", {
|
||||
configurable: true,
|
||||
|
|
@ -428,12 +428,12 @@ test("installed write fallback rejects when ClipboardItem lacks text/plain", asy
|
|||
configurable: true,
|
||||
value: {
|
||||
body: {
|
||||
appendChild: vi.fn(),
|
||||
appendChild: rs.fn(),
|
||||
},
|
||||
createElement: vi.fn().mockReturnValue({
|
||||
remove: vi.fn(),
|
||||
select: vi.fn(),
|
||||
setAttribute: vi.fn(),
|
||||
createElement: rs.fn().mockReturnValue({
|
||||
remove: rs.fn(),
|
||||
select: rs.fn(),
|
||||
setAttribute: rs.fn(),
|
||||
style: {},
|
||||
value: "",
|
||||
}),
|
||||
|
|
@ -454,7 +454,7 @@ test("installed write fallback rejects when ClipboardItem lacks text/plain", asy
|
|||
});
|
||||
|
||||
test("installed write fallback rejects when getType cannot provide text/plain", async () => {
|
||||
const execCommand = vi.fn().mockReturnValue(true);
|
||||
const execCommand = rs.fn().mockReturnValue(true);
|
||||
|
||||
Object.defineProperty(globalThis, "navigator", {
|
||||
configurable: true,
|
||||
|
|
@ -464,12 +464,12 @@ test("installed write fallback rejects when getType cannot provide text/plain",
|
|||
configurable: true,
|
||||
value: {
|
||||
body: {
|
||||
appendChild: vi.fn(),
|
||||
appendChild: rs.fn(),
|
||||
},
|
||||
createElement: vi.fn().mockReturnValue({
|
||||
remove: vi.fn(),
|
||||
select: vi.fn(),
|
||||
setAttribute: vi.fn(),
|
||||
createElement: rs.fn().mockReturnValue({
|
||||
remove: rs.fn(),
|
||||
select: rs.fn(),
|
||||
setAttribute: rs.fn(),
|
||||
style: {},
|
||||
value: "",
|
||||
}),
|
||||
|
|
@ -482,7 +482,7 @@ test("installed write fallback rejects when getType cannot provide text/plain",
|
|||
await expect(
|
||||
globalThis.navigator.clipboard.write([
|
||||
{
|
||||
getType: vi.fn().mockRejectedValue(new Error("missing")),
|
||||
getType: rs.fn().mockRejectedValue(new Error("missing")),
|
||||
types: ["text/plain"],
|
||||
} as unknown as ClipboardItem,
|
||||
]),
|
||||
|
|
@ -491,7 +491,7 @@ test("installed write fallback rejects when getType cannot provide text/plain",
|
|||
});
|
||||
|
||||
test("installed write fallback rejects before getType when item types exclude text/plain", async () => {
|
||||
const getType = vi.fn().mockResolvedValue(new Blob(["ignored"]));
|
||||
const getType = rs.fn().mockResolvedValue(new Blob(["ignored"]));
|
||||
Object.defineProperty(globalThis, "navigator", {
|
||||
configurable: true,
|
||||
value: {},
|
||||
|
|
@ -550,7 +550,7 @@ test("installed write fallback rejects when getType returns a non-Blob", async (
|
|||
await expect(
|
||||
globalThis.navigator.clipboard.write([
|
||||
{
|
||||
getType: vi.fn().mockResolvedValue("plain text"),
|
||||
getType: rs.fn().mockResolvedValue("plain text"),
|
||||
types: ["text/plain"],
|
||||
} as unknown as ClipboardItem,
|
||||
]),
|
||||
|
|
@ -558,7 +558,7 @@ test("installed write fallback rejects when getType returns a non-Blob", async (
|
|||
});
|
||||
|
||||
test("installed write fallback preserves existing clipboard prototype methods", async () => {
|
||||
const readText = vi.fn().mockResolvedValue("existing");
|
||||
const readText = rs.fn().mockResolvedValue("existing");
|
||||
const clipboard = Object.create({
|
||||
readText,
|
||||
});
|
||||
|
|
@ -588,8 +588,8 @@ test("installed write fallback preserves existing clipboard prototype methods",
|
|||
});
|
||||
|
||||
test("installClipboardFallback does not replace existing clipboard methods when only ClipboardItem is missing", async () => {
|
||||
const write = vi.fn().mockResolvedValue(undefined);
|
||||
const writeText = vi.fn().mockResolvedValue(undefined);
|
||||
const write = rs.fn().mockResolvedValue(undefined);
|
||||
const writeText = rs.fn().mockResolvedValue(undefined);
|
||||
const clipboard = {
|
||||
write,
|
||||
writeText,
|
||||
|
|
@ -727,7 +727,7 @@ test("installClipboardFallback does not throw when ClipboardItem cannot be defin
|
|||
value: undefined,
|
||||
});
|
||||
Reflect.deleteProperty(globalThis, "ClipboardItem");
|
||||
vi.spyOn(Object, "defineProperty").mockImplementation(
|
||||
rs.spyOn(Object, "defineProperty").mockImplementation(
|
||||
(target, property, descriptor) => {
|
||||
if (target === globalThis && property === "ClipboardItem") {
|
||||
throw new Error("locked global");
|
||||
|
|
@ -746,8 +746,8 @@ test("installs ClipboardItem fallback when the global property exists but is unu
|
|||
configurable: true,
|
||||
value: {
|
||||
clipboard: {
|
||||
write: vi.fn().mockResolvedValue(undefined),
|
||||
writeText: vi.fn().mockResolvedValue(undefined),
|
||||
write: rs.fn().mockResolvedValue(undefined),
|
||||
writeText: rs.fn().mockResolvedValue(undefined),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@
|
|||
* so the React Query hook's `error` branch can render a friendly empty
|
||||
* state (admin-required for 403) instead of crashing.
|
||||
*/
|
||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, test, rs } from "@rstest/core";
|
||||
|
||||
vi.mock("@/core/api/fetcher", () => ({
|
||||
fetch: vi.fn(),
|
||||
rs.mock("@/core/api/fetcher", () => ({
|
||||
fetch: rs.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/core/config", () => ({
|
||||
rs.mock("@/core/config", () => ({
|
||||
getBackendBaseURL: () => "",
|
||||
}));
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ import {
|
|||
updateMCPConfig,
|
||||
} from "@/core/mcp/api";
|
||||
|
||||
const mockedFetch = vi.mocked(fetcher);
|
||||
const mockedFetch = rs.mocked(fetcher);
|
||||
|
||||
function jsonResponse(status: number, body: unknown): Response {
|
||||
return new Response(JSON.stringify(body), {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { beforeEach, describe, expect, it, rs } from "@rstest/core";
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("@/core/api/fetcher", () => ({
|
||||
fetch: vi.fn(),
|
||||
rs.mock("@/core/api/fetcher", () => ({
|
||||
fetch: rs.fn(),
|
||||
}));
|
||||
|
||||
import { fetch } from "@/core/api/fetcher";
|
||||
import { MCPConfigRequestError, loadMCPConfig } from "@/core/mcp/api";
|
||||
|
||||
const mockedFetch = vi.mocked(fetch);
|
||||
const mockedFetch = rs.mocked(fetch);
|
||||
|
||||
function makeClient() {
|
||||
return new QueryClient({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Message } from "@langchain/langgraph-sdk";
|
||||
import { expect, test } from "vitest";
|
||||
import { expect, test } from "@rstest/core";
|
||||
|
||||
import { enUS } from "@/core/i18n";
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Message } from "@langchain/langgraph-sdk";
|
||||
import { expect, test } from "vitest";
|
||||
import { expect, test } from "@rstest/core";
|
||||
|
||||
import { accumulateUsage, selectHeaderTokenUsage } from "@/core/messages/usage";
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Message } from "@langchain/langgraph-sdk";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { describe, expect, test } from "@rstest/core";
|
||||
|
||||
import {
|
||||
extractContentFromMessage,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { expect, test, rs } from "@rstest/core";
|
||||
import { createElement } from "react";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { expect, test, vi } from "vitest";
|
||||
|
||||
vi.mock("streamdown", () => ({
|
||||
rs.mock("streamdown", () => ({
|
||||
Streamdown: ({ children }: { children: string }) =>
|
||||
createElement("div", null, children),
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { expect, test } from "vitest";
|
||||
import { expect, test } from "@rstest/core";
|
||||
|
||||
import { DEFAULT_LOCAL_SETTINGS } from "@/core/settings/local";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { expect, test } from "vitest";
|
||||
import { expect, test } from "@rstest/core";
|
||||
|
||||
import { normalizeMermaidMarkdown } from "@/core/streamdown/mermaid";
|
||||
import { preprocessStreamdownMarkdown } from "@/core/streamdown/preprocess";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, test } from "@rstest/core";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
import { reasoningPlugins, streamdownPlugins } from "@/core/streamdown/plugins";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { expect, test } from "vitest";
|
||||
import { expect, test } from "@rstest/core";
|
||||
|
||||
import {
|
||||
capBlockquoteNesting,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { readFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
import type { Message } from "@langchain/langgraph-sdk";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, it } from "@rstest/core";
|
||||
|
||||
import {
|
||||
SUBAGENT_ERROR_KEY,
|
||||
|
|
@ -24,13 +24,9 @@ interface ContractFile {
|
|||
cases: ContractCase[];
|
||||
}
|
||||
|
||||
// The frontend package is ESM (`"type": "module"`), so `__dirname` is not
|
||||
// defined. Resolve the cross-language fixture relative to this module URL.
|
||||
const CONTRACT_PATH = fileURLToPath(
|
||||
new URL(
|
||||
"../../../../../contracts/subagent_status_contract.json",
|
||||
import.meta.url,
|
||||
),
|
||||
const CONTRACT_PATH = resolve(
|
||||
__dirname,
|
||||
"../../../../../contracts/subagent_status_contract.json",
|
||||
);
|
||||
const CONTRACT: ContractFile = JSON.parse(
|
||||
readFileSync(CONTRACT_PATH, "utf-8"),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { beforeEach, expect, test, vi } from "vitest";
|
||||
import { beforeEach, expect, test, rs } from "@rstest/core";
|
||||
|
||||
const fetchWithAuth = vi.fn();
|
||||
const fetchWithAuth = rs.fn();
|
||||
|
||||
vi.mock("@/core/api/fetcher", () => ({
|
||||
rs.mock("@/core/api/fetcher", () => ({
|
||||
fetch: fetchWithAuth,
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Message } from "@langchain/langgraph-sdk";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, it } from "@rstest/core";
|
||||
|
||||
import {
|
||||
formatThreadAsJSON,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, test } from "@rstest/core";
|
||||
import { QueryClient, type InfiniteData } from "@tanstack/react-query";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import {
|
||||
filterInfiniteThreadsCache,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Message, Run } from "@langchain/langgraph-sdk";
|
||||
import { expect, test } from "vitest";
|
||||
import { expect, test } from "@rstest/core";
|
||||
|
||||
import {
|
||||
buildRunMessagesUrl,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { expect, test, vi } from "vitest";
|
||||
import { expect, test, rs } from "@rstest/core";
|
||||
|
||||
import {
|
||||
buildThreadsSearchQueryOptions,
|
||||
|
|
@ -7,7 +7,7 @@ import {
|
|||
} from "@/core/threads/thread-search-query";
|
||||
|
||||
test("thread search query refreshes so IM-created sessions appear in the sidebar", () => {
|
||||
const search = vi.fn();
|
||||
const search = rs.fn();
|
||||
const options = buildThreadsSearchQueryOptions(
|
||||
{ threads: { search } },
|
||||
DEFAULT_THREAD_SEARCH_PARAMS,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { expect, test } from "vitest";
|
||||
import { expect, test } from "@rstest/core";
|
||||
|
||||
import { threadTokenUsageToTokenUsage } from "@/core/threads/token-usage";
|
||||
import type { ThreadTokenUsageResponse } from "@/core/threads/types";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Message } from "@langchain/langgraph-sdk";
|
||||
import { expect, test } from "vitest";
|
||||
import { expect, test } from "@rstest/core";
|
||||
|
||||
import {
|
||||
channelSourceOfThread,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { expect, test } from "vitest";
|
||||
import { expect, test } from "@rstest/core";
|
||||
|
||||
import {
|
||||
MACOS_APP_BUNDLE_UPLOAD_MESSAGE,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { afterEach, expect, test, vi } from "vitest";
|
||||
import { afterEach, expect, test, rs } from "@rstest/core";
|
||||
|
||||
import {
|
||||
type PromptInputFilePart,
|
||||
|
|
@ -6,8 +6,8 @@ import {
|
|||
} from "@/core/uploads/prompt-input-files";
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllGlobals();
|
||||
rs.restoreAllMocks();
|
||||
rs.unstubAllGlobals();
|
||||
});
|
||||
|
||||
test("exports the prompt-input file conversion helper", () => {
|
||||
|
|
@ -17,9 +17,9 @@ test("exports the prompt-input file conversion helper", () => {
|
|||
test("reuses the original File when a prompt attachment already has one", async () => {
|
||||
const file = new File(["hello"], "note.txt", { type: "text/plain" });
|
||||
|
||||
vi.stubGlobal(
|
||||
rs.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn(() => {
|
||||
rs.fn(() => {
|
||||
throw new Error("fetch should not run when File is already present");
|
||||
}),
|
||||
);
|
||||
|
|
@ -76,11 +76,11 @@ test("returns null when upload preparation is missing required data", async () =
|
|||
});
|
||||
|
||||
test("returns null when the URL fallback fetch fails", async () => {
|
||||
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => ({}));
|
||||
const warnSpy = rs.spyOn(console, "warn").mockImplementation(() => ({}));
|
||||
|
||||
vi.stubGlobal(
|
||||
rs.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn(async () => {
|
||||
rs.fn(async () => {
|
||||
throw new Error("network down");
|
||||
}),
|
||||
);
|
||||
|
|
@ -96,11 +96,11 @@ test("returns null when the URL fallback fetch fails", async () => {
|
|||
});
|
||||
|
||||
test("returns null when the URL fallback fetch response is non-ok", async () => {
|
||||
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => ({}));
|
||||
const warnSpy = rs.spyOn(console, "warn").mockImplementation(() => ({}));
|
||||
|
||||
vi.stubGlobal(
|
||||
rs.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn(
|
||||
rs.fn(
|
||||
async () =>
|
||||
new Response("missing", {
|
||||
status: 404,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { afterEach, describe, expect, test, vi } from "vitest";
|
||||
import { afterEach, describe, expect, test, rs } from "@rstest/core";
|
||||
|
||||
type KeydownHandler = (event: KeyboardEvent) => void;
|
||||
|
||||
|
|
@ -6,23 +6,23 @@ async function loadHookWithCapturedHandler() {
|
|||
let cleanup: (() => void) | undefined;
|
||||
let keydownHandler: KeydownHandler | undefined;
|
||||
|
||||
const addEventListener = vi.fn(
|
||||
const addEventListener = rs.fn(
|
||||
(type: string, listener: EventListenerOrEventListenerObject) => {
|
||||
if (type === "keydown" && typeof listener === "function") {
|
||||
keydownHandler = listener as KeydownHandler;
|
||||
}
|
||||
},
|
||||
);
|
||||
const removeEventListener = vi.fn();
|
||||
const removeEventListener = rs.fn();
|
||||
|
||||
vi.resetModules();
|
||||
vi.doMock("react", () => ({
|
||||
rs.resetModules();
|
||||
rs.doMock("react", () => ({
|
||||
useEffect: (effect: () => void | (() => void)) => {
|
||||
const result = effect();
|
||||
cleanup = typeof result === "function" ? result : undefined;
|
||||
},
|
||||
}));
|
||||
vi.stubGlobal("window", { addEventListener, removeEventListener });
|
||||
rs.stubGlobal("window", { addEventListener, removeEventListener });
|
||||
|
||||
const { useGlobalShortcuts } = await import("@/hooks/use-global-shortcuts");
|
||||
|
||||
|
|
@ -34,14 +34,14 @@ async function loadHookWithCapturedHandler() {
|
|||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.doUnmock("react");
|
||||
vi.unstubAllGlobals();
|
||||
vi.resetModules();
|
||||
rs.doUnmock("react");
|
||||
rs.unstubAllGlobals();
|
||||
rs.resetModules();
|
||||
});
|
||||
|
||||
describe("useGlobalShortcuts", () => {
|
||||
test("ignores keydown events without a key", async () => {
|
||||
const action = vi.fn();
|
||||
const action = rs.fn();
|
||||
const { getKeydownHandler, useGlobalShortcuts } =
|
||||
await loadHookWithCapturedHandler();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
import { resolve } from "path";
|
||||
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": resolve(__dirname, "src"),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
include: ["tests/unit/**/*.test.ts"],
|
||||
},
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue