From 97524891202985fb1c6ac57b7822742980ff54cd Mon Sep 17 00:00:00 2001 From: GatsbyJS Bot Date: Wed, 9 Dec 2020 12:37:20 -0500 Subject: [PATCH] fix(gatsby-remark-images): allow tracedSVG to accept object with settings (#28242) (#28552) * fix(gatsby-remark-images): allow tracedSVG to accept object with settings * fix test setup that was testing same thing twice (cherry picked from commit 23ecf2d1daaeb8cce8f9530355f42aeea8e803fc) Co-authored-by: Michal Piechowiak --- .../src/__tests__/gatsby-node.js | 209 +++++++++++++++++- .../gatsby-remark-images/src/gatsby-node.js | 40 +++- 2 files changed, 247 insertions(+), 2 deletions(-) diff --git a/packages/gatsby-remark-images/src/__tests__/gatsby-node.js b/packages/gatsby-remark-images/src/__tests__/gatsby-node.js index 22abed3528d62..d89b6d6c4c417 100644 --- a/packages/gatsby-remark-images/src/__tests__/gatsby-node.js +++ b/packages/gatsby-remark-images/src/__tests__/gatsby-node.js @@ -1,5 +1,6 @@ import { testPluginOptionsSchema } from "gatsby-plugin-utils" import { pluginOptionsSchema } from "../gatsby-node" +import { Potrace } from "potrace" describe(`pluginOptionsSchema`, () => { it(`should provide meaningful errors when fields are invalid`, async () => { @@ -13,7 +14,7 @@ describe(`pluginOptionsSchema`, () => { `"backgroundColor" must be a string`, `"quality" must be a number`, `"withWebp" must be one of [object, boolean]`, - `"tracedSVG" must be a boolean`, + `"tracedSVG" must be one of [boolean, object]`, `"loading" must be one of [lazy, eager, auto]`, `"disableBgImageOnAlpha" must be a boolean`, `"disableBgImage" must be a boolean`, @@ -102,4 +103,210 @@ describe(`pluginOptionsSchema`, () => { expect(isValid).toBe(false) }) }) + + describe(`allow different variants of "tracedSVG" option`, () => { + describe(`supports boolean variant`, () => { + it.each([ + [`true`, true], + [`false`, false], + ])(`%s`, async (_title, booleanValue) => { + const { isValid } = await testPluginOptionsSchema(pluginOptionsSchema, { + tracedSVG: booleanValue, + }) + + expect(isValid).toBe(true) + }) + }) + + describe(`supports object notation`, () => { + it(`should validate when all fields are set`, async () => { + const { isValid } = await testPluginOptionsSchema(pluginOptionsSchema, { + tracedSVG: { + turnPolicy: Potrace.TURNPOLICY_RIGHT, + turdSize: 50, + alphaMax: 0.5, + optCurve: false, + optTolerance: 0.9, + threshold: 230, + blackOnWhite: false, + color: `red`, + background: `green`, + }, + }) + + expect(isValid).toBe(true) + }) + + it(`should validate when some fields are set`, async () => { + const { isValid } = await testPluginOptionsSchema(pluginOptionsSchema, { + tracedSVG: { + turnPolicy: Potrace.TURNPOLICY_RIGHT, + turdSize: 50, + // alphaMax: 0.5, + // optCurve: 0.2, + // optTolerance: 0.9, + // threshold: 230, + // blackOnWhite: false, + color: `red`, + background: `green`, + }, + }) + + expect(isValid).toBe(true) + }) + + it(`should fail validation when unknown fields are set`, async () => { + const { isValid, errors } = await testPluginOptionsSchema( + pluginOptionsSchema, + { + tracedSVG: { + foo: `bar`, + }, + } + ) + + expect(isValid).toBe(false) + expect(errors).toMatchInlineSnapshot(` + Array [ + "\\"tracedSVG.foo\\" is not allowed", + ] + `) + }) + + describe(`turnPolicy variants`, () => { + it.each([ + `TURNPOLICY_BLACK`, + `TURNPOLICY_WHITE`, + `TURNPOLICY_LEFT`, + `TURNPOLICY_RIGHT`, + `TURNPOLICY_MINORITY`, + `TURNPOLICY_MAJORITY`, + ])(`supports setting by policy name (%s)`, async name => { + const { isValid } = await testPluginOptionsSchema( + pluginOptionsSchema, + { + tracedSVG: { turnPolicy: name }, + } + ) + + expect(isValid).toBe(true) + }) + + it.each([ + Potrace.TURNPOLICY_BLACK, + Potrace.TURNPOLICY_WHITE, + Potrace.TURNPOLICY_LEFT, + Potrace.TURNPOLICY_RIGHT, + Potrace.TURNPOLICY_MINORITY, + Potrace.TURNPOLICY_MAJORITY, + ])(`supports setting by policy value (%s)`, async value => { + const { isValid } = await testPluginOptionsSchema( + pluginOptionsSchema, + { + tracedSVG: { turnPolicy: value }, + } + ) + + expect(isValid).toBe(true) + }) + + it(`Doesn't support arbitrary string values`, async () => { + const { isValid, errors } = await testPluginOptionsSchema( + pluginOptionsSchema, + { + tracedSVG: { turnPolicy: `foo` }, + } + ) + + expect(isValid).toBe(false) + expect(errors).toMatchInlineSnapshot(` + Array [ + "\\"tracedSVG.turnPolicy\\" must be one of [TURNPOLICY_BLACK, TURNPOLICY_WHITE, TURNPOLICY_LEFT, TURNPOLICY_RIGHT, TURNPOLICY_MINORITY, TURNPOLICY_MAJORITY, black, white, left, right, minority, majority]", + ] + `) + }) + }) + + describe(`threshold`, () => { + // valid settings + it.each([ + [ + `THRESHOLD_AUTO`, + { + value: Potrace.THRESHOLD_AUTO, + expectedIsValid: true, + }, + ], + [ + 0, + { + expectedIsValid: true, + }, + ], + [ + 128, + { + expectedIsValid: true, + }, + ], + [ + 255, + { + expectedIsValid: true, + }, + ], + ])(`Allow setting %s`, async (titleAndMaybeValue, { value }) => { + if (typeof value === `undefined`) { + // if value wasn't explicitly set use title + value = titleAndMaybeValue + } + + const { isValid } = await testPluginOptionsSchema( + pluginOptionsSchema, + { + tracedSVG: { threshold: value }, + } + ) + + expect(isValid).toBe(true) + }) + + // invalid settings + it.each([ + [ + -5, + { + expectedIsValid: false, + errorMessage: `"tracedSVG.threshold" must be greater than or equal to 0`, + }, + ], + [ + 256, + { + expectedIsValid: false, + errorMessage: `"tracedSVG.threshold" must be less than or equal to 255`, + }, + ], + ])( + `Doesn't allow setting %s`, + async (titleAndMaybeValue, { value, errorMessage }) => { + if (typeof value === `undefined`) { + // if value wasn't explicitly set use title + value = titleAndMaybeValue + } + + const { isValid, errors } = await testPluginOptionsSchema( + pluginOptionsSchema, + { + tracedSVG: { threshold: value }, + } + ) + + expect(isValid).toBe(false) + expect(errors[0]).toEqual(errorMessage) + } + ) + }) + }) + }) }) diff --git a/packages/gatsby-remark-images/src/gatsby-node.js b/packages/gatsby-remark-images/src/gatsby-node.js index 127b905412bd2..eaa3e2c8b35ec 100644 --- a/packages/gatsby-remark-images/src/gatsby-node.js +++ b/packages/gatsby-remark-images/src/gatsby-node.js @@ -1,3 +1,5 @@ +const { Potrace } = require(`potrace`) + exports.pluginOptionsSchema = function ({ Joi }) { return Joi.object({ maxWidth: Joi.number() @@ -52,7 +54,43 @@ exports.pluginOptionsSchema = function ({ Joi }) { .description( `Additionally generate WebP versions alongside your chosen file format. They are added as a srcset with the appropriate mimetype and will be loaded in browsers that support the format. Pass true for default support, or an object of options to specifically override those for the WebP files. For example, pass { quality: 80 } to have the WebP images be at quality level 80.` ), - tracedSVG: Joi.boolean() + tracedSVG: Joi.alternatives() + .try( + Joi.boolean(), + Joi.object({ + turnPolicy: Joi.string() + .valid( + // this plugin also allow to use key names and not exact values + `TURNPOLICY_BLACK`, + `TURNPOLICY_WHITE`, + `TURNPOLICY_LEFT`, + `TURNPOLICY_RIGHT`, + `TURNPOLICY_MINORITY`, + `TURNPOLICY_MAJORITY`, + // it also allow using actual policy values + Potrace.TURNPOLICY_BLACK, + Potrace.TURNPOLICY_WHITE, + Potrace.TURNPOLICY_LEFT, + Potrace.TURNPOLICY_RIGHT, + Potrace.TURNPOLICY_MINORITY, + Potrace.TURNPOLICY_MAJORITY + ) + .default(Potrace.TURNPOLICY_MAJORITY), + turdSize: Joi.number().default(100), + alphaMax: Joi.number(), + optCurve: Joi.boolean().default(true), + optTolerance: Joi.number().default(0.4), + threshold: Joi.alternatives() + .try( + Joi.number().min(0).max(255), + Joi.number().valid(Potrace.THRESHOLD_AUTO) + ) + .default(Potrace.THRESHOLD_AUTO), + blackOnWhite: Joi.boolean().default(true), + color: Joi.string().default(`lightgray`), + background: Joi.string().default(`transparent`), + }) + ) .default(false) .description( `Use traced SVGs for placeholder images instead of the “blur up” effect. Pass true for traced SVGs with the default settings (seen here), or an object of options to override the default. For example, pass { color: "#F00", turnPolicy: "TURNPOLICY_MAJORITY" } to change the color of the trace to red and the turn policy to TURNPOLICY_MAJORITY. See node-potrace parameter documentation for a full listing and explanation of the available options.`