From 28719d89531b68dd141c97e66b9bdda066e6d4ad Mon Sep 17 00:00:00 2001 From: Jan-Henrik Bruhn Date: Mon, 10 Nov 2025 12:13:07 +0100 Subject: [PATCH] Running the CI Tests results in errors (see the run here: https://github.com/OFFIS-ESC/constellation-analyzer/actions/runs/19229156468 ). Why is that? (vibe-kanban b6717985) --- src/stores/graphStore.test.ts | 50 +++++++++++++---------- src/stores/historyStore.test.ts | 8 ++-- src/stores/timelineStore.test.ts | 42 ++++++++++++------- src/stores/workspace/useActiveDocument.ts | 2 +- src/test/mocks.ts | 4 +- 5 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/stores/graphStore.test.ts b/src/stores/graphStore.test.ts index 2671c2b..ece8290 100644 --- a/src/stores/graphStore.test.ts +++ b/src/stores/graphStore.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { useGraphStore } from './graphStore'; -import type { Actor, Relation, Group, NodeTypeConfig, EdgeTypeConfig, LabelConfig } from '../types'; +import type { Actor, Relation, Group, NodeTypeConfig, EdgeTypeConfig, LabelConfig, NodeShape } from '../types'; import { MINIMIZED_GROUP_WIDTH, MINIMIZED_GROUP_HEIGHT } from '../constants'; // Helper to create a mock node @@ -10,8 +10,8 @@ function createMockNode(id: string, actorType: string = 'person'): Actor { type: 'custom', position: { x: 100, y: 100 }, data: { - actorType, - name: `Test ${id}`, + type: actorType, + label: `Test ${id}`, description: 'Test description', }, }; @@ -25,7 +25,7 @@ function createMockEdge(id: string, source: string, target: string, relationType target, type: 'custom', data: { - relationType, + type: relationType, description: 'Test relation', }, }; @@ -39,6 +39,7 @@ function createMockGroup(id: string, actorIds: string[] = []): Group { position: { x: 0, y: 0 }, data: { label: `Group ${id}`, + color: '#cccccc', actorIds, minimized: false, }, @@ -158,33 +159,35 @@ describe('graphStore', () => { const { updateNode } = useGraphStore.getState(); updateNode('node-1', { - data: { name: 'Updated Name', actorType: 'person' }, + data: { label: 'Updated Name', type: 'person' }, }); const state = useGraphStore.getState(); - expect(state.nodes[0].data.name).toBe('Updated Name'); + expect(state.nodes[0].data.label).toBe('Updated Name'); }); it('should merge data instead of replacing', () => { const { updateNode } = useGraphStore.getState(); updateNode('node-1', { - data: { description: 'New description' }, + data: { label: 'Test node-1', type: 'person', description: 'New description' }, }); const state = useGraphStore.getState(); - expect(state.nodes[0].data.name).toBe('Test node-1'); // Preserved + expect(state.nodes[0].data.label).toBe('Test node-1'); // Preserved expect(state.nodes[0].data.description).toBe('New description'); // Updated }); it('should validate labels against existing labels', () => { const { addLabel, updateNode } = useGraphStore.getState(); - addLabel({ id: 'label-1', label: 'Valid', color: '#000' }); - addLabel({ id: 'label-2', label: 'Also Valid', color: '#111' }); + addLabel({ id: 'label-1', name: 'Valid', color: '#000', appliesTo: 'actors' }); + addLabel({ id: 'label-2', name: 'Also Valid', color: '#111', appliesTo: 'actors' }); updateNode('node-1', { data: { + label: 'Test node-1', + type: 'person', labels: ['label-1', 'label-999', 'label-2'], // label-999 doesn't exist }, }); @@ -198,6 +201,8 @@ describe('graphStore', () => { updateNode('node-1', { data: { + label: 'Test node-1', + type: 'person', labels: ['invalid-1', 'invalid-2'], }, }); @@ -359,7 +364,7 @@ describe('graphStore', () => { it('should validate labels against existing labels', () => { const { addLabel, updateEdge } = useGraphStore.getState(); - addLabel({ id: 'label-1', label: 'Valid', color: '#000' }); + addLabel({ id: 'label-1', name: 'Valid', color: '#000', appliesTo: 'relations' }); updateEdge('edge-1', { labels: ['label-1', 'invalid-label'], @@ -805,8 +810,9 @@ describe('graphStore', () => { const label: LabelConfig = { id: 'label-1', - label: 'Important', + name: 'Important', color: '#ff0000', + appliesTo: 'both', }; addLabel(label); @@ -820,16 +826,16 @@ describe('graphStore', () => { describe('updateLabel', () => { beforeEach(() => { const { addLabel } = useGraphStore.getState(); - addLabel({ id: 'label-1', label: 'Test', color: '#000' }); + addLabel({ id: 'label-1', name: 'Test', color: '#000', appliesTo: 'both' }); }); it('should update label', () => { const { updateLabel } = useGraphStore.getState(); - updateLabel('label-1', { label: 'Updated', color: '#fff' }); + updateLabel('label-1', { name: 'Updated', color: '#fff' }); const state = useGraphStore.getState(); - expect(state.labels[0].label).toBe('Updated'); + expect(state.labels[0].name).toBe('Updated'); expect(state.labels[0].color).toBe('#fff'); }); }); @@ -837,8 +843,8 @@ describe('graphStore', () => { describe('deleteLabel', () => { beforeEach(() => { const { addNode, addEdge, addLabel } = useGraphStore.getState(); - addLabel({ id: 'label-1', label: 'Test', color: '#000' }); - addLabel({ id: 'label-2', label: 'Other', color: '#111' }); + addLabel({ id: 'label-1', name: 'Test', color: '#000', appliesTo: 'both' }); + addLabel({ id: 'label-2', name: 'Other', color: '#111', appliesTo: 'both' }); // Add nodes and edges with labels const node = createMockNode('node-1'); @@ -846,7 +852,7 @@ describe('graphStore', () => { addNode(node); const edge = createMockEdge('edge-1', 'node-1', 'node-1'); - edge.data = { ...edge.data, labels: ['label-1'] }; + edge.data = { ...edge.data, type: 'collaborates', labels: ['label-1'] }; addEdge(edge); }); @@ -972,7 +978,7 @@ describe('graphStore', () => { it('should set labels', () => { const { setLabels } = useGraphStore.getState(); const labels: LabelConfig[] = [ - { id: 'label-1', label: 'Test', color: '#000' }, + { id: 'label-1', name: 'Test', color: '#000', appliesTo: 'both' }, ]; setLabels(labels); @@ -991,13 +997,13 @@ describe('graphStore', () => { edges: [createMockEdge('edge-1', 'node-1', 'node-1')], groups: [createMockGroup('group-1')], nodeTypes: [ - { id: 'custom', label: 'Custom', color: '#000', shape: 'circle', icon: 'Test', description: 'Test' }, + { id: 'custom', label: 'Custom', color: '#000', shape: 'circle' as NodeShape, icon: 'Test', description: 'Test' }, ], edgeTypes: [ - { id: 'custom', label: 'Custom', color: '#000', style: 'solid' }, + { id: 'custom', label: 'Custom', color: '#000', style: 'solid' as const }, ], labels: [ - { id: 'label-1', label: 'Test', color: '#000' }, + { id: 'label-1', name: 'Test', color: '#000', appliesTo: 'both' as const }, ], }; diff --git a/src/stores/historyStore.test.ts b/src/stores/historyStore.test.ts index b218c80..0801d9e 100644 --- a/src/stores/historyStore.test.ts +++ b/src/stores/historyStore.test.ts @@ -327,7 +327,7 @@ describe('historyStore', () => { id: 'node-1', type: 'custom', position: { x: 100, y: 100 }, - data: { actorType: 'person', name: 'Test' }, + data: { type: 'person', label: 'Test' }, }, ], edges: [], @@ -342,9 +342,9 @@ describe('historyStore', () => { // Snapshot is serialized (Map -> object) during pushAction // Need to access states as a record object, not a Map - const states = snapshot?.timeline.states as Record; + const states = snapshot?.timeline.states as Record | undefined; const currentStateId = snapshot?.timeline.currentStateId; - const currentState = states[currentStateId] as { graph: { nodes: unknown[] } }; + const currentState = currentStateId && states ? states[currentStateId] as { graph: { nodes: unknown[] } } : undefined; expect(currentState?.graph.nodes).toHaveLength(1); }); @@ -872,7 +872,7 @@ describe('historyStore', () => { const history = state.histories.get(TEST_DOC_ID); // Should have consistent state - expect(history?.undoStack.length + history?.redoStack.length).toBe(10); + expect((history?.undoStack.length ?? 0) + (history?.redoStack.length ?? 0)).toBe(10); }); it('should handle empty snapshots', () => { diff --git a/src/stores/timelineStore.test.ts b/src/stores/timelineStore.test.ts index 86fadc6..9fee2e0 100644 --- a/src/stores/timelineStore.test.ts +++ b/src/stores/timelineStore.test.ts @@ -1,5 +1,7 @@ import { describe, it, expect, beforeEach, vi } from 'vitest'; import { useTimelineStore } from './timelineStore'; +import type { Timeline, ConstellationState } from '../types/timeline'; +import type { Actor, Relation, Group, NodeTypeConfig, EdgeTypeConfig, LabelConfig } from '../types'; // Mock dependent stores const mockShowToast = vi.fn(); @@ -8,7 +10,15 @@ const mockLoadGraphState = vi.fn(); const mockPushToHistory = vi.fn(); // Create a mutable mock state for graphStore -const mockGraphState = { +const mockGraphState: { + nodes: Actor[]; + edges: Relation[]; + groups: Group[]; + nodeTypes: NodeTypeConfig[]; + edgeTypes: EdgeTypeConfig[]; + labels: LabelConfig[]; + loadGraphState: typeof mockLoadGraphState; +} = { nodes: [], edges: [], groups: [], @@ -133,7 +143,7 @@ describe('timelineStore', () => { const { initializeTimeline } = useTimelineStore.getState(); const initialGraph = { - nodes: [{ id: 'node-1', type: 'custom', position: { x: 0, y: 0 }, data: {} }], + nodes: [{ id: 'node-1', type: 'custom', position: { x: 0, y: 0 }, data: { label: 'Test', type: 'person' } }], edges: [], groups: [], }; @@ -141,7 +151,7 @@ describe('timelineStore', () => { initializeTimeline(TEST_DOC_ID, initialGraph); // Modify original - initialGraph.nodes.push({ id: 'node-2', type: 'custom', position: { x: 0, y: 0 }, data: {} }); + initialGraph.nodes.push({ id: 'node-2', type: 'custom', position: { x: 0, y: 0 }, data: { label: 'Test', type: 'person' } }); // Timeline should be unaffected const state = useTimelineStore.getState(); @@ -184,7 +194,11 @@ describe('timelineStore', () => { const { loadTimeline } = useTimelineStore.getState(); // Simulate loaded JSON (states as plain object) - const timelineFromJSON = { + const timelineFromJSON: { + states: Record; + currentStateId: string; + rootStateId: string; + } = { states: { 'state-1': { id: 'state-1', @@ -199,7 +213,7 @@ describe('timelineStore', () => { rootStateId: 'state-1', }; - loadTimeline(TEST_DOC_ID, timelineFromJSON as Timeline); + loadTimeline(TEST_DOC_ID, timelineFromJSON as unknown as Timeline); const state = useTimelineStore.getState(); const timeline = state.timelines.get(TEST_DOC_ID); @@ -233,7 +247,7 @@ describe('timelineStore', () => { const { createState } = useTimelineStore.getState(); // Simulate current graph with nodes by mutating mockGraphState - mockGraphState.nodes = [{ id: 'node-1', type: 'custom', position: { x: 0, y: 0 }, data: {} }]; + mockGraphState.nodes = [{ id: 'node-1', type: 'custom', position: { x: 0, y: 0 }, data: { label: 'Test', type: 'person' } }]; const newStateId = createState('With Nodes'); @@ -345,7 +359,7 @@ describe('timelineStore', () => { const { switchToState, getAllStates } = useTimelineStore.getState(); // Mock current graph with nodes by mutating mockGraphState - mockGraphState.nodes = [{ id: 'node-modified', type: 'custom', position: { x: 100, y: 100 }, data: {} }]; + mockGraphState.nodes = [{ id: 'node-modified', type: 'custom', position: { x: 100, y: 100 }, data: { label: 'Test', type: 'person' } }]; const states = getAllStates(); const currentStateId = states[2].id; // Current is State 3 @@ -415,13 +429,13 @@ describe('timelineStore', () => { it('should merge metadata', () => { const { updateState, getState } = useTimelineStore.getState(); - updateState(stateId, { metadata: { custom: 'value1' } }); - updateState(stateId, { metadata: { another: 'value2' } }); + updateState(stateId, { metadata: { date: '2024-01-01' } }); + updateState(stateId, { metadata: { color: '#FF0000' } }); const updatedState = getState(stateId); expect(updatedState?.metadata).toEqual({ - custom: 'value1', - another: 'value2', + date: '2024-01-01', + color: '#FF0000', }); }); @@ -574,7 +588,7 @@ describe('timelineStore', () => { const originalState = timeline?.states.get(stateId); if (originalState) { originalState.graph = { - nodes: [{ id: 'node-1', type: 'custom', position: { x: 0, y: 0 }, data: {} }], + nodes: [{ id: 'node-1', type: 'custom', position: { x: 0, y: 0 }, data: { label: 'Test', type: 'person' } }], edges: [], groups: [], }; @@ -587,7 +601,7 @@ describe('timelineStore', () => { // Modify original if (originalState) { - originalState.graph.nodes.push({ id: 'node-2', type: 'custom', position: { x: 0, y: 0 }, data: {} }); + originalState.graph.nodes.push({ id: 'node-2', type: 'custom', position: { x: 0, y: 0 }, data: { label: 'Test', type: 'person' } }); } // Duplicate should be unaffected @@ -702,7 +716,7 @@ describe('timelineStore', () => { const currentStateId = timeline?.currentStateId; const newGraph = { - nodes: [{ id: 'node-1', type: 'custom', position: { x: 0, y: 0 }, data: {} }], + nodes: [{ id: 'node-1', type: 'custom', position: { x: 0, y: 0 }, data: { label: 'Test', type: 'person' } }], edges: [], groups: [], }; diff --git a/src/stores/workspace/useActiveDocument.ts b/src/stores/workspace/useActiveDocument.ts index 3396424..f1fb24f 100644 --- a/src/stores/workspace/useActiveDocument.ts +++ b/src/stores/workspace/useActiveDocument.ts @@ -39,7 +39,7 @@ export function useActiveDocument() { const graphLabels = useGraphStore((state) => state.labels); // Track unload timers for inactive documents - const unloadTimersRef = useRef>(new Map()); + const unloadTimersRef = useRef>>(new Map()); // Track when we're loading a document to prevent false dirty marking const isLoadingRef = useRef(false); diff --git a/src/test/mocks.ts b/src/test/mocks.ts index 210c50a..eeffb89 100644 --- a/src/test/mocks.ts +++ b/src/test/mocks.ts @@ -22,8 +22,8 @@ export const mockEdgeTypes: EdgeTypeConfig[] = [ // Mock default labels export const mockLabels: LabelConfig[] = [ - { id: 'label-1', label: 'Important', color: '#ef4444' }, - { id: 'label-2', label: 'Archive', color: '#6b7280' }, + { id: 'label-1', name: 'Important', color: '#ef4444', appliesTo: 'both' }, + { id: 'label-2', name: 'Archive', color: '#6b7280', appliesTo: 'both' }, ]; // Create a mock document