1
0
Fork 0
freesewing/packages/core/tests/svg.test.mjs
joostdecock 88cbd6a4f9 chore(core): Drop the chai-string dependency for tests
We're using chai-string as it provides the `equalIgnoreSpaces`
assertion which we use in our SVG tests.

However, that package does not seem to be maintained, and lists chai v4
as its peer dependency. We've moved on to chai v5 and this is causes
issues in one of our github workflows as dependencies cannot be
resolved.

So, I've extracted the assertion we need, and dropped the dependency.
2024-03-16 12:10:31 +01:00

294 lines
9.4 KiB
JavaScript

import { expect, use } from 'chai'
import { Svg } from '../src/svg.mjs'
import { Design, Attributes } from '../src/index.mjs'
import { Defs } from '../src/defs.mjs'
import { version } from '../data.mjs'
import render from './fixtures/render.mjs'
import { binpackPlugin } from '../../../plugins/plugin-bin-pack/src/index.mjs'
/*
* Quick helper assertion for equalIgnoreSpaces
*/
use(function (chai, utils) {
chai.string = chai.string || {}
function isString(value) {
return typeof value === 'string'
}
const { Assertion } = chai
Assertion.addMethod('equalIgnoreSpaces', function (str1, str2) {
if (!isString(str1) || !isString(str2)) {
return false
}
return str1.replace(/\s/g, '') === str2.replace(/\s/g, '')
})
})
const getPattern = (settings = {}, draft = false) => {
const part = {
name: 'test',
plugins: binpackPlugin,
draft: draft
? draft
: ({ paths, Path, Point, part }) => {
paths.test = new Path()
.move(new Point(0, 0))
.line(new Point(40, 20))
.curve(new Point(12, 34), new Point(56, 78), new Point(21, 32))
.close()
.attr('id', 'something')
.attr('class', 'freesewing')
return part
},
}
const Pattern = new Design({ parts: [part], noCorePlugins: true })
return new Pattern(settings)
}
const trim = (svg) =>
svg
.split('\n')
.map((line) => line.trim())
.join('')
describe('Svg', () => {
it('Svg constructor should initialize object', () => {
const svg = new Svg()
expect(svg.attributes instanceof Attributes).to.equal(true)
expect(svg.freeId).to.equal(0)
expect(svg.style).to.equal('')
expect(svg.defs).to.be.an.instanceof(Defs)
expect(svg.prefix).to.equal('<?xml version="1.0" encoding="UTF-8" standalone="no"?>')
expect(svg.attributes.get('xmlns')).to.equal('http://www.w3.org/2000/svg')
expect(svg.attributes.get('xmlns:svg')).to.equal('http://www.w3.org/2000/svg')
expect(svg.attributes.get('xmlns:xlink')).to.equal('http://www.w3.org/1999/xlink')
expect(svg.attributes.get('xmlns:freesewing')).to.equal(
'http://freesewing.org/namespaces/freesewing'
)
expect(svg.attributes.get('freesewing')).to.equal(version)
})
it('Svg constructor should use the object we pass it as pattern', () => {
const obj = {}
const svg = new Svg(obj)
expect(svg.pattern).to.eql(obj)
})
it('Should render a pattern as SVG', () => {
const pattern = getPattern()
const svg = pattern.draft().render()
expect(trim(svg)).to.equalIgnoreSpaces(render.boilerplate)
})
it('Should render the SVG language attribute', () => {
const pattern = getPattern({ locale: 'nl' })
const svg = pattern.draft().render()
expect(svg).to.equalIgnoreSpaces(render.boilerplateNl)
})
it('Should render the SVG viewBox attribute for embedding', () => {
const pattern = getPattern({ embed: true })
const svg = pattern.draft().render()
expect(trim(svg)).to.equalIgnoreSpaces(render.embed)
})
it('Should render a stack as SVG', () => {
const pattern = getPattern()
pattern.draft().render()
const svg = pattern.svg.__renderStack(pattern.stacks.test)
expect(trim(svg)).to.equalIgnoreSpaces(render.part)
})
it('Should render a part as SVG', () => {
const pattern = getPattern()
pattern.draft().render()
const svg = pattern.svg.__renderPart(pattern.parts[0].test)
expect(trim(svg)).to.equalIgnoreSpaces(render.part)
})
it('Should render a path as SVG', () => {
const pattern = getPattern()
pattern.draft().render()
const svg = pattern.svg.__renderPath(pattern.parts[0].test.paths.test)
expect(trim(svg)).to.equalIgnoreSpaces(render.path)
})
it('Should render Svg text', () => {
const pattern = getPattern({}, ({ points, Point, part }) => {
points.test = new Point(20, 20)
.attr('data-text', 'This is a test')
.attr('data-text-class', 'text-lg')
points.other = new Point(10, 10).attr('data-text', '')
return part
})
pattern.draft().render()
const svg = pattern.svg.__renderPart(pattern.parts[0].test)
expect(trim(svg)).to.equalIgnoreSpaces(render.text)
})
it('Should render Svg multi-line text', () => {
const pattern = getPattern({}, ({ points, Point, part }) => {
points.test = new Point(20, 20)
.attr('data-text', 'This is a test\nwith text on\nmultiple lines')
.attr('data-text-class', 'text-lg')
.attr('data-text-lineheight', 8)
return part
})
pattern.draft().render()
const svg = pattern.svg.__renderPart(pattern.parts[0].test)
expect(trim(svg)).to.equalIgnoreSpaces(render.multiText)
})
it('Should render Svg multi-line text with default lineheight', () => {
const pattern = getPattern({}, ({ points, Point, part }) => {
points.test = new Point(20, 20)
.attr('data-text', 'This is a test\nwith text on\nmultiple lines')
.attr('data-text-class', 'text-lg')
return part
})
pattern.draft().render()
const svg = pattern.svg.__renderPart(pattern.parts[0].test)
expect(trim(svg)).to.equalIgnoreSpaces(render.multiTextDflt)
})
it('Should render Svg text on path', () => {
const pattern = getPattern({}, ({ paths, Path, Point, part }) => {
paths.test = new Path()
.move(new Point(0, 0))
.line(new Point(40, 20))
.curve(new Point(12, 34), new Point(56, 78), new Point(21, 32))
.close()
.attr('data-text', 'This is another test')
.attr('data-text-class', 'text-sm')
.attr('class', 'freesewing')
return part
})
pattern.draft().render()
const svg = pattern.svg.__renderPart(pattern.parts[0].test)
expect(trim(svg)).to.equalIgnoreSpaces(render.textOnPath)
})
it('Should render Svg text on path, center aligned', () => {
const pattern = getPattern({}, ({ paths, Path, part }) => {
paths.test = new Path()
.attr('data-text', 'This is another test')
.attr('data-text-class', 'center')
.attr('class', 'freesewing')
return part
})
pattern.draft().render()
const svg = pattern.svg.__renderPart(pattern.parts[0].test)
expect(trim(svg)).to.equalIgnoreSpaces(render.textOnPathCenter)
})
it('Should render Svg text on path, right aligned', () => {
const pattern = getPattern({}, ({ paths, Path, part }) => {
paths.test = new Path()
.attr('data-text', 'This is another test')
.attr('data-text-class', 'right')
.attr('class', 'freesewing')
return part
})
pattern.draft().render()
const svg = pattern.svg.__renderPart(pattern.parts[0].test)
expect(trim(svg)).to.equalIgnoreSpaces(render.textOnPathRight)
})
it('Should render an Svg circle', () => {
const pattern = getPattern({}, ({ points, Point, part }) => {
points.test = new Point(20, 20).attr('data-circle', '50')
return part
})
pattern.draft().render()
const svg = pattern.svg.__renderPart(pattern.parts[0].test)
expect(trim(svg)).to.equalIgnoreSpaces(render.circle)
})
it('Should render an Svg snippet', () => {
const pattern = getPattern({}, ({ snippets, Snippet, Point, part }) => {
snippets.test = new Snippet('test', new Point(20, 20))
return part
})
pattern.draft().render()
const svg = pattern.svg.__renderPart(pattern.parts[0].test)
expect(trim(svg)).to.equalIgnoreSpaces(render.snippet)
})
it('Should render a rotated Svg snippet', () => {
const pattern = getPattern({}, ({ snippets, Snippet, Point, part }) => {
snippets.test = new Snippet('test', new Point(20, 20)).attr('data-rotate', 90)
return part
})
pattern.draft().render()
const svg = pattern.svg.__renderPart(pattern.parts[0].test)
expect(trim(svg)).to.equalIgnoreSpaces(render.rotatedSnippet)
})
it('Should replaced double quotes in Svg text', () => {
const svg = new Svg()
expect(svg.__escapeText('This is a "test" message')).to.equal(
'This is a &#8220;test&#8220; message'
)
})
it('Should scale an Svg snippet', () => {
const pattern = getPattern({}, ({ snippets, Snippet, Point, part }) => {
snippets.test = new Snippet('test', new Point(20, 20)).attr('data-scale', 2)
return part
})
pattern.draft().render()
const svg = pattern.svg.__renderPart(pattern.parts[0].test)
expect(trim(svg)).to.equalIgnoreSpaces(render.scaledSnippet)
})
it('Should run preRender hook', () => {
const pattern = getPattern()
pattern.on('preRender', (svg) => {
svg.attributes.set('data-hook', 'preRender')
})
pattern.draft().render()
expect(pattern.svg.attributes.get('data-hook')).to.equal('preRender')
})
it('Should run insertText hook', () => {
const pattern = getPattern({}, ({ points, Point, part }) => {
points.test = new Point(20, 20)
.attr('data-text', 'This is a test')
.attr('data-text-class', 'text-lg')
return part
})
pattern.on('insertText', (locale, text) => {
return text.toUpperCase()
})
pattern.draft()
expect(pattern.render()).to.contain('THIS IS A TEST')
})
it('Should run postRender hook', () => {
const pattern = getPattern()
pattern.on('postRender', (svg) => {
svg.svg = 'test'
})
expect(pattern.draft().render()).to.equal('test')
})
it('Should tab in and out', () => {
const svg = new Svg()
svg.tabs = 2
expect(svg.__tab()).to.equal(' ')
})
})