77 lines
2.7 KiB
TypeScript
77 lines
2.7 KiB
TypeScript
import { fireEvent, render, screen } from '@testing-library/react';
|
|
import { describe, expect, it, vi } from 'vitest';
|
|
import { ChatCommandPalette } from '@/pages/Chat/ChatCommandPalette';
|
|
import type { ChatCommandPaletteItem } from '@/pages/Chat/chat-command-registry';
|
|
|
|
function item(
|
|
inputName: string,
|
|
enabled: boolean,
|
|
reason?: string,
|
|
): ChatCommandPaletteItem {
|
|
return {
|
|
name: inputName === 'compact' ? 'compact' : 'project',
|
|
inputName,
|
|
...(inputName === 'review' ? { rawName: 'review' } : {}),
|
|
aliases: [],
|
|
title: inputName === 'compact' ? '压缩会话' : 'Review',
|
|
description: inputName === 'compact' ? '总结上下文' : 'Review changes',
|
|
source: inputName === 'compact' ? 'builtin' : 'project',
|
|
confirmation: 'none',
|
|
computedAvailability: enabled ? { enabled: true } : { enabled: false, reason },
|
|
};
|
|
}
|
|
|
|
describe('ChatCommandPalette', () => {
|
|
it('renders listbox semantics, selection, availability reason, and project source', () => {
|
|
const onSelect = vi.fn();
|
|
const onActiveIndexChange = vi.fn();
|
|
render(
|
|
<ChatCommandPalette
|
|
items={[
|
|
item('compact', true),
|
|
item('review', false, 'OpenCode 运行时未启动'),
|
|
]}
|
|
activeIndex={0}
|
|
onActiveIndexChange={onActiveIndexChange}
|
|
onSelect={onSelect}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.getByRole('listbox', { name: '斜杠命令' })).toBeInTheDocument();
|
|
expect(screen.getByRole('option', { name: /compact/ })).toHaveAttribute(
|
|
'aria-selected',
|
|
'true',
|
|
);
|
|
expect(screen.getByRole('option', { name: /compact/ })).toHaveAttribute(
|
|
'tabindex',
|
|
'-1',
|
|
);
|
|
expect(screen.getByRole('option', { name: /review/i })).toBeDisabled();
|
|
expect(screen.getByText('OpenCode 运行时未启动')).toBeInTheDocument();
|
|
expect(screen.getByText('项目')).toBeInTheDocument();
|
|
|
|
fireEvent.mouseEnter(screen.getByRole('option', { name: /review/i }));
|
|
expect(onActiveIndexChange).toHaveBeenCalledWith(1);
|
|
fireEvent.mouseDown(screen.getByRole('option', { name: /compact/i }));
|
|
expect(onSelect).toHaveBeenCalledWith(
|
|
expect.objectContaining({ inputName: 'compact' }),
|
|
);
|
|
fireEvent.mouseDown(screen.getByRole('option', { name: /review/i }));
|
|
expect(onSelect).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('shows an explicit empty search result without inventing a selectable option', () => {
|
|
render(
|
|
<ChatCommandPalette
|
|
items={[]}
|
|
activeIndex={-1}
|
|
onActiveIndexChange={vi.fn()}
|
|
onSelect={vi.fn()}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.getByText('没有匹配的命令')).toBeInTheDocument();
|
|
expect(screen.queryAllByRole('option')).toHaveLength(0);
|
|
});
|
|
});
|