mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-04 04:37:28 +02:00
test(v2): add tests for config validation (#3142)
* test(v2): add tests for correctly defined fields * test(v2): add test for remarkPlugins and rehypePlugins validation * test(v2): modify tests and comments
This commit is contained in:
parent
ee2d1b42f6
commit
e7ec93b0b9
7 changed files with 144 additions and 69 deletions
|
@ -1,5 +1,5 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`throw Error in case of invalid feedtype 1`] = `[ValidationError: "feedOptions.type" does not match any of the allowed types]`;
|
exports[`should throw Error in case of invalid feedtype 1`] = `[ValidationError: "feedOptions.type" does not match any of the allowed types]`;
|
||||||
|
|
||||||
exports[`throw Error in case of invalid options 1`] = `[ValidationError: "postsPerPage" must be larger than or equal to 1]`;
|
exports[`should throw Error in case of invalid options 1`] = `[ValidationError: "postsPerPage" must be larger than or equal to 1]`;
|
||||||
|
|
|
@ -7,28 +7,47 @@
|
||||||
|
|
||||||
import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema';
|
import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema';
|
||||||
|
|
||||||
test('normalize options', () => {
|
// the type of remark/rehype plugins is function
|
||||||
|
const remarkRehypePluginStub = () => {};
|
||||||
|
|
||||||
|
test('should normalize options', () => {
|
||||||
const {value} = PluginOptionSchema.validate({});
|
const {value} = PluginOptionSchema.validate({});
|
||||||
expect(value).toEqual(DEFAULT_OPTIONS);
|
expect(value).toEqual(DEFAULT_OPTIONS);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('validate options', () => {
|
test('should accept correctly defined user options', () => {
|
||||||
const {value} = PluginOptionSchema.validate({
|
const userOptions = {
|
||||||
path: 'not_blog',
|
|
||||||
postsPerPage: 5,
|
|
||||||
include: ['api/*', 'docs/*'],
|
|
||||||
routeBasePath: 'not_blog',
|
|
||||||
});
|
|
||||||
expect(value).toEqual({
|
|
||||||
...DEFAULT_OPTIONS,
|
...DEFAULT_OPTIONS,
|
||||||
|
feedOptions: {type: 'rss', title: 'myTitle'},
|
||||||
|
path: 'not_blog',
|
||||||
|
routeBasePath: '',
|
||||||
postsPerPage: 5,
|
postsPerPage: 5,
|
||||||
include: ['api/*', 'docs/*'],
|
include: ['api/*', 'docs/*'],
|
||||||
routeBasePath: 'not_blog',
|
};
|
||||||
path: 'not_blog',
|
const {value} = PluginOptionSchema.validate(userOptions);
|
||||||
|
expect(value).toEqual({
|
||||||
|
...userOptions,
|
||||||
|
feedOptions: {type: ['rss'], title: 'myTitle'},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throw Error in case of invalid options', () => {
|
test('should accept valid user options', async () => {
|
||||||
|
const userOptions = {
|
||||||
|
...DEFAULT_OPTIONS,
|
||||||
|
routebasePath: '',
|
||||||
|
beforeDefaultRemarkPlugins: [],
|
||||||
|
beforeDefaultRehypePlugins: [remarkRehypePluginStub],
|
||||||
|
remarkPlugins: [remarkRehypePluginStub, {option1: '42'}],
|
||||||
|
rehypePlugins: [
|
||||||
|
remarkRehypePluginStub,
|
||||||
|
[remarkRehypePluginStub, {option1: '42'}],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const {value} = await PluginOptionSchema.validate(userOptions);
|
||||||
|
expect(value).toEqual(userOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should throw Error in case of invalid options', () => {
|
||||||
const {error} = PluginOptionSchema.validate({
|
const {error} = PluginOptionSchema.validate({
|
||||||
path: 'not_blog',
|
path: 'not_blog',
|
||||||
postsPerPage: -1,
|
postsPerPage: -1,
|
||||||
|
@ -39,7 +58,7 @@ test('throw Error in case of invalid options', () => {
|
||||||
expect(error).toMatchSnapshot();
|
expect(error).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throw Error in case of invalid feedtype', () => {
|
test('should throw Error in case of invalid feedtype', () => {
|
||||||
const {error} = PluginOptionSchema.validate({
|
const {error} = PluginOptionSchema.validate({
|
||||||
feedOptions: {
|
feedOptions: {
|
||||||
type: 'none',
|
type: 'none',
|
||||||
|
@ -49,7 +68,7 @@ test('throw Error in case of invalid feedtype', () => {
|
||||||
expect(error).toMatchSnapshot();
|
expect(error).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('convert all feed type to array with other feed type', () => {
|
test('should convert all feed type to array with other feed type', () => {
|
||||||
const {value} = PluginOptionSchema.validate({
|
const {value} = PluginOptionSchema.validate({
|
||||||
feedOptions: {type: 'all'},
|
feedOptions: {type: 'all'},
|
||||||
});
|
});
|
||||||
|
|
|
@ -63,10 +63,20 @@ export const PluginOptionSchema = Joi.object({
|
||||||
truncateMarker: Joi.object().default(DEFAULT_OPTIONS.truncateMarker),
|
truncateMarker: Joi.object().default(DEFAULT_OPTIONS.truncateMarker),
|
||||||
admonitions: Joi.object().default(DEFAULT_OPTIONS.admonitions),
|
admonitions: Joi.object().default(DEFAULT_OPTIONS.admonitions),
|
||||||
beforeDefaultRemarkPlugins: Joi.array()
|
beforeDefaultRemarkPlugins: Joi.array()
|
||||||
.items(Joi.object())
|
.items(
|
||||||
|
Joi.array()
|
||||||
|
.items(Joi.function().required(), Joi.object().required())
|
||||||
|
.length(2),
|
||||||
|
Joi.function(),
|
||||||
|
)
|
||||||
.default(DEFAULT_OPTIONS.beforeDefaultRemarkPlugins),
|
.default(DEFAULT_OPTIONS.beforeDefaultRemarkPlugins),
|
||||||
beforeDefaultRehypePlugins: Joi.array()
|
beforeDefaultRehypePlugins: Joi.array()
|
||||||
.items(Joi.object())
|
.items(
|
||||||
|
Joi.array()
|
||||||
|
.items(Joi.function().required(), Joi.object().required())
|
||||||
|
.length(2),
|
||||||
|
Joi.function(),
|
||||||
|
)
|
||||||
.default(DEFAULT_OPTIONS.beforeDefaultRehypePlugins),
|
.default(DEFAULT_OPTIONS.beforeDefaultRehypePlugins),
|
||||||
feedOptions: Joi.object({
|
feedOptions: Joi.object({
|
||||||
type: Joi.alternatives().conditional(
|
type: Joi.alternatives().conditional(
|
||||||
|
@ -75,8 +85,8 @@ export const PluginOptionSchema = Joi.object({
|
||||||
then: Joi.custom((val) => (val === 'all' ? ['rss', 'atom'] : [val])),
|
then: Joi.custom((val) => (val === 'all' ? ['rss', 'atom'] : [val])),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
title: Joi.string(),
|
title: Joi.string().allow(''),
|
||||||
description: Joi.string(),
|
description: Joi.string().allow(''),
|
||||||
copyright: Joi.string(),
|
copyright: Joi.string(),
|
||||||
language: Joi.string(),
|
language: Joi.string(),
|
||||||
}).default(DEFAULT_OPTIONS.feedOptions),
|
}).default(DEFAULT_OPTIONS.feedOptions),
|
||||||
|
|
|
@ -18,6 +18,9 @@ export default function normalizePluginOptions(options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the type of remark/rehype plugins is function
|
||||||
|
const remarkRehypePluginStub = () => {};
|
||||||
|
|
||||||
describe('normalizeDocsPluginOptions', () => {
|
describe('normalizeDocsPluginOptions', () => {
|
||||||
test('should return default options for undefined user options', async () => {
|
test('should return default options for undefined user options', async () => {
|
||||||
const {value} = await PluginOptionSchema.validate({});
|
const {value} = await PluginOptionSchema.validate({});
|
||||||
|
@ -34,14 +37,26 @@ describe('normalizeDocsPluginOptions', () => {
|
||||||
docLayoutComponent: '@theme/DocPage',
|
docLayoutComponent: '@theme/DocPage',
|
||||||
docItemComponent: '@theme/DocItem',
|
docItemComponent: '@theme/DocItem',
|
||||||
remarkPlugins: [],
|
remarkPlugins: [],
|
||||||
rehypePlugins: [],
|
rehypePlugins: [remarkRehypePluginStub],
|
||||||
showLastUpdateTime: true,
|
showLastUpdateTime: true,
|
||||||
showLastUpdateAuthor: true,
|
showLastUpdateAuthor: true,
|
||||||
admonitions: {},
|
admonitions: {},
|
||||||
excludeNextVersionDocs: true,
|
excludeNextVersionDocs: true,
|
||||||
disableVersioning: true,
|
disableVersioning: true,
|
||||||
};
|
};
|
||||||
|
const {value} = await PluginOptionSchema.validate(userOptions);
|
||||||
|
expect(value).toEqual(userOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should accept correctly defined remark and rehype plugin options', async () => {
|
||||||
|
const userOptions = {
|
||||||
|
...DEFAULT_OPTIONS,
|
||||||
|
remarkPlugins: [remarkRehypePluginStub, {option1: '42'}],
|
||||||
|
rehypePlugins: [
|
||||||
|
remarkRehypePluginStub,
|
||||||
|
[remarkRehypePluginStub, {option1: '42'}],
|
||||||
|
],
|
||||||
|
};
|
||||||
const {value} = await PluginOptionSchema.validate(userOptions);
|
const {value} = await PluginOptionSchema.validate(userOptions);
|
||||||
expect(value).toEqual(userOptions);
|
expect(value).toEqual(userOptions);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,50 +1,51 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`validateConfig throw error for baseUrl without trailing \`/\` 1`] = `
|
exports[`normalizeConfig should throw error for baseUrl without trailing \`/\` 1`] = `
|
||||||
"\\"baseUrl\\" must be a string with a trailing \`/\`
|
"\\"baseUrl\\" must be a string with a trailing \`/\`
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`validateConfig throw error for required fields 1`] = `
|
exports[`normalizeConfig should throw error for required fields 1`] = `
|
||||||
"\\"baseUrl\\" is required
|
"\\"baseUrl\\" is required
|
||||||
\\"favicon\\" is required
|
\\"favicon\\" is required
|
||||||
\\"title\\" is required
|
\\"title\\" is required
|
||||||
\\"url\\" is required
|
\\"url\\" is required
|
||||||
\\"themes\\" must be an array
|
\\"themes\\" must be an array
|
||||||
|
\\"presets\\" must be an array
|
||||||
\\"scripts\\" must be an array
|
\\"scripts\\" must be an array
|
||||||
\\"stylesheets\\" must be an array
|
\\"stylesheets\\" must be an array
|
||||||
These field(s) [\\"invalid\\",\\"preset\\",] are not recognized in docusaurus.config.js.
|
These field(s) [\\"invalidField\\",] are not recognized in docusaurus.config.js.
|
||||||
If you still want these fields to be in your configuration, put them in the 'customFields' attribute.
|
If you still want these fields to be in your configuration, put them in the 'customFields' attribute.
|
||||||
See https://v2.docusaurus.io/docs/docusaurus.config.js/#customfields"
|
See https://v2.docusaurus.io/docs/docusaurus.config.js/#customfields"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`validateConfig throw error for unknown field 1`] = `
|
exports[`normalizeConfig should throw error for unknown field 1`] = `
|
||||||
"These field(s) [\\"invalid\\",] are not recognized in docusaurus.config.js.
|
"These field(s) [\\"invalid\\",] are not recognized in docusaurus.config.js.
|
||||||
If you still want these fields to be in your configuration, put them in the 'customFields' attribute.
|
If you still want these fields to be in your configuration, put them in the 'customFields' attribute.
|
||||||
See https://v2.docusaurus.io/docs/docusaurus.config.js/#customfields"
|
See https://v2.docusaurus.io/docs/docusaurus.config.js/#customfields"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`validateConfig throw error if css doesn't have href 1`] = `
|
exports[`normalizeConfig should throw error if css doesn't have href 1`] = `
|
||||||
"\\"stylesheets[1]\\" does not match any of the allowed types
|
"\\"stylesheets[1]\\" does not match any of the allowed types
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`validateConfig throw error if plugins is not array 1`] = `
|
exports[`normalizeConfig should throw error if plugins is not array 1`] = `
|
||||||
"\\"plugins\\" must be an array
|
"\\"plugins\\" must be an array
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`validateConfig throw error if presets is not array 1`] = `
|
exports[`normalizeConfig should throw error if presets is not array 1`] = `
|
||||||
"\\"presets\\" must be an array
|
"\\"presets\\" must be an array
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`validateConfig throw error if scripts doesn't have src 1`] = `
|
exports[`normalizeConfig should throw error if scripts doesn't have src 1`] = `
|
||||||
"\\"scripts[1]\\" does not match any of the allowed types
|
"\\"scripts[1]\\" does not match any of the allowed types
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`validateConfig throw error if themes is not array 1`] = `
|
exports[`normalizeConfig should throw error if themes is not array 1`] = `
|
||||||
"\\"themes\\" must be an array
|
"\\"themes\\" must be an array
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -15,94 +15,124 @@ const baseConfig = {
|
||||||
url: 'https://mysite.com',
|
url: 'https://mysite.com',
|
||||||
};
|
};
|
||||||
|
|
||||||
const testConfig = (config) => validateConfig({...baseConfig, ...config});
|
const normalizeConfig = (config) => validateConfig({...baseConfig, ...config});
|
||||||
|
|
||||||
describe('validateConfig', () => {
|
describe('normalizeConfig', () => {
|
||||||
test('normalize config', () => {
|
test('should normalize empty config', () => {
|
||||||
const value = testConfig({});
|
const value = normalizeConfig({});
|
||||||
expect(value).toEqual({
|
expect(value).toEqual({
|
||||||
...DEFAULT_CONFIG,
|
...DEFAULT_CONFIG,
|
||||||
...baseConfig,
|
...baseConfig,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throw error for unknown field', () => {
|
test('should accept correctly defined config options', () => {
|
||||||
|
const userConfig = {
|
||||||
|
...DEFAULT_CONFIG,
|
||||||
|
...baseConfig,
|
||||||
|
tagline: 'my awesome site',
|
||||||
|
organizationName: 'facebook',
|
||||||
|
projectName: 'docusaurus',
|
||||||
|
githubHost: 'github.com',
|
||||||
|
customFields: {
|
||||||
|
myCustomField: '42',
|
||||||
|
},
|
||||||
|
scripts: [
|
||||||
|
{
|
||||||
|
src: `/analytics.js`,
|
||||||
|
async: true,
|
||||||
|
defer: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
stylesheets: [
|
||||||
|
{
|
||||||
|
href: '/katex/katex.min.css',
|
||||||
|
type: 'text/css',
|
||||||
|
crossorigin: 'anonymous',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const normalizedConfig = normalizeConfig(userConfig);
|
||||||
|
expect(normalizedConfig).toEqual(userConfig);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should accept custom field in config', () => {
|
||||||
|
const value = normalizeConfig({
|
||||||
|
customFields: {
|
||||||
|
author: 'anshul',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(value).toEqual({
|
||||||
|
...DEFAULT_CONFIG,
|
||||||
|
...baseConfig,
|
||||||
|
customFields: {
|
||||||
|
author: 'anshul',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should throw error for unknown field', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
testConfig({
|
normalizeConfig({
|
||||||
invalid: true,
|
invalid: true,
|
||||||
});
|
});
|
||||||
}).toThrowErrorMatchingSnapshot();
|
}).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throw error for baseUrl without trailing `/`', () => {
|
test('should throw error for baseUrl without trailing `/`', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
testConfig({
|
normalizeConfig({
|
||||||
baseUrl: 'noslash',
|
baseUrl: 'noslash',
|
||||||
});
|
});
|
||||||
}).toThrowErrorMatchingSnapshot();
|
}).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throw error if plugins is not array', () => {
|
test('should throw error if plugins is not array', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
testConfig({
|
normalizeConfig({
|
||||||
plugins: {},
|
plugins: {},
|
||||||
});
|
});
|
||||||
}).toThrowErrorMatchingSnapshot();
|
}).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throw error if themes is not array', () => {
|
test('should throw error if themes is not array', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
testConfig({
|
normalizeConfig({
|
||||||
themes: {},
|
themes: {},
|
||||||
});
|
});
|
||||||
}).toThrowErrorMatchingSnapshot();
|
}).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throw error if presets is not array', () => {
|
test('should throw error if presets is not array', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
testConfig({
|
normalizeConfig({
|
||||||
presets: {},
|
presets: {},
|
||||||
});
|
});
|
||||||
}).toThrowErrorMatchingSnapshot();
|
}).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("throw error if scripts doesn't have src", () => {
|
test("should throw error if scripts doesn't have src", () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
testConfig({
|
normalizeConfig({
|
||||||
scripts: ['https://some.com', {}],
|
scripts: ['https://some.com', {}],
|
||||||
});
|
});
|
||||||
}).toThrowErrorMatchingSnapshot();
|
}).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("throw error if css doesn't have href", () => {
|
test("should throw error if css doesn't have href", () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
testConfig({
|
normalizeConfig({
|
||||||
stylesheets: ['https://somescript.com', {type: 'text/css'}],
|
stylesheets: ['https://somescript.com', {type: 'text/css'}],
|
||||||
});
|
});
|
||||||
}).toThrowErrorMatchingSnapshot();
|
}).toThrowErrorMatchingSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('custom field in config', () => {
|
test('should throw error for required fields', () => {
|
||||||
const value = testConfig({
|
|
||||||
customFields: {
|
|
||||||
author: 'anshul',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(value).toEqual({
|
|
||||||
...DEFAULT_CONFIG,
|
|
||||||
...baseConfig,
|
|
||||||
customFields: {
|
|
||||||
author: 'anshul',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('throw error for required fields', () => {
|
|
||||||
expect(
|
expect(
|
||||||
() =>
|
() =>
|
||||||
validateConfig(({
|
validateConfig(({
|
||||||
invalid: true,
|
invalidField: true,
|
||||||
preset: {},
|
presets: {},
|
||||||
stylesheets: {},
|
stylesheets: {},
|
||||||
themes: {},
|
themes: {},
|
||||||
scripts: {},
|
scripts: {},
|
||||||
|
|
|
@ -56,8 +56,8 @@ const ConfigSchema = Joi.object({
|
||||||
onBrokenLinks: Joi.string()
|
onBrokenLinks: Joi.string()
|
||||||
.equal('ignore', 'log', 'error', 'throw')
|
.equal('ignore', 'log', 'error', 'throw')
|
||||||
.default(DEFAULT_CONFIG.onBrokenLinks),
|
.default(DEFAULT_CONFIG.onBrokenLinks),
|
||||||
organizationName: Joi.string(),
|
organizationName: Joi.string().allow(''),
|
||||||
projectName: Joi.string(),
|
projectName: Joi.string().allow(''),
|
||||||
customFields: Joi.object().unknown().default(DEFAULT_CONFIG.customFields),
|
customFields: Joi.object().unknown().default(DEFAULT_CONFIG.customFields),
|
||||||
githubHost: Joi.string(),
|
githubHost: Joi.string(),
|
||||||
plugins: Joi.array().items(PluginSchema).default(DEFAULT_CONFIG.plugins),
|
plugins: Joi.array().items(PluginSchema).default(DEFAULT_CONFIG.plugins),
|
||||||
|
@ -79,7 +79,7 @@ const ConfigSchema = Joi.object({
|
||||||
type: Joi.string().required(),
|
type: Joi.string().required(),
|
||||||
}).unknown(),
|
}).unknown(),
|
||||||
),
|
),
|
||||||
tagline: Joi.string(),
|
tagline: Joi.string().allow(''),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function validateConfig(
|
export function validateConfig(
|
||||||
|
|
Loading…
Add table
Reference in a new issue