agent-ecosystem/test/renderer/components/team/editor/fileIcons.test.ts
iliya cb8017b0db feat: enhance file icon handling and keyboard shortcuts
- Introduced a new FileIcon component to render file-type icons with support for Devicon CDN and fallback to lucide-react icons.
- Added a glow effect for file icons in dark mode to improve visibility.
- Updated various components to utilize the new FileIcon component for consistent icon rendering.
- Refined keyboard shortcut handling to use event.code for layout-independent key detection, improving cross-platform compatibility.
- Enhanced the EditorTabBar with a context menu for tab management, including options to close tabs and manage open files more efficiently.
2026-03-01 14:24:24 +02:00

154 lines
4.9 KiB
TypeScript

/**
* Tests for fileIcons utility — extension-to-icon mapping with Devicon support.
*/
import { describe, expect, it } from 'vitest';
import { getDeviconUrl, getFileIcon } from '@renderer/components/team/editor/fileIcons';
describe('getFileIcon', () => {
it('returns TypeScript icon for .ts files', () => {
const info = getFileIcon('index.ts');
expect(info.color).toBe('#3178c6');
expect(info.deviconSlug).toBe('typescript');
});
it('returns TypeScript icon for .tsx files', () => {
const info = getFileIcon('App.tsx');
expect(info.color).toBe('#3178c6');
expect(info.deviconSlug).toBe('react');
});
it('returns JavaScript icon for .js files', () => {
const info = getFileIcon('app.js');
expect(info.color).toBe('#f7df1e');
expect(info.deviconSlug).toBe('javascript');
});
it('returns JSON icon for .json files', () => {
const info = getFileIcon('package.json');
// package.json has special mapping
expect(info.color).toBe('#cb3837');
expect(info.deviconSlug).toBe('nodejs');
});
it('returns markdown icon for .md files', () => {
const info = getFileIcon('README.md');
expect(info.color).toBe('#519aba');
expect(info.deviconSlug).toBe('markdown');
});
it('returns Python icon for .py files', () => {
const info = getFileIcon('main.py');
expect(info.color).toBe('#3572a5');
expect(info.deviconSlug).toBe('python');
});
it('returns Rust icon for .rs files', () => {
const info = getFileIcon('lib.rs');
expect(info.color).toBe('#dea584');
expect(info.deviconSlug).toBe('rust');
});
it('returns default icon for unknown extensions', () => {
const info = getFileIcon('file.xyz123');
expect(info.color).toBe('#89949f');
expect(info.deviconSlug).toBeUndefined();
});
it('returns default icon for files without extension', () => {
const info = getFileIcon('Procfile');
expect(info.color).toBe('#89949f');
expect(info.deviconSlug).toBeUndefined();
});
it('matches special filenames exactly', () => {
const docker = getFileIcon('Dockerfile');
expect(docker.color).toBe('#2496ed');
expect(docker.deviconSlug).toBe('docker');
const gitignore = getFileIcon('.gitignore');
expect(gitignore.color).toBe('#f05032');
expect(gitignore.deviconSlug).toBe('git');
const claudeMd = getFileIcon('CLAUDE.md');
expect(claudeMd.color).toBe('#d97706');
expect(claudeMd.deviconSlug).toBeUndefined();
});
it('prefers filename match over extension match', () => {
// tsconfig.json should match FILENAME_MAP, not generic .json
const tsconfig = getFileIcon('tsconfig.json');
expect(tsconfig.color).toBe('#3178c6');
expect(tsconfig.deviconSlug).toBe('typescript');
});
it('returns lock icon for sensitive files', () => {
const env = getFileIcon('.env');
expect(env.color).toBe('#e5a00d');
expect(env.deviconSlug).toBeUndefined();
const pnpmLock = getFileIcon('pnpm-lock.yaml');
expect(pnpmLock.color).toBe('#f69220');
expect(pnpmLock.deviconSlug).toBeUndefined();
});
it('handles image files', () => {
const png = getFileIcon('logo.png');
expect(png.color).toBe('#a074c4');
expect(png.deviconSlug).toBeUndefined();
const svg = getFileIcon('icon.svg');
expect(svg.color).toBe('#ffb13b');
expect(svg.deviconSlug).toBeUndefined();
});
it('provides devicon slugs for major languages', () => {
const cases: [string, string][] = [
['app.go', 'go'],
['lib.rb', 'ruby'],
['Main.java', 'java'],
['style.css', 'css3'],
['page.html', 'html5'],
['Component.vue', 'vuejs'],
['App.svelte', 'svelte'],
['main.dart', 'dart'],
['app.swift', 'swift'],
['main.php', 'php'],
['main.kt', 'kotlin'],
['main.scala', 'scala'],
['app.ex', 'elixir'],
['query.graphql', 'graphql'],
];
for (const [fileName, expectedSlug] of cases) {
const info = getFileIcon(fileName);
expect(info.deviconSlug, `Expected ${fileName} to have slug "${expectedSlug}"`).toBe(
expectedSlug
);
}
});
it('provides devicon slugs for special config files', () => {
expect(getFileIcon('vite.config.ts').deviconSlug).toBe('vitejs');
expect(getFileIcon('docker-compose.yml').deviconSlug).toBe('docker');
expect(getFileIcon('.eslintrc').deviconSlug).toBe('eslint');
expect(getFileIcon('Cargo.toml').deviconSlug).toBe('rust');
expect(getFileIcon('go.mod').deviconSlug).toBe('go');
expect(getFileIcon('tailwind.config.js').deviconSlug).toBe('tailwindcss');
});
});
describe('getDeviconUrl', () => {
it('builds correct CDN URL for a slug', () => {
const url = getDeviconUrl('typescript');
expect(url).toBe(
'https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/typescript/typescript-original.svg'
);
});
it('works for multi-word slugs', () => {
const url = getDeviconUrl('cplusplus');
expect(url).toContain('/cplusplus/cplusplus-original.svg');
});
});