mirror of
https://github.com/facebook/docusaurus.git
synced 2025-08-06 02:08:55 +02:00
refactor(content-docs): clean up sidebars logic; validate generator returns (#6596)
* refactor(content-docs): clean up sidebars logic; validate generator returns * remove another TODO * fix types * refactors * refactor...
This commit is contained in:
parent
d6bdf7e804
commit
e3fd3e74ce
23 changed files with 750 additions and 615 deletions
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
{
|
||||
"type": "category",
|
||||
"label": true,
|
||||
"items": ["doc1"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
{
|
||||
"type": "doc",
|
||||
"id": ["doc1"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
{
|
||||
"type": "link",
|
||||
"label": "GitHub",
|
||||
"href": ["example.com"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
{
|
||||
"type": "link",
|
||||
"label": false,
|
||||
"href": "https://github.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
"foo/bar",
|
||||
"foo/baz",
|
||||
{
|
||||
"type": "superman"
|
||||
}
|
||||
],
|
||||
"Guides": [
|
||||
"hello"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
"foo/bar",
|
||||
"foo/baz",
|
||||
{
|
||||
"type": "category",
|
||||
"label": "category",
|
||||
"href": "https://github.com"
|
||||
},
|
||||
{
|
||||
"type": "ref",
|
||||
"id": "hello"
|
||||
}
|
||||
],
|
||||
"Guides": [
|
||||
"hello"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`loadNormalizedSidebars sidebars link 1`] = `
|
||||
exports[`loadSidebars sidebars link 1`] = `
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
|
@ -21,7 +21,7 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`loadNormalizedSidebars sidebars with category.collapsed property 1`] = `
|
||||
exports[`loadSidebars sidebars with category.collapsed property 1`] = `
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
|
@ -72,7 +72,7 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`loadNormalizedSidebars sidebars with category.collapsed property at first level 1`] = `
|
||||
exports[`loadSidebars sidebars with category.collapsed property at first level 1`] = `
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
|
@ -105,7 +105,7 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`loadNormalizedSidebars sidebars with deep level of category 1`] = `
|
||||
exports[`loadSidebars sidebars with deep level of category 1`] = `
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
|
@ -177,7 +177,7 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`loadNormalizedSidebars sidebars with first level not a category 1`] = `
|
||||
exports[`loadSidebars sidebars with first level not a category 1`] = `
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
|
@ -201,7 +201,7 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`loadNormalizedSidebars sidebars with known sidebar item type 1`] = `
|
||||
exports[`loadSidebars sidebars with known sidebar item type 1`] = `
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
|
@ -246,3 +246,23 @@ Object {
|
|||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`loadSidebars undefined path 1`] = `
|
||||
Object {
|
||||
"defaultSidebar": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"collapsible": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "bar",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "foo",
|
||||
"link": undefined,
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -214,8 +214,6 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
{
|
||||
type: 'category',
|
||||
label: 'Tutorials',
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'tutorials-index',
|
||||
|
@ -228,19 +226,16 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
{
|
||||
type: 'category',
|
||||
label: 'Guides',
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'guides-index',
|
||||
},
|
||||
collapsed: false,
|
||||
items: [
|
||||
{type: 'doc', id: 'guide1', className: 'foo'},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'SubGuides (metadata file label)',
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
items: [{type: 'doc', id: 'nested-guide'}],
|
||||
link: {
|
||||
type: 'generated-index',
|
||||
|
@ -279,8 +274,6 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
'subfolder/subsubfolder/subsubsubfolder3': {
|
||||
position: 1,
|
||||
label: 'subsubsubfolder3 (_category_.json label)',
|
||||
collapsible: false,
|
||||
collapsed: false,
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'doc1', // This is a "fully-qualified" ID that can't be found locally
|
||||
|
@ -355,8 +348,6 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
{
|
||||
type: 'category',
|
||||
label: 'subsubsubfolder3 (_category_.json label)',
|
||||
collapsed: false,
|
||||
collapsible: false,
|
||||
link: {
|
||||
id: 'doc1',
|
||||
type: 'doc',
|
||||
|
@ -369,8 +360,6 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
{
|
||||
type: 'category',
|
||||
label: 'subsubsubfolder2 (_category_.yml label)',
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
className: 'bar',
|
||||
items: [{type: 'doc', id: 'doc6'}],
|
||||
},
|
||||
|
@ -379,8 +368,6 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
{
|
||||
type: 'category',
|
||||
label: 'subsubsubfolder',
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
items: [{type: 'doc', id: 'doc5'}],
|
||||
},
|
||||
] as Sidebar);
|
||||
|
@ -458,8 +445,6 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
{
|
||||
type: 'category',
|
||||
label: 'Category label',
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
link: {
|
||||
id: 'parent/doc3',
|
||||
type: 'doc',
|
||||
|
@ -478,8 +463,6 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
{
|
||||
type: 'category',
|
||||
label: 'Category 2 label',
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
items: [
|
||||
{
|
||||
id: 'parent/doc4',
|
||||
|
@ -583,8 +566,6 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
{
|
||||
type: 'category',
|
||||
label: 'Tutorials',
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'tutorials-index',
|
||||
|
@ -597,8 +578,6 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
{
|
||||
type: 'category',
|
||||
label: 'Guides',
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
items: [
|
||||
{type: 'doc', id: 'guide1', className: 'foo'},
|
||||
{type: 'doc', id: 'guide2'},
|
||||
|
|
|
@ -6,32 +6,36 @@
|
|||
*/
|
||||
|
||||
import path from 'path';
|
||||
import {
|
||||
loadNormalizedSidebars,
|
||||
DefaultSidebars,
|
||||
DisabledSidebars,
|
||||
} from '../index';
|
||||
import type {NormalizeSidebarsParams, VersionMetadata} from '../../types';
|
||||
import {loadSidebars, DisabledSidebars} from '../index';
|
||||
import type {SidebarProcessorParams} from '../types';
|
||||
import {DefaultSidebarItemsGenerator} from '../generator';
|
||||
|
||||
describe('loadNormalizedSidebars', () => {
|
||||
describe('loadSidebars', () => {
|
||||
const fixtureDir = path.join(__dirname, '__fixtures__', 'sidebars');
|
||||
const options: NormalizeSidebarsParams = {
|
||||
sidebarCollapsed: true,
|
||||
sidebarCollapsible: true,
|
||||
version: {
|
||||
versionName: 'version',
|
||||
versionPath: 'versionPath',
|
||||
} as VersionMetadata,
|
||||
const params: SidebarProcessorParams = {
|
||||
sidebarItemsGenerator: DefaultSidebarItemsGenerator,
|
||||
numberPrefixParser: (filename) => ({filename}),
|
||||
docs: [
|
||||
{
|
||||
source: '@site/docs/foo/bar.md',
|
||||
sourceDirName: 'foo',
|
||||
id: 'bar',
|
||||
frontMatter: {},
|
||||
},
|
||||
],
|
||||
version: {contentPath: 'docs/foo', contentPathLocalized: 'docs/foo'},
|
||||
categoryLabelSlugger: null,
|
||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
||||
};
|
||||
test('sidebars with known sidebar item type', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars.json');
|
||||
const result = await loadNormalizedSidebars(sidebarPath, options);
|
||||
const result = await loadSidebars(sidebarPath, params);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('sidebars with deep level of category', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-category.js');
|
||||
const result = await loadNormalizedSidebars(sidebarPath, options);
|
||||
const result = await loadSidebars(sidebarPath, params);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -41,8 +45,8 @@ describe('loadNormalizedSidebars', () => {
|
|||
fixtureDir,
|
||||
'sidebars-category-shorthand.js',
|
||||
);
|
||||
const sidebar1 = await loadNormalizedSidebars(sidebarPath1, options);
|
||||
const sidebar2 = await loadNormalizedSidebars(sidebarPath2, options);
|
||||
const sidebar1 = await loadSidebars(sidebarPath1, params);
|
||||
const sidebar2 = await loadSidebars(sidebarPath2, params);
|
||||
expect(sidebar1).toEqual(sidebar2);
|
||||
});
|
||||
|
||||
|
@ -51,53 +55,11 @@ describe('loadNormalizedSidebars', () => {
|
|||
fixtureDir,
|
||||
'sidebars-category-wrong-items.json',
|
||||
);
|
||||
await expect(() => loadNormalizedSidebars(sidebarPath, options)).rejects
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"category\\",
|
||||
\\"label\\": \\"Category Label\\",
|
||||
\\"items\\" [31m[1][0m: \\"doc1\\"
|
||||
}
|
||||
[31m
|
||||
[1] \\"items\\" must be an array[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebars with category but category label is not a string', async () => {
|
||||
const sidebarPath = path.join(
|
||||
fixtureDir,
|
||||
'sidebars-category-wrong-label.json',
|
||||
await expect(() =>
|
||||
loadSidebars(sidebarPath, params),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"Invalid category {\\"type\\":\\"category\\",\\"label\\":\\"Category Label\\",\\"items\\":\\"doc1\\"}: items must be an array"`,
|
||||
);
|
||||
await expect(() => loadNormalizedSidebars(sidebarPath, options)).rejects
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"category\\",
|
||||
\\"items\\": [
|
||||
\\"doc1\\"
|
||||
],
|
||||
\\"label\\" [31m[1][0m: true
|
||||
}
|
||||
[31m
|
||||
[1] \\"label\\" must be a string[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebars item doc but id is not a string', async () => {
|
||||
const sidebarPath = path.join(
|
||||
fixtureDir,
|
||||
'sidebars-doc-id-not-string.json',
|
||||
);
|
||||
await expect(() => loadNormalizedSidebars(sidebarPath, options)).rejects
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"doc\\",
|
||||
\\"id\\" [31m[1][0m: [
|
||||
\\"doc1\\"
|
||||
]
|
||||
}
|
||||
[31m
|
||||
[1] \\"id\\" must be a string[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebars with first level not a category', async () => {
|
||||
|
@ -105,95 +67,35 @@ describe('loadNormalizedSidebars', () => {
|
|||
fixtureDir,
|
||||
'sidebars-first-level-not-category.js',
|
||||
);
|
||||
const result = await loadNormalizedSidebars(sidebarPath, options);
|
||||
const result = await loadSidebars(sidebarPath, params);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('sidebars link', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-link.json');
|
||||
const result = await loadNormalizedSidebars(sidebarPath, options);
|
||||
const result = await loadSidebars(sidebarPath, params);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('sidebars link wrong label', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-link-wrong-label.json');
|
||||
await expect(() => loadNormalizedSidebars(sidebarPath, options)).rejects
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"link\\",
|
||||
\\"href\\": \\"https://github.com\\",
|
||||
\\"label\\" [31m[1][0m: false
|
||||
}
|
||||
[31m
|
||||
[1] \\"label\\" must be a string[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebars link wrong href', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-link-wrong-href.json');
|
||||
await expect(() => loadNormalizedSidebars(sidebarPath, options)).rejects
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"link\\",
|
||||
\\"label\\": \\"GitHub\\",
|
||||
\\"href\\" [31m[1][0m: [
|
||||
\\"example.com\\"
|
||||
]
|
||||
}
|
||||
[31m
|
||||
[1] \\"href\\" contains an invalid value[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebars with unknown sidebar item type', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-unknown-type.json');
|
||||
await expect(() => loadNormalizedSidebars(sidebarPath, options)).rejects
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"superman\\",
|
||||
[41m\\"undefined\\"[0m[31m [1]: -- missing --[0m
|
||||
}
|
||||
[31m
|
||||
[1] Unknown sidebar item type \\"superman\\".[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebars with known sidebar item type but wrong field', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-wrong-field.json');
|
||||
await expect(() => loadNormalizedSidebars(sidebarPath, options)).rejects
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"category\\",
|
||||
\\"label\\": \\"category\\",
|
||||
\\"href\\": \\"https://github.com\\",
|
||||
[41m\\"items\\"[0m[31m [1]: -- missing --[0m
|
||||
}
|
||||
[31m
|
||||
[1] \\"items\\" is required[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('unexisting path', async () => {
|
||||
await expect(loadNormalizedSidebars('badpath', options)).resolves.toEqual(
|
||||
await expect(loadSidebars('badpath', params)).resolves.toEqual(
|
||||
DisabledSidebars,
|
||||
);
|
||||
});
|
||||
|
||||
test('undefined path', async () => {
|
||||
await expect(loadNormalizedSidebars(undefined, options)).resolves.toEqual(
|
||||
DefaultSidebars,
|
||||
);
|
||||
await expect(loadSidebars(undefined, params)).resolves.toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('literal false path', async () => {
|
||||
await expect(loadNormalizedSidebars(false, options)).resolves.toEqual(
|
||||
await expect(loadSidebars(false, params)).resolves.toEqual(
|
||||
DisabledSidebars,
|
||||
);
|
||||
});
|
||||
|
||||
test('sidebars with category.collapsed property', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-collapsed.json');
|
||||
const result = await loadNormalizedSidebars(sidebarPath, options);
|
||||
const result = await loadSidebars(sidebarPath, params);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -202,7 +104,7 @@ describe('loadNormalizedSidebars', () => {
|
|||
fixtureDir,
|
||||
'sidebars-collapsed-first-level.json',
|
||||
);
|
||||
const result = await loadNormalizedSidebars(sidebarPath, options);
|
||||
const result = await loadSidebars(sidebarPath, params);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {postProcessSidebars} from '../postProcessor';
|
||||
|
||||
describe('postProcess', () => {
|
||||
test('transforms category without subitems', () => {
|
||||
const processedSidebar = postProcessSidebars(
|
||||
{
|
||||
sidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category',
|
||||
link: {
|
||||
type: 'generated-index',
|
||||
slug: 'generated/permalink',
|
||||
},
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category 2',
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'doc ID',
|
||||
},
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
||||
version: {versionPath: 'version'},
|
||||
},
|
||||
);
|
||||
|
||||
expect(processedSidebar).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"sidebar": Array [
|
||||
Object {
|
||||
"href": "version/generated/permalink",
|
||||
"label": "Category",
|
||||
"type": "link",
|
||||
},
|
||||
Object {
|
||||
"id": "doc ID",
|
||||
"label": "Category 2",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
|
||||
expect(() => {
|
||||
postProcessSidebars(
|
||||
{
|
||||
sidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Bad category',
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
||||
version: {versionPath: 'version'},
|
||||
},
|
||||
);
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Sidebar category Bad category has neither any subitem nor a link. This makes this item not able to link to anything."`,
|
||||
);
|
||||
});
|
||||
|
||||
test('corrects collapsed state inconsistencies', () => {
|
||||
expect(
|
||||
postProcessSidebars(
|
||||
{
|
||||
sidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category',
|
||||
collapsed: true,
|
||||
collapsible: false,
|
||||
items: [{type: 'doc', id: 'foo'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
|
||||
version: {versionPath: 'version'},
|
||||
},
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"sidebar": Array [
|
||||
Object {
|
||||
"collapsed": false,
|
||||
"collapsible": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "foo",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "Category",
|
||||
"link": undefined,
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
|
||||
expect(
|
||||
postProcessSidebars(
|
||||
{
|
||||
sidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category',
|
||||
collapsed: true,
|
||||
items: [{type: 'doc', id: 'foo'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
sidebarOptions: {sidebarCollapsed: false, sidebarCollapsible: false},
|
||||
version: {versionPath: 'version'},
|
||||
},
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"sidebar": Array [
|
||||
Object {
|
||||
"collapsed": false,
|
||||
"collapsible": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "foo",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "Category",
|
||||
"link": undefined,
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
|
||||
expect(
|
||||
postProcessSidebars(
|
||||
{
|
||||
sidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category',
|
||||
items: [{type: 'doc', id: 'foo'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: false},
|
||||
version: {versionPath: 'version'},
|
||||
},
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"sidebar": Array [
|
||||
Object {
|
||||
"collapsed": false,
|
||||
"collapsible": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "foo",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "Category",
|
||||
"link": undefined,
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
|
@ -5,12 +5,15 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {processSidebars, type SidebarProcessorParams} from '../processor';
|
||||
import {processSidebars} from '../processor';
|
||||
import type {
|
||||
SidebarItem,
|
||||
SidebarItemsGenerator,
|
||||
Sidebars,
|
||||
NormalizedSidebar,
|
||||
NormalizedSidebars,
|
||||
SidebarProcessorParams,
|
||||
CategoryMetadataFile,
|
||||
ProcessedSidebars,
|
||||
} from '../types';
|
||||
import {DefaultSidebarItemsGenerator} from '../generator';
|
||||
import {createSlugger} from '@docusaurus/utils';
|
||||
|
@ -25,7 +28,7 @@ describe('processSidebars', () => {
|
|||
return jest.fn(async () => sidebarSlice);
|
||||
}
|
||||
|
||||
const StaticGeneratedSidebarSlice: SidebarItem[] = [
|
||||
const StaticGeneratedSidebarSlice: NormalizedSidebar = [
|
||||
{type: 'doc', id: 'doc-generated-id-1'},
|
||||
{type: 'doc', id: 'doc-generated-id-2'},
|
||||
];
|
||||
|
@ -53,9 +56,10 @@ describe('processSidebars', () => {
|
|||
|
||||
async function testProcessSidebars(
|
||||
unprocessedSidebars: NormalizedSidebars,
|
||||
categoriesMetadata: Record<string, CategoryMetadataFile> = {},
|
||||
paramsOverrides: Partial<SidebarProcessorParams> = {},
|
||||
) {
|
||||
return processSidebars(unprocessedSidebars, {
|
||||
return processSidebars(unprocessedSidebars, categoriesMetadata, {
|
||||
...params,
|
||||
...paramsOverrides,
|
||||
});
|
||||
|
@ -101,10 +105,7 @@ describe('processSidebars', () => {
|
|||
link: {
|
||||
type: 'generated-index',
|
||||
slug: 'category-generated-index-slug',
|
||||
permalink: 'category-generated-index-permalink',
|
||||
},
|
||||
collapsed: true, // A suspicious bad config that will be normalized
|
||||
collapsible: false,
|
||||
items: [
|
||||
{type: 'doc', id: 'doc2'},
|
||||
{type: 'autogenerated', dirName: 'dir1'},
|
||||
|
@ -131,6 +132,7 @@ describe('processSidebars', () => {
|
|||
|
||||
expect(StaticSidebarItemsGenerator).toHaveBeenCalledTimes(3);
|
||||
expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({
|
||||
categoriesMetadata: {},
|
||||
defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
|
||||
item: {type: 'autogenerated', dirName: 'dir1'},
|
||||
docs: params.docs,
|
||||
|
@ -143,6 +145,7 @@ describe('processSidebars', () => {
|
|||
});
|
||||
expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({
|
||||
defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
|
||||
categoriesMetadata: {},
|
||||
item: {type: 'autogenerated', dirName: 'dir2'},
|
||||
docs: params.docs,
|
||||
version: {
|
||||
|
@ -154,6 +157,7 @@ describe('processSidebars', () => {
|
|||
});
|
||||
expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({
|
||||
defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
|
||||
categoriesMetadata: {},
|
||||
item: {type: 'autogenerated', dirName: 'dir3'},
|
||||
docs: params.docs,
|
||||
version: {
|
||||
|
@ -173,10 +177,7 @@ describe('processSidebars', () => {
|
|||
link: {
|
||||
type: 'generated-index',
|
||||
slug: 'category-generated-index-slug',
|
||||
permalink: 'category-generated-index-permalink',
|
||||
},
|
||||
collapsed: false,
|
||||
collapsible: false,
|
||||
items: [{type: 'doc', id: 'doc2'}, ...StaticGeneratedSidebarSlice],
|
||||
},
|
||||
{type: 'link', href: 'https://facebook.com', label: 'FB'},
|
||||
|
@ -194,20 +195,17 @@ describe('processSidebars', () => {
|
|||
items: [{type: 'doc', id: 'doc4'}],
|
||||
},
|
||||
],
|
||||
} as Sidebars);
|
||||
} as ProcessedSidebars);
|
||||
});
|
||||
|
||||
test('ensure generated items are normalized', async () => {
|
||||
const sidebarSliceContainingCategoryGeneratedIndex: SidebarItem[] = [
|
||||
const sidebarSliceContainingCategoryGeneratedIndex: NormalizedSidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Generated category',
|
||||
link: {
|
||||
type: 'generated-index',
|
||||
slug: 'generated-cat-index-slug',
|
||||
// @ts-expect-error: TODO undefined should be allowed here,
|
||||
// typing error needing refactor
|
||||
permalink: undefined,
|
||||
},
|
||||
items: [
|
||||
{
|
||||
|
@ -218,15 +216,19 @@ describe('processSidebars', () => {
|
|||
},
|
||||
];
|
||||
|
||||
const unprocessedSidebars: NormalizedSidebars = {
|
||||
const unprocessedSidebars = {
|
||||
someSidebar: [{type: 'autogenerated', dirName: 'dir2'}],
|
||||
};
|
||||
|
||||
const processedSidebar = await testProcessSidebars(unprocessedSidebars, {
|
||||
sidebarItemsGenerator: createStaticSidebarItemGenerator(
|
||||
sidebarSliceContainingCategoryGeneratedIndex,
|
||||
),
|
||||
});
|
||||
const processedSidebar = await testProcessSidebars(
|
||||
unprocessedSidebars,
|
||||
{},
|
||||
{
|
||||
sidebarItemsGenerator: createStaticSidebarItemGenerator(
|
||||
sidebarSliceContainingCategoryGeneratedIndex,
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
expect(processedSidebar).toEqual({
|
||||
someSidebar: [
|
||||
|
@ -236,7 +238,6 @@ describe('processSidebars', () => {
|
|||
link: {
|
||||
type: 'generated-index',
|
||||
slug: 'generated-cat-index-slug',
|
||||
permalink: '/docs/1.0.0/generated-cat-index-slug',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
|
@ -244,67 +245,8 @@ describe('processSidebars', () => {
|
|||
id: 'foo',
|
||||
},
|
||||
],
|
||||
collapsible: true,
|
||||
collapsed: true,
|
||||
},
|
||||
],
|
||||
} as Sidebars);
|
||||
});
|
||||
|
||||
test('transforms category without subitems', async () => {
|
||||
const sidebarSlice: SidebarItem[] = [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category',
|
||||
link: {
|
||||
type: 'generated-index',
|
||||
permalink: 'generated/permalink',
|
||||
},
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category 2',
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'doc ID',
|
||||
},
|
||||
items: [],
|
||||
},
|
||||
];
|
||||
|
||||
const processedSidebar = await testProcessSidebars(
|
||||
{sidebar: sidebarSlice},
|
||||
{},
|
||||
);
|
||||
|
||||
expect(processedSidebar).toEqual({
|
||||
sidebar: [
|
||||
{
|
||||
type: 'link',
|
||||
label: 'Category',
|
||||
href: 'generated/permalink',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
label: 'Category 2',
|
||||
id: 'doc ID',
|
||||
},
|
||||
],
|
||||
} as Sidebars);
|
||||
|
||||
await expect(async () => {
|
||||
await testProcessSidebars({
|
||||
sidebar: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Bad category',
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
}).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"Sidebar category Bad category has neither any subitem nor a link. This makes this item not able to link to anything."`,
|
||||
);
|
||||
} as ProcessedSidebars);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,14 +6,9 @@
|
|||
*/
|
||||
|
||||
import {validateSidebars, validateCategoryMetadataFile} from '../validation';
|
||||
import type {CategoryMetadataFile} from '../generator';
|
||||
import type {SidebarsConfig} from '../types';
|
||||
import type {SidebarsConfig, CategoryMetadataFile} from '../types';
|
||||
|
||||
describe('validateSidebars', () => {
|
||||
// TODO add more tests
|
||||
|
||||
// TODO it seems many error cases are not validated properly
|
||||
// and error messages are quite bad
|
||||
test('throw for bad value', async () => {
|
||||
expect(() => validateSidebars({sidebar: [{type: 42}]}))
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
|
@ -45,10 +40,193 @@ describe('validateSidebars', () => {
|
|||
};
|
||||
validateSidebars(sidebars);
|
||||
});
|
||||
});
|
||||
|
||||
describe('html item type', () => {
|
||||
test('requires a value', () => {
|
||||
test('sidebar category wrong label', () => {
|
||||
expect(() =>
|
||||
validateSidebars({
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: true,
|
||||
items: [{type: 'doc', id: 'doc1'}],
|
||||
},
|
||||
],
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"category\\",
|
||||
\\"items\\": [
|
||||
{
|
||||
\\"type\\": \\"doc\\",
|
||||
\\"id\\": \\"doc1\\"
|
||||
}
|
||||
],
|
||||
\\"label\\" [31m[1][0m: true
|
||||
}
|
||||
[31m
|
||||
[1] \\"label\\" must be a string[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebars link wrong label', () => {
|
||||
expect(() =>
|
||||
validateSidebars({
|
||||
docs: [
|
||||
{
|
||||
type: 'link',
|
||||
label: false,
|
||||
href: 'https://github.com',
|
||||
},
|
||||
],
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"link\\",
|
||||
\\"href\\": \\"https://github.com\\",
|
||||
\\"label\\" [31m[1][0m: false
|
||||
}
|
||||
[31m
|
||||
[1] \\"label\\" must be a string[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebars link wrong href', () => {
|
||||
expect(() =>
|
||||
validateSidebars({
|
||||
docs: [
|
||||
{
|
||||
type: 'link',
|
||||
label: 'GitHub',
|
||||
href: ['example.com'],
|
||||
},
|
||||
],
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"link\\",
|
||||
\\"label\\": \\"GitHub\\",
|
||||
\\"href\\" [31m[1][0m: [
|
||||
\\"example.com\\"
|
||||
]
|
||||
}
|
||||
[31m
|
||||
[1] \\"href\\" contains an invalid value[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebars with unknown sidebar item type', () => {
|
||||
expect(() =>
|
||||
validateSidebars({
|
||||
docs: [
|
||||
{
|
||||
type: 'superman',
|
||||
},
|
||||
],
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"superman\\",
|
||||
[41m\\"undefined\\"[0m[31m [1]: -- missing --[0m
|
||||
}
|
||||
[31m
|
||||
[1] Unknown sidebar item type \\"superman\\".[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebars category missing items', () => {
|
||||
expect(() =>
|
||||
validateSidebars({
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'category',
|
||||
},
|
||||
|
||||
{
|
||||
type: 'ref',
|
||||
id: 'hello',
|
||||
},
|
||||
],
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"category\\",
|
||||
\\"label\\": \\"category\\",
|
||||
[41m\\"items\\"[0m[31m [1]: -- missing --[0m
|
||||
}
|
||||
[31m
|
||||
[1] \\"items\\" is required[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebars category wrong field', () => {
|
||||
expect(() =>
|
||||
validateSidebars({
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'category',
|
||||
items: [],
|
||||
href: 'https://google.com',
|
||||
},
|
||||
|
||||
{
|
||||
type: 'ref',
|
||||
id: 'hello',
|
||||
},
|
||||
],
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"category\\",
|
||||
\\"label\\": \\"category\\",
|
||||
\\"items\\": [],
|
||||
\\"href\\" [31m[1][0m: \\"https://google.com\\"
|
||||
}
|
||||
[31m
|
||||
[1] \\"href\\" is not allowed[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('sidebar category wrong items', () => {
|
||||
expect(() =>
|
||||
validateSidebars({
|
||||
docs: {
|
||||
Test: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category Label',
|
||||
items: 'doc1',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`"sidebar.forEach is not a function"`);
|
||||
});
|
||||
|
||||
test('sidebars item doc but id is not a string', async () => {
|
||||
expect(() =>
|
||||
validateSidebars({
|
||||
docs: [
|
||||
{
|
||||
type: 'doc',
|
||||
id: ['doc1'],
|
||||
},
|
||||
],
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"{
|
||||
\\"type\\": \\"doc\\",
|
||||
\\"id\\" [31m[1][0m: [
|
||||
\\"doc1\\"
|
||||
]
|
||||
}
|
||||
[31m
|
||||
[1] \\"id\\" must be a string[0m"
|
||||
`);
|
||||
});
|
||||
|
||||
test('HTML type requires a value', () => {
|
||||
const sidebars: SidebarsConfig = {
|
||||
sidebar1: [
|
||||
{
|
||||
|
@ -68,7 +246,7 @@ describe('html item type', () => {
|
|||
`);
|
||||
});
|
||||
|
||||
test('accepts valid values', () => {
|
||||
test('HTML type accepts valid values', () => {
|
||||
const sidebars: SidebarsConfig = {
|
||||
sidebar1: [
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue