Skip to content

Commit 23ecf2d

Browse files
authored
fix(gatsby-remark-images): allow tracedSVG to accept object with settings (#28242)
* fix(gatsby-remark-images): allow tracedSVG to accept object with settings * fix test setup that was testing same thing twice
1 parent da04f3c commit 23ecf2d

File tree

2 files changed

+247
-2
lines changed

2 files changed

+247
-2
lines changed

packages/gatsby-remark-images/src/__tests__/gatsby-node.js

Lines changed: 208 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { testPluginOptionsSchema } from "gatsby-plugin-utils"
22
import { pluginOptionsSchema } from "../gatsby-node"
3+
import { Potrace } from "potrace"
34

45
describe(`pluginOptionsSchema`, () => {
56
it(`should provide meaningful errors when fields are invalid`, async () => {
@@ -13,7 +14,7 @@ describe(`pluginOptionsSchema`, () => {
1314
`"backgroundColor" must be a string`,
1415
`"quality" must be a number`,
1516
`"withWebp" must be one of [object, boolean]`,
16-
`"tracedSVG" must be a boolean`,
17+
`"tracedSVG" must be one of [boolean, object]`,
1718
`"loading" must be one of [lazy, eager, auto]`,
1819
`"disableBgImageOnAlpha" must be a boolean`,
1920
`"disableBgImage" must be a boolean`,
@@ -102,4 +103,210 @@ describe(`pluginOptionsSchema`, () => {
102103
expect(isValid).toBe(false)
103104
})
104105
})
106+
107+
describe(`allow different variants of "tracedSVG" option`, () => {
108+
describe(`supports boolean variant`, () => {
109+
it.each([
110+
[`true`, true],
111+
[`false`, false],
112+
])(`%s`, async (_title, booleanValue) => {
113+
const { isValid } = await testPluginOptionsSchema(pluginOptionsSchema, {
114+
tracedSVG: booleanValue,
115+
})
116+
117+
expect(isValid).toBe(true)
118+
})
119+
})
120+
121+
describe(`supports object notation`, () => {
122+
it(`should validate when all fields are set`, async () => {
123+
const { isValid } = await testPluginOptionsSchema(pluginOptionsSchema, {
124+
tracedSVG: {
125+
turnPolicy: Potrace.TURNPOLICY_RIGHT,
126+
turdSize: 50,
127+
alphaMax: 0.5,
128+
optCurve: false,
129+
optTolerance: 0.9,
130+
threshold: 230,
131+
blackOnWhite: false,
132+
color: `red`,
133+
background: `green`,
134+
},
135+
})
136+
137+
expect(isValid).toBe(true)
138+
})
139+
140+
it(`should validate when some fields are set`, async () => {
141+
const { isValid } = await testPluginOptionsSchema(pluginOptionsSchema, {
142+
tracedSVG: {
143+
turnPolicy: Potrace.TURNPOLICY_RIGHT,
144+
turdSize: 50,
145+
// alphaMax: 0.5,
146+
// optCurve: 0.2,
147+
// optTolerance: 0.9,
148+
// threshold: 230,
149+
// blackOnWhite: false,
150+
color: `red`,
151+
background: `green`,
152+
},
153+
})
154+
155+
expect(isValid).toBe(true)
156+
})
157+
158+
it(`should fail validation when unknown fields are set`, async () => {
159+
const { isValid, errors } = await testPluginOptionsSchema(
160+
pluginOptionsSchema,
161+
{
162+
tracedSVG: {
163+
foo: `bar`,
164+
},
165+
}
166+
)
167+
168+
expect(isValid).toBe(false)
169+
expect(errors).toMatchInlineSnapshot(`
170+
Array [
171+
"\\"tracedSVG.foo\\" is not allowed",
172+
]
173+
`)
174+
})
175+
176+
describe(`turnPolicy variants`, () => {
177+
it.each([
178+
`TURNPOLICY_BLACK`,
179+
`TURNPOLICY_WHITE`,
180+
`TURNPOLICY_LEFT`,
181+
`TURNPOLICY_RIGHT`,
182+
`TURNPOLICY_MINORITY`,
183+
`TURNPOLICY_MAJORITY`,
184+
])(`supports setting by policy name (%s)`, async name => {
185+
const { isValid } = await testPluginOptionsSchema(
186+
pluginOptionsSchema,
187+
{
188+
tracedSVG: { turnPolicy: name },
189+
}
190+
)
191+
192+
expect(isValid).toBe(true)
193+
})
194+
195+
it.each([
196+
Potrace.TURNPOLICY_BLACK,
197+
Potrace.TURNPOLICY_WHITE,
198+
Potrace.TURNPOLICY_LEFT,
199+
Potrace.TURNPOLICY_RIGHT,
200+
Potrace.TURNPOLICY_MINORITY,
201+
Potrace.TURNPOLICY_MAJORITY,
202+
])(`supports setting by policy value (%s)`, async value => {
203+
const { isValid } = await testPluginOptionsSchema(
204+
pluginOptionsSchema,
205+
{
206+
tracedSVG: { turnPolicy: value },
207+
}
208+
)
209+
210+
expect(isValid).toBe(true)
211+
})
212+
213+
it(`Doesn't support arbitrary string values`, async () => {
214+
const { isValid, errors } = await testPluginOptionsSchema(
215+
pluginOptionsSchema,
216+
{
217+
tracedSVG: { turnPolicy: `foo` },
218+
}
219+
)
220+
221+
expect(isValid).toBe(false)
222+
expect(errors).toMatchInlineSnapshot(`
223+
Array [
224+
"\\"tracedSVG.turnPolicy\\" must be one of [TURNPOLICY_BLACK, TURNPOLICY_WHITE, TURNPOLICY_LEFT, TURNPOLICY_RIGHT, TURNPOLICY_MINORITY, TURNPOLICY_MAJORITY, black, white, left, right, minority, majority]",
225+
]
226+
`)
227+
})
228+
})
229+
230+
describe(`threshold`, () => {
231+
// valid settings
232+
it.each([
233+
[
234+
`THRESHOLD_AUTO`,
235+
{
236+
value: Potrace.THRESHOLD_AUTO,
237+
expectedIsValid: true,
238+
},
239+
],
240+
[
241+
0,
242+
{
243+
expectedIsValid: true,
244+
},
245+
],
246+
[
247+
128,
248+
{
249+
expectedIsValid: true,
250+
},
251+
],
252+
[
253+
255,
254+
{
255+
expectedIsValid: true,
256+
},
257+
],
258+
])(`Allow setting %s`, async (titleAndMaybeValue, { value }) => {
259+
if (typeof value === `undefined`) {
260+
// if value wasn't explicitly set use title
261+
value = titleAndMaybeValue
262+
}
263+
264+
const { isValid } = await testPluginOptionsSchema(
265+
pluginOptionsSchema,
266+
{
267+
tracedSVG: { threshold: value },
268+
}
269+
)
270+
271+
expect(isValid).toBe(true)
272+
})
273+
274+
// invalid settings
275+
it.each([
276+
[
277+
-5,
278+
{
279+
expectedIsValid: false,
280+
errorMessage: `"tracedSVG.threshold" must be greater than or equal to 0`,
281+
},
282+
],
283+
[
284+
256,
285+
{
286+
expectedIsValid: false,
287+
errorMessage: `"tracedSVG.threshold" must be less than or equal to 255`,
288+
},
289+
],
290+
])(
291+
`Doesn't allow setting %s`,
292+
async (titleAndMaybeValue, { value, errorMessage }) => {
293+
if (typeof value === `undefined`) {
294+
// if value wasn't explicitly set use title
295+
value = titleAndMaybeValue
296+
}
297+
298+
const { isValid, errors } = await testPluginOptionsSchema(
299+
pluginOptionsSchema,
300+
{
301+
tracedSVG: { threshold: value },
302+
}
303+
)
304+
305+
expect(isValid).toBe(false)
306+
expect(errors[0]).toEqual(errorMessage)
307+
}
308+
)
309+
})
310+
})
311+
})
105312
})

packages/gatsby-remark-images/src/gatsby-node.js

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const { Potrace } = require(`potrace`)
2+
13
exports.pluginOptionsSchema = function ({ Joi }) {
24
return Joi.object({
35
maxWidth: Joi.number()
@@ -52,7 +54,43 @@ exports.pluginOptionsSchema = function ({ Joi }) {
5254
.description(
5355
`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.`
5456
),
55-
tracedSVG: Joi.boolean()
57+
tracedSVG: Joi.alternatives()
58+
.try(
59+
Joi.boolean(),
60+
Joi.object({
61+
turnPolicy: Joi.string()
62+
.valid(
63+
// this plugin also allow to use key names and not exact values
64+
`TURNPOLICY_BLACK`,
65+
`TURNPOLICY_WHITE`,
66+
`TURNPOLICY_LEFT`,
67+
`TURNPOLICY_RIGHT`,
68+
`TURNPOLICY_MINORITY`,
69+
`TURNPOLICY_MAJORITY`,
70+
// it also allow using actual policy values
71+
Potrace.TURNPOLICY_BLACK,
72+
Potrace.TURNPOLICY_WHITE,
73+
Potrace.TURNPOLICY_LEFT,
74+
Potrace.TURNPOLICY_RIGHT,
75+
Potrace.TURNPOLICY_MINORITY,
76+
Potrace.TURNPOLICY_MAJORITY
77+
)
78+
.default(Potrace.TURNPOLICY_MAJORITY),
79+
turdSize: Joi.number().default(100),
80+
alphaMax: Joi.number(),
81+
optCurve: Joi.boolean().default(true),
82+
optTolerance: Joi.number().default(0.4),
83+
threshold: Joi.alternatives()
84+
.try(
85+
Joi.number().min(0).max(255),
86+
Joi.number().valid(Potrace.THRESHOLD_AUTO)
87+
)
88+
.default(Potrace.THRESHOLD_AUTO),
89+
blackOnWhite: Joi.boolean().default(true),
90+
color: Joi.string().default(`lightgray`),
91+
background: Joi.string().default(`transparent`),
92+
})
93+
)
5694
.default(false)
5795
.description(
5896
`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.`

0 commit comments

Comments
 (0)