diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ecff5eed4..61ee6ef73 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -161,7 +161,7 @@ jobs: - name: Run integration tests run: > bun x vitest run - --config tests/configs/integration.config.ts + --config tests/configs/integration.config.mts --passWithNoTests # ==================== API 测试(需要运行服务)==================== diff --git a/biome.json b/biome.json index 64236f172..236dff937 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.4.16/schema.json", + "$schema": "https://biomejs.dev/schemas/2.5.6/schema.json", "vcs": { "enabled": true, "clientKind": "git", @@ -9,9 +9,9 @@ "linter": { "enabled": true, "rules": { - "recommended": true, + "preset": "recommended", "a11y": { - "recommended": false + "preset": "none" }, "correctness": { "noUnusedImports": "error", diff --git a/package.json b/package.json index 8b5b3aa3a..3b8dadac8 100644 --- a/package.json +++ b/package.json @@ -16,136 +16,137 @@ "format": "biome format --write .", "format:check": "biome format .", "clean:cache": "rm -rf .next tsconfig.tsbuildinfo node_modules/.cache", - "test": "vitest run", - "test:ui": "vitest --ui --watch", - "test:e2e": "vitest run --config tests/configs/e2e.config.ts --reporter=verbose", - "test:integration": "vitest run --config tests/configs/integration.config.ts --reporter=verbose", - "test:integration:provider-batch-ledger": "vitest run --config tests/configs/provider-batch-ledger-postgres.config.ts", - "test:coverage": "vitest run --coverage", - "test:coverage:logs-sessionid-time-filter": "vitest run --config tests/configs/logs-sessionid-time-filter.config.ts --coverage", - "test:coverage:codex-session-id-completer": "vitest run --config tests/configs/codex-session-id-completer.config.ts --coverage", - "test:coverage:thinking-signature-rectifier": "vitest run --config tests/configs/thinking-signature-rectifier.config.ts --coverage", - "test:coverage:thinking-effort-conflict-rectifier": "vitest run --config tests/configs/thinking-effort-conflict-rectifier.config.ts --coverage", - "test:coverage:quota": "vitest run --config tests/configs/quota.config.ts --coverage", - "test:coverage:my-usage": "vitest run --config tests/configs/my-usage.config.ts --coverage", - "test:coverage:proxy-guard-pipeline": "vitest run --config tests/configs/proxy-guard-pipeline.config.ts --coverage", - "test:coverage:include-session-id-in-errors": "vitest run --config tests/configs/include-session-id-in-errors.config.ts --coverage", - "test:coverage:usage-logs-sessionid-search": "vitest run --config tests/configs/usage-logs-sessionid-search.config.ts --coverage", - "test:coverage:session-binding": "vitest run --config tests/configs/session-binding.config.ts --coverage", - "test:ci": "vitest run --reporter=default --reporter=junit --outputFile.junit=reports/vitest-junit.xml", - "test:v1": "vitest run --config tests/configs/v1.config.ts --coverage --reporter=verbose && bun scripts/check-v1-critical-coverage.ts", + "test": "vitest run --configLoader bundle", + "test:ui": "vitest --ui --watch --configLoader bundle", + "test:e2e": "vitest run --config tests/configs/e2e.config.mts --reporter=verbose --configLoader bundle", + "test:integration": "vitest run --config tests/configs/integration.config.mts --reporter=verbose --configLoader bundle", + "test:integration:provider-batch-ledger": "vitest run --config tests/configs/provider-batch-ledger-postgres.config.mts --configLoader bundle", + "test:coverage": "vitest run --coverage --configLoader bundle", + "test:coverage:logs-sessionid-time-filter": "vitest run --config tests/configs/logs-sessionid-time-filter.config.mts --coverage --configLoader bundle", + "test:coverage:codex-session-id-completer": "vitest run --config tests/configs/codex-session-id-completer.config.mts --coverage --configLoader bundle", + "test:coverage:thinking-signature-rectifier": "vitest run --config tests/configs/thinking-signature-rectifier.config.mts --coverage --configLoader bundle", + "test:coverage:thinking-effort-conflict-rectifier": "vitest run --config tests/configs/thinking-effort-conflict-rectifier.config.mts --coverage --configLoader bundle", + "test:coverage:quota": "vitest run --config tests/configs/quota.config.mts --coverage --configLoader bundle", + "test:coverage:my-usage": "vitest run --config tests/configs/my-usage.config.mts --coverage --configLoader bundle", + "test:coverage:proxy-guard-pipeline": "vitest run --config tests/configs/proxy-guard-pipeline.config.mts --coverage --configLoader bundle", + "test:coverage:include-session-id-in-errors": "vitest run --config tests/configs/include-session-id-in-errors.config.mts --coverage --configLoader bundle", + "test:coverage:usage-logs-sessionid-search": "vitest run --config tests/configs/usage-logs-sessionid-search.config.mts --coverage --configLoader bundle", + "test:coverage:session-binding": "vitest run --config tests/configs/session-binding.config.mts --coverage --configLoader bundle", + "test:ci": "vitest run --configLoader bundle --reporter=default --reporter=junit --outputFile.junit=reports/vitest-junit.xml", + "test:v1": "vitest run --config tests/configs/v1.config.mts --coverage --reporter=verbose --configLoader bundle && bun scripts/check-v1-critical-coverage.ts", "openapi:generate": "bun scripts/generate-v1-types.ts", "openapi:check": "bun scripts/generate-v1-types.ts --check", "openapi:lint": "bun scripts/lint-openapi.ts", "cui": "npx cui-server --host 0.0.0.0 --port 30000 --token a7564bc8882aa9a2d25d8b4ea6ea1e2e", - "db:generate": "drizzle-kit generate && node scripts/validate-migrations.js", + "db:generate": "drizzle-kit generate && node scripts/validate-migrations.mjs", "db:migrate": "bun --conditions=react-server scripts/migrate.ts", "db:push": "drizzle-kit push", "db:studio": "drizzle-kit studio", - "validate:migrations": "node scripts/validate-migrations.js", + "validate:migrations": "node scripts/validate-migrations.mjs", "i18n:audit-placeholders": "node scripts/audit-settings-placeholders.js --scope=settings,dashboard,myUsage --format=tsv", "i18n:audit-placeholders:fail": "node scripts/audit-settings-placeholders.js --scope=settings,dashboard,myUsage --format=tsv --fail", "i18n:audit-messages-no-emoji": "node scripts/audit-messages-no-emoji.js --format=tsv", "i18n:audit-messages-no-emoji:fail": "node scripts/audit-messages-no-emoji.js --format=tsv --fail" }, "dependencies": { - "@bull-board/api": "^7", - "@bull-board/express": "^7", + "@bull-board/api": "^8.5.0", + "@bull-board/express": "^8.5.0", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@hono/swagger-ui": "^0.6", - "@hono/zod-openapi": "^1", - "@hookform/resolvers": "^5", - "@iarna/toml": "^2", - "@langfuse/client": "^5", - "@langfuse/otel": "^5", - "@langfuse/tracing": "^5", - "@lobehub/icons": "^2", - "@opentelemetry/sdk-node": "^0.217", - "@radix-ui/react-alert-dialog": "^1", - "@radix-ui/react-avatar": "^1", - "@radix-ui/react-checkbox": "^1", - "@radix-ui/react-collapsible": "^1", - "@radix-ui/react-dialog": "^1", - "@radix-ui/react-dropdown-menu": "^2", - "@radix-ui/react-label": "^2", - "@radix-ui/react-popover": "^1", - "@radix-ui/react-progress": "^1", - "@radix-ui/react-scroll-area": "^1", - "@radix-ui/react-select": "^2", - "@radix-ui/react-slider": "^1", - "@radix-ui/react-slot": "^1", - "@radix-ui/react-switch": "^1", - "@radix-ui/react-tabs": "^1", - "@radix-ui/react-tooltip": "^1", - "@scalar/hono-api-reference": "^0.10", - "@tanstack/react-query": "^5", - "@tanstack/react-virtual": "^3", - "@tanstack/virtual-core": "^3", - "agentation": "^3", - "antd": "~6.3", - "bull": "^4", - "class-variance-authority": "^0.7", - "clsx": "^2", - "cmdk": "^1", - "date-fns": "4.1.0", - "date-fns-tz": "^3", - "decimal.js-light": "^2", - "dotenv": "^17", - "drizzle-orm": "^0.45", - "fetch-socks": "^1", - "fflate": "^0.8.2", - "framer-motion": "^12", - "hono": "^4", - "html2canvas": "^1", - "ioredis": "^5", - "jspdf": "^4", - "lucide-react": "^1.8.0", - "maplibre-gl": "^5.23.0", - "next": "^16", - "next-intl": "^4", - "next-themes": "^0.4", - "pino": "^10", - "pino-pretty": "^13", - "postgres": "^3", - "react": "^19", - "react-day-picker": "^10", - "react-dom": "^19", - "react-hook-form": "^7", - "react-syntax-highlighter": "^16", - "recharts": "^3", - "safe-regex": "^2", + "@hono/swagger-ui": "^0.6.1", + "@hono/zod-openapi": "^1.5.1", + "@hookform/resolvers": "^5.6.0", + "@iarna/toml": "^2.2.5", + "@langfuse/client": "^5.10.0", + "@langfuse/otel": "^5.10.0", + "@langfuse/tracing": "^5.10.0", + "@lobehub/icons": "^5.15.0", + "@opentelemetry/sdk-node": "^0.221.0", + "@radix-ui/react-alert-dialog": "^1.1.23", + "@radix-ui/react-avatar": "^1.2.6", + "@radix-ui/react-checkbox": "^1.3.11", + "@radix-ui/react-collapsible": "^1.1.20", + "@radix-ui/react-dialog": "^1.1.23", + "@radix-ui/react-dropdown-menu": "^2.1.24", + "@radix-ui/react-label": "^2.1.15", + "@radix-ui/react-popover": "^1.1.23", + "@radix-ui/react-progress": "^1.1.16", + "@radix-ui/react-scroll-area": "^1.2.18", + "@radix-ui/react-select": "^2.3.7", + "@radix-ui/react-slider": "^1.4.7", + "@radix-ui/react-slot": "^1.3.3", + "@radix-ui/react-switch": "^1.3.7", + "@radix-ui/react-tabs": "^1.1.21", + "@radix-ui/react-tooltip": "^1.2.16", + "@scalar/hono-api-reference": "^0.11.12", + "@tanstack/react-query": "^5.101.4", + "@tanstack/react-virtual": "^3.14.9", + "@tanstack/virtual-core": "^3.17.7", + "agentation": "^3.0.2", + "antd": "~6.5.3", + "bull": "^4.16.5", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "date-fns": "4.4.0", + "date-fns-tz": "^3.2.0", + "decimal.js-light": "^2.5.1", + "dotenv": "^17.4.2", + "drizzle-orm": "^0.45.2", + "fetch-socks": "^1.3.3", + "fflate": "^0.8.3", + "framer-motion": "^12.43.0", + "hono": "^4.12.33", + "html2canvas": "^1.4.1", + "ioredis": "^6.0.0", + "jspdf": "^4.2.1", + "lucide-react": "^1.28.0", + "maplibre-gl": "^6.1.0", + "next": "^16.2.12", + "next-intl": "^4.13.4", + "next-themes": "^0.4.6", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", + "postgres": "^3.4.9", + "react": "^19.2.8", + "react-day-picker": "^10.0.1", + "react-dom": "^19.2.8", + "react-hook-form": "^7.84.0", + "react-syntax-highlighter": "^16.1.1", + "recharts": "^3.10.1", + "safe-regex": "^2.1.1", "server-only": "^0.0.1", - "sonner": "^2", - "tailwind-merge": "^3", - "timeago.js": "^4", - "tw-animate-css": "^1", - "undici": "^7", - "vaul": "^1", - "ws": "^8", - "zod": "^4" + "sonner": "^2.0.7", + "tailwind-merge": "^3.6.0", + "timeago.js": "^4.0.2", + "tw-animate-css": "^1.4.0", + "undici": "^8.9.0", + "vaul": "^1.1.2", + "ws": "^8.21.1", + "zod": "^4.4.3" }, "devDependencies": { - "@biomejs/biome": "^2", - "@tailwindcss/postcss": "^4.2.0", + "@biomejs/biome": "^2.5.6", + "@tailwindcss/postcss": "^4.3.3", "@types/geojson": "^7946.0.16", - "@types/ioredis": "^5", - "@types/node": "^25", - "@types/pg": "^8", - "@types/react": "^19", - "@types/react-dom": "^19", - "@types/react-syntax-highlighter": "^15", - "@types/ws": "^8", - "@typescript/native-preview": "7.0.0-dev.20260512.1", - "@vitest/coverage-v8": "^4", - "@vitest/ui": "^4", - "bun-types": "^1", - "drizzle-kit": "^0.31", - "happy-dom": "^20", + "@types/ioredis": "^5.0.0", + "@types/node": "^26.1.2", + "@types/pg": "^8.20.3", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.4", + "@types/react-syntax-highlighter": "^15.5.13", + "@types/ws": "^8.18.1", + "@typescript/native-preview": "7.0.0-dev.20260707.2", + "@vitest/coverage-v8": "^4.1.10", + "@vitest/ui": "^4.1.10", + "bun-types": "^1.3.14", + "drizzle-kit": "^0.31.10", + "happy-dom": "^20.11.1", "openapi-typescript": "^7.13.0", - "tailwindcss": "^4", - "typescript": "^6", - "vitest": "^4" + "tailwindcss": "^4.3.3", + "typescript": "6.0.2", + "typescript-7": "npm:typescript@7.0.2", + "vitest": "^4.1.10" } } diff --git a/scripts/validate-migrations.js b/scripts/validate-migrations.mjs similarity index 100% rename from scripts/validate-migrations.js rename to scripts/validate-migrations.mjs diff --git a/src/app/v1/_lib/proxy/affinity/affinity-store.ts b/src/app/v1/_lib/proxy/affinity/affinity-store.ts index ffea5ae77..be97613b8 100644 --- a/src/app/v1/_lib/proxy/affinity/affinity-store.ts +++ b/src/app/v1/_lib/proxy/affinity/affinity-store.ts @@ -406,7 +406,7 @@ export class AffinityStore { await redis.zremrangebyscore(descendantsV2Key, "-inf", now); const [legacyDescendants, descendants] = await Promise.all([ redis.smembers(descendantsKey), - redis.zrange(descendantsV2Key, 0, -1), + redis.zrange(descendantsV2Key, "0", "-1"), ]); const keys = [...new Set([...knownKeys, ...legacyDescendants, ...descendants])]; await redis.eval( diff --git a/src/components/ui/__tests__/map.test.tsx b/src/components/ui/__tests__/map.test.tsx index e5ab2561e..8c3f5a6f9 100644 --- a/src/components/ui/__tests__/map.test.tsx +++ b/src/components/ui/__tests__/map.test.tsx @@ -368,6 +368,9 @@ const maplibreMocks = vi.hoisted(() => { vi.mock("maplibre-gl/dist/maplibre-gl.css", () => ({})); vi.mock("maplibre-gl", () => ({ + Map: maplibreMocks.FakeMap, + Marker: maplibreMocks.FakeMarker, + Popup: maplibreMocks.FakePopup, default: { Map: maplibreMocks.FakeMap, Marker: maplibreMocks.FakeMarker, diff --git a/src/components/ui/map.tsx b/src/components/ui/map.tsx index fa4f25b54..40e68030c 100644 --- a/src/components/ui/map.tsx +++ b/src/components/ui/map.tsx @@ -2,7 +2,8 @@ import type * as GeoJSON from "geojson"; import { Loader2, Locate, Maximize, Minus, Plus, X } from "lucide-react"; -import MapLibreGL, { type MarkerOptions, type PopupOptions } from "maplibre-gl"; +import type { MarkerOptions, PopupOptions } from "maplibre-gl"; +import * as MapLibreGL from "maplibre-gl"; import { createContext, forwardRef, diff --git a/src/lib/model-vendor-icons.tsx b/src/lib/model-vendor-icons.tsx index 15c04d294..ddfbe4c2d 100644 --- a/src/lib/model-vendor-icons.tsx +++ b/src/lib/model-vendor-icons.tsx @@ -112,7 +112,7 @@ const VENDOR_ICON_COMPONENTS: Record = { zhipuai: Zhipu.Color, minimax: Minimax.Color, perplexity: Perplexity.Color, - stepfun: Stepfun.Color, + stepfun: Stepfun, baidu: Baidu.Color, tencent: Tencent.Color, bytedance: ByteDance.Color, diff --git a/src/lib/public-status/vendor-icon.ts b/src/lib/public-status/vendor-icon.ts index 77399c599..a31f03038 100644 --- a/src/lib/public-status/vendor-icon.ts +++ b/src/lib/public-status/vendor-icon.ts @@ -69,7 +69,7 @@ const PUBLIC_STATUS_VENDOR_ICON_REGISTRY: Record< qwen: Qwen.Color, sensenova: SenseNova.Color, spark: Spark.Color, - stepfun: Stepfun.Color, + stepfun: Stepfun, together: Together.Color, volcengine: Doubao.Color, wenxin: Wenxin.Color, diff --git a/src/lib/session-manager.ts b/src/lib/session-manager.ts index 1cfc72a23..03b2ae725 100644 --- a/src/lib/session-manager.ts +++ b/src/lib/session-manager.ts @@ -3175,7 +3175,7 @@ export class SessionManager { try { const pipeline = redis.pipeline(); for (const providerId of uniqueProviderIds) { - pipeline.zrange(`provider:${providerId}:active_sessions`, 0, -1); + pipeline.zrange(`provider:${providerId}:active_sessions`, "0", "-1"); } const results = await pipeline.exec(); diff --git a/src/lib/session-tracker.ts b/src/lib/session-tracker.ts index bdef1b38d..5a247b9ed 100644 --- a/src/lib/session-tracker.ts +++ b/src/lib/session-tracker.ts @@ -536,7 +536,7 @@ export class SessionTracker { cleanupPipeline.zrangebyscore(key, "-inf", cutoffMs); cleanupPipeline.zremrangebyscore(key, "-inf", cutoffMs); // 获取剩余 session IDs - cleanupPipeline.zrange(key, 0, -1); + cleanupPipeline.zrange(key, "0", "-1"); } const cleanupResults = await cleanupPipeline.exec(); @@ -665,7 +665,7 @@ export class SessionTracker { await redis.zremrangebyscore(key, "-inf", cutoffMs); // 获取剩余的 session ID - return await redis.zrange(key, 0, -1); + return await redis.zrange(key, "0", "-1"); } return []; @@ -688,7 +688,7 @@ export class SessionTracker { } const cutoffMs = Date.now() - SessionTracker.SESSION_TTL_MS; await redis.zremrangebyscore(key, "-inf", cutoffMs); - const sessionIdentities = await redis.zrange(key, 0, -1); + const sessionIdentities = await redis.zrange(key, "0", "-1"); if (sessionIdentities.length === 0) return []; const pipeline = redis.pipeline(); @@ -739,7 +739,7 @@ export class SessionTracker { } // 2. 获取剩余的 session ID - const sessionIds = await redis.zrange(key, 0, -1); + const sessionIds = await redis.zrange(key, "0", "-1"); if (sessionIds.length === 0) return 0; // 3. 批量验证 info 是否存在 diff --git a/tests/README.md b/tests/README.md index 8f927585f..f0d4dbbd9 100644 --- a/tests/README.md +++ b/tests/README.md @@ -174,7 +174,7 @@ echo 'DSN=postgres://postgres:postgres@localhost:5432/claude_code_hub' > .env.te 3. **启用所有测试**: -编辑 `vitest.config.ts`,注释掉 exclude 中的这几行: +编辑 `vitest.config.mts`,注释掉 exclude 中的这几行: ```typescript // "tests/integration/**", // "tests/api/users-actions.test.ts", @@ -272,7 +272,7 @@ bun run test:ui # 启动数据库 docker compose up -d postgres redis -# 启用所有测试(修改 vitest.config.ts) +# 启用所有测试(修改 vitest.config.mts) # 然后运行 bun run test ``` diff --git a/tests/configs/codex-session-id-completer.config.ts b/tests/configs/codex-session-id-completer.config.mts similarity index 83% rename from tests/configs/codex-session-id-completer.config.ts rename to tests/configs/codex-session-id-completer.config.mts index c57847ae5..14a53222a 100644 --- a/tests/configs/codex-session-id-completer.config.ts +++ b/tests/configs/codex-session-id-completer.config.mts @@ -1,4 +1,4 @@ -import { createCoverageConfig } from "../vitest.base"; +import { createCoverageConfig } from "../vitest.base.mts"; export default createCoverageConfig({ name: "codex-session-id-completer", diff --git a/tests/configs/e2e.config.ts b/tests/configs/e2e.config.mts similarity index 86% rename from tests/configs/e2e.config.ts rename to tests/configs/e2e.config.mts index 9f23e4dc2..79b693972 100644 --- a/tests/configs/e2e.config.ts +++ b/tests/configs/e2e.config.mts @@ -1,4 +1,4 @@ -import { createTestRunnerConfig } from "../vitest.base"; +import { createTestRunnerConfig } from "../vitest.base.mts"; export default createTestRunnerConfig({ environment: "node", diff --git a/tests/configs/include-session-id-in-errors.config.ts b/tests/configs/include-session-id-in-errors.config.mts similarity index 89% rename from tests/configs/include-session-id-in-errors.config.ts rename to tests/configs/include-session-id-in-errors.config.mts index 651cbeb63..20337a94e 100644 --- a/tests/configs/include-session-id-in-errors.config.ts +++ b/tests/configs/include-session-id-in-errors.config.mts @@ -1,4 +1,4 @@ -import { createCoverageConfig } from "../vitest.base"; +import { createCoverageConfig } from "../vitest.base.mts"; export default createCoverageConfig({ name: "include-session-id-in-errors", diff --git a/tests/configs/integration.config.ts b/tests/configs/integration.config.mts similarity index 93% rename from tests/configs/integration.config.ts rename to tests/configs/integration.config.mts index 58b4c0de3..6351f7ca8 100644 --- a/tests/configs/integration.config.ts +++ b/tests/configs/integration.config.mts @@ -1,4 +1,4 @@ -import { createTestRunnerConfig } from "../vitest.base"; +import { createTestRunnerConfig } from "../vitest.base.mts"; export default createTestRunnerConfig({ environment: "node", diff --git a/tests/configs/logs-sessionid-time-filter.config.ts b/tests/configs/logs-sessionid-time-filter.config.mts similarity index 94% rename from tests/configs/logs-sessionid-time-filter.config.ts rename to tests/configs/logs-sessionid-time-filter.config.mts index 789a7385f..69ba0484a 100644 --- a/tests/configs/logs-sessionid-time-filter.config.ts +++ b/tests/configs/logs-sessionid-time-filter.config.mts @@ -1,4 +1,4 @@ -import { createCoverageConfig } from "../vitest.base"; +import { createCoverageConfig } from "../vitest.base.mts"; export default createCoverageConfig({ name: "logs-sessionid-time-filter", diff --git a/tests/configs/my-usage.config.ts b/tests/configs/my-usage.config.mts similarity index 95% rename from tests/configs/my-usage.config.ts rename to tests/configs/my-usage.config.mts index cee864008..c32b6bb5b 100644 --- a/tests/configs/my-usage.config.ts +++ b/tests/configs/my-usage.config.mts @@ -1,4 +1,4 @@ -import { createCoverageConfig } from "../vitest.base"; +import { createCoverageConfig } from "../vitest.base.mts"; export default createCoverageConfig({ name: "my-usage", diff --git a/tests/configs/provider-batch-ledger-postgres.config.ts b/tests/configs/provider-batch-ledger-postgres.config.mts similarity index 93% rename from tests/configs/provider-batch-ledger-postgres.config.ts rename to tests/configs/provider-batch-ledger-postgres.config.mts index 80a54533d..4eea85b67 100644 --- a/tests/configs/provider-batch-ledger-postgres.config.ts +++ b/tests/configs/provider-batch-ledger-postgres.config.mts @@ -1,7 +1,7 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import { defineConfig } from "vitest/config"; -import { sharedResolve } from "../vitest.base"; +import { sharedResolve } from "../vitest.base.mts"; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); diff --git a/tests/configs/proxy-guard-pipeline.config.ts b/tests/configs/proxy-guard-pipeline.config.mts similarity index 86% rename from tests/configs/proxy-guard-pipeline.config.ts rename to tests/configs/proxy-guard-pipeline.config.mts index eb372eb8e..e1bc109cd 100644 --- a/tests/configs/proxy-guard-pipeline.config.ts +++ b/tests/configs/proxy-guard-pipeline.config.mts @@ -1,4 +1,4 @@ -import { createCoverageConfig } from "../vitest.base"; +import { createCoverageConfig } from "../vitest.base.mts"; export default createCoverageConfig({ name: "proxy-guard-pipeline", diff --git a/tests/configs/public-status.integration.config.ts b/tests/configs/public-status.integration.config.mts similarity index 89% rename from tests/configs/public-status.integration.config.ts rename to tests/configs/public-status.integration.config.mts index a5661bb98..e5489313c 100644 --- a/tests/configs/public-status.integration.config.ts +++ b/tests/configs/public-status.integration.config.mts @@ -1,4 +1,4 @@ -import { createTestRunnerConfig } from "../vitest.base"; +import { createTestRunnerConfig } from "../vitest.base.mts"; export default createTestRunnerConfig({ environment: "node", diff --git a/tests/configs/quota.config.ts b/tests/configs/quota.config.mts similarity index 87% rename from tests/configs/quota.config.ts rename to tests/configs/quota.config.mts index 56ec52ff0..34b6f9bab 100644 --- a/tests/configs/quota.config.ts +++ b/tests/configs/quota.config.mts @@ -1,4 +1,4 @@ -import { createCoverageConfig } from "../vitest.base"; +import { createCoverageConfig } from "../vitest.base.mts"; export default createCoverageConfig({ name: "quota", diff --git a/tests/configs/session-binding.config.ts b/tests/configs/session-binding.config.mts similarity index 82% rename from tests/configs/session-binding.config.ts rename to tests/configs/session-binding.config.mts index 0815cba93..6d2be6000 100644 --- a/tests/configs/session-binding.config.ts +++ b/tests/configs/session-binding.config.mts @@ -1,4 +1,4 @@ -import { createCoverageConfig } from "../vitest.base"; +import { createCoverageConfig } from "../vitest.base.mts"; export default createCoverageConfig({ name: "session-binding", diff --git a/tests/configs/thinking-effort-conflict-rectifier.config.ts b/tests/configs/thinking-effort-conflict-rectifier.config.mts similarity index 88% rename from tests/configs/thinking-effort-conflict-rectifier.config.ts rename to tests/configs/thinking-effort-conflict-rectifier.config.mts index 5585c41c1..b138b44f1 100644 --- a/tests/configs/thinking-effort-conflict-rectifier.config.ts +++ b/tests/configs/thinking-effort-conflict-rectifier.config.mts @@ -1,4 +1,4 @@ -import { createCoverageConfig } from "../vitest.base"; +import { createCoverageConfig } from "../vitest.base.mts"; export default createCoverageConfig({ name: "thinking-effort-conflict-rectifier", diff --git a/tests/configs/thinking-signature-rectifier.config.ts b/tests/configs/thinking-signature-rectifier.config.mts similarity index 87% rename from tests/configs/thinking-signature-rectifier.config.ts rename to tests/configs/thinking-signature-rectifier.config.mts index 670961f65..d29bd5a4d 100644 --- a/tests/configs/thinking-signature-rectifier.config.ts +++ b/tests/configs/thinking-signature-rectifier.config.mts @@ -1,4 +1,4 @@ -import { createCoverageConfig } from "../vitest.base"; +import { createCoverageConfig } from "../vitest.base.mts"; export default createCoverageConfig({ name: "thinking-signature-rectifier", diff --git a/tests/configs/usage-logs-sessionid-search.config.ts b/tests/configs/usage-logs-sessionid-search.config.mts similarity index 92% rename from tests/configs/usage-logs-sessionid-search.config.ts rename to tests/configs/usage-logs-sessionid-search.config.mts index c57ac0581..f1eb80fe3 100644 --- a/tests/configs/usage-logs-sessionid-search.config.ts +++ b/tests/configs/usage-logs-sessionid-search.config.mts @@ -1,4 +1,4 @@ -import { createCoverageConfig } from "../vitest.base"; +import { createCoverageConfig } from "../vitest.base.mts"; export default createCoverageConfig({ name: "usage-logs-sessionid-search", diff --git a/tests/configs/v1.config.ts b/tests/configs/v1.config.mts similarity index 96% rename from tests/configs/v1.config.ts rename to tests/configs/v1.config.mts index fa661b5d2..55ca09227 100644 --- a/tests/configs/v1.config.ts +++ b/tests/configs/v1.config.mts @@ -1,5 +1,5 @@ import { defineConfig } from "vitest/config"; -import { sharedResolve } from "../vitest.base"; +import { sharedResolve } from "../vitest.base.mts"; export default defineConfig({ test: { diff --git a/tests/e2e/responses-ws-codex-cli-transport.test.ts b/tests/e2e/responses-ws-codex-cli-transport.test.ts index 384b46ee6..9d511c626 100644 --- a/tests/e2e/responses-ws-codex-cli-transport.test.ts +++ b/tests/e2e/responses-ws-codex-cli-transport.test.ts @@ -12,9 +12,9 @@ import WebSocket, { type RawData, WebSocketServer } from "ws"; * * Default Vitest/E2E runs skip this file's body. To run it locally: * PowerShell: - * $env:CCH_CODEX_E2E="1"; $env:CCH_CODEX_E2E_EXPECT_TRANSPORT="websocket"; npx vitest run --config tests/configs/e2e.config.ts tests/e2e/responses-ws-codex-cli-transport.test.ts + * $env:CCH_CODEX_E2E="1"; $env:CCH_CODEX_E2E_EXPECT_TRANSPORT="websocket"; npx vitest run --config tests/configs/e2e.config.mts tests/e2e/responses-ws-codex-cli-transport.test.ts * POSIX: - * CCH_CODEX_E2E=1 CCH_CODEX_E2E_EXPECT_TRANSPORT=websocket npx vitest run --config tests/configs/e2e.config.ts tests/e2e/responses-ws-codex-cli-transport.test.ts + * CCH_CODEX_E2E=1 CCH_CODEX_E2E_EXPECT_TRANSPORT=websocket npx vitest run --config tests/configs/e2e.config.mts tests/e2e/responses-ws-codex-cli-transport.test.ts * * `CCH_CODEX_E2E_EXPECT_TRANSPORT=any|http|websocket` controls how strict the * assertion is. Use `websocket` when validating a Codex build that should speak @@ -23,7 +23,7 @@ import WebSocket, { type RawData, WebSocketServer } from "ws"; * * Fault-injection probes are also opt-in: * PowerShell: - * $env:CCH_CODEX_E2E="1"; $env:CCH_CODEX_E2E_FAULTS="1"; npx vitest run --config tests/configs/e2e.config.ts tests/e2e/responses-ws-codex-cli-transport.test.ts + * $env:CCH_CODEX_E2E="1"; $env:CCH_CODEX_E2E_FAULTS="1"; npx vitest run --config tests/configs/e2e.config.mts tests/e2e/responses-ws-codex-cli-transport.test.ts */ type ProbeEvent = diff --git a/tests/fluent-emoji.mock.tsx b/tests/fluent-emoji.mock.tsx new file mode 100644 index 000000000..56701b4d6 --- /dev/null +++ b/tests/fluent-emoji.mock.tsx @@ -0,0 +1,22 @@ +import { createElement, forwardRef } from "react"; + +export const FluentEmoji = forwardRef( + ({ emoji = "", className }, ref) => + createElement("span", { ref, className, "aria-hidden": true }, emoji) +); + +FluentEmoji.displayName = "FluentEmoji"; + +export function getEmoji(character: string): string { + return character; +} + +export function getEmojiNameByCharacter(character: string): string { + return character; +} + +export function getFluentEmojiCDN(): string { + return ""; +} + +export default FluentEmoji; diff --git a/tests/tsconfig.provider-batch-ledger.json b/tests/tsconfig.provider-batch-ledger.json index e94f34a91..9369b4aef 100644 --- a/tests/tsconfig.provider-batch-ledger.json +++ b/tests/tsconfig.provider-batch-ledger.json @@ -9,7 +9,7 @@ "../src/**/*.d.ts", "../src/**/*.ts", "integration/provider-batch-ledger-postgres.test.ts", - "configs/provider-batch-ledger-postgres.config.ts" + "configs/provider-batch-ledger-postgres.config.mts" ], "exclude": ["../node_modules", "../.next", "../dist", "../build"] } diff --git a/tests/unit/lib/session-manager-terminate-provider-sessions.test.ts b/tests/unit/lib/session-manager-terminate-provider-sessions.test.ts index 30d346484..05b3c823c 100644 --- a/tests/unit/lib/session-manager-terminate-provider-sessions.test.ts +++ b/tests/unit/lib/session-manager-terminate-provider-sessions.test.ts @@ -48,8 +48,8 @@ describe("SessionManager.terminateProviderSessionsBatch", () => { expect(result).toBe(3); expect(pipelineRef.zrange).toHaveBeenCalledTimes(2); - expect(pipelineRef.zrange).toHaveBeenCalledWith("provider:42:active_sessions", 0, -1); - expect(pipelineRef.zrange).toHaveBeenCalledWith("provider:43:active_sessions", 0, -1); + expect(pipelineRef.zrange).toHaveBeenCalledWith("provider:42:active_sessions", "0", "-1"); + expect(pipelineRef.zrange).toHaveBeenCalledWith("provider:43:active_sessions", "0", "-1"); expect(terminateSessionsBatchSpy).toHaveBeenCalledWith( ["sess-a", "sess-b", "sess-c"], [42, 43] diff --git a/tests/vitest.base.ts b/tests/vitest.base.mts similarity index 88% rename from tests/vitest.base.ts rename to tests/vitest.base.mts index 5f7db290c..9fd932911 100644 --- a/tests/vitest.base.ts +++ b/tests/vitest.base.mts @@ -13,6 +13,11 @@ export function sharedResolve(opts?: { includeMessages?: boolean }) { const alias: Record = { "@": path.resolve(root, "src"), "server-only": path.resolve(root, "tests/server-only.mock.ts"), + "@lobehub/fluent-emoji/es/FluentEmoji": path.resolve( + root, + "node_modules/@lobehub/fluent-emoji/es/FluentEmoji/index.js" + ), + "@lobehub/fluent-emoji": path.resolve(root, "tests/fluent-emoji.mock.tsx"), }; if (opts?.includeMessages) { alias["@messages"] = path.resolve(root, "messages"); @@ -106,13 +111,25 @@ export function createCoverageConfig(opts: CoverageConfigOptions) { thresholds: opts.thresholds, }, reporters: ["verbose"], + testTimeout: 10000, + hookTimeout: 10000, + teardownTimeout: parsePositiveInt(process.env.VITEST_TEARDOWN_TIMEOUT_MS, 15000), + slowTestThreshold: parsePositiveInt(process.env.VITEST_SLOW_TEST_THRESHOLD_MS, 1000), isolate: true, mockReset: true, restoreMocks: true, clearMocks: true, resolveSnapshotPath, + server: { + deps: { + inline: ["@lobehub/icons", "@lobehub/ui", "@lobehub/fluent-emoji"], + }, + }, }, resolve: sharedResolve(), + ssr: { + noExternal: ["@lobehub/icons", "@lobehub/ui", "@lobehub/fluent-emoji"], + }, }); } diff --git a/vitest.config.ts b/vitest.config.mts similarity index 95% rename from vitest.config.ts rename to vitest.config.mts index 520c48fcd..6830f7f6a 100644 --- a/vitest.config.ts +++ b/vitest.config.mts @@ -1,6 +1,6 @@ import { availableParallelism } from "node:os"; import { defineConfig } from "vitest/config"; -import { parsePositiveInt, parseWorkerLimit, sharedResolve } from "./tests/vitest.base"; +import { parsePositiveInt, parseWorkerLimit, sharedResolve } from "./tests/vitest.base.mts"; const isIntegrationFileFilterRequested = process.argv.some((arg) => /tests[\\/]+integration(?:[\\/].+\.(test|spec)\.[cm]?[jt]sx?|[\\/]?$)/.test(arg) @@ -144,7 +144,15 @@ export default defineConfig({ resolveSnapshotPath: (testPath, snapExtension) => { return testPath.replace(/\.test\.([tj]sx?)$/, `${snapExtension}.$1`); }, + server: { + deps: { + inline: ["@lobehub/icons", "@lobehub/ui", "@lobehub/fluent-emoji"], + }, + }, }, resolve: sharedResolve({ includeMessages: true }), + ssr: { + noExternal: ["@lobehub/icons", "@lobehub/ui", "@lobehub/fluent-emoji"], + }, });