agent-ecosystem/test/renderer/hooks/useFileSuggestions.test.ts
infiniti 4adc233fa4 fix: harden Windows frontend path handling
Harden Windows path handling and packaged app smoke checks.
2026-05-16 17:40:15 +03:00

137 lines
4.5 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
extractDirectories,
filterFileSuggestions,
filterFolderSuggestions,
formatFileMentionPath,
} from '@renderer/hooks/useFileSuggestions';
import type { QuickOpenFile } from '@shared/types/editor';
function file(name: string, relativePath: string, path?: string): QuickOpenFile {
return {
name,
relativePath,
path: path ?? `/project/${relativePath}`,
};
}
const FILES: QuickOpenFile[] = [
file('index.ts', 'src/index.ts'),
file('App.tsx', 'src/App.tsx'),
file('test.ts', 'src/test.ts'),
file('telemetry.ts', 'src/utils/telemetry.ts'),
file('auth.ts', 'src/services/auth.ts'),
file('authMiddleware.ts', 'src/middleware/authMiddleware.ts'),
file('package.json', 'package.json'),
file('README.md', 'README.md'),
file('config.ts', 'src/config.ts'),
file('database.ts', 'src/services/database.ts'),
file('router.ts', 'src/router.ts'),
file('types.ts', 'src/types.ts'),
];
describe('filterFileSuggestions', () => {
it('returns empty array for empty query', () => {
expect(filterFileSuggestions(FILES, '')).toEqual([]);
});
it('returns empty array for empty file list', () => {
expect(filterFileSuggestions([], 'test')).toEqual([]);
});
it('filters by file name', () => {
const results = filterFileSuggestions(FILES, 'test');
expect(results).toHaveLength(1);
expect(results[0].name).toBe('test.ts');
expect(results[0].type).toBe('file');
expect(results[0].filePath).toBe('/project/src/test.ts');
expect(results[0].relativePath).toBe('src/test.ts');
expect(results[0].insertText).toBe('src/test.ts');
});
it('filters by relative path', () => {
const results = filterFileSuggestions(FILES, 'middleware');
expect(results).toHaveLength(1);
expect(results[0].name).toBe('authMiddleware.ts');
});
it('is case-insensitive', () => {
const results = filterFileSuggestions(FILES, 'APP');
expect(results).toHaveLength(1);
expect(results[0].name).toBe('App.tsx');
});
it('returns multiple matches', () => {
const results = filterFileSuggestions(FILES, 'auth');
expect(results).toHaveLength(2);
expect(results.map((r) => r.name)).toEqual(['auth.ts', 'authMiddleware.ts']);
});
it('matches on name substring', () => {
const results = filterFileSuggestions(FILES, 'te');
// 'te' matches: test.ts, telemetry.ts, and router.ts (rou-te-r)
expect(results.map((r) => r.name)).toEqual(['test.ts', 'telemetry.ts', 'router.ts']);
});
it('limits results to 8', () => {
const results = filterFileSuggestions(FILES, 'ts');
expect(results.length).toBeLessThanOrEqual(8);
});
it('sets id with file: prefix', () => {
const results = filterFileSuggestions(FILES, 'config');
expect(results[0].id).toBe('file:/project/src/config.ts');
});
it('sets subtitle to relativePath', () => {
const results = filterFileSuggestions(FILES, 'config');
expect(results[0].subtitle).toBe('src/config.ts');
});
it('matches partial path segments', () => {
const results = filterFileSuggestions(FILES, 'services/');
expect(results).toHaveLength(2);
expect(results.map((r) => r.name)).toEqual(['auth.ts', 'database.ts']);
});
it('matches Windows backslash queries against normalized relative paths', () => {
const results = filterFileSuggestions(FILES, 'services\\auth');
expect(results).toHaveLength(1);
expect(results[0].relativePath).toBe('src/services/auth.ts');
});
it('returns results in file list order', () => {
const results = filterFileSuggestions(FILES, '.ts');
expect(results[0].name).toBe('index.ts');
});
it('quotes inserted paths that contain spaces', () => {
expect(formatFileMentionPath('src/My Component/App.tsx')).toBe('"src/My Component/App.tsx"');
});
});
describe('folder suggestions', () => {
it('derives stable folders from Windows relative paths', () => {
const folders = extractDirectories(
[
{
name: 'auth.ts',
relativePath: 'src\\services\\auth.ts',
path: 'C:\\Repo\\src\\services\\auth.ts',
},
],
'C:\\Repo'
);
expect(folders.map((f) => [f.name, f.relativePath, f.absolutePath])).toEqual([
['src', 'src/', 'C:\\Repo\\src'],
['services', 'src/services/', 'C:\\Repo\\src\\services'],
]);
const suggestions = filterFolderSuggestions(folders, 'src\\services\\');
expect(suggestions).toHaveLength(1);
expect(suggestions[0].insertText).toBe('src/services/');
});
});