157 lines
5.2 KiB
TypeScript
157 lines
5.2 KiB
TypeScript
/* @vitest-environment jsdom */
|
||
|
||
import { Waves } from 'lucide-react';
|
||
import { fireEvent, render, screen } from '@testing-library/react';
|
||
import { expect, test, vi } from 'vitest';
|
||
|
||
import { PlatformStatusDialog } from './PlatformStatusDialog';
|
||
|
||
test('renders result state with description and primary action', () => {
|
||
const onClose = vi.fn();
|
||
const onAction = vi.fn();
|
||
|
||
render(
|
||
<PlatformStatusDialog
|
||
status="success"
|
||
title="支付成功"
|
||
description="账户状态已刷新"
|
||
onClose={onClose}
|
||
action={{ label: '知道了', onClick: onAction }}
|
||
/>,
|
||
);
|
||
|
||
const dialog = screen.getByRole('dialog', { name: '支付成功' });
|
||
const overlay = dialog.parentElement as HTMLElement;
|
||
const badge = dialog.querySelector('.platform-icon-badge');
|
||
const action = screen.getByRole('button', { name: '知道了' });
|
||
const visibleDescription = dialog.querySelector(
|
||
'.mt-3.text-sm.font-semibold.leading-6.text-\\[var\\(--platform-text-soft\\)\\]',
|
||
);
|
||
|
||
expect(dialog).toBeTruthy();
|
||
expect(overlay.className).toContain('platform-theme--light');
|
||
expect(overlay.className).toContain('platform-profile-modal-overlay');
|
||
expect(visibleDescription?.textContent).toBe('账户状态已刷新');
|
||
expect(badge?.className).toContain('text-[var(--platform-success-text)]');
|
||
expect(action.className).toContain('platform-primary-button');
|
||
|
||
fireEvent.click(action);
|
||
expect(onAction).toHaveBeenCalledTimes(1);
|
||
});
|
||
|
||
test('supports blocking confirming state without close action', () => {
|
||
const onClose = vi.fn();
|
||
|
||
render(
|
||
<PlatformStatusDialog
|
||
status="confirming"
|
||
title="正在确认支付"
|
||
description="订单 A100 正在同步到账状态,请先停留在当前页面。"
|
||
onClose={onClose}
|
||
closeDisabled
|
||
zIndexClassName="z-[95]"
|
||
/>,
|
||
);
|
||
|
||
const dialog = screen.getByRole('dialog', { name: '正在确认支付' });
|
||
const overlay = dialog.parentElement as HTMLElement;
|
||
const spinner = dialog.querySelector('.platform-icon-badge svg');
|
||
|
||
expect(overlay.className).toContain('z-[95]');
|
||
expect(spinner?.getAttribute('class')).toContain('animate-spin');
|
||
expect(
|
||
screen.queryByRole('button', { name: '关闭' }) ||
|
||
screen.queryByRole('button', { name: '知道了' }),
|
||
).toBeNull();
|
||
|
||
fireEvent.click(overlay);
|
||
fireEvent.keyDown(window, { key: 'Escape' });
|
||
|
||
expect(onClose).not.toHaveBeenCalled();
|
||
});
|
||
|
||
test('supports custom badge icon label and action button styling', () => {
|
||
render(
|
||
<PlatformStatusDialog
|
||
status="error"
|
||
title="发布失败"
|
||
description="还缺少 16 个基础动作"
|
||
onClose={vi.fn()}
|
||
icon={<Waves className="h-4 w-4" />}
|
||
iconLabel="发布失败提示"
|
||
iconClassName="bg-[var(--platform-button-danger-fill)] text-[var(--platform-button-danger-text)]"
|
||
action={{
|
||
label: '知道了',
|
||
onClick: vi.fn(),
|
||
surface: 'platform',
|
||
className: 'border-slate-950 bg-slate-950 text-white',
|
||
}}
|
||
/>,
|
||
);
|
||
|
||
const badge = screen.getByLabelText('发布失败提示');
|
||
const action = screen.getByRole('button', { name: '知道了' });
|
||
|
||
expect(badge.className).toContain('bg-[var(--platform-button-danger-fill)]');
|
||
expect(badge.className).toContain(
|
||
'text-[var(--platform-button-danger-text)]',
|
||
);
|
||
expect(action.className).toContain('border-slate-950');
|
||
expect(action.className).toContain('bg-slate-950');
|
||
});
|
||
|
||
test('keeps default theme classes when callers customize the overlay', () => {
|
||
render(
|
||
<PlatformStatusDialog
|
||
status="error"
|
||
title="发布失败"
|
||
description="图片生成失败"
|
||
onClose={vi.fn()}
|
||
overlayClassName="bg-slate-950/58 custom-overlay"
|
||
action={{ label: '知道了', onClick: vi.fn(), surface: 'platform' }}
|
||
/>,
|
||
);
|
||
|
||
const dialog = screen.getByRole('dialog', { name: '发布失败' });
|
||
const overlay = dialog.parentElement as HTMLElement;
|
||
|
||
expect(overlay.className).toContain('platform-theme--light');
|
||
expect(overlay.className).toContain('platform-profile-modal-overlay');
|
||
expect(overlay.className).toContain('bg-slate-950/58');
|
||
expect(overlay.className).toContain('custom-overlay');
|
||
});
|
||
|
||
test('supports header notice layout with body content and close button', () => {
|
||
const onClose = vi.fn();
|
||
|
||
render(
|
||
<PlatformStatusDialog
|
||
status="error"
|
||
title="泥点不足"
|
||
description="当前表单不会丢失,关闭后可继续编辑或补足泥点再继续。"
|
||
onClose={onClose}
|
||
showHeader
|
||
showCloseButton
|
||
closeOnBackdrop
|
||
action={{ label: '知道了', onClick: onClose, surface: 'platform' }}
|
||
>
|
||
本次需要 6 泥点,当前 5 泥点。
|
||
</PlatformStatusDialog>,
|
||
);
|
||
|
||
const dialog = screen.getByRole('dialog', { name: '泥点不足' });
|
||
|
||
expect(
|
||
dialog.querySelector('.mt-4.text-xl.font-black.text-\\[var\\(--platform-text-strong\\)\\]'),
|
||
).toBeNull();
|
||
expect(screen.getByText('本次需要 6 泥点,当前 5 泥点。')).toBeTruthy();
|
||
expect(
|
||
screen.getByText(
|
||
'当前表单不会丢失,关闭后可继续编辑或补足泥点再继续。',
|
||
),
|
||
).toBeTruthy();
|
||
|
||
fireEvent.click(screen.getByRole('button', { name: '关闭' }));
|
||
expect(onClose).toHaveBeenCalledTimes(1);
|
||
});
|