- {(['Folder', 'File', 'Class', 'Function', 'Interface', 'Method'] as NodeLabel[]).map(label => (
+ {(['Folder', 'File', 'Class', 'Interface', 'Enum', 'Type', 'Function', 'Method', 'Variable', 'Decorator'] as NodeLabel[]).map(label => (
{
});
});
+describe('FILTERABLE_LABELS', () => {
+ it('includes all newly added node types', () => {
+ expect(FILTERABLE_LABELS).toContain('Enum');
+ expect(FILTERABLE_LABELS).toContain('Type');
+ expect(FILTERABLE_LABELS).toContain('Decorator');
+ expect(FILTERABLE_LABELS).toContain('Variable');
+ });
+
+ it('every filterable label has a defined color in NODE_COLORS', () => {
+ for (const label of FILTERABLE_LABELS) {
+ expect(NODE_COLORS).toHaveProperty(label);
+ expect(NODE_COLORS[label as keyof typeof NODE_COLORS]).toMatch(/^#[0-9a-f]{6}$/i);
+ }
+ });
+
+ it('every filterable label has a defined size in NODE_SIZES', () => {
+ for (const label of FILTERABLE_LABELS) {
+ expect(NODE_SIZES).toHaveProperty(label);
+ expect(NODE_SIZES[label as keyof typeof NODE_SIZES]).toBeGreaterThan(0);
+ }
+ });
+
+ it('has no duplicate entries', () => {
+ const unique = new Set(FILTERABLE_LABELS);
+ expect(unique.size).toBe(FILTERABLE_LABELS.length);
+ });
+
+ it('is a subset of DEFAULT_VISIBLE_LABELS plus togglable labels', () => {
+ const allKnown = new Set(Object.keys(NODE_COLORS));
+ for (const label of FILTERABLE_LABELS) {
+ expect(allKnown.has(label)).toBe(true);
+ }
+ });
+});
+
describe('edge types', () => {
it('ALL_EDGE_TYPES contains all EDGE_INFO keys', () => {
const edgeInfoKeys = Object.keys(EDGE_INFO).sort();
diff --git a/gitnexus-web/test/unit/filter-panel.test.ts b/gitnexus-web/test/unit/filter-panel.test.ts
new file mode 100644
index 0000000000..19d20fb020
--- /dev/null
+++ b/gitnexus-web/test/unit/filter-panel.test.ts
@@ -0,0 +1,81 @@
+import { describe, expect, it } from 'vitest';
+import { FILTERABLE_LABELS, NODE_COLORS } from '../../src/lib/constants';
+import type { NodeLabel } from '../../src/core/graph/types';
+import * as lucideIcons from '../../src/lib/lucide-icons';
+
+const LEGEND_LABELS: NodeLabel[] = [
+ 'Folder', 'File', 'Class', 'Interface', 'Enum', 'Type',
+ 'Function', 'Method', 'Variable', 'Decorator',
+];
+
+const ICON_MAP: Record = {
+ Folder: 'Folder',
+ File: 'FileCode',
+ Class: 'Box',
+ Function: 'Braces',
+ Method: 'Braces',
+ Interface: 'Hash',
+ Enum: 'List',
+ Type: 'Type',
+ Decorator: 'AtSign',
+ Import: 'FileCode',
+ Variable: 'Variable',
+};
+
+describe('filter panel icon mappings', () => {
+ it('every filterable label has a mapped icon', () => {
+ for (const label of FILTERABLE_LABELS) {
+ expect(ICON_MAP).toHaveProperty(label);
+ }
+ });
+
+ it('every mapped icon is exported from lucide-icons', () => {
+ const exportedNames = new Set(Object.keys(lucideIcons));
+ const requiredIcons = new Set(Object.values(ICON_MAP));
+ for (const iconName of requiredIcons) {
+ expect(exportedNames.has(iconName), `${iconName} should be exported from lucide-icons`).toBe(true);
+ }
+ });
+
+ it('newly added node types have distinct icons', () => {
+ expect(ICON_MAP.Enum).toBe('List');
+ expect(ICON_MAP.Type).toBe('Type');
+ expect(ICON_MAP.Decorator).toBe('AtSign');
+ });
+});
+
+describe('color legend', () => {
+ it('includes all newly added node types', () => {
+ expect(LEGEND_LABELS).toContain('Enum');
+ expect(LEGEND_LABELS).toContain('Type');
+ expect(LEGEND_LABELS).toContain('Decorator');
+ expect(LEGEND_LABELS).toContain('Variable');
+ });
+
+ it('every legend label has a color defined', () => {
+ for (const label of LEGEND_LABELS) {
+ expect(NODE_COLORS).toHaveProperty(label);
+ expect(NODE_COLORS[label]).toMatch(/^#[0-9a-f]{6}$/i);
+ }
+ });
+
+ it('legend labels match the order used in FileTreePanel', () => {
+ const expected: NodeLabel[] = [
+ 'Folder', 'File', 'Class', 'Interface', 'Enum', 'Type',
+ 'Function', 'Method', 'Variable', 'Decorator',
+ ];
+ expect(LEGEND_LABELS).toEqual(expected);
+ });
+
+ it('legend labels are a subset of filterable labels plus Import', () => {
+ const filterableSet = new Set(FILTERABLE_LABELS);
+ for (const label of LEGEND_LABELS) {
+ expect(filterableSet.has(label), `${label} should be in FILTERABLE_LABELS`).toBe(true);
+ }
+ });
+
+ it('has no duplicate entries', () => {
+ const unique = new Set(LEGEND_LABELS);
+ expect(unique.size).toBe(LEGEND_LABELS.length);
+ });
+});