Files
Genarrative/apps/ai-game-creator-shell/tests/runNoticeToast.test.tsx
suzmii 6dde321bd1
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m5s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m13s
Project CI / Frontend tests (pull_request) Successful in 3m15s
Project CI / Repository checks (pull_request) Failing after 15s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m56s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 7m55s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m21s
Project CI / Native shell tests (pull_request) Successful in 8m53s
修 review 发现:运行反馈全面退出对话区,并补齐顶栏与守卫细节
- executeRunLocal 的三条失败路径(缺 Tauri / 缺项目 / 启动预览报错)也改走 onRunNotice 失败色提示,对话区不再出现过程行;随之删除已无调用方的 announceProjectChatMessage 与不再有意义的 announceToChat 参数
- RunNoticeToast 的失败提示延长到 6 秒(成功仍 2.6 秒),避免错误一闪而过
- 版本入口在 UI 编辑器壳里不渲染;版本名改由一层 span 承载省略号,长版本名不再被硬裁
- 视图拿不到 onNotice 时把「在浏览器打开失败」写进 console,不再静默吞掉
- check-native-shells 增加「运行页视图里 openUrl( 只有一个调用点」的判据,堵住自动开浏览器的口子
- 新增外壳级接线用例 runNoticeShellWiring;previewActivation 补「启动失败走失败色提示且不写对话区」;runNoticeToast 补失败时长;样式守卫补省略号
- decision-log 收敛到最终口径(成功与失败都出对话区、失败留 6 秒、编辑器不挂版本入口)
2026-09-22 13:51:30 +08:00

121 lines
3.0 KiB
TypeScript

/** @vitest-environment jsdom */
import { act, cleanup, render, screen } from '@testing-library/react';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { RunNoticeToast } from '../src/features/app-shell/RunNoticeToast';
const RUN_MESSAGE = '运行通过,已载入客户端运行视图';
function toastElement() {
return document.querySelector('[data-project-run-notice-toast="true"]');
}
describe('运行 / 预览浮层提示', () => {
afterEach(() => {
cleanup();
vi.useRealTimers();
});
it('没有提示时不渲染任何浮层', () => {
render(<RunNoticeToast notice={null} onDismiss={vi.fn()} />);
expect(toastElement()).toBeNull();
expect(screen.queryByText(RUN_MESSAGE)).toBeNull();
});
it('在浮层里显示提示,并在到点后自动收起', () => {
vi.useFakeTimers();
const onDismiss = vi.fn();
render(
<RunNoticeToast
notice={{ id: 1, message: RUN_MESSAGE }}
onDismiss={onDismiss}
/>,
);
expect(toastElement()).not.toBeNull();
expect(screen.getByText(RUN_MESSAGE)).not.toBeNull();
act(() => {
vi.advanceTimersByTime(2_600);
});
expect(onDismiss).toHaveBeenCalledTimes(1);
});
it('同一句文案连续触发时重新计时', () => {
vi.useFakeTimers();
const onDismiss = vi.fn();
const { rerender } = render(
<RunNoticeToast
notice={{ id: 1, message: RUN_MESSAGE }}
onDismiss={onDismiss}
/>,
);
rerender(
<RunNoticeToast
notice={{ id: 2, message: RUN_MESSAGE }}
onDismiss={onDismiss}
/>,
);
act(() => {
vi.advanceTimersByTime(2_000);
});
expect(onDismiss).not.toHaveBeenCalled();
act(() => {
vi.advanceTimersByTime(600);
});
expect(onDismiss).toHaveBeenCalledTimes(1);
});
it('失败提示用错误色调,不需要调用方再拼一套文案', () => {
render(
<RunNoticeToast
notice={{
id: 1,
tone: 'error',
message: '在浏览器打开失败:permission denied',
}}
onDismiss={vi.fn()}
/>,
);
const toast = toastElement()?.querySelector(
'.platform-runtime-status-toast',
);
// `PlatformRuntimeStatusToast` 的失败态就是 alert + assertive,成功态是 status + polite。
expect(toast?.getAttribute('role')).toBe('alert');
expect(
screen.getByText('在浏览器打开失败:permission denied'),
).not.toBeNull();
});
it('失败提示比成功提示留得久:2.6 秒不该把错误收走', () => {
vi.useFakeTimers();
const onDismiss = vi.fn();
render(
<RunNoticeToast
notice={{
id: 1,
tone: 'error',
message: '运行游戏失败:预览端口被占用',
}}
onDismiss={onDismiss}
/>,
);
act(() => {
vi.advanceTimersByTime(2_600);
});
expect(onDismiss).not.toHaveBeenCalled();
act(() => {
vi.advanceTimersByTime(3_400);
});
expect(onDismiss).toHaveBeenCalledTimes(1);
});
});