- "app/src/types/canvas.ts" - "app/src/hooks/useCanvasState.ts" - "app/src/hooks/__tests__/useCanvasState.test.ts" - "app/src/utils/artboardShapes.ts" - "app/src/utils/__tests__/artboardShapes.test.ts" - "app/src/utils/alignment.ts" - "app/src/utils/__tests__/alignment.test.ts" - "app/src/components/canvas/ArtboardSetup.tsx" GSD-Task: S02/T01
104 lines
3.1 KiB
TypeScript
104 lines
3.1 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
shieldPath,
|
|
pennantPath,
|
|
toPx,
|
|
fromPx,
|
|
artboardClipPath,
|
|
ARTBOARD_PRESETS,
|
|
} from '../artboardShapes';
|
|
import type { ArtboardConfig } from '../../types/canvas';
|
|
|
|
describe('artboardShapes', () => {
|
|
describe('ARTBOARD_PRESETS', () => {
|
|
it('has presets for all shapes', () => {
|
|
const shapes = ['rect', 'square', 'circle', 'oval', 'shield', 'pennant', 'custom'] as const;
|
|
for (const s of shapes) {
|
|
expect(ARTBOARD_PRESETS[s]).toBeDefined();
|
|
expect(ARTBOARD_PRESETS[s].width).toBeGreaterThan(0);
|
|
expect(ARTBOARD_PRESETS[s].height).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
|
|
it('square preset has equal width and height', () => {
|
|
expect(ARTBOARD_PRESETS.square.width).toBe(ARTBOARD_PRESETS.square.height);
|
|
});
|
|
|
|
it('circle preset has equal width and height', () => {
|
|
expect(ARTBOARD_PRESETS.circle.width).toBe(ARTBOARD_PRESETS.circle.height);
|
|
});
|
|
});
|
|
|
|
describe('shieldPath', () => {
|
|
it('produces a closed SVG path', () => {
|
|
const p = shieldPath(100, 120);
|
|
expect(p).toContain('M');
|
|
expect(p).toContain('Z');
|
|
});
|
|
|
|
it('stays within bounding box', () => {
|
|
const p = shieldPath(200, 300);
|
|
// path starts at indent, ends at w-indent so all coords ≤ 200/300
|
|
expect(p).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('pennantPath', () => {
|
|
it('produces a triangular closed path', () => {
|
|
const p = pennantPath(100, 200);
|
|
expect(p).toBe('M 0 0 L 100 0 L 50 200 Z');
|
|
});
|
|
});
|
|
|
|
describe('toPx / fromPx', () => {
|
|
it('converts inches to pixels at 96 PPI', () => {
|
|
expect(toPx(1, 'inches')).toBe(96);
|
|
expect(toPx(2, 'inches')).toBe(192);
|
|
});
|
|
|
|
it('converts mm to pixels', () => {
|
|
const px = toPx(25.4, 'mm');
|
|
expect(px).toBeCloseTo(96, 1);
|
|
});
|
|
|
|
it('fromPx inverts toPx for inches', () => {
|
|
expect(fromPx(96, 'inches')).toBe(1);
|
|
});
|
|
|
|
it('fromPx inverts toPx for mm', () => {
|
|
expect(fromPx(toPx(10, 'mm'), 'mm')).toBeCloseTo(10, 5);
|
|
});
|
|
});
|
|
|
|
describe('artboardClipPath', () => {
|
|
it('returns undefined for rect', () => {
|
|
const cfg: ArtboardConfig = { shape: 'rect', width: 4, height: 6, unit: 'inches' };
|
|
expect(artboardClipPath(cfg)).toBeUndefined();
|
|
});
|
|
|
|
it('returns a path string for shield', () => {
|
|
const cfg: ArtboardConfig = { shape: 'shield', width: 4, height: 5, unit: 'inches' };
|
|
const p = artboardClipPath(cfg);
|
|
expect(p).toBeDefined();
|
|
expect(p).toContain('Z');
|
|
});
|
|
|
|
it('returns a triangular path for pennant', () => {
|
|
const cfg: ArtboardConfig = { shape: 'pennant', width: 3, height: 8, unit: 'inches' };
|
|
const p = artboardClipPath(cfg);
|
|
expect(p).toBeDefined();
|
|
expect(p).toContain('Z');
|
|
});
|
|
|
|
it('returns custom clipPath when shape is custom', () => {
|
|
const cfg: ArtboardConfig = {
|
|
shape: 'custom',
|
|
width: 4,
|
|
height: 4,
|
|
unit: 'inches',
|
|
clipPath: 'M 0 0 L 50 0 L 50 50 Z',
|
|
};
|
|
expect(artboardClipPath(cfg)).toBe('M 0 0 L 50 0 L 50 50 Z');
|
|
});
|
|
});
|
|
});
|