1ff1a9965b
- controller 删 `pendingUserItemId` / `beginTurnCommand` / `endTurnCommand`:忙态改由 `beginTurnBusy` / `endTurnBusy` 持有,宿主认领判据 = `turnRunning` 或收口计数变过(一轮在同一次 consume 里开始并结束) - controller 删 `startTurn` 的乐观追加与 `messageAppended` 重跑参数、`DirectProjectTurnInput.messageText` 与首轮的 `directInitialTurnText`;controller 不再需要 `assets` - 投影删 `awaiting-start` 展示态(只剩 `running` / `finished`)、`localSentTimes` / `sameIdentitySentAt`、本地用户气泡与它开回合的路径;带身份的拒单提示在会话末尾自成一组,不挂进上一轮,也不开运行态标记 - 时间口径:起点只认 `turn.started.at`、终点只认 `turn.completed.at`,用户气泡时钟取宿主落盘 / 观测时间;两边都空的回合整条「本轮结束于 … 」隐藏,不再出现 0.0 秒 - 用例:改造 `directTurnPresentation`(本地用户消息不进回合、拒单提示自成一组、两态判据、失败说明按身份归位)、`directProjectTurn` / `directProjectTurnStatus` / appSurface 窗口期用例,`directProjectTurn` 补 `afterEach(cleanup)` - 注释与文档:ADR「命令接单化」后续更新、实施计划新增「删掉本地乐观用户气泡」、decision-log 与 pitfalls 同日条目、Codex 原始历史方案的口径句、`codex_app_server` 用户条目时间注释
64 lines
2.4 KiB
TypeScript
64 lines
2.4 KiB
TypeScript
/** @vitest-environment jsdom */
|
|
import { cleanup, render } from '@testing-library/react';
|
|
import React from 'react';
|
|
import { afterEach, expect, it } from 'vitest';
|
|
|
|
import { DirectProjectTurn } from '../src/view/project-development/chat/components/DirectProjectConversation/DirectProjectTurn';
|
|
import type {
|
|
DirectChatTurn,
|
|
DirectChatTurnState,
|
|
} from '../src/view/project-development/chat/conversation/directTurnPresentation';
|
|
|
|
afterEach(() => cleanup());
|
|
|
|
const SENT_AT = 1_800_000_000_000;
|
|
const ENDED_AT = SENT_AT + 12_400;
|
|
|
|
const turn = (
|
|
state: DirectChatTurnState,
|
|
overrides: Partial<DirectChatTurn> = {},
|
|
): DirectChatTurn => ({
|
|
key: 'direct-codex:turn-1:user',
|
|
users: [{ kind: 'user', key: 'u', text: '帮我做一个跳跃动作', at: SENT_AT }],
|
|
process: [
|
|
{ kind: 'reasoning', key: 'r', text: '先看目录' },
|
|
{ kind: 'assistant', key: 'a', text: '正在写' },
|
|
],
|
|
finals: [{ kind: 'assistant', key: 'a-final', text: '改好了', at: ENDED_AT }],
|
|
state,
|
|
startedAt: SENT_AT,
|
|
endedAt: state === 'finished' ? ENDED_AT : 0,
|
|
...overrides,
|
|
});
|
|
|
|
it('running:宿主已认领、回合还没结束时不显示终态文案,也不折叠过程', () => {
|
|
const view = render(
|
|
React.createElement(DirectProjectTurn, { turn: turn('running') }),
|
|
);
|
|
expect(view.queryByTestId('turn-usage')).toBeNull();
|
|
expect(view.queryByText(/本轮结束于/)).toBeNull();
|
|
// 否定式判据:未结束的回合把过程平铺出来,不折进「执行过程」。
|
|
expect(view.queryByTestId('turn-process')).toBeNull();
|
|
expect(view.getByLabelText('思考过程')).not.toBeNull();
|
|
});
|
|
|
|
it('finished 但没有回合边界(重进项目读回来的历史回合):整条终态文案隐藏', () => {
|
|
const view = render(
|
|
React.createElement(DirectProjectTurn, {
|
|
turn: turn('finished', { startedAt: 0, endedAt: 0 }),
|
|
}),
|
|
);
|
|
expect(view.queryByTestId('turn-usage')).toBeNull();
|
|
expect(view.queryByText(/本轮结束于/)).toBeNull();
|
|
});
|
|
|
|
it('finished 且有明确终态:显示结束时间与耗时,过程折叠', () => {
|
|
const view = render(
|
|
React.createElement(DirectProjectTurn, { turn: turn('finished') }),
|
|
);
|
|
const usage = view.getByTestId('turn-usage');
|
|
expect(usage.textContent).toContain('本轮结束于');
|
|
expect(usage.textContent).toContain('耗时 12.4秒');
|
|
expect(view.queryByTestId('turn-process')).not.toBeNull();
|
|
});
|