takt/src/__tests__/bookmark.test.ts
2026-02-04 11:07:41 +09:00

103 lines
4.2 KiB
TypeScript

/**
* Tests for piece bookmark functionality
*/
import { describe, it, expect } from 'vitest';
import { handleKeyInput } from '../shared/prompt/index.js';
import { applyBookmarks, type SelectionOption } from '../features/pieceSelection/index.js';
describe('handleKeyInput - bookmark action', () => {
const totalItems = 4;
const optionCount = 3;
const hasCancelOption = true;
it('should return bookmark action for b key', () => {
const result = handleKeyInput('b', 1, totalItems, hasCancelOption, optionCount);
expect(result).toEqual({ action: 'bookmark', selectedIndex: 1 });
});
it('should return bookmark action with current index', () => {
const result = handleKeyInput('b', 0, totalItems, hasCancelOption, optionCount);
expect(result).toEqual({ action: 'bookmark', selectedIndex: 0 });
});
it('should return bookmark action at last option index', () => {
const result = handleKeyInput('b', 2, totalItems, hasCancelOption, optionCount);
expect(result).toEqual({ action: 'bookmark', selectedIndex: 2 });
});
it('should not interfere with existing key bindings', () => {
// j/k should still work
expect(handleKeyInput('j', 0, totalItems, hasCancelOption, optionCount)).toEqual({ action: 'move', newIndex: 1 });
expect(handleKeyInput('k', 1, totalItems, hasCancelOption, optionCount)).toEqual({ action: 'move', newIndex: 0 });
// Enter should still confirm
expect(handleKeyInput('\r', 0, totalItems, hasCancelOption, optionCount)).toEqual({ action: 'confirm', selectedIndex: 0 });
// Esc should still cancel
expect(handleKeyInput('\x1B', 0, totalItems, hasCancelOption, optionCount)).toEqual({ action: 'cancel', cancelIndex: 3 });
});
});
describe('applyBookmarks', () => {
const options: SelectionOption[] = [
{ label: 'alpha', value: 'alpha' },
{ label: 'beta', value: 'beta' },
{ label: 'gamma', value: 'gamma' },
{ label: 'delta', value: 'delta' },
];
it('should add [*] suffix to bookmarked items without changing order', () => {
const result = applyBookmarks(options, ['gamma']);
expect(result[2]!.label).toBe('gamma [*]');
expect(result[2]!.value).toBe('gamma');
expect(result).toHaveLength(4);
});
it('should preserve original order of all items', () => {
const result = applyBookmarks(options, ['gamma']);
expect(result.map((o) => o.value)).toEqual(['alpha', 'beta', 'gamma', 'delta']);
});
it('should handle multiple bookmarks preserving original order', () => {
const result = applyBookmarks(options, ['delta', 'alpha']);
expect(result[0]!.value).toBe('alpha');
expect(result[0]!.label).toBe('alpha [*]');
expect(result[3]!.value).toBe('delta');
expect(result[3]!.label).toBe('delta [*]');
expect(result.map((o) => o.value)).toEqual(['alpha', 'beta', 'gamma', 'delta']);
});
it('should return unchanged options when no bookmarks', () => {
const result = applyBookmarks(options, []);
expect(result).toEqual(options);
});
it('should ignore bookmarks that do not match any option', () => {
const result = applyBookmarks(options, ['nonexistent']);
expect(result).toEqual(options);
});
it('should not mutate original options', () => {
const original = options.map((o) => ({ ...o }));
applyBookmarks(options, ['gamma']);
expect(options).toEqual(original);
});
it('should work with category-prefixed values', () => {
const categoryOptions: SelectionOption[] = [
{ label: 'simple', value: 'simple' },
{ label: '📁 frontend/', value: '__category__:frontend' },
{ label: '📁 backend/', value: '__category__:backend' },
];
// Only piece values should match; categories are not bookmarkable
const result = applyBookmarks(categoryOptions, ['simple']);
expect(result[0]!.label).toBe('simple [*]');
expect(result.map((o) => o.value)).toEqual(['simple', '__category__:frontend', '__category__:backend']);
});
it('should handle all items bookmarked', () => {
const result = applyBookmarks(options, ['alpha', 'beta', 'gamma', 'delta']);
expect(result.every((o) => o.label.endsWith(' [*]'))).toBe(true);
expect(result.map((o) => o.value)).toEqual(['alpha', 'beta', 'gamma', 'delta']);
});
});