From 3a6ec3e602c8bf9da1c7d44d962fb38c117a6eab Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sat, 24 Oct 2026 15:13:14 +0400 Subject: [PATCH] =?UTF-8?q?fix(web-modules):=20I-1=20=D0=BF=D0=B0=D0=BA?= =?UTF-8?q?=D0=B5=D1=82=20=D0=B2=D0=B8=D0=BA=D0=B8=20=D0=B8=D0=BD=D0=B2?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B4=D0=B8=D1=80=D1=83=D0=B5=D1=82=20=D0=B2?= =?UTF-8?q?=D0=B5=D1=81=D1=8C=20wiki/<=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82?= =?UTF-8?q?>,=20=D0=B2=D0=BA=D0=BB=D1=8E=D1=87=D0=B0=D1=8F=20status?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- web/src/modules/wiki/WikiPage.test.tsx | 21 +++++++++++++++++++++ web/src/modules/wiki/status.ts | 3 ++- web/src/shell/activity/activity.test.tsx | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/web/src/modules/wiki/WikiPage.test.tsx b/web/src/modules/wiki/WikiPage.test.tsx index a4f78e6..960592a 100644 --- a/web/src/modules/wiki/WikiPage.test.tsx +++ b/web/src/modules/wiki/WikiPage.test.tsx @@ -246,4 +246,25 @@ describe("страница «Вики»", () => { open("/wiki?project=AWPCA&page=DOC-2"); expect(await screen.findByText(/Eva не ответила: 502/)).toBeInTheDocument(); }); + + it("I-1: пакет wiki_sync завершён — подзаголовок «обновлено …» и дерево обновляются без перезагрузки", async () => { + let synced = false; + const fresh = { ...STATUS, synced_at: "2026-10-24T12:00:00+00:00" }; + const empty = { ...STATUS, synced_at: null, pages: 0 }; + mockFetch((method, url) => { + if (url.pathname === "/wiki/status") return json(200, synced ? fresh : empty); + if (url.pathname === "/wiki/sync" && method === "POST") { synced = true; return json(202, { batch_id: 5 }); } + if (url.pathname === "/batches/5") return json(200, { id: 5, status: "done", module: "wiki", commands: [{ type: "wiki_sync", status: "done" }], author: "viewer", title: "t", created_at: "2026-10-24T12:00:00+00:00" }); + if (url.pathname === "/wiki/tree") return json(200, TREE); + if (url.pathname === "/agents") return json(200, { agents: [] }); + const m = /^\/wiki\/pages\/([^/]+)$/.exec(url.pathname); + if (m) return json(200, page(decodeURIComponent(m[1]))); + return json(404, { error: "not_found" }); + }); + open("/wiki?project=AWPCA"); + await screen.findByText("Вики ещё не синхронизирована. Нажмите «Обновить вики»."); + await userEvent.click(screen.getByRole("button", { name: "Обновить вики" })); + expect(await screen.findByText(`Корень · 3 страниц · обновлено ${fmtStamp(fresh.synced_at)}`, {}, { timeout: 8000 })).toBeInTheDocument(); + expect(await screen.findByRole("treeitem", { name: /Модель данных/ })).toBeInTheDocument(); + }, 15000); }); diff --git a/web/src/modules/wiki/status.ts b/web/src/modules/wiki/status.ts index 6d66e26..9c07327 100644 --- a/web/src/modules/wiki/status.ts +++ b/web/src/modules/wiki/status.ts @@ -19,6 +19,7 @@ export const wikiStatus: ModuleStatus = { }, invalidate: (qc, project) => { if (project === null) return; - for (const key of ["tree", "page", "search"]) void qc.invalidateQueries({ queryKey: [...wikiQk.project(project), key] }); + // всё про проект разом: status (подзаголовок «обновлено …», появление дерева у проекта без синхронизаций), tree, page, search + void qc.invalidateQueries({ queryKey: wikiQk.project(project) }); }, }; diff --git a/web/src/shell/activity/activity.test.tsx b/web/src/shell/activity/activity.test.tsx index 347c57a..159406f 100644 --- a/web/src/shell/activity/activity.test.tsx +++ b/web/src/shell/activity/activity.test.tsx @@ -398,7 +398,7 @@ describe("ActivityProvider", () => { await act(() => m.now().wiki.start()); await waitFor(() => expect(m.now().wiki.event).toEqual({ kind: "batch-done", id: 7 })); const keys = spy.mock.calls.map(([f]) => (f as { queryKey: unknown[] }).queryKey); - expect(keys).toEqual(expect.arrayContaining([["wiki", "AWPCA", "tree"], ["wiki", "AWPCA", "page"], ["wiki", "AWPCA", "search"], ["projects"]])); + expect(keys).toEqual(expect.arrayContaining([["wiki", "AWPCA"], ["projects"]])); expect(keys.map((k) => k[0])).not.toContain("board"); expect(keys.map((k) => k[0])).not.toContain("issues"); });