From f1bcdbff63aaeb3f1bcbee83b8c3cd85892c5f95 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Fri, 25 Mar 2022 21:50:37 +0800 Subject: [PATCH] fix(validation): improve error messages for a few schemas (#6997) * fix(validation): improve error messages for a few schemas * kick CI * fix test --- .../src/__tests__/options.test.ts | 16 +++-- .../validationSchemas.test.ts.snap | 60 +++++++++++++++---- .../src/validationSchemas.ts | 5 ++ .../configValidation.test.ts.snap | 20 ------- .../server/__tests__/configValidation.test.ts | 33 ++++++++-- .../docusaurus/src/server/configValidation.ts | 24 ++++++-- 6 files changed, 114 insertions(+), 44 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts index 89bec2179d..8f21906faa 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/options.test.ts @@ -150,9 +150,11 @@ describe('normalizeDocsPluginOptions', () => { testValidate({ remarkPlugins: [[{option1: '42'}, markdownPluginsFunctionStub]], }), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"remarkPlugins[0]\\" does not match any of the allowed types"`, - ); + ).toThrowErrorMatchingInlineSnapshot(` + "\\"remarkPlugins[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: + - A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or + - A simple module, like \`require(\\"remark-math\\")\`" + `); }); it('rejects invalid rehype plugin options', () => { @@ -166,9 +168,11 @@ describe('normalizeDocsPluginOptions', () => { ], ], }), - ).toThrowErrorMatchingInlineSnapshot( - `"\\"rehypePlugins[0]\\" does not match any of the allowed types"`, - ); + ).toThrowErrorMatchingInlineSnapshot(` + "\\"rehypePlugins[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: + - A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or + - A simple module, like \`require(\\"remark-math\\")\`" + `); }); it('rejects bad path inputs', () => { diff --git a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap index 56a45cbbc2..dc6695380d 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap +++ b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap @@ -28,15 +28,35 @@ exports[`validation schemas pluginIdSchema: for value=null 1`] = `"\\"value\\" m exports[`validation schemas pluginIdSchema: for value=true 1`] = `"\\"value\\" must be a string"`; -exports[`validation schemas rehypePluginsSchema: for value=[[]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[[]] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; -exports[`validation schemas rehypePluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[[null,null]] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; -exports[`validation schemas rehypePluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[3] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; -exports[`validation schemas rehypePluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[false] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; -exports[`validation schemas rehypePluginsSchema: for value=[null] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas rehypePluginsSchema: for value=[null] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; exports[`validation schemas rehypePluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`; @@ -44,15 +64,35 @@ exports[`validation schemas rehypePluginsSchema: for value=false 1`] = `"\\"valu exports[`validation schemas rehypePluginsSchema: for value=null 1`] = `"\\"value\\" must be an array"`; -exports[`validation schemas remarkPluginsSchema: for value=[[]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[[]] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; -exports[`validation schemas remarkPluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[[null,null]] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; -exports[`validation schemas remarkPluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[3] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; -exports[`validation schemas remarkPluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[false] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; -exports[`validation schemas remarkPluginsSchema: for value=[null] 1`] = `"\\"[0]\\" does not match any of the allowed types"`; +exports[`validation schemas remarkPluginsSchema: for value=[null] 1`] = ` +"\\"[0]\\" does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require(\\"rehype-katex\\"), { strict: false }]\`, or +- A simple module, like \`require(\\"remark-math\\")\`" +`; exports[`validation schemas remarkPluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`; diff --git a/packages/docusaurus-utils-validation/src/validationSchemas.ts b/packages/docusaurus-utils-validation/src/validationSchemas.ts index bf2bf6826f..f49b962a85 100644 --- a/packages/docusaurus-utils-validation/src/validationSchemas.ts +++ b/packages/docusaurus-utils-validation/src/validationSchemas.ts @@ -23,6 +23,11 @@ const MarkdownPluginsSchema = Joi.array() Joi.function(), Joi.object(), ) + .messages({ + 'array.includes': `{#label} does not look like a valid MDX plugin config. A plugin config entry should be one of: +- A tuple, like \`[require("rehype-katex"), \\{ strict: false \\}]\`, or +- A simple module, like \`require("remark-math")\``, + }) .default([]); export const RemarkPluginsSchema = MarkdownPluginsSchema; diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap index aad69e1e28..0c24cbaf8b 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap @@ -161,23 +161,3 @@ exports[`normalizeConfig throws error for unknown field 1`] = ` If you still want these fields to be in your configuration, put them in the \\"customFields\\" field. See https://docusaurus.io/docs/docusaurus.config.js/#customfields" `; - -exports[`normalizeConfig throws error if css doesn't have href 1`] = ` -"\\"stylesheets[1]\\" does not match any of the allowed types -" -`; - -exports[`normalizeConfig throws error if presets is not array 1`] = ` -"\\"presets\\" must be an array -" -`; - -exports[`normalizeConfig throws error if scripts doesn't have src 1`] = ` -"\\"scripts[1]\\" does not match any of the allowed types -" -`; - -exports[`normalizeConfig throws error if themes is not array 1`] = ` -"\\"themes\\" must be an array -" -`; diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index 90233c3537..b6d606b417 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -224,7 +224,10 @@ describe('normalizeConfig', () => { normalizeConfig({ themes: {}, }); - }).toThrowErrorMatchingSnapshot(); + }).toThrowErrorMatchingInlineSnapshot(` + "\\"themes\\" must be an array + " + `); }); it('throws error if presets is not array', () => { @@ -232,7 +235,23 @@ describe('normalizeConfig', () => { normalizeConfig({ presets: {}, }); - }).toThrowErrorMatchingSnapshot(); + }).toThrowErrorMatchingInlineSnapshot(` + "\\"presets\\" must be an array + " + `); + }); + + it('throws error if presets looks invalid', () => { + expect(() => { + normalizeConfig({ + presets: [() => {}], + }); + }).toThrowErrorMatchingInlineSnapshot(` + "\\"presets[0]\\" does not look like a valid preset config. A preset config entry should be one of: + - A tuple of [presetName, options], like \`[\\"classic\\", { blog: false }]\`, or + - A simple string, like \`\\"classic\\"\` + " + `); }); it("throws error if scripts doesn't have src", () => { @@ -240,7 +259,10 @@ describe('normalizeConfig', () => { normalizeConfig({ scripts: ['https://some.com', {}], }); - }).toThrowErrorMatchingSnapshot(); + }).toThrowErrorMatchingInlineSnapshot(` + "\\"scripts[1]\\" is invalid. A script must be a plain string (the src), or an object with at least a \\"src\\" property. + " + `); }); it("throws error if css doesn't have href", () => { @@ -248,7 +270,10 @@ describe('normalizeConfig', () => { normalizeConfig({ stylesheets: ['https://somescript.com', {type: 'text/css'}], }); - }).toThrowErrorMatchingSnapshot(); + }).toThrowErrorMatchingInlineSnapshot(` + "\\"stylesheets[1]\\" is invalid. A stylesheet must be a plain string (the href), or an object with at least a \\"href\\" property. + " + `); }); it('throws error for required fields', () => { diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index d4dfb2f4fd..4ad8103756 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -113,10 +113,18 @@ const PluginSchema = createPluginSchema(false); const ThemeSchema = createPluginSchema(true); -const PresetSchema = Joi.alternatives().try( - Joi.string(), - Joi.array().items(Joi.string().required(), Joi.object().required()).length(2), -); +const PresetSchema = Joi.alternatives() + .try( + Joi.string(), + Joi.array() + .items(Joi.string().required(), Joi.object().required()) + .length(2), + ) + .messages({ + 'alternatives.types': `{#label} does not look like a valid preset config. A preset config entry should be one of: +- A tuple of [presetName, options], like \`["classic", \\{ blog: false \\}]\`, or +- A simple string, like \`"classic"\``, + }); const LocaleConfigSchema = Joi.object({ label: Joi.string(), @@ -190,6 +198,10 @@ export const ConfigSchema = Joi.object({ // See https://github.com/facebook/docusaurus/issues/3378 .unknown(), ) + .messages({ + 'array.includes': + '{#label} is invalid. A script must be a plain string (the src), or an object with at least a "src" property.', + }) .default(DEFAULT_CONFIG.scripts), ssrTemplate: Joi.string(), stylesheets: Joi.array() @@ -200,6 +212,10 @@ export const ConfigSchema = Joi.object({ type: Joi.string(), }).unknown(), ) + .messages({ + 'array.includes': + '{#label} is invalid. A stylesheet must be a plain string (the href), or an object with at least a "href" property.', + }) .default(DEFAULT_CONFIG.stylesheets), clientModules: Joi.array() .items(Joi.string())