import { describe, expect, it } from 'vitest'; import { version } from '../../fabric'; import { Rect } from './Rect'; import { FabricObject } from './Object/FabricObject'; import { Gradient } from '../gradient'; import { Pattern } from '../Pattern'; // will require some kind of handling here import { getEnv } from '../env'; import { loadSVGFromString } from '../parser/loadSVGFromString'; const REFERENCE_RECT = { version, type: 'Rect', originX: 'left', originY: 'top', left: 0, top: 0, width: 0, height: 0, fill: 'rgb(0,0,0)', stroke: null, strokeWidth: 1, strokeDashArray: null, strokeLineCap: 'butt', strokeDashOffset: 0, strokeLineJoin: 'miter', strokeMiterLimit: 4, scaleX: 1, scaleY: 1, angle: 0, flipX: false, flipY: false, opacity: 1, shadow: null, visible: true, backgroundColor: '', fillRule: 'nonzero', paintFirst: 'fill', globalCompositeOperation: 'source-over', rx: 0, ry: 0, skewX: 0, skewY: 0, strokeUniform: false, }; describe('Rect', () => { it('constructor', function () { const rect = new Rect(); expect(rect).toBeInstanceOf(Rect); expect(rect, 'Inherits from FabricObject').toBeInstanceOf(FabricObject); expect(rect.constructor.type).toBe('Rect'); }); it('cache properties', function () { expect(Rect.cacheProperties, 'rx is in cacheProperties array').toContain( 'rx', ); expect(Rect.cacheProperties, 'ry is in cacheProperties array').toContain( 'ry', ); }); it('toObject', function () { const rect = new Rect(); const object = rect.toObject(); expect(object).toEqual(REFERENCE_RECT); }); it('fromObject', async () => { const rect = await Rect.fromObject(REFERENCE_RECT); expect(rect).toBeInstanceOf(Rect); expect(rect.toObject()).toEqual(REFERENCE_RECT); const expectedObject = { ...REFERENCE_RECT, fill: { type: 'linear', coords: { x1: 0, y1: 0, x2: 200, y2: 0 }, colorStops: [ { offset: '0', color: 'rgb(255,0,0)', opacity: 1 }, { offset: '1', color: 'rgb(0,0,255)', opacity: 1 }, ], offsetX: 0, offsetY: 0, }, stroke: { type: 'linear', coords: { x1: 0, y1: 0, x2: 200, y2: 0 }, colorStops: [ { offset: '0', color: 'rgb(255,0,0)', opacity: 1 }, { offset: '1', color: 'rgb(0,0,255)', opacity: 1 }, ], offsetX: 0, offsetY: 0, }, }; const rect2 = await Rect.fromObject(expectedObject); expect(rect2.fill).toBeInstanceOf(Gradient); expect(rect2.stroke).toBeInstanceOf(Gradient); }); it('Rect.fromObject with pattern fill', async () => { const fillObj = { type: 'Pattern', source: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==', }; const rect = await Rect.fromObject({ fill: fillObj }); expect(rect.fill).toBeInstanceOf(Pattern); }); it('Rect.fromElement', async () => { const elRect = getEnv().document.createElementNS( 'http://www.w3.org/2000/svg', 'rect', ); const rect = await Rect.fromElement(elRect); expect(rect).toBeInstanceOf(Rect); expect(rect.toObject()).toEqual({ ...REFERENCE_RECT, visible: false }); }); it('fromElement with custom attributes', async () => { const namespace = 'http://www.w3.org/2000/svg'; const elRectWithAttrs = getEnv().document.createElementNS( namespace, 'rect', ); elRectWithAttrs.setAttributeNS(namespace, 'x', '10'); elRectWithAttrs.setAttributeNS(namespace, 'y', '20'); elRectWithAttrs.setAttributeNS(namespace, 'width', '222'); elRectWithAttrs.setAttributeNS(namespace, 'height', '333'); elRectWithAttrs.setAttributeNS(namespace, 'rx', '11'); elRectWithAttrs.setAttributeNS(namespace, 'ry', '12'); elRectWithAttrs.setAttributeNS(namespace, 'fill', 'rgb(255,255,255)'); elRectWithAttrs.setAttributeNS(namespace, 'opacity', '0.45'); elRectWithAttrs.setAttributeNS(namespace, 'stroke', 'blue'); elRectWithAttrs.setAttributeNS(namespace, 'stroke-width', '3'); elRectWithAttrs.setAttributeNS(namespace, 'stroke-dasharray', '5, 2'); elRectWithAttrs.setAttributeNS(namespace, 'stroke-linecap', 'round'); elRectWithAttrs.setAttributeNS(namespace, 'stroke-linejoin', 'bevel'); elRectWithAttrs.setAttributeNS(namespace, 'stroke-miterlimit', '5'); elRectWithAttrs.setAttributeNS( namespace, 'vector-effect', 'non-scaling-stroke', ); const rectWithAttrs = await Rect.fromElement(elRectWithAttrs); expect(rectWithAttrs).toBeInstanceOf(Rect); expect(rectWithAttrs.strokeUniform, 'strokeUniform is parsed').toBe(true); const expectedObject = { ...REFERENCE_RECT, left: 10, top: 20, width: 222, height: 333, fill: 'rgb(255,255,255)', opacity: 0.45, stroke: 'blue', strokeWidth: 3, strokeDashArray: [5, 2], strokeLineCap: 'round', strokeLineJoin: 'bevel', strokeMiterLimit: 5, rx: 11, ry: 12, strokeUniform: true, }; expect(rectWithAttrs.toObject()).toEqual(expectedObject); }); it('clone with rounded corners', async () => { const rect = new Rect({ width: 100, height: 100, rx: 20, ry: 30 }); const clone = await rect.clone(); expect(clone.get('rx'), rect.get('rx')); expect(clone.get('ry'), rect.get('ry')); }); it('toSVG with rounded corners', async () => { const rect = new Rect({ width: 100, height: 100, rx: 20, ry: 30, strokeWidth: 0, }); const svg = rect.toSVG(); expect(svg).toBe( '\n\n\n', ); }); it('toSVG with alpha colors fill', async () => { const rect = new Rect({ width: 100, height: 100, strokeWidth: 0, fill: 'rgba(255, 0, 0, 0.5)', }); const svg = rect.toSVG(); expect(svg).toBe( '\n\n\n', ); }); it('toSVG with id', async () => { const rect = new Rect({ id: 'myRect', width: 100, height: 100, strokeWidth: 0, fill: 'rgba(255, 0, 0, 0.5)', }); const svg = rect.toSVG(); expect(svg).toBe( '\n\n\n', ); }); it('toSVG with alpha colors stroke', async () => { const rect = new Rect({ width: 100, height: 100, strokeWidth: 0, fill: '', stroke: 'rgba(255, 0, 0, 0.5)', }); const svg = rect.toSVG(); expect(svg).toBe( '\n\n\n', ); }); it('toSVG with paintFirst set to stroke', async () => { const rect = new Rect({ width: 100, height: 100, paintFirst: 'stroke', }); const svg = rect.toSVG(); expect(svg).toBe( '\n\n\n', ); }); it('toObject without default values', async () => { const options = { width: 69, height: 50, left: 10, top: 20, version, }; const rect = new Rect(options); rect.includeDefaultValues = false; expect(rect.toObject()).toEqual({ type: 'Rect', ...options }); }); it('paintFirst life cycle', async () => { const svg = ''; const { objects } = await loadSVGFromString(svg); const rect = objects[0]; expect(rect).toBeTruthy(); const rectObject = rect!.toObject(); const rectSvg = rect!.toSVG(); expect(rect?.paintFirst).toBe('stroke'); expect(rectObject.paintFirst).toBe('stroke'); expect(rectSvg).toContain('paint-order="stroke"'); }); });