import { beforeEach, describe, expect, it } from 'vitest'; import { createEmptyMap } from '@/services/mapFactory'; import { getTheme } from '@/features/editor/themes'; import { resolveNodeAppearance } from '@/features/editor/nodeStyleResolver'; import { estimateNodeSize } from '@/utils/nodeSize'; import { useEditorStore } from '@/stores/editorStore'; function store() { return useEditorStore.getState(); } function rootId(): string { return store().map?.nodes[0]?.id as string; } function nodeById(id: string) { return store().map?.nodes.find((node) => node.id === id); } function layoutOf(id: string) { return nodeById(id)?.layout; } /** Cree un noeud circulaire et renvoie son identifiant. */ function circleNode(): string { const id = store().addChild(rootId()) as string; store().setEditingNode(null); store().updateNodeText(id, 'Coeur de reseau'); store().updateNodesStyle([id], { shape: 'circle' }); return id; } beforeEach(() => { useEditorStore.getState().loadMap(createEmptyMap('Cercles')); }); describe('noeud circulaire', () => { it('reste carre en dimensionnement automatique', () => { const id = circleNode(); const node = nodeById(id); const size = estimateNodeSize(node!, getTheme('default')); expect(size.width).toBe(size.height); expect(resolveNodeAppearance(node!, 1, getTheme('default')).circle).toBe(true); }); it('reste carre pendant un redimensionnement a la souris', () => { const id = circleNode(); store().beginResize(); for (const [width, height] of [ [100, 100], [150, 148], [220, 90], ] as Array<[number, number]>) { store().resizeNode(id, { width, height }); expect(layoutOf(id)?.width).toBe(layoutOf(id)?.height); } // Le cote retenu est le plus grand des deux, jamais un ovale. expect(layoutOf(id)?.width).toBe(220); expect(layoutOf(id)?.height).toBe(220); }); it('fait suivre la hauteur quand la largeur change', () => { const id = circleNode(); store().updateNodesLayout([id], { widthMode: 'fixed', width: 180 }); expect(layoutOf(id)?.width).toBe(180); expect(layoutOf(id)?.height).toBe(180); expect(layoutOf(id)?.heightMode).toBe('fixed'); }); it('fait suivre la largeur quand la hauteur change', () => { const id = circleNode(); store().updateNodesLayout([id], { heightMode: 'fixed', height: 260 }); expect(layoutOf(id)?.width).toBe(260); expect(layoutOf(id)?.height).toBe(260); expect(layoutOf(id)?.widthMode).toBe('fixed'); }); it('carre un noeud rectangulaire converti en cercle', () => { const id = store().addChild(rootId()) as string; store().setEditingNode(null); store().updateNodesLayout([id], { widthMode: 'fixed', width: 320, heightMode: 'fixed', height: 90, }); store().updateNodesStyle([id], { shape: 'circle' }); expect(layoutOf(id)?.width).toBe(320); expect(layoutOf(id)?.height).toBe(320); }); it('annule tout un redimensionnement circulaire en une seule fois', () => { const id = circleNode(); const before = store().past.length; store().beginResize(); for (let side = 120; side <= 200; side += 20) { store().resizeNode(id, { width: side, height: side }); } expect(store().past.length).toBe(before + 1); store().undo(); expect(layoutOf(id)?.width).toBeUndefined(); expect(layoutOf(id)?.height).toBeUndefined(); expect(nodeById(id)?.style?.shape).toBe('circle'); }); it('laisse les autres formes libres de leurs proportions', () => { const id = store().addChild(rootId()) as string; store().setEditingNode(null); store().updateNodesStyle([id], { shape: 'rounded' }); store().beginResize(); store().resizeNode(id, { width: 300, height: 80 }); expect(layoutOf(id)?.width).toBe(300); expect(layoutOf(id)?.height).toBe(80); }); });