Files
bitmappery/tests/unit/utils/document-util.spec.ts
Igor Zinken b205a553d9 Restructure document model, factories and actions (#93)
Split `definitions/document.ts` into unique files per actor type.
Create `model` folder to store the above types, their factories and the state changing actions.
2026-04-19 20:34:06 +02:00

131 lines
6.0 KiB
TypeScript

import { it, describe, expect, beforeEach, vi } from "vitest";
import { createMockCanvasElement, mockZCanvas } from "../mocks";
import type { Document } from "@/model/types/document";
import type { Layer } from "@/model/types/layer";
import DocumentFactory from "@/model/factories/document-factory";
import LayerFactory from "@/model/factories/layer-factory";
import TextFactory from "@/model/factories/text-factory";
import { cloneLayers, getAlignableObjects, restoreFromClone } from "@/utils/document-util";
mockZCanvas();
vi.mock( "@/utils/canvas-util", () => ({
createCanvas : vi.fn().mockReturnValue({ cvs: {}, ctx: {}}),
cloneCanvas: ( cvs: HTMLCanvasElement ): HTMLCanvasElement => cvs
}));
describe( "Document utilities", () => {
describe( "When calculating the alignable objects within a document", () => {
let document: Document;
let width: number;
let height: number;
beforeEach(() => {
document = DocumentFactory.create();
({ width, height } = document );
});
it( "should be able to calculate the documents horizontal and vertical center", () => {
const alignableObjects = getAlignableObjects( document );
expect( alignableObjects ).toEqual([
{ left: 0, top: height / 2, width, height: 0 }, // vertical document center
{ left: width / 2, top: 0, width: 0, height } // horizontal document center
]);
});
it( "should ignore layers that are currently invisible", () => {
const layer = LayerFactory.create({ left: 10, top: 10, width: width / 2, height: height / 2, visible: false });
document.layers.push( layer );
const alignableObjects = getAlignableObjects( document );
expect( alignableObjects ).toEqual([
{ left: 0, top: height / 2, width, height: 0 }, // vertical document center
{ left: width / 2, top: 0, width: 0, height } // horizontal document center
]);
});
it( "should ignore layers that occupy the same bounding box as the document to prevent duplicates", () => {
document.layers.push( LayerFactory.create({ left: 0, top: 0, width, height }));
const alignableObjects = getAlignableObjects( document );
expect( alignableObjects ).toEqual([
{ left: 0, top: height / 2, width, height: 0 }, // vertical document center
{ left: width / 2, top: 0, width: 0, height } // horizontal document center
]);
});
it( "should be able to calculate the horizontal and vertical center for each additional layer", () => {
document.layers.push( LayerFactory.create({ left: 10, top: 10, width: width / 2, height: height / 2 }));
const alignableObjects = getAlignableObjects( document );
expect( alignableObjects ).toEqual([
{ left: 0, top: height / 2, width, height: 0 }, // vertical document center
{ left: width / 2, top: 0, width: 0, height }, // horizontal document center
// added layer
{ left: 0, top: 10, width, height: 0 }, // vertical layer top
{ left: 0, top: 260, width, height: 0 }, // vertical layer center
{ left: 0, top: 510, width, height: 0 }, // vertical layer bottom
{ left: 10, top: 0, width: 0, height }, // horizontal layer left
{ left: 260, top: 0, width: 0, height }, // horizontal layer center
{ left: 510, top: 0, width: 0, height }, // horizontal layer right
]);
});
it( "should ignore the optionally provided layer to exclude", () => {
const layer = LayerFactory.create({ left: 10, top: 10, width: width / 2, height: height / 2 });
document.layers.push( layer );
const alignableObjects = getAlignableObjects( document, layer );
expect( alignableObjects ).toEqual([
{ left: 0, top: height / 2, width, height: 0 }, // vertical document center
{ left: width / 2, top: 0, width: 0, height } // horizontal document center
]);
});
});
it( "Should be able to clone and restore a Documents Layers contents", () => {
const layer1mask = createMockCanvasElement();
const layer1source = createMockCanvasElement();
const layer1props = {
left: 1, top: 2, width: 3, height: 4, maskX: 5, maskY: 6, mask: layer1mask, source: layer1source,
text: TextFactory.create({ value: "foo bar" }),
};
const layer2mask = createMockCanvasElement();
const layer2source = createMockCanvasElement();
const layer2props = {
left: -5, top: -5, width: 10, height: 15, maskX: 0, maskY: 0, mask: layer2mask, source: layer2source
};
const layer1 = LayerFactory.create( layer1props );
const layer2 = LayerFactory.create( layer2props );
// create document
const document = DocumentFactory.create({ layers: [ layer1, layer2 ]});
// clone document content
const clonedLayers = cloneLayers( document );
// adjust document data
for ( const layer of document.layers ) {
layer.left = 10;
layer.top = 10;
layer.width = 30;
layer.height = 40;
layer.maskX = 100;
layer.maskY = 100;
layer.text = TextFactory.create({ value: "baz qux" });
layer.source = createMockCanvasElement();
layer.mask = createMockCanvasElement();
}
// restore clone
restoreFromClone( document, clonedLayers );
// assert properties have been restored
Object.entries( layer1props ).forEach(([ key, value ]) => {
expect( layer1[ key as keyof Layer ]).toEqual( value );
});
Object.entries( layer2props ).forEach(([ key, value ]) => {
expect( layer2[ key as keyof Layer ]).toEqual( value );
});
});
});