From c9a4b3e15863c1a51da8a7df08e4403979931dff Mon Sep 17 00:00:00 2001 From: suguanYang Date: Wed, 13 May 2026 18:32:34 +0800 Subject: [PATCH 1/2] fix: update tests for Effect-wrapped repository and reconcile dependencies - Use expect.any(Function) for chat route repository assertions since chatTurnPersistence.createRepository() now wraps service methods - Return Promises from reconcile mock defaults so Effect.tryPromise doesn't fail on bare vi.fn() (which returns undefined) - Add 4th "parsing" arg to markSourceFailed expectation to match updated lifecycle function signature --- src/domains/chat/route-service.test.ts | 6 +++--- src/domains/sources/reconcile.test.ts | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/domains/chat/route-service.test.ts b/src/domains/chat/route-service.test.ts index b963d41..8fcc9cf 100644 --- a/src/domains/chat/route-service.test.ts +++ b/src/domains/chat/route-service.test.ts @@ -117,9 +117,9 @@ describe("chat route services", () => { generateRetrievalQuery: mocks.generateContextualRetrievalQuery, generateAnswer: mocks.generateGroundedAnswer, repository: expect.objectContaining({ - appendMessageToThread: mocks.appendMessageToThread, - ensureDefaultChatThread: mocks.ensureDefaultChatThread, - findChatThreadInWorkspace: mocks.findChatThreadInWorkspace, + appendMessageToThread: expect.any(Function), + ensureDefaultChatThread: expect.any(Function), + findChatThreadInWorkspace: expect.any(Function), listMessagesForThread: expect.any(Function), }), }), diff --git a/src/domains/sources/reconcile.test.ts b/src/domains/sources/reconcile.test.ts index 88803e1..808fd82 100644 --- a/src/domains/sources/reconcile.test.ts +++ b/src/domains/sources/reconcile.test.ts @@ -36,9 +36,9 @@ function makeSource(overrides: Partial): Source { async function loadReconcile({ listSourcesForWorkspace, - markSourceFailed = vi.fn(), - markSourceReady = vi.fn(), - saveSourceParseResult = vi.fn(), + markSourceFailed = vi.fn().mockResolvedValue(undefined), + markSourceReady = vi.fn().mockResolvedValue(undefined), + saveSourceParseResult = vi.fn().mockResolvedValue(undefined), storeParsedResultAssets = vi.fn().mockResolvedValue({ resultBlobUrl: "https://blob.example/result.zip", assetUrlsByFilePath: {}, @@ -247,6 +247,7 @@ describe("reconcileSourcesForWorkspace", () => { workspace.id, "source_1", "Parser rejected this document.", + "parsing", ) }) From e0cb078c94887ba3f61fa9c000ea3ec09f49c87b Mon Sep 17 00:00:00 2001 From: suguanYang Date: Wed, 13 May 2026 18:45:19 +0800 Subject: [PATCH 2/2] fix: update tests for removed chunk search, Effect HTTP client, and page size - Remove obsolete search test from chunks-panel.test.ts (search was removed from the component in 9ee238e) - Switch workspace/client.test.ts from stubbing global fetch to mocking workspaceRouteClient (now uses Effect FetchHttpClient) - Update page size from 100 to 50 in workspace-shell test assertion (changed in 9ee238e) --- src/components/chunks-panel.test.ts | 64 ---------------------- src/components/workspace-shell.test.ts | 2 +- src/domains/workspace/client.test.ts | 74 +++++++++++++------------- 3 files changed, 37 insertions(+), 103 deletions(-) diff --git a/src/components/chunks-panel.test.ts b/src/components/chunks-panel.test.ts index 281616f..edfa49d 100644 --- a/src/components/chunks-panel.test.ts +++ b/src/components/chunks-panel.test.ts @@ -63,70 +63,6 @@ describe("ChunksPanel", () => { expect(screen.getByText(/Showing all parsed chunks from/)).toBeTruthy(); }); - it("searches loaded chunks and jumps between matching chunks", async () => { - mockVisibleVirtualViewport(); - const user = userEvent.setup(); - const { container } = render( - React.createElement(C, { - chunks: [ - { - chunkId: "chunk_1", - type: "text", - content: "Revenue increased.", - sourceTitle: "report.pdf", - pageNums: [1], - }, - { - chunkId: "chunk_2", - type: "text", - content: "Operating margin improved.", - sourceTitle: "report.pdf", - pageNums: [2], - }, - { - chunkId: "chunk_3", - type: "image", - content: "", - summary: "Margin bridge chart.", - keywords: ["gross margin"], - sourceTitle: "report.pdf", - pageNums: [3], - }, - ], - selectedSource: "report.pdf", - }), - ); - - await user.type( - screen.getByRole("searchbox", { name: "Search parsed chunks" }), - "margin", - ); - - expect(screen.getByText("1/2 chunks ยท 3 hits")).toBeTruthy(); - await waitFor(() => { - expect( - container.querySelector( - '[data-chunk-id="chunk_2"][data-focused-chunk="true"]', - ), - ).toBeTruthy(); - }); - expect( - container.querySelectorAll('mark[data-chunk-search-match="true"]').length, - ).toBeGreaterThan(0); - - await user.click( - screen.getByRole("button", { name: "Next chunk search match" }), - ); - - await waitFor(() => { - expect( - container.querySelector( - '[data-chunk-id="chunk_3"][data-focused-chunk="true"]', - ), - ).toBeTruthy(); - }); - }); - it("shows a large upload target when no document is selected", async () => { const user = userEvent.setup(); diff --git a/src/components/workspace-shell.test.ts b/src/components/workspace-shell.test.ts index a4e1909..4a2609c 100644 --- a/src/components/workspace-shell.test.ts +++ b/src/components/workspace-shell.test.ts @@ -720,7 +720,7 @@ describe("WorkspaceShell", () => { ); await waitFor(() => { expect( - countFetchesWithSearch(fetch, "/api/sources/source_1/chunks", "?page=1&pageSize=100"), + countFetchesWithSearch(fetch, "/api/sources/source_1/chunks", "?page=1&pageSize=50"), ).toBeGreaterThan(0); }); diff --git a/src/domains/workspace/client.test.ts b/src/domains/workspace/client.test.ts index 21b26d8..6b83cb9 100644 --- a/src/domains/workspace/client.test.ts +++ b/src/domains/workspace/client.test.ts @@ -1,41 +1,49 @@ import { beforeEach, describe, expect, it, vi } from "vitest" +const { mockRouteClient } = vi.hoisted(() => ({ + mockRouteClient: { + getJson: vi.fn(), + postJsonWithStatus: vi.fn(), + postJson: vi.fn(), + patchJson: vi.fn(), + deleteJson: vi.fn(), + }, +})) + +vi.mock("./route-client", () => ({ + workspaceRouteClient: mockRouteClient, +})) + import { workspaceClient } from "./client" describe("workspaceClient", () => { beforeEach(() => { - vi.unstubAllGlobals() + vi.clearAllMocks() }) it("fetches a normalized chunk page with an encoded source id", async () => { - const fetch = vi.fn(async (input) => { - const requestUrl = new URL(String(input), "http://localhost") - - expect(requestUrl.pathname).toBe("/api/sources/source%20one/chunks") - expect(requestUrl.searchParams.get("page")).toBe("2") - expect(requestUrl.searchParams.get("pageSize")).toBe("100") - - return Response.json({ - chunks: [ - { - chunkId: "chunk_1", - type: "text", - content: "Chunk body", - sourceTitle: "source one", - }, - ], - pagination: { - page: 2, - pageSize: 100, - total: 3, - totalPages: 3, + mockRouteClient.getJson.mockResolvedValue({ + chunks: [ + { + chunkId: "chunk_1", + type: "text", + content: "Chunk body", + sourceTitle: "source one", }, - }) + ], + pagination: { + page: 2, + pageSize: 50, + total: 3, + totalPages: 3, + }, }) - vi.stubGlobal("fetch", fetch) const page = await workspaceClient.fetchChunkPage("source one", 2) + expect(mockRouteClient.getJson).toHaveBeenCalledWith( + "/api/sources/source%20one/chunks?page=2&pageSize=50", + ) expect(page).toEqual({ chunks: [ { @@ -47,28 +55,18 @@ describe("workspaceClient", () => { ], pagination: { page: 2, - pageSize: 100, + pageSize: 50, total: 3, totalPages: 3, }, }) - expect(fetch).toHaveBeenCalledOnce() }) it("throws materialization route errors instead of treating them as empty sources", async () => { - const fetch = vi.fn(async (input, init) => { - const request = input instanceof Request ? input : new Request(input, init) - const requestUrl = new URL(request.url) - - expect(request.method).toBe("POST") - expect(requestUrl.pathname).toBe("/api/demo-sources/materialize") - - return Response.json( - { message: "Demo sources could not be prepared right now." }, - { status: 502 }, - ) + mockRouteClient.postJsonWithStatus.mockResolvedValue({ + status: 502, + body: { message: "Demo sources could not be prepared right now." }, }) - vi.stubGlobal("fetch", fetch) await expect( workspaceClient.materializeDemoSources({