- 上下文清单、任务列表与详情、恢复控制、运行观察、创作对话与消息流、正式变更决策面板、正文写作与候选审阅、资料研究等页面同步本轮后端能力。 - 事件标签表补齐后端事件类型;查询键与生成客户端随 HTTP 契约重新生成。 - 依赖调整后 lockfile 同步;交互用例与浏览器旅程 spec 一并更新。 - 证据:make 前端检查(lint + typecheck + Pi 工具桥 tsc)exit 0;make 前端测试 37 文件 / 120 用例通过。
144 lines
5.5 KiB
TypeScript
144 lines
5.5 KiB
TypeScript
import { beforeEach, afterEach, expect, it, vi } from "vitest";
|
||
import {
|
||
cleanup,
|
||
fireEvent,
|
||
render,
|
||
screen,
|
||
waitFor,
|
||
} from "@testing-library/react";
|
||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||
import { MemoryRouter, Routes, Route } from "react-router-dom";
|
||
import { Ui改进提案页 } from "../../src/功能/作者经验/改进提案页";
|
||
const api = vi.hoisted(() => ({ read: vi.fn(), check: vi.fn(), act: vi.fn() }));
|
||
vi.mock("../../src/功能/作者经验/数据", () => ({
|
||
读取改进: api.read,
|
||
核对方法凭据: api.check,
|
||
请求改进启停: api.act,
|
||
提出改进: vi.fn(),
|
||
读取反馈: vi.fn(),
|
||
读取观察: async () => ({ groups: [], observations: [] }),
|
||
记录观察: vi.fn(),
|
||
}));
|
||
vi.mock("../../src/功能/知识方法/数据", () => ({
|
||
useMuse方法列表: () => ({ data: [] }),
|
||
}));
|
||
const point = {
|
||
improvement_id: "improvement",
|
||
revision: 1,
|
||
content_hash: "hash",
|
||
};
|
||
function row() {
|
||
return {
|
||
...point,
|
||
payload: {
|
||
title: "具体方法改进",
|
||
rationale: "检验承接",
|
||
target: {
|
||
target_ref: "B04.method:method",
|
||
version: "1",
|
||
content_hash: "method-hash",
|
||
},
|
||
feedback_ids: ["feedback"],
|
||
},
|
||
target_state: "confirmed",
|
||
is_current_target: true,
|
||
actions: [],
|
||
};
|
||
}
|
||
function mount() {
|
||
render(
|
||
<MemoryRouter initialEntries={["/improvements/improvement"]}>
|
||
<QueryClientProvider
|
||
client={
|
||
new QueryClient({ defaultOptions: { queries: { retry: false } } })
|
||
}
|
||
>
|
||
<Routes>
|
||
<Route
|
||
path="/improvements/:improvement_id"
|
||
element={<Ui改进提案页 />}
|
||
/>
|
||
</Routes>
|
||
</QueryClientProvider>
|
||
</MemoryRouter>,
|
||
);
|
||
}
|
||
beforeEach(() => {
|
||
vi.clearAllMocks();
|
||
api.read.mockResolvedValue(row());
|
||
api.check.mockResolvedValue({ receipt_id: "proof" });
|
||
api.act.mockResolvedValue({});
|
||
});
|
||
afterEach(cleanup);
|
||
|
||
// @muse-case {"case_id":"NC-ui-improvement-retry","environment":"离线界面与传输替身","given":"确切方法版本、真实反馈和同作者用途配置","when":"登记具体改进、实际验证和owner启停并恢复已提交结果;记录分版本观察","then":["核对后明确启用且网络重试复用原命令"],"contract":"docs/系统架构/新版设计/模块设计/B07-作者经验.md"}
|
||
it("NC-ui-improvement-retry:核对后明确启用且网络重试复用原命令", async () => {
|
||
api.act.mockRejectedValueOnce(new Error("连接中断"));
|
||
mount();
|
||
await screen.findByRole("heading", { name: "具体方法改进" });
|
||
const button = screen.getByRole("button", {
|
||
name: "确认启用已测版本",
|
||
}) as HTMLButtonElement;
|
||
expect(button.disabled).toBe(true);
|
||
fireEvent.change(screen.getByLabelText("已测版本凭据"), {
|
||
target: { value: "proof" },
|
||
});
|
||
fireEvent.click(screen.getByRole("button", { name: "核对启用依据" }));
|
||
await waitFor(() => expect(button.disabled).toBe(false));
|
||
expect(api.act).not.toHaveBeenCalled();
|
||
fireEvent.click(button);
|
||
await screen.findByText("连接中断");
|
||
expect(button.disabled).toBe(true);
|
||
fireEvent.click(screen.getByRole("button", { name: "核对启用依据" }));
|
||
await waitFor(() => expect(button.disabled).toBe(false));
|
||
fireEvent.click(button);
|
||
await waitFor(() => expect(api.act).toHaveBeenCalledTimes(2));
|
||
expect(api.act.mock.calls[0]).toEqual(api.act.mock.calls[1]);
|
||
expect(api.act.mock.calls[0].slice(1)).toEqual([point, "enable", "proof"]);
|
||
});
|
||
|
||
// @muse-case {"case_id":"NC-ui-improvement-recover","environment":"离线界面与传输替身","given":"确切方法版本、真实反馈和同作者用途配置","when":"登记具体改进、实际验证和owner启停并恢复已提交结果;记录分版本观察","then":["刷新后保留请求仍用原版本与命令恢复"],"contract":"docs/系统架构/新版设计/模块设计/B07-作者经验.md"}
|
||
it("NC-ui-improvement-recover:刷新后保留请求仍用原版本与命令恢复", async () => {
|
||
api.read.mockResolvedValue({
|
||
...row(),
|
||
target_state: "enabled",
|
||
actions: [
|
||
{
|
||
action_id: "action",
|
||
command_id: "persisted-command",
|
||
kind: "enable",
|
||
revision: 1,
|
||
payload: { selection: point, proof_id: "original-proof" },
|
||
receipt: null,
|
||
},
|
||
],
|
||
});
|
||
mount();
|
||
fireEvent.click(await screen.findByRole("button", { name: "恢复这次请求" }));
|
||
await waitFor(() =>
|
||
expect(api.act).toHaveBeenCalledWith(
|
||
"persisted-command",
|
||
point,
|
||
"enable",
|
||
"original-proof",
|
||
),
|
||
);
|
||
expect(api.check).not.toHaveBeenCalled();
|
||
});
|
||
|
||
// @muse-case {"case_id":"NC-ui-improvement-version","environment":"离线界面与传输替身","given":"确切方法版本、真实反馈和同作者用途配置","when":"登记具体改进、实际验证和owner启停并恢复已提交结果;记录分版本观察","then":["已改变目标不继续当前启停"],"contract":"docs/系统架构/新版设计/模块设计/B07-作者经验.md"}
|
||
it("NC-ui-improvement-version:已改变目标不继续当前启停", async () => {
|
||
api.read.mockResolvedValue({
|
||
...row(),
|
||
is_current_target: false,
|
||
target_state: "enabled",
|
||
});
|
||
mount();
|
||
await screen.findByRole("heading", { name: "具体方法改进" });
|
||
for (const name of ["核对启用依据", "确认启用已测版本", "停用目标方法"])
|
||
expect(
|
||
(screen.getByRole("button", { name }) as HTMLButtonElement).disabled,
|
||
).toBe(true);
|
||
expect(api.act).not.toHaveBeenCalled();
|
||
});
|