126 lines
3.5 KiB
TypeScript
126 lines
3.5 KiB
TypeScript
import { fireEvent, render, screen } from '@testing-library/react';
|
|
import { describe, expect, it, vi } from 'vitest';
|
|
import {
|
|
ChatCommandRenameDialog,
|
|
ChatCommandTimelineDialog,
|
|
type ChatTimelineEntry,
|
|
} from '@/pages/Chat/ChatCommandDialogs';
|
|
|
|
const entries: ChatTimelineEntry[] = [
|
|
{ messageId: 'user-1', role: 'user', label: 'User', preview: 'First prompt' },
|
|
{
|
|
messageId: 'assistant-1',
|
|
role: 'assistant',
|
|
label: 'Assistant',
|
|
preview: 'First answer',
|
|
},
|
|
];
|
|
|
|
describe('ChatCommandDialogs', () => {
|
|
it('submits a trimmed controlled rename and rejects a whitespace-only title', () => {
|
|
const onTitleChange = vi.fn();
|
|
const onSubmit = vi.fn();
|
|
const onCancel = vi.fn();
|
|
const { rerender } = render(
|
|
<ChatCommandRenameDialog
|
|
open
|
|
title=" New title "
|
|
onTitleChange={onTitleChange}
|
|
onSubmit={onSubmit}
|
|
onCancel={onCancel}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.getByRole('textbox', { name: '会话标题' })).toHaveFocus();
|
|
fireEvent.keyDown(screen.getByRole('textbox', { name: '会话标题' }), {
|
|
key: 'Escape',
|
|
});
|
|
expect(onCancel).toHaveBeenCalledOnce();
|
|
fireEvent.click(screen.getByRole('button', { name: '重命名' }));
|
|
expect(onSubmit).toHaveBeenCalledWith('New title');
|
|
|
|
rerender(
|
|
<ChatCommandRenameDialog
|
|
open
|
|
title=" "
|
|
onTitleChange={onTitleChange}
|
|
onSubmit={onSubmit}
|
|
onCancel={onCancel}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.getByRole('button', { name: '重命名' })).toBeDisabled();
|
|
});
|
|
|
|
it('returns the exact selected message for timeline navigation', () => {
|
|
const onSelect = vi.fn();
|
|
const { rerender } = render(
|
|
<ChatCommandTimelineDialog
|
|
open
|
|
entries={entries}
|
|
onSelect={onSelect}
|
|
onCancel={vi.fn()}
|
|
/>,
|
|
);
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: /First answer/ }));
|
|
expect(onSelect).toHaveBeenLastCalledWith('assistant-1');
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: /First prompt/ }));
|
|
expect(onSelect).toHaveBeenLastCalledWith('user-1');
|
|
});
|
|
|
|
it('contains timeline focus and restores the previously focused control', () => {
|
|
const onCancel = vi.fn();
|
|
const { rerender } = render(
|
|
<>
|
|
<textarea aria-label="Composer" />
|
|
<ChatCommandTimelineDialog
|
|
open={false}
|
|
entries={entries}
|
|
onSelect={vi.fn()}
|
|
onCancel={onCancel}
|
|
/>
|
|
</>,
|
|
);
|
|
const composer = screen.getByRole('textbox', { name: 'Composer' });
|
|
composer.focus();
|
|
|
|
rerender(
|
|
<>
|
|
<textarea aria-label="Composer" />
|
|
<ChatCommandTimelineDialog
|
|
open
|
|
entries={entries}
|
|
onSelect={vi.fn()}
|
|
onCancel={onCancel}
|
|
/>
|
|
</>,
|
|
);
|
|
|
|
const firstEntry = screen.getByRole('button', { name: /First prompt/ });
|
|
const cancel = screen.getByRole('button', { name: '取消' });
|
|
expect(firstEntry).toHaveFocus();
|
|
|
|
fireEvent.keyDown(firstEntry, { key: 'Tab', shiftKey: true });
|
|
expect(cancel).toHaveFocus();
|
|
fireEvent.keyDown(cancel, { key: 'Tab' });
|
|
expect(firstEntry).toHaveFocus();
|
|
fireEvent.keyDown(firstEntry, { key: 'Escape' });
|
|
expect(onCancel).toHaveBeenCalledOnce();
|
|
|
|
rerender(
|
|
<>
|
|
<textarea aria-label="Composer" />
|
|
<ChatCommandTimelineDialog
|
|
open={false}
|
|
entries={entries}
|
|
onSelect={vi.fn()}
|
|
onCancel={onCancel}
|
|
/>
|
|
</>,
|
|
);
|
|
expect(composer).toHaveFocus();
|
|
});
|
|
});
|