e80279c174
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m8s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 53s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 8m21s
Project CI / Backend tests (pull_request) Successful in 4m12s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 10m2s
Project CI / Frontend tests (pull_request) Successful in 2m11s
Project CI / Repository checks (pull_request) Successful in 2m33s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m1s
Project CI / Native shell tests (pull_request) Successful in 6m27s
- apps/ai-game-creator-shell/src/view/project-development/chat/components/DirectProjectConversation/DirectProjectConversation.tsx 的 DirectTurnElapsed 改用对话侧共享时钟 useLiveNow(100ms),删掉组件自带的 1000ms setInterval 与 now state:耗时文案不足一分钟保留一位小数,秒级 tick 会让小数位一秒才动一格 - apps/ai-game-creator-shell/src/styles.css 重写 .project-chat-process-card:去掉旧面板遗留的 78px 最小高度与 9px 行距,收敛为单行状态条(padding 8px 12px) - apps/ai-game-creator-shell/src/styles.css 状态点与扫光改走 --platform-accent(原先写死绿色),标题提到 --platform-text-strong,耗时改 --platform-text-base 并加 tabular-nums - apps/ai-game-creator-shell/src/styles.css 删除两条永不命中的选择器(卡片渲染在消息列表外,规则却写着 …message-list > .project-chat-process-card)与已无 <p> 渲染的多行摘要样式 - apps/ai-game-creator-shell/src/styles.css 过程卡与最后一条消息之间补 12px 上间距,原先 margin 简写把它清零 - apps/ai-game-creator-shell/tests/directProjectProcessStatus.test.tsx 新增读秒粒度回归用例与「无运行中回合不订阅时钟」用例 - apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts 与 tests/AgentMessageContent.test.tsx 的选择器契约同步到现行 DOM 结构 - docs/project-memory/shared-memory/pitfalls.md 记录「刷新粒度必须与显示精度同格」这条复发坑
76 lines
2.4 KiB
TypeScript
76 lines
2.4 KiB
TypeScript
// @vitest-environment jsdom
|
||
import { cleanup, render } from '@testing-library/react';
|
||
import { act, createRef } from 'react';
|
||
import { afterEach, expect, test, vi } from 'vitest';
|
||
|
||
import { DirectProjectConversation } from '../src/view/project-development/chat/components/DirectProjectConversation/DirectProjectConversation';
|
||
|
||
afterEach(() => {
|
||
cleanup();
|
||
});
|
||
|
||
const STARTED_AT = 1_800_000_000_000;
|
||
|
||
/**
|
||
* 读秒粒度:走对话侧唯一的 `useLiveNow`(`LIVE_TIMER_TICK_MS = 100`)。
|
||
*
|
||
* 状态条的耗时文案不足一分钟保留一位小数,刷新就必须是 100ms——按 1 秒一跳时,用户看到的
|
||
* 是一块「带小数却一格一格跳」的表,像卡住不动。这里用假时钟钉住粒度:把时钟改回 1000ms
|
||
* 时第二步即红。
|
||
*/
|
||
test('运行中状态条的读秒按 100ms 刷新:不足一分钟的耗时以 0.1 秒递增', () => {
|
||
vi.useFakeTimers();
|
||
try {
|
||
vi.setSystemTime(STARTED_AT);
|
||
const view = render(
|
||
<DirectProjectConversation
|
||
turns={[]}
|
||
messagesRef={createRef<HTMLDivElement>()}
|
||
historyHasMore={false}
|
||
nativeRunning
|
||
activeTurnStartedAt={STARTED_AT}
|
||
onLoadEarlierHistory={() => undefined}
|
||
onScroll={() => undefined}
|
||
/>,
|
||
);
|
||
const elapsed = () => view.getByText(/^已耗时 /u).textContent;
|
||
expect(elapsed()).toBe('已耗时 0.0秒');
|
||
|
||
act(() => {
|
||
vi.advanceTimersByTime(100);
|
||
});
|
||
expect(elapsed()).toBe('已耗时 0.1秒');
|
||
|
||
// 1 秒一跳的实现会停在上面的 0.1 秒:再走 400ms 必须继续往上加。
|
||
act(() => {
|
||
vi.advanceTimersByTime(400);
|
||
});
|
||
expect(elapsed()).toBe('已耗时 0.5秒');
|
||
} finally {
|
||
vi.useRealTimers();
|
||
}
|
||
});
|
||
|
||
/** 回合不在跑时不订阅时钟:否则空转的 tick 会持续重建状态条所在的那块视图。 */
|
||
test('没有运行中的回合时不订阅时钟', () => {
|
||
vi.useFakeTimers();
|
||
const spy = vi.spyOn(globalThis, 'setInterval');
|
||
try {
|
||
render(
|
||
<DirectProjectConversation
|
||
turns={[]}
|
||
messagesRef={createRef<HTMLDivElement>()}
|
||
historyHasMore={false}
|
||
nativeRunning={false}
|
||
activeTurnStartedAt={0}
|
||
onLoadEarlierHistory={() => undefined}
|
||
onScroll={() => undefined}
|
||
/>,
|
||
);
|
||
expect(spy).not.toHaveBeenCalled();
|
||
} finally {
|
||
spy.mockRestore();
|
||
vi.useRealTimers();
|
||
}
|
||
});
|