Files

121 lines
3.8 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { AppState } from '../src/lib/app-state.svelte';
const image = { width: 100, height: 80, data: new Uint8ClampedArray(100 * 80 * 4) };
function withImage() {
const app = new AppState();
app.setImage(image);
return app;
}
describe('AppState', () => {
it('starts with sensible defaults', () => {
const app = new AppState();
expect(app.marginMm).toBe(-2);
expect(app.mode).toBe('auto');
expect(app.tool).toBe('none');
expect(app.shapePx).toBeNull();
expect(app.exportShape).toBeNull();
});
it('sets the scale from two clicks, then leaves the scale tool', () => {
const app = withImage();
app.tool = 'scale';
app.handleImageClick({ x: 10, y: 10 });
expect(app.tool).toBe('scale');
app.handleImageClick({ x: 70, y: 10 });
expect(app.tool).toBe('none');
app.lengthMm = 30;
expect(app.pxPerMm).toBeCloseTo(2);
expect(app.marginPx).toBeCloseTo(-4);
});
it('restarts the scale line on a third click', () => {
const app = withImage();
app.tool = 'scale';
app.handleImageClick({ x: 10, y: 10 });
app.handleImageClick({ x: 70, y: 10 });
app.tool = 'scale';
app.handleImageClick({ x: 5, y: 5 });
expect(app.scalePoints).toEqual([{ x: 5, y: 5 }]);
expect(app.pxPerMm).toBeNull();
});
it('flags an invalid scale and keeps the margin at 0 until the scale is valid', () => {
const app = withImage();
app.tool = 'scale';
app.handleImageClick({ x: 10, y: 10 });
app.handleImageClick({ x: 10, y: 10 });
app.lengthMm = 50;
expect(app.scaleInvalid).toBe(true);
expect(app.marginPx).toBe(0);
});
it('ignores clicks outside the image', () => {
const app = withImage();
app.tool = 'seed';
app.handleImageClick({ x: -1, y: 10 });
app.handleImageClick({ x: 50, y: 80 });
expect(app.seed).toBeNull();
expect(app.tool).toBe('seed');
});
it('sets the seed and leaves the seed tool', () => {
const app = withImage();
app.tool = 'seed';
app.handleImageClick({ x: 20, y: 30 });
expect(app.seed).toEqual({ x: 20, y: 30 });
expect(app.tool).toBe('none');
});
it('draws an outline then holes, switching to manual mode', () => {
const app = withImage();
app.tool = 'draw';
[{ x: 1, y: 1 }, { x: 90, y: 1 }, { x: 90, y: 70 }].forEach((p) => app.handleImageClick(p));
app.finishPolygon();
expect(app.manualOuter).toHaveLength(3);
expect(app.mode).toBe('manual');
[{ x: 20, y: 20 }, { x: 30, y: 20 }, { x: 30, y: 30 }].forEach((p) => app.handleImageClick(p));
app.finishPolygon();
expect(app.manualHoles).toHaveLength(1);
expect(app.drawing).toEqual([]);
});
it('discards a polygon with fewer than 3 points', () => {
const app = withImage();
app.tool = 'draw';
app.handleImageClick({ x: 1, y: 1 });
app.finishPolygon();
expect(app.manualOuter).toEqual([]);
expect(app.mode).toBe('auto');
});
it('clearManual returns to auto mode', () => {
const app = withImage();
app.tool = 'draw';
[{ x: 1, y: 1 }, { x: 90, y: 1 }, { x: 90, y: 70 }].forEach((p) => app.handleImageClick(p));
app.finishPolygon();
app.clearManual();
expect(app.mode).toBe('auto');
expect(app.manualOuter).toEqual([]);
expect(app.tool).toBe('none');
});
it('a new image resets scale, seed and manual work', () => {
const app = withImage();
app.tool = 'scale';
app.handleImageClick({ x: 10, y: 10 });
app.seed = { x: 5, y: 5 };
app.manualOuter = [{ x: 1, y: 1 }, { x: 2, y: 2 }, { x: 3, y: 1 }];
app.mode = 'manual';
app.setImage(image);
expect(app.scalePoints).toEqual([]);
expect(app.seed).toBeNull();
expect(app.manualOuter).toEqual([]);
expect(app.mode).toBe('auto');
expect(app.tool).toBe('none');
expect(app.threshold).toBe(128);
});
});