From e25b2537fdcfe207c3b9413563e704890ad67426 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Thu, 4 Jun 2026 18:50:58 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=B6=88=E9=99=A4=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=B8=AD=E7=9A=84=20tool=20=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E7=AB=9E=E4=BA=89=E5=92=8C=20SQLite=20=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E7=A2=B0=E6=92=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/helpers.ts | 3 ++- tests/server/ai/registry.test.ts | 15 ++--------- tests/server/mocks/ai.ts | 36 +++++++++++++++++++++++++ tests/server/routes/chat.test.ts | 38 ++------------------------- tests/server/routes/models.test.ts | 10 ++----- tests/server/routes/providers.test.ts | 9 ++----- 6 files changed, 46 insertions(+), 65 deletions(-) create mode 100644 tests/server/mocks/ai.ts diff --git a/tests/helpers.ts b/tests/helpers.ts index 494a932..ce0b4b9 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -1,4 +1,5 @@ import Database from "bun:sqlite"; +import { randomUUID } from "node:crypto"; import { mkdirSync, rmSync } from "node:fs"; import { rm } from "node:fs/promises"; import { tmpdir } from "node:os"; @@ -105,7 +106,7 @@ export function createTestDatabase(prefix: string, migrations: MigrationRecord[] } export function makeTempDir(prefix: string): string { - const dir = join(tmpdir(), `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`); + const dir = join(tmpdir(), `${prefix}-${randomUUID()}`); mkdirSync(dir, { recursive: true }); return dir; } diff --git a/tests/server/ai/registry.test.ts b/tests/server/ai/registry.test.ts index 406177b..3a179bd 100644 --- a/tests/server/ai/registry.test.ts +++ b/tests/server/ai/registry.test.ts @@ -1,19 +1,8 @@ -import { describe, expect, mock, test } from "bun:test"; +import { describe, expect, test } from "bun:test"; import { createNoopLogger } from "../../../src/server/logger"; import { createMigratedTestDatabase } from "../../helpers"; - -void mock.module("ai", () => ({ - createProviderRegistry: (providers: Record unknown }>) => ({ - languageModel: (id: string) => { - const [providerId, modelId] = id.split(":"); - const provider = providers[providerId ?? ""]; - if (!provider || !modelId) throw new Error(`No such provider: ${id}`); - return provider.languageModel(modelId); - }, - }), - generateText: () => Promise.resolve({ text: "Hi" }), -})); +import "../mocks/ai"; async function withProviderServer( modelsResponse: Response, diff --git a/tests/server/mocks/ai.ts b/tests/server/mocks/ai.ts new file mode 100644 index 0000000..7a47c63 --- /dev/null +++ b/tests/server/mocks/ai.ts @@ -0,0 +1,36 @@ +import { mock } from "bun:test"; + +void mock.module("ai", () => ({ + createAgentUIStreamResponse: (opts: { + agent: unknown; + messages: unknown[]; + onFinish: + | ((event: { finishReason?: string; responseMessage: { parts?: Array<{ text: string; type: string }> } }) => void) + | undefined; + }) => { + if (opts.onFinish) { + opts.onFinish({ + responseMessage: { + parts: [{ text: "test reply from AI", type: "text" }], + }, + }); + } + return Promise.resolve( + new Response( + 'data: {"type":"start-step"}\n\ndata: {"type":"text-start","id":"txt-1"}\n\ndata: {"type":"text-delta","id":"txt-1","delta":"test reply from AI"}\n\ndata: {"type":"text-end","id":"txt-1"}\n\ndata: {"type":"finish-step"}\n\ndata: {"type":"finish"}\n\n', + { + headers: { "Content-Type": "text/event-stream" }, + }, + ), + ); + }, + createProviderRegistry: () => ({ + languageModel: () => ({}), + }), + generateText: () => Promise.resolve({ text: "AI\u603B\u7ED3\u6807\u9898", usage: {} }), + stepCountIs: () => () => true, + tool: () => ({ execute: async () => await Promise.resolve({}) }), + ToolLoopAgent: function M() { + // no-op: createAgentUIStreamResponse handles streaming + }, +})); diff --git a/tests/server/routes/chat.test.ts b/tests/server/routes/chat.test.ts index 86500e9..ee8ec5b 100644 --- a/tests/server/routes/chat.test.ts +++ b/tests/server/routes/chat.test.ts @@ -1,6 +1,6 @@ import type Database from "bun:sqlite"; -import { describe, expect, mock, test } from "bun:test"; +import { describe, expect, test } from "bun:test"; import type { Conversation, Message, RuntimeMode } from "../../../src/shared/api"; @@ -9,45 +9,11 @@ import { createProject } from "../../../src/server/db/projects"; import { createProvider } from "../../../src/server/db/providers"; import { createNoopLogger } from "../../../src/server/logger"; import { createMigratedMemoryTestDatabase } from "../../helpers"; +import "../mocks/ai"; const MODE: RuntimeMode = "test"; const LOG = createNoopLogger(); -void mock.module("ai", () => ({ - createAgentUIStreamResponse: (opts: { - agent: unknown; - messages: unknown[]; - onFinish: - | ((event: { finishReason?: string; responseMessage: { parts?: Array<{ text: string; type: string }> } }) => void) - | undefined; - }) => { - if (opts.onFinish) { - opts.onFinish({ - responseMessage: { - parts: [{ text: "test reply from AI", type: "text" }], - }, - }); - } - return Promise.resolve( - new Response( - 'data: {"type":"start-step"}\n\ndata: {"type":"text-start","id":"txt-1"}\n\ndata: {"type":"text-delta","id":"txt-1","delta":"test reply from AI"}\n\ndata: {"type":"text-end","id":"txt-1"}\n\ndata: {"type":"finish-step"}\n\ndata: {"type":"finish"}\n\n', - { - headers: { "Content-Type": "text/event-stream" }, - }, - ), - ); - }, - createProviderRegistry: () => ({ - languageModel: () => ({}), - }), - generateText: () => Promise.resolve({ text: "AI总结标题", usage: {} }), - stepCountIs: () => () => true, - tool: () => ({ execute: async () => await Promise.resolve({}) }), - ToolLoopAgent: function M() { - // no-op: createAgentUIStreamResponse handles streaming - }, -})); - async function createConversationViaHandler(req: Request, db: Database): Promise { const { handleCreateConversation: h } = await import("../../../src/server/routes/chat/create"); return h(req, db, MODE, LOG); diff --git a/tests/server/routes/models.test.ts b/tests/server/routes/models.test.ts index eddefde..f587b7f 100644 --- a/tests/server/routes/models.test.ts +++ b/tests/server/routes/models.test.ts @@ -1,11 +1,12 @@ import type Database from "bun:sqlite"; -import { describe, expect, mock, test } from "bun:test"; +import { describe, expect, test } from "bun:test"; import type { Model, RuntimeMode } from "../../../src/shared/api"; import { createNoopLogger } from "../../../src/server/logger"; import { createMigratedMemoryTestDatabase } from "../../helpers"; +import "../mocks/ai"; const MODE: RuntimeMode = "test"; const LOG = createNoopLogger(); @@ -49,13 +50,6 @@ async function listModelsViaHandler(req: Request, db: Database): Promise ({ - createProviderRegistry: () => ({ - languageModel: () => ({}), - }), - generateText: () => Promise.resolve({ text: "Hi" }), -})); - function seedProvider(db: Database, name?: string): string { const result = createProvider( db, diff --git a/tests/server/routes/providers.test.ts b/tests/server/routes/providers.test.ts index 8ea6c28..d21131b 100644 --- a/tests/server/routes/providers.test.ts +++ b/tests/server/routes/providers.test.ts @@ -1,6 +1,6 @@ import type Database from "bun:sqlite"; -import { describe, expect, mock, test } from "bun:test"; +import { describe, expect, test } from "bun:test"; import type { Provider, ProviderOption, RuntimeMode } from "../../../src/shared/api"; @@ -8,16 +8,11 @@ import { createModel } from "../../../src/server/db/models"; import { createProvider } from "../../../src/server/db/providers"; import { createNoopLogger } from "../../../src/server/logger"; import { createMigratedMemoryTestDatabase } from "../../helpers"; +import "../mocks/ai"; const MODE: RuntimeMode = "test"; const LOG = createNoopLogger(); -void mock.module("ai", () => ({ - createProviderRegistry: () => ({ - languageModel: () => ({}), - }), -})); - async function createProviderViaHandler(req: Request, db: Database): Promise { const { handleCreateProvider: h } = await import("../../../src/server/routes/providers/create"); return h(req, db, MODE, LOG);