From 904e0044c51458297eb7e55a3554c551358f7aac Mon Sep 17 00:00:00 2001 From: joostdecock Date: Sat, 10 Sep 2022 15:04:57 +0200 Subject: [PATCH] wip(core): Work on pattern/design unit tests --- packages/core/src/config.mjs | 1 - packages/core/src/design.mjs | 1 - packages/core/src/pattern.mjs | 73 +- packages/core/src/utils.mjs | 4 +- packages/core/tests/new.test.mjs | 1 - packages/core/tests/pattern-draft.mjs | 557 ++-------- packages/core/tests/pattern-init.mjs | 236 ++-- packages/core/tests/pattern-sample.test.mjs | 337 ++++++ packages/core/tests/pattern.test.mjs | 1064 ------------------- 9 files changed, 612 insertions(+), 1662 deletions(-) create mode 100644 packages/core/tests/pattern-sample.test.mjs delete mode 100644 packages/core/tests/pattern.test.mjs diff --git a/packages/core/src/config.mjs b/packages/core/src/config.mjs index 90754a4d4e7..d16cee9df4a 100644 --- a/packages/core/src/config.mjs +++ b/packages/core/src/config.mjs @@ -19,4 +19,3 @@ export const loadPatternDefaults = () => ({ options: {}, absoluteOptions: {}, }) - diff --git a/packages/core/src/design.mjs b/packages/core/src/design.mjs index 975a2b586f2..77b3e002710 100644 --- a/packages/core/src/design.mjs +++ b/packages/core/src/design.mjs @@ -7,7 +7,6 @@ import { loadDesignDefaults } from './config.mjs' * So it's sort of a super-constructor */ export function Design(config) { - // Initialize config with defaults config = { ...loadDesignDefaults(), ...config } diff --git a/packages/core/src/pattern.mjs b/packages/core/src/pattern.mjs index 08762b6880b..8562e873294 100644 --- a/packages/core/src/pattern.mjs +++ b/packages/core/src/pattern.mjs @@ -39,9 +39,9 @@ export function Pattern(config) { addNonEnumProp(this, '__hide', {}) // Enumerable properties - this.config = config // Design config - this.parts = {} // Drafted parts container - this.store = new Store() // Store for sharing data across parts + this.config = config // Design config + this.parts = {} // Drafted parts container + this.store = new Store() // Store for sharing data across parts return this } @@ -66,7 +66,10 @@ Pattern.prototype.init = function () { // Say hello this.store.log.info( `New \`${this.store.get('data.name', 'No Name')}:` + - `${this.store.get('data.version', 'No version')}\` pattern using \`@freesewing/core:${version}\`` + `${this.store.get( + 'data.version', + 'No version' + )}\` pattern using \`@freesewing/core:${version}\`` ) this.store.log.info(`Pattern initialized. Draft order is: ${this.__draftOrder.join(', ')}`) @@ -385,7 +388,9 @@ Pattern.prototype.sampleMeasurement = function (measurementName) { let parts = this.sampleParts() let val = this.settings.measurements[measurementName] if (val === undefined) - this.store.log.error(`Cannot sample measurement \`${measurementName}\` because it's \`undefined\``) + this.store.log.error( + `Cannot sample measurement \`${measurementName}\` because it's \`undefined\`` + ) let step = val / 50 val = val * 0.9 for (let run = 1; run < 11; run++) { @@ -722,18 +727,24 @@ Pattern.prototype.__resolveDependencies = function (graph = false) { * configured dependencies. */ Pattern.prototype.needs = function (partName) { - if (typeof this.settings.only === 'undefined' || this.settings.only === false) return true - else if (typeof this.settings.only === 'string') { - if (this.settings.only === partName) return true - if (Array.isArray(this.resolvedDependencies[this.settings.only])) { - for (let dependency of this.resolvedDependencies[this.settings.only]) { - if (dependency === partName) return true - } - } - } else if (Array.isArray(this.settings.only)) { - for (let part of this.settings.only) { - if (part === partName) return true - for (let dependency of this.resolvedDependencies[part]) { + + // If only is unset, all parts are needed + if ( + typeof this.settings.only === 'undefined' || + this.settings.only === false || + ( Array.isArray(this.settings.only) && this.settings.only.length === 0 ) + ) return true + + // Make only to always be an array + const only = typeof this.settings.only === 'string' + ? [ this.settings.only ] + : this.settings.only + + // Walk the only parts, checking each one for a match in its dependencies + for (const part of only) { + if (part === partName) return true + if (this.__resolvedDependencies[part]) { + for (const dependency of this.__resolvedDependencies[part]) { if (dependency === partName) return true } } @@ -742,22 +753,11 @@ Pattern.prototype.needs = function (partName) { return false } -/* Checks whether a part is hidden in the config */ -Pattern.prototype.isHidden = function (partName) { - if (Array.isArray(this.settings.only)) { - if (this.settings.only.includes(partName)) return false - } - - if (this.__parts?.[partName]?.hide) return true - if (this.__parts?.[partName]?.hideAll) return true - - return false -} - /** Determines whether a part is wanted by the user * This depends on the 'only' setting */ Pattern.prototype.wants = function (partName) { + // Hidden parts are not wanted if (this.isHidden(partName)) return false else if (typeof this.settings.only === 'string') return this.settings.only === partName else if (Array.isArray(this.settings.only)) { @@ -770,11 +770,16 @@ Pattern.prototype.wants = function (partName) { return true } -/** - * Returns the cutList property - */ -Pattern.prototype.getCutList = function () { - return this.cutList +/* Checks whether a part is hidden in the config */ +Pattern.prototype.isHidden = function (partName) { + if (Array.isArray(this.settings.only)) { + if (this.settings.only.includes(partName)) return false + } + + if (this.__parts?.[partName]?.hide) return true + if (this.__parts?.[partName]?.hideAll) return true + + return false } /** Returns props required to render this pattern through diff --git a/packages/core/src/utils.mjs b/packages/core/src/utils.mjs index 92eb46c8cbb..294346c5ba9 100644 --- a/packages/core/src/utils.mjs +++ b/packages/core/src/utils.mjs @@ -484,7 +484,7 @@ const addPartOptionalMeasurements = (part, config, store, list = false) => { for (const m of part.optionalMeasurements) { // Don't add it's a required measurement for another part if (config.measurements.indexOf(m) === -1) { - store.log.debug(`Config resolver: Measurement __${m}__ is optional in ${part.name}`) + store.log.debug(`Config resolver: Measurement __${m}__ is optional in ${part.name}`) list.push(m) } } @@ -538,7 +538,7 @@ export const addPartPlugins = (part, config, store) => { return { ...config, - plugins: [...new Set(Object.values(plugins))] + plugins: [...new Set(Object.values(plugins))], } } diff --git a/packages/core/tests/new.test.mjs b/packages/core/tests/new.test.mjs index 095f8e84cbc..47281553b7a 100644 --- a/packages/core/tests/new.test.mjs +++ b/packages/core/tests/new.test.mjs @@ -48,7 +48,6 @@ describe('Design', () => { paperless: true, }) pattern.init() - console.log(pattern.store.logs) //console.log('plugins:', pattern.config.plugins) }) }) diff --git a/packages/core/tests/pattern-draft.mjs b/packages/core/tests/pattern-draft.mjs index 4cb8a087be6..287b25db281 100644 --- a/packages/core/tests/pattern-draft.mjs +++ b/packages/core/tests/pattern-draft.mjs @@ -51,7 +51,7 @@ describe('Pattern', () => { }) const pattern = new Pattern() - it('Should draft according to settings', () => { + it('Pattern.draft() should draft according to settings', () => { let count = 0 const back = { name: 'back', @@ -78,70 +78,103 @@ describe('Pattern', () => { pattern.draft() expect(count).to.equal(2) }) - + }) it('Should check whether a part is needed', () => { - let config = { - name: 'test', - dependencies: { back: 'front', side: 'back' }, - inject: { back: 'front' }, - hide: ['back'], + const partA = { + name: 'test.partA', + measurements: ['head', 'knee'], + optionalMeasurements: [ 'chest', 'waist'], + options: { + optA: { pct: 40, min: 20, max: 80 } + }, + draft: () => { } } - const Test = new Design(config) - Test.prototype.draftBack = function (part) { - return part + const partB = { + name: 'test.partB', + measurements: ['head', 'knee'], + optionalMeasurements: [ 'knee'], + after: partA, + plugins: [{ + name: 'testPlugin', + hooks: { + preRender: () => {} + } + }], + options: { + optB: { deg: 40, min: 20, max: 80 } + }, + draft: () => { } } - Test.prototype.draftFront = function (part) { - return part + const partC = { + name: 'test.partC', + measurements: ['head', 'knee'], + optionalMeasurements: [ 'knee'], + options: { + optC: { pct: 20, min: 10, max: 30 } + }, + draft: () => { } } - - let pattern = new Test().init() - pattern.settings.only = 'back' - //expect(pattern.needs("back")).to.equal(true); - expect(pattern.needs('front')).to.equal(true) - //expect(pattern.needs("side")).to.equal(false); - //pattern.settings.only = ["back", "side"]; - //expect(pattern.needs("back")).to.equal(true); - //expect(pattern.needs("front")).to.equal(true); - //expect(pattern.needs("side")).to.equal(true); + const Pattern = new Design({ + parts: [ partA, partB, partC ] + }) + const pattern = new Pattern({ + only: [ 'test.partB' ] + }) + pattern.init() + expect(pattern.needs('test.partA')).to.equal(true) + expect(pattern.needs('test.partB')).to.equal(true) + expect(pattern.needs('test.partC')).to.equal(false) }) it('Should check whether a part is wanted', () => { - let config = { - name: 'test', - dependencies: { back: 'front', side: 'back' }, - inject: { back: 'front' }, - hide: ['back'], + const partA = { + name: 'test.partA', + measurements: ['head', 'knee'], + optionalMeasurements: [ 'chest', 'waist'], + options: { + optA: { pct: 40, min: 20, max: 80 } + }, + draft: () => { } } - const Test = function (settings = false) { - Pattern.call(this, config) - return this + const partB = { + name: 'test.partB', + measurements: ['head', 'knee'], + optionalMeasurements: [ 'knee'], + after: partA, + plugins: [{ + name: 'testPlugin', + hooks: { + preRender: () => {} + } + }], + options: { + optB: { deg: 40, min: 20, max: 80 } + }, + draft: () => { } } - Test.prototype = Object.create(Pattern.prototype) - Test.prototype.constructor = Test - Test.prototype.draftBack = function (part) { - return part + const partC = { + name: 'test.partC', + measurements: ['head', 'knee'], + optionalMeasurements: [ 'knee'], + options: { + optC: { pct: 20, min: 10, max: 30 } + }, + draft: () => { } } - Test.prototype.draftFront = function (part) { - return part - } - - let pattern = new Test() - pattern.settings.only = 'back' - expect(pattern.wants('back')).to.equal(true) - expect(pattern.wants('front')).to.equal(false) - expect(pattern.wants('side')).to.equal(false) - pattern.settings.only = ['back', 'side'] - expect(pattern.wants('back')).to.equal(true) - expect(pattern.wants('front')).to.equal(false) - expect(pattern.wants('side')).to.equal(true) + const Pattern = new Design({ + parts: [ partA, partB, partC ] + }) + const pattern = new Pattern({ + only: [ 'test.partB' ] + }) + pattern.init() + expect(pattern.wants('test.partA')).to.equal(false) + expect(pattern.wants('test.partB')).to.equal(true) + expect(pattern.wants('test.partC')).to.equal(false) }) - it('Should check whether created parts get the pattern context', () => { - let pattern = new Pattern() - let part = new pattern.Part() - expect(part.context.settings).to.equal(pattern.settings) - }) + /* it('Should return all render props', () => { const front = { @@ -173,7 +206,6 @@ describe('Pattern', () => { ) }) - /* it("Should generate an auto layout if there is no set layout", () => { const Test = new freesewing.Design({ name: "test", @@ -304,425 +336,6 @@ describe('Pattern', () => { }); - it("Should retrieve the cutList", () => { - const Test = new Design({ - name: "test", - parts: [{ - name: 'front', - draft: function(part) { - const { addCut } = part.shorthand() - addCut(4, 'lining', true) - return part - } - }], - }) - const pattern = new Test() - expect(JSON.stringify(pattern.getCutList())).to.equal(JSON.stringify({})) - pattern.draft() - const list = `{"front":{"grain":90,"materials":{"lining":{"cut":4,"identical":true}}}}` - expect(JSON.stringify(pattern.getCutList())).to.equal(list) - }); */ - // 2022 style part inheritance - // I am aware this does too much for one unit test, but this is to simplify TDD - // we can split it up later - it('Design constructor should resolve nested injections', () => { - const partA = { - name: 'partA', - options: { optionA: { bool: true } }, - measurements: ['measieA'], - optionalMeasurements: ['optmeasieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.a1 = new Point(1, 1) - points.a2 = new Point(11, 11) - paths.a = new Path().move(points.a1).line(points.a2) - return part - }, - } - const partB = { - name: 'partB', - from: partA, - options: { optionB: { pct: 12, min: 2, max: 20 } }, - measurements: ['measieB'], - optionalMeasurements: ['optmeasieB', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.b1 = new Point(2, 2) - points.b2 = new Point(22, 22) - paths.b = new Path().move(points.b1).line(points.b2) - return part - }, - } - const partC = { - name: 'partC', - from: partB, - options: { optionC: { deg: 5, min: 0, max: 15 } }, - measurements: ['measieC'], - optionalMeasurements: ['optmeasieC', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.c1 = new Point(3, 3) - points.c2 = new Point(33, 33) - paths.c = new Path().move(points.c1).line(points.c2) - return part - }, - } - const partR = { - // R for runtime, which is when this wil be attached - name: 'partR', - from: partA, - after: partC, - options: { optionR: { dflt: 'red', list: ['red', 'green', 'blue'] } }, - measurements: ['measieR'], - optionalMeasurements: ['optmeasieR', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.r1 = new Point(4, 4) - points.r2 = new Point(44, 44) - paths.r = new Path().move(points.r1).line(points.r2) - return part - }, - } - - const design = new Design({ parts: [partC] }) - const pattern = new design().addPart(partR).draft() - // Measurements - expect(pattern.config.measurements.length).to.equal(4) - expect(pattern.config.measurements.indexOf('measieA') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieB') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieC') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieR') === -1).to.equal(false) - // Optional measurements - expect(pattern.config.optionalMeasurements.length).to.equal(4) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieA') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieB') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieC') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieR') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('measieA') === -1).to.equal(true) - // Options - expect(pattern.config.options.optionA.bool).to.equal(true) - expect(pattern.config.options.optionB.pct).to.equal(12) - expect(pattern.config.options.optionB.min).to.equal(2) - expect(pattern.config.options.optionB.max).to.equal(20) - expect(pattern.config.options.optionC.deg).to.equal(5) - expect(pattern.config.options.optionC.min).to.equal(0) - expect(pattern.config.options.optionC.max).to.equal(15) - expect(pattern.config.options.optionR.dflt).to.equal('red') - expect(pattern.config.options.optionR.list[0]).to.equal('red') - expect(pattern.config.options.optionR.list[1]).to.equal('green') - expect(pattern.config.options.optionR.list[2]).to.equal('blue') - // Dependencies - expect(pattern.config.dependencies.partB[0]).to.equal('partA') - expect(pattern.config.dependencies.partC[0]).to.equal('partB') - expect(pattern.config.dependencies.partR[0]).to.equal('partC') - expect(pattern.config.dependencies.partR[1]).to.equal('partA') - // Inject - expect(pattern.config.inject.partB).to.equal('partA') - expect(pattern.config.inject.partC).to.equal('partB') - expect(pattern.config.inject.partR).to.equal('partA') - // Draft order - expect(pattern.config.draftOrder[0]).to.equal('partA') - expect(pattern.config.draftOrder[1]).to.equal('partB') - expect(pattern.config.draftOrder[2]).to.equal('partC') - expect(pattern.config.draftOrder[3]).to.equal('partR') - // Points - expect(pattern.parts.partA.points.a1.x).to.equal(1) - expect(pattern.parts.partA.points.a1.y).to.equal(1) - expect(pattern.parts.partA.points.a2.x).to.equal(11) - expect(pattern.parts.partA.points.a2.y).to.equal(11) - expect(pattern.parts.partB.points.b1.x).to.equal(2) - expect(pattern.parts.partB.points.b1.y).to.equal(2) - expect(pattern.parts.partB.points.b2.x).to.equal(22) - expect(pattern.parts.partB.points.b2.y).to.equal(22) - expect(pattern.parts.partC.points.c1.x).to.equal(3) - expect(pattern.parts.partC.points.c1.y).to.equal(3) - expect(pattern.parts.partC.points.c2.x).to.equal(33) - expect(pattern.parts.partC.points.c2.y).to.equal(33) - expect(pattern.parts.partR.points.r1.x).to.equal(4) - expect(pattern.parts.partR.points.r1.y).to.equal(4) - expect(pattern.parts.partR.points.r2.x).to.equal(44) - expect(pattern.parts.partR.points.r2.y).to.equal(44) - // Paths in partA - expect(pattern.parts.partA.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partA.paths.a.ops[1].to.y).to.equal(11) - // Paths in partB - expect(pattern.parts.partB.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partB.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partB.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partB.paths.b.ops[1].to.y).to.equal(22) - // Paths in partC - expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partC.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partC.paths.b.ops[1].to.y).to.equal(22) - expect(pattern.parts.partC.paths.c.ops[0].to.x).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[0].to.y).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[1].to.x).to.equal(33) - expect(pattern.parts.partC.paths.c.ops[1].to.y).to.equal(33) - // Paths in partR - expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partR.paths.r.ops[0].to.x).to.equal(4) - expect(pattern.parts.partR.paths.r.ops[0].to.y).to.equal(4) - expect(pattern.parts.partR.paths.r.ops[1].to.x).to.equal(44) - expect(pattern.parts.partR.paths.r.ops[1].to.y).to.equal(44) - }) - - it('Design constructor should resolve nested dependencies (2022)', () => { - const partA = { - name: 'partA', - options: { optionA: { bool: true } }, - measurements: ['measieA'], - optionalMeasurements: ['optmeasieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.a1 = new Point(1, 1) - points.a2 = new Point(11, 11) - paths.a = new Path().move(points.a1).line(points.a2) - return part - }, - } - const partB = { - name: 'partB', - from: partA, - options: { optionB: { pct: 12, min: 2, max: 20 } }, - measurements: ['measieB'], - optionalMeasurements: ['optmeasieB', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.b1 = new Point(2, 2) - points.b2 = new Point(22, 22) - paths.b = new Path().move(points.b1).line(points.b2) - return part - }, - } - const partC = { - name: 'partC', - from: partB, - options: { optionC: { deg: 5, min: 0, max: 15 } }, - measurements: ['measieC'], - optionalMeasurements: ['optmeasieC', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.c1 = new Point(3, 3) - points.c2 = new Point(33, 33) - paths.c = new Path().move(points.c1).line(points.c2) - return part - }, - } - const partD = { - name: 'partD', - after: partC, - options: { optionD: { dflt: 'red', list: ['red', 'green', 'blue'] } }, - measurements: ['measieD'], - optionalMeasurements: ['optmeasieD', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.d1 = new Point(4, 4) - points.d2 = new Point(44, 44) - paths.d = new Path().move(points.d1).line(points.d2) - return part - }, - } - const design = new Design({ parts: [partD] }) - const pattern = new design().draft() - // Measurements - expect(pattern.config.measurements.length).to.equal(4) - expect(pattern.config.measurements.indexOf('measieA') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieB') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieC') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieD') === -1).to.equal(false) - // Optional measurements - expect(pattern.config.optionalMeasurements.length).to.equal(4) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieA') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieB') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieC') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieD') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('measieA') === -1).to.equal(true) - // Options - expect(pattern.config.options.optionA.bool).to.equal(true) - expect(pattern.config.options.optionB.pct).to.equal(12) - expect(pattern.config.options.optionB.min).to.equal(2) - expect(pattern.config.options.optionB.max).to.equal(20) - expect(pattern.config.options.optionC.deg).to.equal(5) - expect(pattern.config.options.optionC.min).to.equal(0) - expect(pattern.config.options.optionC.max).to.equal(15) - expect(pattern.config.options.optionD.dflt).to.equal('red') - expect(pattern.config.options.optionD.list[0]).to.equal('red') - expect(pattern.config.options.optionD.list[1]).to.equal('green') - expect(pattern.config.options.optionD.list[2]).to.equal('blue') - // Dependencies - expect(pattern.config.dependencies.partB[0]).to.equal('partA') - expect(pattern.config.dependencies.partC[0]).to.equal('partB') - expect(pattern.config.dependencies.partD[0]).to.equal('partC') - // Inject - expect(pattern.config.inject.partB).to.equal('partA') - expect(pattern.config.inject.partC).to.equal('partB') - // Draft order - expect(pattern.config.draftOrder[0]).to.equal('partA') - expect(pattern.config.draftOrder[1]).to.equal('partB') - expect(pattern.config.draftOrder[2]).to.equal('partC') - expect(pattern.config.draftOrder[3]).to.equal('partD') - // Points - expect(pattern.parts.partA.points.a1.x).to.equal(1) - expect(pattern.parts.partA.points.a1.y).to.equal(1) - expect(pattern.parts.partA.points.a2.x).to.equal(11) - expect(pattern.parts.partA.points.a2.y).to.equal(11) - expect(pattern.parts.partB.points.b1.x).to.equal(2) - expect(pattern.parts.partB.points.b1.y).to.equal(2) - expect(pattern.parts.partB.points.b2.x).to.equal(22) - expect(pattern.parts.partB.points.b2.y).to.equal(22) - expect(pattern.parts.partC.points.c1.x).to.equal(3) - expect(pattern.parts.partC.points.c1.y).to.equal(3) - expect(pattern.parts.partC.points.c2.x).to.equal(33) - expect(pattern.parts.partC.points.c2.y).to.equal(33) - expect(pattern.parts.partD.points.d1.x).to.equal(4) - expect(pattern.parts.partD.points.d1.y).to.equal(4) - expect(pattern.parts.partD.points.d2.x).to.equal(44) - expect(pattern.parts.partD.points.d2.y).to.equal(44) - // Paths in partA - expect(pattern.parts.partA.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partA.paths.a.ops[1].to.y).to.equal(11) - // Paths in partB - expect(pattern.parts.partB.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partB.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partB.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partB.paths.b.ops[1].to.y).to.equal(22) - // Paths in partC - expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partC.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partC.paths.b.ops[1].to.y).to.equal(22) - expect(pattern.parts.partC.paths.c.ops[0].to.x).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[0].to.y).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[1].to.x).to.equal(33) - expect(pattern.parts.partC.paths.c.ops[1].to.y).to.equal(33) - // Paths in partR - expect(pattern.parts.partD.paths.d.ops[0].to.x).to.equal(4) - expect(pattern.parts.partD.paths.d.ops[0].to.y).to.equal(4) - expect(pattern.parts.partD.paths.d.ops[1].to.x).to.equal(44) - expect(pattern.parts.partD.paths.d.ops[1].to.y).to.equal(44) - }) - - it('Pattern should load single plugin', () => { - const plugin = { - name: 'example', - version: 1, - hooks: { - preRender: function (svg, attributes) { - svg.attributes.add('freesewing:plugin-example', version) - }, - }, - } - - const part = { - name: 'test.part', - plugins: plugin, - draft: (part) => part, - } - const design = new Design({ parts: [part] }) - const pattern = new design() - pattern.init() - expect(pattern.hooks.preRender.length).to.equal(1) - }) - /* - it("Design constructor should load array of plugins", () => { - let plugin1 = { - name: "example1", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example1", version); - } - } - }; - let plugin2 = { - name: "example2", - version: 2, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example2", version); - } - } - }; - - let design = new Design( { plugins: [plugin1, plugin2] }); - let pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(2); - }); - it("Design constructor should load conditional plugin", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition = () => true - const design = new Design({ plugins: { plugin, condition } }); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(1); - }); - - it("Design constructor should not load conditional plugin", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition = () => false - const design = new Design({ plugins: { plugin, condition } }); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(0); - }); - - it("Design constructor should load multiple conditional plugins", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition1 = () => true - const condition2 = () => false - const design = new Design({ plugins: [ - { plugin, condition: condition1 }, - { plugin, condition: condition2 }, - ]}); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(1); -*/ }) diff --git a/packages/core/tests/pattern-init.mjs b/packages/core/tests/pattern-init.mjs index 59aefe8dfb0..f7b4184a791 100644 --- a/packages/core/tests/pattern-init.mjs +++ b/packages/core/tests/pattern-init.mjs @@ -4,9 +4,7 @@ import { round, Design, Point, pctBasedOn } from '../src/index.mjs' const expect = chai.expect describe('Pattern', () => { - describe('Pattern.constructor()', () => { - it('Pattern constructor should return pattern object', () => { const Pattern = new Design() const pattern = new Pattern() @@ -65,45 +63,45 @@ describe('Pattern', () => { else expect(pattern.settings[key]).to.equal(value) } }) - }) describe('Pattern.init()', () => { - const partA = { name: 'test.partA', measurements: ['head', 'knee'], - optionalMeasurements: [ 'chest', 'waist'], + optionalMeasurements: ['chest', 'waist'], options: { - optA: { pct: 40, min: 20, max: 80 } + optA: { pct: 40, min: 20, max: 80 }, }, - draft: () => { } + draft: () => {}, } const partB = { name: 'test.partB', measurements: ['head', 'knee'], - optionalMeasurements: [ 'knee'], + optionalMeasurements: ['knee'], after: partA, - plugins: [{ - name: 'testPlugin', - hooks: { - preRender: () => {} - } - }], + plugins: [ + { + name: 'testPlugin', + hooks: { + preRender: () => {}, + }, + }, + ], options: { - optB: { deg: 40, min: 20, max: 80 } + optB: { deg: 40, min: 20, max: 80 }, }, - draft: () => { } + draft: () => {}, } const partC = { name: 'test.partC', measurements: ['head', 'knee'], - optionalMeasurements: [ 'knee'], + optionalMeasurements: ['knee'], from: partB, options: { - optC: { pct: 20, min: 10, max: 30 } + optC: { pct: 20, min: 10, max: 30 }, }, - draft: () => { } + draft: () => {}, } const Pattern = new Design({ @@ -111,16 +109,15 @@ describe('Pattern', () => { name: 'test', version: '1.2.3', }, - parts: [ partC ] + parts: [partC], }) const pattern = new Pattern() pattern.init() it('Pattern.init() should resolve all measurements', () => { - expect([ - ...pattern.config.measurements, - ...pattern.config.optionalMeasurements - ].length).to.equal(4) + expect( + [...pattern.config.measurements, ...pattern.config.optionalMeasurements].length + ).to.equal(4) }) it('Pattern.init() should resolve required measurements', () => { @@ -170,8 +167,12 @@ describe('Pattern', () => { expect(pattern.config.resolvedDependencies['test.partB'][0]).to.equal('test.partA') expect(Array.isArray(pattern.config.resolvedDependencies['test.partC'])).to.equal(true) expect(pattern.config.resolvedDependencies['test.partC'].length).to.equal(2) - expect(pattern.config.resolvedDependencies['test.partC'].indexOf('test.partA') !== -1).to.equal(true) - expect(pattern.config.resolvedDependencies['test.partC'].indexOf('test.partB') !== -1).to.equal(true) + expect( + pattern.config.resolvedDependencies['test.partC'].indexOf('test.partA') !== -1 + ).to.equal(true) + expect( + pattern.config.resolvedDependencies['test.partC'].indexOf('test.partB') !== -1 + ).to.equal(true) }) it('Pattern.init() should resolve the draft order', () => { @@ -505,88 +506,152 @@ describe('Pattern', () => { expect(pattern.hooks.preRender.length).to.equal(1) }) - it("Pattern.init() should load array of plugins", () => { + it('Pattern.init() should load array of plugins', () => { const plugin1 = { - name: "example1", + name: 'example1', version: 1, hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example1", version); - } - } - }; + preRender: function (svg, attributes) { + svg.attributes.add('freesewing:plugin-example1', version) + }, + }, + } const plugin2 = { - name: "example2", + name: 'example2', version: 2, hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example2", version); - } - } - }; + preRender: function (svg, attributes) { + svg.attributes.add('freesewing:plugin-example2', version) + }, + }, + } - const design = new Design( { plugins: [plugin1, plugin2] }); - const pattern = new design(); + const design = new Design({ plugins: [plugin1, plugin2] }) + const pattern = new design() pattern.init() - expect(pattern.hooks.preRender.length).to.equal(2); - }); - it("Pattern.init() should load conditional plugin", () => { + expect(pattern.hooks.preRender.length).to.equal(2) + }) + it('Pattern.init() should load conditional plugin', () => { const plugin = { - name: "example", + name: 'example', version: 1, hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; + preRender: function (svg, attributes) { + svg.attributes.add('freesewing:plugin-example', version) + }, + }, + } const condition = () => true - const design = new Design({ plugins: [ { plugin, condition } ] }); - const pattern = new design(); + const design = new Design({ plugins: [{ plugin, condition }] }) + const pattern = new design() pattern.init() - expect(pattern.hooks.preRender.length).to.equal(1); - }); + expect(pattern.hooks.preRender.length).to.equal(1) + }) - it("Pattern.init() should not load conditional plugin", () => { + it('Pattern.init() should not load conditional plugin', () => { const plugin = { - name: "example", + name: 'example', version: 1, hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; + preRender: function (svg, attributes) { + svg.attributes.add('freesewing:plugin-example', version) + }, + }, + } const condition = () => false - const design = new Design({ plugins: { plugin, condition } }); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(0); - }); + const design = new Design({ plugins: { plugin, condition } }) + const pattern = new design() + expect(pattern.hooks.preRender.length).to.equal(0) + }) - it("Pattern.init() should load multiple conditional plugins", () => { + it('Pattern.init() should load multiple conditional plugins', () => { const plugin = { - name: "example", + name: 'example', version: 1, hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; + preRender: function (svg, attributes) { + svg.attributes.add('freesewing:plugin-example', version) + }, + }, + } const condition1 = () => true const condition2 = () => false - const design = new Design({ plugins: [ - { plugin, condition: condition1 }, - { plugin, condition: condition2 }, - ]}); - const pattern = new design(); + const design = new Design({ + plugins: [ + { plugin, condition: condition1 }, + { plugin, condition: condition2 }, + ], + }) + const pattern = new design() pattern.init() - expect(pattern.hooks.preRender.length).to.equal(1); + expect(pattern.hooks.preRender.length).to.equal(1) }) + + it('Pattern.init() should register a hook via on', () => { + const Pattern = new Design() + const pattern = new Pattern() + let count = 0 + pattern.on('preDraft', function (pattern) { + count++ + }) + pattern.draft() + expect(count).to.equal(1) + }) + + it('Pattern.init() should register a hook from a plugin', () => { + const Pattern = new Design() + const pattern = new Pattern() + let count = 0 + pattern._draft = () => {} + const plugin = { + name: 'test', + version: '0.1-test', + hooks: { + preDraft: function (pattern) { + count++ + }, + }, + } + pattern.use(plugin) + pattern.draft() + expect(count).to.equal(1) + }) + + it("Pattern.init() should register multiple methods on a single hook", () => { + const plugin = { + name: "test", + version: "0.1-test", + hooks: { + preDraft: [ + function(pattern) { + count++; + }, + function(pattern) { + count++; + } + ] + } + }; + const Pattern = new Design() + const pattern = new Pattern() + let count = 0 + pattern._draft = () => {} + pattern.use(plugin) + pattern.draft() + expect(count).to.equal(2); + }); + + it('Should check whether created parts get the pattern context', () => { + const Pattern = new Design() + const pattern = new Pattern() + const part = pattern.__createPartWithContext('test') + expect(typeof part.context).to.equal('object') + expect(part.context.settings).to.equal(pattern.settings) + }) + }) describe('Pattern.settings', () => { - const part = { name: 'test.part', options: { @@ -596,19 +661,19 @@ describe('Pattern', () => { deg: { deg: 2, min: 1, max: 3 }, list: { dflt: 'd', - choices: ['a', 'b' ,'c', 'd'] + choices: ['a', 'b', 'c', 'd'], }, count: { count: 4, min: 1, max: 13 }, bool: { bool: false }, }, - draft: () => { } + draft: () => {}, } const Pattern = new Design({ data: { name: 'test', version: '1.2.3', }, - parts: [ part ] + parts: [part], }) const pattern = new Pattern() pattern.init() @@ -641,17 +706,14 @@ describe('Pattern', () => { const part = { name: 'test.part', options: { unknown: { foo: 30 } }, - draft: () => { } + draft: () => {}, } const Pattern = new Design({ data: { name: 'test', version: '1.2.3' }, - parts: [ part ] + parts: [part], }) const pattern = new Pattern() expect(() => pattern.init()).to.throw() }) - }) - - }) diff --git a/packages/core/tests/pattern-sample.test.mjs b/packages/core/tests/pattern-sample.test.mjs new file mode 100644 index 00000000000..5b781cf9703 --- /dev/null +++ b/packages/core/tests/pattern-sample.test.mjs @@ -0,0 +1,337 @@ +import chai from 'chai' +import { round, Pattern, Design, pctBasedOn } from '../src/index.mjs' + +const expect = chai.expect + +describe('Pattern', () => { + describe('Pattern.sample()', () => { + /* + it('Should sample an option', () => { + let pattern = new Pattern({ + options: { + len: { pct: 30, min: 10 }, + bonus: 10, + }, + }) + pattern.draft = function () { + pattern.parts.a = new pattern.Part() + pattern.parts.b = new pattern.Part() + let a = pattern.parts.a + a.points.from = new a.Point(0, 0) + a.points.to = new a.Point( + 100 * a.context.settings.options.len, + a.context.settings.options.bonus + ) + a.paths.test = new a.Path().move(a.points.from).line(a.points.to) + pattern.parts.b.inject(a) + } + pattern.settings.sample = { + type: 'option', + option: 'len', + } + pattern.sample() + expect(pattern.parts.a.paths.test_1.render).to.equal(true) + expect(pattern.parts.b.paths.test_10.ops[1].to.y).to.equal(10) + }) + it("Should sample a list option", () => { + const front = { + name: 'front', + options: { + len: { + dflt: 1, + list: [1,2,3] + } + }, + draft: function(part) { + const { Point, points, Path, paths, options } = part.shorthand() + points.from = new Point(0, 0); + points.to = new Point( 100 * options.len, 0) + paths.line = new Path() + .move(points.from) + .line(points.to) + + return part + } + } + const Test = new freesewing.Design({ + name: "test", + parts: [front], + }) + const pattern = new Test({ + sample: { + type: 'option', + option: 'len' + } + }) + pattern.sample(); + console.log(pattern.parts) + expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(100); + expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(200); + expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(300); + }); + + it("Should sample a measurement", () => { + const Test = new freesewing.Design({ + name: "test", + parts: ['front'], + measurements: ['head'] + }) + Test.prototype.draftFront = function(part) { + const { Point, points, Path, paths, measurements } = part.shorthand() + points.from = new Point(0, 0); + points.to = new Point( measurements.head, 0) + paths.line = new Path() + .move(points.from) + .line(points.to) + + return part + }; + const pattern = new Test({ + measurements: { + head: 100 + }, + sample: { + type: 'measurement', + measurement: 'head' + } + }) + pattern.sample(); + expect(pattern.is).to.equal('sample') + expect(pattern.events.debug[0]).to.equal('Sampling measurement `head`') + for (let i=0;i<10;i++) { + const j = i + 1 + expect(pattern.parts.front.paths[`line_${j}`].ops[1].to.x).to.equal(90 + 2*i); + } + pattern.sampleMeasurement('nope') + expect(pattern.events.error.length).to.equal(1) + expect(pattern.events.error[0]).to.equal("Cannot sample measurement `nope` because it's `undefined`") + }); + + it("Should sample models", () => { + const Test = new freesewing.Design({ + name: "test", + parts: ['front'], + measurements: ['head'] + }) + Test.prototype.draftFront = function(part) { + const { Point, points, Path, paths, measurements } = part.shorthand() + points.from = new Point(0, 0); + points.to = new Point( measurements.head, 0) + paths.line = new Path() + .move(points.from) + .line(points.to) + + return part + }; + let pattern = new Test({ + sample: { + type: 'models', + models : { + a: { head: 100 }, + b: { head: 50 }, + } + } + }) + pattern.sample(); + expect(pattern.is).to.equal('sample') + expect(pattern.events.debug[0]).to.equal('Sampling models') + expect(pattern.parts.front.paths[`line_0`].ops[1].to.x).to.equal(100); + expect(pattern.parts.front.paths[`line_1`].ops[1].to.x).to.equal(50); + pattern = new Test({ + sample: { + type: 'models', + models : { + a: { head: 100 }, + b: { head: 50 }, + }, + focus: 'b' + } + }) + pattern.sample(); + expect(pattern.is).to.equal('sample') + expect(pattern.parts.front.paths[`line_-1`].ops[1].to.x).to.equal(50); + expect(pattern.parts.front.paths[`line_0`].ops[1].to.x).to.equal(100); + }); + + + it('Should return all render props', () => { + const front = { + name: 'front', + draft: function (part) { + return part + }, + } + const Test = new Design({ + name: 'test', + parts: [front], + }) + const pattern = new Test() + pattern.draft() + const rp = pattern.getRenderProps() + expect(rp.svg.body).to.equal('') + expect(rp.width).to.equal(4) + expect(rp.height).to.equal(4) + expect(rp.parts.front.height).to.equal(4) + }) + + it('Should not pack a pattern with errors', () => { + const pattern = new Pattern() + pattern.events.error.push('error') + pattern.pack() + expect(pattern.events.warning.length).to.equal(1) + expect(pattern.events.warning[0]).to.equal( + 'One or more errors occured. Not packing pattern parts' + ) + }) + + it("Should generate an auto layout if there is no set layout", () => { + const Test = new freesewing.Design({ + name: "test", + parts: [ + { + name: 'front', + draft: function(part) { + const {Path, paths, Point} = part.shorthand() + paths.seam = new Path().move(new Point(0,0)) + .line(new Point(5,5)) + return part + } + } + ] + }) + const pattern = new Test() + pattern.parts.front = new pattern.Part('front') + pattern.draftFront(pattern.parts.front); + pattern.pack() + expect(pattern.autoLayout.parts.front).to.exist + expect(pattern.autoLayout.parts.front.move.y).to.equal(2) + expect(pattern.autoLayout.parts.front.move.x).to.equal(2) + }) + + it("Should handle custom layouts", () => { + const Test = new Design({ name: "test", parts: ['front'] }) + Test.prototype.draftFront = function(part) { return part } + const pattern = new Test({ + layout: { + width: 400, + height: 200, + parts: { front: { move: { x: 14, y: -202 } } } + } + }) + pattern.pack() + expect(pattern.width).to.equal(400) + expect(pattern.height).to.equal(200) + }); + + it("Should handle a simple snapped option", () => { + const Test = new Design({ + name: "test", + parts: ['front'], + measurements: [ 'head' ], + options: { + len: { pct: 50, min: 22, max: 78, snap: 10, ...pctBasedOn('head') } + } + }) + Test.prototype.draftFront = function(part) { + const { Point, points, Path, paths, absoluteOptions } = part.shorthand() + points.from = new Point(0, 0); + points.to = new Point( 2 * absoluteOptions.len, 0) + paths.line = new Path() + .move(points.from) + .line(points.to) + + return part + }; + let pattern = new Test({ + sample: { + type: 'option', + option: 'len' + }, + measurements: { + head: 43.23 + } + }) + pattern.sample(); + expect(pattern.is).to.equal('sample') + expect(pattern.events.debug[0]).to.equal('Sampling option `len`') + expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(20); + expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(40); + expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(40); + expect(pattern.parts.front.paths.line_4.ops[1].to.x).to.equal(40); + expect(pattern.parts.front.paths.line_5.ops[1].to.x).to.equal(60); + expect(pattern.parts.front.paths.line_6.ops[1].to.x).to.equal(60); + expect(pattern.parts.front.paths.line_7.ops[1].to.x).to.equal(60); + expect(pattern.parts.front.paths.line_8.ops[1].to.x).to.equal(60); + expect(pattern.parts.front.paths.line_9.ops[1].to.x).to.equal(80); + expect(pattern.parts.front.paths.line_10.ops[1].to.x).to.equal(80); + }); + + it("Should handle a list snapped option", () => { + const Test = new Design({ + name: "test", + parts: [ + { + name: 'front', + draft: function(part) { + const { Point, points, Path, paths, absoluteOptions } = part.shorthand() + points.from = new Point(0, 0); + points.to = new Point( absoluteOptions.len, 0) + paths.line = new Path() + .move(points.from) + .line(points.to) + + return part + } + } + ], + measurements: [ 'head' ], + options: { + len: { pct: 50, min: 22, max: 78, snap: [10,14,19,28], ...pctBasedOn('head') } + } + }) + let pattern = new Test({ + sample: { + type: 'option', + option: 'len' + }, + measurements: { + head: 43.23 + } + }) + pattern.sample(); + expect(pattern.is).to.equal('sample') + expect(pattern.events.debug[0]).to.equal('Sampling option `len`') + expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(10); + expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(14); + expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(14); + expect(pattern.parts.front.paths.line_4.ops[1].to.x).to.equal(19); + expect(pattern.parts.front.paths.line_5.ops[1].to.x).to.equal(19); + expect(pattern.parts.front.paths.line_6.ops[1].to.x).to.equal(19); + expect(pattern.parts.front.paths.line_7.ops[1].to.x).to.equal(28); + expect(pattern.parts.front.paths.line_8.ops[1].to.x).to.equal(28); + expect(pattern.parts.front.paths.line_9.ops[1].to.x).to.equal(28); + expect(round(pattern.parts.front.paths.line_10.ops[1].to.x)).to.equal(33.72); + }); + + + it("Should retrieve the cutList", () => { + const Test = new Design({ + name: "test", + parts: [{ + name: 'front', + draft: function(part) { + const { addCut } = part.shorthand() + addCut(4, 'lining', true) + return part + } + }], + }) + const pattern = new Test() + expect(JSON.stringify(pattern.getCutList())).to.equal(JSON.stringify({})) + pattern.draft() + const list = `{"front":{"grain":90,"materials":{"lining":{"cut":4,"identical":true}}}}` + expect(JSON.stringify(pattern.getCutList())).to.equal(list) + }); + */ + }) +}) diff --git a/packages/core/tests/pattern.test.mjs b/packages/core/tests/pattern.test.mjs deleted file mode 100644 index f52be094fdf..00000000000 --- a/packages/core/tests/pattern.test.mjs +++ /dev/null @@ -1,1064 +0,0 @@ -import chai from 'chai' -import { round, Pattern, Design, pctBasedOn } from '../src/index.mjs' - -const expect = chai.expect - -describe('Pattern', () => { - - it('Should draft according to settings', () => { - let count = 0 - const back = { - name: 'back', - hide: true, - draft: function (part) { - count++ - return part - }, - } - const front = { - name: 'front', - from: back, - draft: function (part) { - count++ - return part - }, - } - const Test = new Design({ - name: 'test', - parts: [back, front], - }) - - const pattern = new Test() - pattern.draft() - expect(count).to.equal(2) - }) - - it('Should sample an option', () => { - let pattern = new Pattern({ - options: { - len: { pct: 30, min: 10 }, - bonus: 10, - }, - }) - pattern.draft = function () { - pattern.parts.a = new pattern.Part() - pattern.parts.b = new pattern.Part() - let a = pattern.parts.a - a.points.from = new a.Point(0, 0) - a.points.to = new a.Point( - 100 * a.context.settings.options.len, - a.context.settings.options.bonus - ) - a.paths.test = new a.Path().move(a.points.from).line(a.points.to) - pattern.parts.b.inject(a) - } - pattern.settings.sample = { - type: 'option', - option: 'len', - } - pattern.sample() - expect(pattern.parts.a.paths.test_1.render).to.equal(true) - expect(pattern.parts.b.paths.test_10.ops[1].to.y).to.equal(10) - }) - /* - it("Should sample a list option", () => { - const front = { - name: 'front', - options: { - len: { - dflt: 1, - list: [1,2,3] - } - }, - draft: function(part) { - const { Point, points, Path, paths, options } = part.shorthand() - points.from = new Point(0, 0); - points.to = new Point( 100 * options.len, 0) - paths.line = new Path() - .move(points.from) - .line(points.to) - - return part - } - } - const Test = new freesewing.Design({ - name: "test", - parts: [front], - }) - const pattern = new Test({ - sample: { - type: 'option', - option: 'len' - } - }) - pattern.sample(); - console.log(pattern.parts) - expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(100); - expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(200); - expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(300); - }); - - it("Should sample a measurement", () => { - const Test = new freesewing.Design({ - name: "test", - parts: ['front'], - measurements: ['head'] - }) - Test.prototype.draftFront = function(part) { - const { Point, points, Path, paths, measurements } = part.shorthand() - points.from = new Point(0, 0); - points.to = new Point( measurements.head, 0) - paths.line = new Path() - .move(points.from) - .line(points.to) - - return part - }; - const pattern = new Test({ - measurements: { - head: 100 - }, - sample: { - type: 'measurement', - measurement: 'head' - } - }) - pattern.sample(); - expect(pattern.is).to.equal('sample') - expect(pattern.events.debug[0]).to.equal('Sampling measurement `head`') - for (let i=0;i<10;i++) { - const j = i + 1 - expect(pattern.parts.front.paths[`line_${j}`].ops[1].to.x).to.equal(90 + 2*i); - } - pattern.sampleMeasurement('nope') - expect(pattern.events.error.length).to.equal(1) - expect(pattern.events.error[0]).to.equal("Cannot sample measurement `nope` because it's `undefined`") - }); - - it("Should sample models", () => { - const Test = new freesewing.Design({ - name: "test", - parts: ['front'], - measurements: ['head'] - }) - Test.prototype.draftFront = function(part) { - const { Point, points, Path, paths, measurements } = part.shorthand() - points.from = new Point(0, 0); - points.to = new Point( measurements.head, 0) - paths.line = new Path() - .move(points.from) - .line(points.to) - - return part - }; - let pattern = new Test({ - sample: { - type: 'models', - models : { - a: { head: 100 }, - b: { head: 50 }, - } - } - }) - pattern.sample(); - expect(pattern.is).to.equal('sample') - expect(pattern.events.debug[0]).to.equal('Sampling models') - expect(pattern.parts.front.paths[`line_0`].ops[1].to.x).to.equal(100); - expect(pattern.parts.front.paths[`line_1`].ops[1].to.x).to.equal(50); - pattern = new Test({ - sample: { - type: 'models', - models : { - a: { head: 100 }, - b: { head: 50 }, - }, - focus: 'b' - } - }) - pattern.sample(); - expect(pattern.is).to.equal('sample') - expect(pattern.parts.front.paths[`line_-1`].ops[1].to.x).to.equal(50); - expect(pattern.parts.front.paths[`line_0`].ops[1].to.x).to.equal(100); - }); - - it("Should register a hook via on", () => { - let pattern = new Pattern(); - let count = 0; - pattern._draft = () => {}; - pattern.on("preDraft", function(pattern) { - count++; - }); - pattern.draft(); - expect(count).to.equal(1); - }); - - it("Should register a hook from a plugin", () => { - let pattern = new Pattern(); - let count = 0; - pattern._draft = () => {}; - let plugin = { - name: "test", - version: "0.1-test", - hooks: { - preDraft: function(pattern) { - count++; - } - } - }; - pattern.use(plugin); - pattern.draft(); - expect(count).to.equal(1); - }); - - it("Should register multiple methods on a single hook", () => { - let pattern = new Pattern(); - let count = 0; - pattern._draft = () => {}; - let plugin = { - name: "test", - version: "0.1-test", - hooks: { - preDraft: [ - function(pattern) { - count++; - }, - function(pattern) { - count++; - } - ] - } - }; - pattern.use(plugin); - pattern.draft(); - expect(count).to.equal(2); - }); - */ - - it('Should check whether a part is needed', () => { - let config = { - name: 'test', - dependencies: { back: 'front', side: 'back' }, - inject: { back: 'front' }, - hide: ['back'], - } - const Test = new Design(config) - Test.prototype.draftBack = function (part) { - return part - } - Test.prototype.draftFront = function (part) { - return part - } - - let pattern = new Test().init() - pattern.settings.only = 'back' - //expect(pattern.needs("back")).to.equal(true); - expect(pattern.needs('front')).to.equal(true) - //expect(pattern.needs("side")).to.equal(false); - //pattern.settings.only = ["back", "side"]; - //expect(pattern.needs("back")).to.equal(true); - //expect(pattern.needs("front")).to.equal(true); - //expect(pattern.needs("side")).to.equal(true); - }) - - it('Should check whether a part is wanted', () => { - let config = { - name: 'test', - dependencies: { back: 'front', side: 'back' }, - inject: { back: 'front' }, - hide: ['back'], - } - const Test = function (settings = false) { - Pattern.call(this, config) - return this - } - Test.prototype = Object.create(Pattern.prototype) - Test.prototype.constructor = Test - Test.prototype.draftBack = function (part) { - return part - } - Test.prototype.draftFront = function (part) { - return part - } - - let pattern = new Test() - pattern.settings.only = 'back' - expect(pattern.wants('back')).to.equal(true) - expect(pattern.wants('front')).to.equal(false) - expect(pattern.wants('side')).to.equal(false) - pattern.settings.only = ['back', 'side'] - expect(pattern.wants('back')).to.equal(true) - expect(pattern.wants('front')).to.equal(false) - expect(pattern.wants('side')).to.equal(true) - }) - - it('Should correctly resolve dependencies - string version', () => { - let config = { - name: 'test', - dependencies: { front: 'back', side: 'back', hood: 'front', stripe: 'hood' }, - } - const Test = new Design(config) - Test.prototype = Object.create(Pattern.prototype) - Test.prototype.constructor = Test - Test.prototype.draftBack = function (part) { - return part - } - Test.prototype.draftFront = function (part) { - return part - } - - let pattern = new Test().init() - expect(pattern.config.resolvedDependencies.front.length).to.equal(1) - expect(pattern.config.resolvedDependencies.front[0]).to.equal('back') - expect(pattern.config.resolvedDependencies.side.length).to.equal(1) - expect(pattern.config.resolvedDependencies.side[0]).to.equal('back') - expect(pattern.config.resolvedDependencies.hood.length).to.equal(2) - expect(pattern.config.resolvedDependencies.hood[0]).to.equal('front') - expect(pattern.config.resolvedDependencies.hood[1]).to.equal('back') - expect(pattern.config.resolvedDependencies.stripe.length).to.equal(3) - expect(pattern.config.resolvedDependencies.stripe[0]).to.equal('hood') - expect(pattern.config.resolvedDependencies.stripe[1]).to.equal('front') - expect(pattern.config.resolvedDependencies.stripe[2]).to.equal('back') - expect(pattern.config.resolvedDependencies.back.length).to.equal(0) - expect(pattern.config.draftOrder[0]).to.equal('back') - expect(pattern.config.draftOrder[1]).to.equal('front') - expect(pattern.config.draftOrder[2]).to.equal('side') - expect(pattern.config.draftOrder[3]).to.equal('hood') - }) - - it('Should correctly resolve dependencies - array version', () => { - let config = { - name: 'test', - dependencies: { front: ['back'], side: ['back'], hood: ['front'], stripe: ['hood'] }, - } - const Test = function (settings = false) { - Pattern.call(this, config) - return this - } - Test.prototype = Object.create(Pattern.prototype) - Test.prototype.constructor = Test - Test.prototype.draftBack = function (part) { - return part - } - Test.prototype.draftFront = function (part) { - return part - } - - let pattern = new Test().init() - expect(pattern.config.resolvedDependencies.front.length).to.equal(1) - expect(pattern.config.resolvedDependencies.front[0]).to.equal('back') - expect(pattern.config.resolvedDependencies.side.length).to.equal(1) - expect(pattern.config.resolvedDependencies.side[0]).to.equal('back') - expect(pattern.config.resolvedDependencies.hood.length).to.equal(2) - expect(pattern.config.resolvedDependencies.hood[0]).to.equal('front') - expect(pattern.config.resolvedDependencies.hood[1]).to.equal('back') - expect(pattern.config.resolvedDependencies.stripe.length).to.equal(3) - expect(pattern.config.resolvedDependencies.stripe[0]).to.equal('hood') - expect(pattern.config.resolvedDependencies.stripe[1]).to.equal('front') - expect(pattern.config.resolvedDependencies.stripe[2]).to.equal('back') - expect(pattern.config.resolvedDependencies.back.length).to.equal(0) - expect(pattern.config.draftOrder[0]).to.equal('back') - expect(pattern.config.draftOrder[1]).to.equal('front') - expect(pattern.config.draftOrder[2]).to.equal('side') - expect(pattern.config.draftOrder[3]).to.equal('hood') - }) - - it('Should correctly resolve dependencies - issue #971 - working version', () => { - let config = { - name: 'test', - dependencies: { front: ['back'], crotch: ['front', 'back'] }, - parts: ['back', 'front', 'crotch'], - } - const Test = function (settings = false) { - Pattern.call(this, config) - return this - } - Test.prototype = Object.create(Pattern.prototype) - Test.prototype.constructor = Test - Test.prototype.draftBack = function (part) { - return part - } - Test.prototype.draftFront = function (part) { - return part - } - - let pattern = new Test().init() - expect(pattern.config.draftOrder[0]).to.equal('back') - expect(pattern.config.draftOrder[1]).to.equal('front') - expect(pattern.config.draftOrder[2]).to.equal('crotch') - }) - - it('Should correctly resolve dependencies - issue #971 - broken version', () => { - let config = { - name: 'test', - dependencies: { front: 'back', crotch: ['front', 'back'] }, - parts: ['back', 'front', 'crotch'], - } - const Test = function (settings = false) { - Pattern.call(this, config) - return this - } - Test.prototype = Object.create(Pattern.prototype) - Test.prototype.constructor = Test - Test.prototype.draftBack = function (part) { - return part - } - Test.prototype.draftFront = function (part) { - return part - } - - let pattern = new Test().init() - expect(pattern.config.draftOrder[0]).to.equal('back') - expect(pattern.config.draftOrder[1]).to.equal('front') - expect(pattern.config.draftOrder[2]).to.equal('crotch') - }) - - it('Should correctly resolve dependencies - Handle uncovered code path', () => { - let config = { - name: 'test', - dependencies: { - front: 'side', - crotch: ['front', 'back'], - back: 1, - }, - inject: { - front: 'back', - }, - parts: ['back', 'front', 'crotch'], - } - const Test = function (settings = false) { - Pattern.call(this, config) - return this - } - Test.prototype = Object.create(Pattern.prototype) - Test.prototype.constructor = Test - Test.prototype.draftBack = function (part) { - return part - } - Test.prototype.draftFront = function (part) { - return part - } - - let pattern = new Test().init() - const deps = pattern.resolveDependencies() - expect(pattern.config.draftOrder[0]).to.equal('side') - expect(pattern.config.draftOrder[1]).to.equal('back') - expect(pattern.config.draftOrder[2]).to.equal('front') - }) - - it('Should check whether created parts get the pattern context', () => { - let pattern = new Pattern() - let part = new pattern.Part() - expect(part.context.settings).to.equal(pattern.settings) - }) - - it('Should correctly merge settings', () => { - let pattern = new Pattern() - let settings = { - complete: false, - only: [1, 2, 3], - margin: 5, - } - pattern.apply(settings) - expect(pattern.settings.complete).to.equal(false) - expect(pattern.settings.only[1]).to.equal(2) - expect(pattern.settings.margin).to.equal(5) - expect(pattern.settings.only.length).to.equal(3) - }) - - it('Should correctly merge settings for existing array', () => { - let pattern = new Pattern() - pattern.settings.only = [1] - let settings = { - complete: false, - only: [2, 3, 4], - margin: 5, - } - pattern.apply(settings) - expect(pattern.settings.complete).to.equal(false) - expect(pattern.settings.only.length).to.equal(4) - expect(pattern.settings.margin).to.equal(5) - }) - - it('Should return all render props', () => { - const front = { - name: 'front', - draft: function (part) { - return part - }, - } - const Test = new Design({ - name: 'test', - parts: [front], - }) - const pattern = new Test() - pattern.draft() - const rp = pattern.getRenderProps() - expect(rp.svg.body).to.equal('') - expect(rp.width).to.equal(4) - expect(rp.height).to.equal(4) - expect(rp.parts.front.height).to.equal(4) - }) - - it('Should not pack a pattern with errors', () => { - const pattern = new Pattern() - pattern.events.error.push('error') - pattern.pack() - expect(pattern.events.warning.length).to.equal(1) - expect(pattern.events.warning[0]).to.equal( - 'One or more errors occured. Not packing pattern parts' - ) - }) - - /* - it("Should generate an auto layout if there is no set layout", () => { - const Test = new freesewing.Design({ - name: "test", - parts: [ - { - name: 'front', - draft: function(part) { - const {Path, paths, Point} = part.shorthand() - paths.seam = new Path().move(new Point(0,0)) - .line(new Point(5,5)) - return part - } - } - ] - }) - const pattern = new Test() - pattern.parts.front = new pattern.Part('front') - pattern.draftFront(pattern.parts.front); - pattern.pack() - expect(pattern.autoLayout.parts.front).to.exist - expect(pattern.autoLayout.parts.front.move.y).to.equal(2) - expect(pattern.autoLayout.parts.front.move.x).to.equal(2) - }) - - it("Should handle custom layouts", () => { - const Test = new Design({ name: "test", parts: ['front'] }) - Test.prototype.draftFront = function(part) { return part } - const pattern = new Test({ - layout: { - width: 400, - height: 200, - parts: { front: { move: { x: 14, y: -202 } } } - } - }) - pattern.pack() - expect(pattern.width).to.equal(400) - expect(pattern.height).to.equal(200) - }); - - it("Should handle a simple snapped option", () => { - const Test = new Design({ - name: "test", - parts: ['front'], - measurements: [ 'head' ], - options: { - len: { pct: 50, min: 22, max: 78, snap: 10, ...pctBasedOn('head') } - } - }) - Test.prototype.draftFront = function(part) { - const { Point, points, Path, paths, absoluteOptions } = part.shorthand() - points.from = new Point(0, 0); - points.to = new Point( 2 * absoluteOptions.len, 0) - paths.line = new Path() - .move(points.from) - .line(points.to) - - return part - }; - let pattern = new Test({ - sample: { - type: 'option', - option: 'len' - }, - measurements: { - head: 43.23 - } - }) - pattern.sample(); - expect(pattern.is).to.equal('sample') - expect(pattern.events.debug[0]).to.equal('Sampling option `len`') - expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(20); - expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(40); - expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(40); - expect(pattern.parts.front.paths.line_4.ops[1].to.x).to.equal(40); - expect(pattern.parts.front.paths.line_5.ops[1].to.x).to.equal(60); - expect(pattern.parts.front.paths.line_6.ops[1].to.x).to.equal(60); - expect(pattern.parts.front.paths.line_7.ops[1].to.x).to.equal(60); - expect(pattern.parts.front.paths.line_8.ops[1].to.x).to.equal(60); - expect(pattern.parts.front.paths.line_9.ops[1].to.x).to.equal(80); - expect(pattern.parts.front.paths.line_10.ops[1].to.x).to.equal(80); - }); - - it("Should handle a list snapped option", () => { - const Test = new Design({ - name: "test", - parts: [ - { - name: 'front', - draft: function(part) { - const { Point, points, Path, paths, absoluteOptions } = part.shorthand() - points.from = new Point(0, 0); - points.to = new Point( absoluteOptions.len, 0) - paths.line = new Path() - .move(points.from) - .line(points.to) - - return part - } - } - ], - measurements: [ 'head' ], - options: { - len: { pct: 50, min: 22, max: 78, snap: [10,14,19,28], ...pctBasedOn('head') } - } - }) - let pattern = new Test({ - sample: { - type: 'option', - option: 'len' - }, - measurements: { - head: 43.23 - } - }) - pattern.sample(); - expect(pattern.is).to.equal('sample') - expect(pattern.events.debug[0]).to.equal('Sampling option `len`') - expect(pattern.parts.front.paths.line_1.ops[1].to.x).to.equal(10); - expect(pattern.parts.front.paths.line_2.ops[1].to.x).to.equal(14); - expect(pattern.parts.front.paths.line_3.ops[1].to.x).to.equal(14); - expect(pattern.parts.front.paths.line_4.ops[1].to.x).to.equal(19); - expect(pattern.parts.front.paths.line_5.ops[1].to.x).to.equal(19); - expect(pattern.parts.front.paths.line_6.ops[1].to.x).to.equal(19); - expect(pattern.parts.front.paths.line_7.ops[1].to.x).to.equal(28); - expect(pattern.parts.front.paths.line_8.ops[1].to.x).to.equal(28); - expect(pattern.parts.front.paths.line_9.ops[1].to.x).to.equal(28); - expect(round(pattern.parts.front.paths.line_10.ops[1].to.x)).to.equal(33.72); - }); - - - it("Should retrieve the cutList", () => { - const Test = new Design({ - name: "test", - parts: [{ - name: 'front', - draft: function(part) { - const { addCut } = part.shorthand() - addCut(4, 'lining', true) - return part - } - }], - }) - const pattern = new Test() - expect(JSON.stringify(pattern.getCutList())).to.equal(JSON.stringify({})) - pattern.draft() - const list = `{"front":{"grain":90,"materials":{"lining":{"cut":4,"identical":true}}}}` - expect(JSON.stringify(pattern.getCutList())).to.equal(list) - }); - */ - - // 2022 style part inheritance - // I am aware this does too much for one unit test, but this is to simplify TDD - // we can split it up later - it('Design constructor should resolve nested injections', () => { - const partA = { - name: 'partA', - options: { optionA: { bool: true } }, - measurements: ['measieA'], - optionalMeasurements: ['optmeasieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.a1 = new Point(1, 1) - points.a2 = new Point(11, 11) - paths.a = new Path().move(points.a1).line(points.a2) - return part - }, - } - const partB = { - name: 'partB', - from: partA, - options: { optionB: { pct: 12, min: 2, max: 20 } }, - measurements: ['measieB'], - optionalMeasurements: ['optmeasieB', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.b1 = new Point(2, 2) - points.b2 = new Point(22, 22) - paths.b = new Path().move(points.b1).line(points.b2) - return part - }, - } - const partC = { - name: 'partC', - from: partB, - options: { optionC: { deg: 5, min: 0, max: 15 } }, - measurements: ['measieC'], - optionalMeasurements: ['optmeasieC', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.c1 = new Point(3, 3) - points.c2 = new Point(33, 33) - paths.c = new Path().move(points.c1).line(points.c2) - return part - }, - } - const partR = { - // R for runtime, which is when this wil be attached - name: 'partR', - from: partA, - after: partC, - options: { optionR: { dflt: 'red', list: ['red', 'green', 'blue'] } }, - measurements: ['measieR'], - optionalMeasurements: ['optmeasieR', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.r1 = new Point(4, 4) - points.r2 = new Point(44, 44) - paths.r = new Path().move(points.r1).line(points.r2) - return part - }, - } - - const design = new Design({ parts: [partC] }) - const pattern = new design().addPart(partR).draft() - // Measurements - expect(pattern.config.measurements.length).to.equal(4) - expect(pattern.config.measurements.indexOf('measieA') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieB') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieC') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieR') === -1).to.equal(false) - // Optional measurements - expect(pattern.config.optionalMeasurements.length).to.equal(4) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieA') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieB') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieC') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieR') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('measieA') === -1).to.equal(true) - // Options - expect(pattern.config.options.optionA.bool).to.equal(true) - expect(pattern.config.options.optionB.pct).to.equal(12) - expect(pattern.config.options.optionB.min).to.equal(2) - expect(pattern.config.options.optionB.max).to.equal(20) - expect(pattern.config.options.optionC.deg).to.equal(5) - expect(pattern.config.options.optionC.min).to.equal(0) - expect(pattern.config.options.optionC.max).to.equal(15) - expect(pattern.config.options.optionR.dflt).to.equal('red') - expect(pattern.config.options.optionR.list[0]).to.equal('red') - expect(pattern.config.options.optionR.list[1]).to.equal('green') - expect(pattern.config.options.optionR.list[2]).to.equal('blue') - // Dependencies - expect(pattern.config.dependencies.partB[0]).to.equal('partA') - expect(pattern.config.dependencies.partC[0]).to.equal('partB') - expect(pattern.config.dependencies.partR[0]).to.equal('partC') - expect(pattern.config.dependencies.partR[1]).to.equal('partA') - // Inject - expect(pattern.config.inject.partB).to.equal('partA') - expect(pattern.config.inject.partC).to.equal('partB') - expect(pattern.config.inject.partR).to.equal('partA') - // Draft order - expect(pattern.config.draftOrder[0]).to.equal('partA') - expect(pattern.config.draftOrder[1]).to.equal('partB') - expect(pattern.config.draftOrder[2]).to.equal('partC') - expect(pattern.config.draftOrder[3]).to.equal('partR') - // Points - expect(pattern.parts.partA.points.a1.x).to.equal(1) - expect(pattern.parts.partA.points.a1.y).to.equal(1) - expect(pattern.parts.partA.points.a2.x).to.equal(11) - expect(pattern.parts.partA.points.a2.y).to.equal(11) - expect(pattern.parts.partB.points.b1.x).to.equal(2) - expect(pattern.parts.partB.points.b1.y).to.equal(2) - expect(pattern.parts.partB.points.b2.x).to.equal(22) - expect(pattern.parts.partB.points.b2.y).to.equal(22) - expect(pattern.parts.partC.points.c1.x).to.equal(3) - expect(pattern.parts.partC.points.c1.y).to.equal(3) - expect(pattern.parts.partC.points.c2.x).to.equal(33) - expect(pattern.parts.partC.points.c2.y).to.equal(33) - expect(pattern.parts.partR.points.r1.x).to.equal(4) - expect(pattern.parts.partR.points.r1.y).to.equal(4) - expect(pattern.parts.partR.points.r2.x).to.equal(44) - expect(pattern.parts.partR.points.r2.y).to.equal(44) - // Paths in partA - expect(pattern.parts.partA.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partA.paths.a.ops[1].to.y).to.equal(11) - // Paths in partB - expect(pattern.parts.partB.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partB.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partB.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partB.paths.b.ops[1].to.y).to.equal(22) - // Paths in partC - expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partC.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partC.paths.b.ops[1].to.y).to.equal(22) - expect(pattern.parts.partC.paths.c.ops[0].to.x).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[0].to.y).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[1].to.x).to.equal(33) - expect(pattern.parts.partC.paths.c.ops[1].to.y).to.equal(33) - // Paths in partR - expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partR.paths.r.ops[0].to.x).to.equal(4) - expect(pattern.parts.partR.paths.r.ops[0].to.y).to.equal(4) - expect(pattern.parts.partR.paths.r.ops[1].to.x).to.equal(44) - expect(pattern.parts.partR.paths.r.ops[1].to.y).to.equal(44) - }) - - it('Design constructor should resolve nested dependencies (2022)', () => { - const partA = { - name: 'partA', - options: { optionA: { bool: true } }, - measurements: ['measieA'], - optionalMeasurements: ['optmeasieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.a1 = new Point(1, 1) - points.a2 = new Point(11, 11) - paths.a = new Path().move(points.a1).line(points.a2) - return part - }, - } - const partB = { - name: 'partB', - from: partA, - options: { optionB: { pct: 12, min: 2, max: 20 } }, - measurements: ['measieB'], - optionalMeasurements: ['optmeasieB', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.b1 = new Point(2, 2) - points.b2 = new Point(22, 22) - paths.b = new Path().move(points.b1).line(points.b2) - return part - }, - } - const partC = { - name: 'partC', - from: partB, - options: { optionC: { deg: 5, min: 0, max: 15 } }, - measurements: ['measieC'], - optionalMeasurements: ['optmeasieC', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.c1 = new Point(3, 3) - points.c2 = new Point(33, 33) - paths.c = new Path().move(points.c1).line(points.c2) - return part - }, - } - const partD = { - name: 'partD', - after: partC, - options: { optionD: { dflt: 'red', list: ['red', 'green', 'blue'] } }, - measurements: ['measieD'], - optionalMeasurements: ['optmeasieD', 'measieA'], - draft: (part) => { - const { points, Point, paths, Path } = part.shorthand() - points.d1 = new Point(4, 4) - points.d2 = new Point(44, 44) - paths.d = new Path().move(points.d1).line(points.d2) - return part - }, - } - const design = new Design({ parts: [partD] }) - const pattern = new design().draft() - // Measurements - expect(pattern.config.measurements.length).to.equal(4) - expect(pattern.config.measurements.indexOf('measieA') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieB') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieC') === -1).to.equal(false) - expect(pattern.config.measurements.indexOf('measieD') === -1).to.equal(false) - // Optional measurements - expect(pattern.config.optionalMeasurements.length).to.equal(4) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieA') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieB') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieC') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('optmeasieD') === -1).to.equal(false) - expect(pattern.config.optionalMeasurements.indexOf('measieA') === -1).to.equal(true) - // Options - expect(pattern.config.options.optionA.bool).to.equal(true) - expect(pattern.config.options.optionB.pct).to.equal(12) - expect(pattern.config.options.optionB.min).to.equal(2) - expect(pattern.config.options.optionB.max).to.equal(20) - expect(pattern.config.options.optionC.deg).to.equal(5) - expect(pattern.config.options.optionC.min).to.equal(0) - expect(pattern.config.options.optionC.max).to.equal(15) - expect(pattern.config.options.optionD.dflt).to.equal('red') - expect(pattern.config.options.optionD.list[0]).to.equal('red') - expect(pattern.config.options.optionD.list[1]).to.equal('green') - expect(pattern.config.options.optionD.list[2]).to.equal('blue') - // Dependencies - expect(pattern.config.dependencies.partB[0]).to.equal('partA') - expect(pattern.config.dependencies.partC[0]).to.equal('partB') - expect(pattern.config.dependencies.partD[0]).to.equal('partC') - // Inject - expect(pattern.config.inject.partB).to.equal('partA') - expect(pattern.config.inject.partC).to.equal('partB') - // Draft order - expect(pattern.config.draftOrder[0]).to.equal('partA') - expect(pattern.config.draftOrder[1]).to.equal('partB') - expect(pattern.config.draftOrder[2]).to.equal('partC') - expect(pattern.config.draftOrder[3]).to.equal('partD') - // Points - expect(pattern.parts.partA.points.a1.x).to.equal(1) - expect(pattern.parts.partA.points.a1.y).to.equal(1) - expect(pattern.parts.partA.points.a2.x).to.equal(11) - expect(pattern.parts.partA.points.a2.y).to.equal(11) - expect(pattern.parts.partB.points.b1.x).to.equal(2) - expect(pattern.parts.partB.points.b1.y).to.equal(2) - expect(pattern.parts.partB.points.b2.x).to.equal(22) - expect(pattern.parts.partB.points.b2.y).to.equal(22) - expect(pattern.parts.partC.points.c1.x).to.equal(3) - expect(pattern.parts.partC.points.c1.y).to.equal(3) - expect(pattern.parts.partC.points.c2.x).to.equal(33) - expect(pattern.parts.partC.points.c2.y).to.equal(33) - expect(pattern.parts.partD.points.d1.x).to.equal(4) - expect(pattern.parts.partD.points.d1.y).to.equal(4) - expect(pattern.parts.partD.points.d2.x).to.equal(44) - expect(pattern.parts.partD.points.d2.y).to.equal(44) - // Paths in partA - expect(pattern.parts.partA.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partA.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partA.paths.a.ops[1].to.y).to.equal(11) - // Paths in partB - expect(pattern.parts.partB.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partB.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partB.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partB.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partB.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partB.paths.b.ops[1].to.y).to.equal(22) - // Paths in partC - expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1) - expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11) - expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11) - expect(pattern.parts.partC.paths.b.ops[0].to.x).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[0].to.y).to.equal(2) - expect(pattern.parts.partC.paths.b.ops[1].to.x).to.equal(22) - expect(pattern.parts.partC.paths.b.ops[1].to.y).to.equal(22) - expect(pattern.parts.partC.paths.c.ops[0].to.x).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[0].to.y).to.equal(3) - expect(pattern.parts.partC.paths.c.ops[1].to.x).to.equal(33) - expect(pattern.parts.partC.paths.c.ops[1].to.y).to.equal(33) - // Paths in partR - expect(pattern.parts.partD.paths.d.ops[0].to.x).to.equal(4) - expect(pattern.parts.partD.paths.d.ops[0].to.y).to.equal(4) - expect(pattern.parts.partD.paths.d.ops[1].to.x).to.equal(44) - expect(pattern.parts.partD.paths.d.ops[1].to.y).to.equal(44) - }) - - it('Pattern should load single plugin', () => { - const plugin = { - name: 'example', - version: 1, - hooks: { - preRender: function (svg, attributes) { - svg.attributes.add('freesewing:plugin-example', version) - }, - }, - } - - const part = { - name: 'test.part', - plugins: plugin, - draft: (part) => part, - } - const design = new Design({ parts: [part] }) - const pattern = new design() - pattern.init() - expect(pattern.hooks.preRender.length).to.equal(1) - }) - /* - it("Design constructor should load array of plugins", () => { - let plugin1 = { - name: "example1", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example1", version); - } - } - }; - let plugin2 = { - name: "example2", - version: 2, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example2", version); - } - } - }; - - let design = new Design( { plugins: [plugin1, plugin2] }); - let pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(2); - }); - it("Design constructor should load conditional plugin", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition = () => true - const design = new Design({ plugins: { plugin, condition } }); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(1); - }); - - it("Design constructor should not load conditional plugin", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition = () => false - const design = new Design({ plugins: { plugin, condition } }); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(0); - }); - - it("Design constructor should load multiple conditional plugins", () => { - const plugin = { - name: "example", - version: 1, - hooks: { - preRender: function(svg, attributes) { - svg.attributes.add("freesewing:plugin-example", version); - } - } - }; - const condition1 = () => true - const condition2 = () => false - const design = new Design({ plugins: [ - { plugin, condition: condition1 }, - { plugin, condition: condition2 }, - ]}); - const pattern = new design(); - expect(pattern.hooks.preRender.length).to.equal(1); -*/ -})