/** @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();
expect(toastElement()).toBeNull();
expect(screen.queryByText(RUN_MESSAGE)).toBeNull();
});
it('在浮层里显示提示,并在到点后自动收起', () => {
vi.useFakeTimers();
const onDismiss = vi.fn();
render(
,
);
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(
,
);
rerender(
,
);
act(() => {
vi.advanceTimersByTime(2_000);
});
expect(onDismiss).not.toHaveBeenCalled();
act(() => {
vi.advanceTimersByTime(600);
});
expect(onDismiss).toHaveBeenCalledTimes(1);
});
it('失败提示用错误色调,不需要调用方再拼一套文案', () => {
render(
,
);
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(
,
);
act(() => {
vi.advanceTimersByTime(2_600);
});
expect(onDismiss).not.toHaveBeenCalled();
act(() => {
vi.advanceTimersByTime(3_400);
});
expect(onDismiss).toHaveBeenCalledTimes(1);
});
});