mirror of
https://github.com/OFFIS-ESC/constellation-analyzer
synced 2026-01-27 07:43:41 +00:00
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)
This commit is contained in:
parent
97583e412a
commit
28719d8953
5 changed files with 63 additions and 43 deletions
|
|
@ -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 },
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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<string, unknown>;
|
||||
const states = snapshot?.timeline.states as Record<string, unknown> | 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', () => {
|
||||
|
|
|
|||
|
|
@ -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<string, ConstellationState>;
|
||||
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: [],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export function useActiveDocument() {
|
|||
const graphLabels = useGraphStore((state) => state.labels);
|
||||
|
||||
// Track unload timers for inactive documents
|
||||
const unloadTimersRef = useRef<Map<string, number>>(new Map());
|
||||
const unloadTimersRef = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());
|
||||
|
||||
// Track when we're loading a document to prevent false dirty marking
|
||||
const isLoadingRef = useRef(false);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue