docusaurus/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts
Joshua Chen 2bcac29cd4
refactor(content-docs): deduplicate types, JSDoc for some APIs (#7027)
* refactor(content-docs): deduplicate types, JSDoc for some APIs

* little refactor
2022-03-27 12:57:15 +08:00

767 lines
18 KiB
TypeScript

/**
* 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 {
createSidebarsUtils,
collectSidebarDocItems,
collectSidebarCategories,
collectSidebarLinks,
transformSidebarItems,
collectSidebarsDocIds,
toDocNavigationLink,
toNavigationLink,
} from '../utils';
import type {Sidebar, Sidebars} from '../types';
import type {
DocMetadataBase,
PropNavigationLink,
} from '@docusaurus/plugin-content-docs';
describe('createSidebarsUtils', () => {
const sidebar1: Sidebar = [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'S1 Category',
items: [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'S1 Subcategory',
items: [{type: 'doc', id: 'doc1'}],
},
{type: 'doc', id: 'doc2'},
],
},
];
const sidebar2: Sidebar = [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'S2 Category',
items: [
{type: 'doc', id: 'doc3', label: 'Doc 3'},
{type: 'doc', id: 'doc4'},
],
},
];
const sidebar3: Sidebar = [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'S3 Category',
link: {
type: 'doc',
id: 'doc5',
},
items: [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'S3 SubCategory',
link: {
type: 'generated-index',
slug: '/s3-subcategory-index-slug',
permalink: '/s3-subcategory-index-permalink',
},
items: [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'S3 SubSubCategory',
link: {
type: 'generated-index',
slug: '/s3-subsubcategory-slug',
permalink: '/s3-subsubcategory-index-permalink',
},
items: [
{type: 'doc', id: 'doc6'},
{type: 'doc', id: 'doc7'},
],
},
],
},
],
},
];
const sidebar4: Sidebar = [
{
type: 'category',
items: [
{type: 'link', href: 'https://facebook.com'},
{type: 'link', href: 'https://reactjs.org'},
{type: 'link', href: 'https://docusaurus.io'},
],
},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'S4 Category',
link: {
type: 'generated-index',
slug: '/s4-category-slug',
permalink: '/s4-category-slug',
},
items: [
{type: 'doc', id: 'doc8'},
{type: 'doc', id: 'doc9'},
],
},
];
const sidebars: Sidebars = {sidebar1, sidebar2, sidebar3, sidebar4};
const {
getFirstDocIdOfFirstSidebar,
getSidebarNameByDocId,
getDocNavigation,
getCategoryGeneratedIndexNavigation,
getCategoryGeneratedIndexList,
getFirstLink,
} = createSidebarsUtils(sidebars);
it('getFirstDocIdOfFirstSidebar', async () => {
expect(getFirstDocIdOfFirstSidebar()).toBe('doc1');
});
it('getSidebarNameByDocId', async () => {
expect(getSidebarNameByDocId('doc1')).toBe('sidebar1');
expect(getSidebarNameByDocId('doc2')).toBe('sidebar1');
expect(getSidebarNameByDocId('doc3')).toBe('sidebar2');
expect(getSidebarNameByDocId('doc4')).toBe('sidebar2');
expect(getSidebarNameByDocId('doc5')).toBe('sidebar3');
expect(getSidebarNameByDocId('doc6')).toBe('sidebar3');
expect(getSidebarNameByDocId('doc7')).toBe('sidebar3');
expect(getSidebarNameByDocId('unknown_id')).toBeUndefined();
});
it('getDocNavigation', async () => {
expect(getDocNavigation('doc1', 'doc1', undefined)).toEqual({
sidebarName: 'sidebar1',
previous: undefined,
next: {
type: 'doc',
id: 'doc2',
},
});
expect(getDocNavigation('doc2', 'doc2', undefined)).toEqual({
sidebarName: 'sidebar1',
previous: {
type: 'doc',
id: 'doc1',
},
next: undefined,
});
expect(getDocNavigation('doc3', 'doc3', undefined)).toEqual({
sidebarName: 'sidebar2',
previous: undefined,
next: {
type: 'doc',
id: 'doc4',
},
});
expect(getDocNavigation('doc4', 'doc4', undefined)).toEqual({
sidebarName: 'sidebar2',
previous: {
type: 'doc',
id: 'doc3',
label: 'Doc 3',
},
next: undefined,
});
expect(getDocNavigation('doc5', 'doc5', undefined)).toMatchObject({
sidebarName: 'sidebar3',
previous: undefined,
next: {
type: 'category',
label: 'S3 SubCategory',
},
});
expect(getDocNavigation('doc6', 'doc6', undefined)).toMatchObject({
sidebarName: 'sidebar3',
previous: {
type: 'category',
label: 'S3 SubSubCategory',
},
next: {
type: 'doc',
id: 'doc7',
},
});
expect(getDocNavigation('doc7', 'doc7', undefined)).toEqual({
sidebarName: 'sidebar3',
previous: {
type: 'doc',
id: 'doc6',
},
next: undefined,
});
expect(getDocNavigation('doc3', 'doc3', null)).toEqual({
sidebarName: undefined,
previous: undefined,
next: undefined,
});
expect(() =>
getDocNavigation('doc3', 'doc3', 'foo'),
).toThrowErrorMatchingInlineSnapshot(
`"Doc with ID doc3 wants to display sidebar foo but a sidebar with this name doesn't exist"`,
);
expect(getDocNavigation('doc3', 'doc3', 'sidebar1')).toEqual({
sidebarName: 'sidebar1',
previous: undefined,
next: undefined,
});
});
it('getCategoryGeneratedIndexNavigation', async () => {
expect(
getCategoryGeneratedIndexNavigation('/s3-subcategory-index-permalink'),
).toMatchObject({
sidebarName: 'sidebar3',
previous: {
type: 'category',
label: 'S3 Category',
},
next: {
type: 'category',
label: 'S3 SubSubCategory',
},
});
expect(
getCategoryGeneratedIndexNavigation('/s3-subsubcategory-index-permalink'),
).toMatchObject({
sidebarName: 'sidebar3',
previous: {
type: 'category',
label: 'S3 SubCategory',
},
next: {
type: 'doc',
id: 'doc6',
},
});
});
it('getCategoryGeneratedIndexList', async () => {
expect(getCategoryGeneratedIndexList()).toMatchObject([
{
type: 'category',
label: 'S3 SubCategory',
},
{
type: 'category',
label: 'S3 SubSubCategory',
},
{
type: 'category',
label: 'S4 Category',
},
]);
});
it('getFirstLink', () => {
expect(getFirstLink('sidebar1')).toEqual({
id: 'doc1',
type: 'doc',
label: 'doc1',
});
expect(getFirstLink('sidebar2')).toEqual({
id: 'doc3',
type: 'doc',
label: 'Doc 3',
});
expect(getFirstLink('sidebar3')).toEqual({
id: 'doc5',
type: 'doc',
label: 'S3 Category',
});
expect(getFirstLink('sidebar4')).toEqual({
type: 'generated-index',
permalink: '/s4-category-slug',
label: 'S4 Category',
});
});
});
describe('collectSidebarDocItems', () => {
it('can collect docs', async () => {
const sidebar: Sidebar = [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Category1',
items: [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Subcategory 1',
items: [{type: 'doc', id: 'doc1'}],
},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Subcategory 2',
items: [
{type: 'doc', id: 'doc2'},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Sub sub category 1',
items: [{type: 'doc', id: 'doc3'}],
},
],
},
],
},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Category2',
items: [
{type: 'doc', id: 'doc4'},
{type: 'doc', id: 'doc5'},
],
},
];
expect(collectSidebarDocItems(sidebar).map((doc) => doc.id)).toEqual([
'doc1',
'doc2',
'doc3',
'doc4',
'doc5',
]);
});
});
describe('collectSidebarCategories', () => {
it('can collect categories', async () => {
const sidebar: Sidebar = [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Category1',
items: [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Subcategory 1',
items: [{type: 'doc', id: 'doc1'}],
},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Subcategory 2',
items: [
{type: 'doc', id: 'doc2'},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Sub sub category 1',
items: [{type: 'doc', id: 'doc3'}],
},
],
},
],
},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Category2',
items: [
{type: 'doc', id: 'doc4'},
{type: 'doc', id: 'doc5'},
],
},
];
expect(
collectSidebarCategories(sidebar).map((category) => category.label),
).toEqual([
'Category1',
'Subcategory 1',
'Subcategory 2',
'Sub sub category 1',
'Category2',
]);
});
});
describe('collectSidebarLinks', () => {
it('can collect links', async () => {
const sidebar: Sidebar = [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Category1',
items: [
{
type: 'link',
href: 'https://google.com',
label: 'Google',
},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Subcategory 2',
items: [
{
type: 'link',
href: 'https://facebook.com',
label: 'Facebook',
},
],
},
],
},
];
expect(collectSidebarLinks(sidebar).map((link) => link.href)).toEqual([
'https://google.com',
'https://facebook.com',
]);
});
});
describe('collectSidebarsDocIds', () => {
it('can collect sidebars doc items', async () => {
const sidebar1: Sidebar = [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Category1',
items: [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Subcategory 1',
items: [{type: 'doc', id: 'doc1'}],
},
{type: 'doc', id: 'doc2'},
],
},
];
const sidebar2: Sidebar = [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Category2',
items: [
{type: 'doc', id: 'doc3'},
{type: 'doc', id: 'doc4'},
],
},
];
const sidebar3: Sidebar = [
{type: 'doc', id: 'doc5'},
{type: 'doc', id: 'doc6'},
];
expect(collectSidebarsDocIds({sidebar1, sidebar2, sidebar3})).toEqual({
sidebar1: ['doc1', 'doc2'],
sidebar2: ['doc3', 'doc4'],
sidebar3: ['doc5', 'doc6'],
});
});
});
describe('transformSidebarItems', () => {
it('can transform sidebar items', async () => {
const sidebar: Sidebar = [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Category1',
items: [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Subcategory 1',
items: [{type: 'doc', id: 'doc1'}],
customProps: {fakeProp: false},
},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Subcategory 2',
items: [
{type: 'doc', id: 'doc2'},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Sub sub category 1',
items: [
{type: 'doc', id: 'doc3', customProps: {lorem: 'ipsum'}},
],
},
],
},
],
},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'Category2',
items: [
{type: 'doc', id: 'doc4'},
{type: 'doc', id: 'doc5'},
],
},
];
expect(
transformSidebarItems(sidebar, (item) => {
if (item.type === 'category') {
return {...item, label: `MODIFIED LABEL: ${item.label}`};
}
return item;
}),
).toEqual([
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'MODIFIED LABEL: Category1',
items: [
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'MODIFIED LABEL: Subcategory 1',
items: [{type: 'doc', id: 'doc1'}],
customProps: {fakeProp: false},
},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'MODIFIED LABEL: Subcategory 2',
items: [
{type: 'doc', id: 'doc2'},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'MODIFIED LABEL: Sub sub category 1',
items: [
{type: 'doc', id: 'doc3', customProps: {lorem: 'ipsum'}},
],
},
],
},
],
},
{
type: 'category',
collapsed: false,
collapsible: true,
label: 'MODIFIED LABEL: Category2',
items: [
{type: 'doc', id: 'doc4'},
{type: 'doc', id: 'doc5'},
],
},
]);
});
});
describe('toDocNavigationLink', () => {
type TestDoc = Pick<DocMetadataBase, 'permalink' | 'title' | 'frontMatter'>;
function testDoc(data: TestDoc) {
return data as DocMetadataBase;
}
it('with no front matter', () => {
expect(
toDocNavigationLink(
testDoc({
title: 'Doc Title',
permalink: '/docPermalink',
frontMatter: {},
}),
),
).toEqual({
title: 'Doc Title',
permalink: '/docPermalink',
} as PropNavigationLink);
});
it('with pagination_label front matter', () => {
expect(
toDocNavigationLink(
testDoc({
title: 'Doc Title',
permalink: '/docPermalink',
frontMatter: {
pagination_label: 'pagination_label',
},
}),
),
).toEqual({
title: 'pagination_label',
permalink: '/docPermalink',
} as PropNavigationLink);
});
it('with sidebar_label front matter', () => {
expect(
toDocNavigationLink(
testDoc({
title: 'Doc Title',
permalink: '/docPermalink',
frontMatter: {
sidebar_label: 'sidebar_label',
},
}),
),
).toEqual({
title: 'sidebar_label',
permalink: '/docPermalink',
} as PropNavigationLink);
});
it('with pagination_label + sidebar_label front matter', () => {
expect(
toDocNavigationLink(
testDoc({
title: 'Doc Title',
permalink: '/docPermalink',
frontMatter: {
pagination_label: 'pagination_label',
sidebar_label: 'sidebar_label',
},
}),
),
).toEqual({
title: 'pagination_label',
permalink: '/docPermalink',
} as PropNavigationLink);
});
});
describe('toNavigationLink', () => {
type TestDoc = Pick<DocMetadataBase, 'permalink' | 'title'>;
function testDoc(data: TestDoc) {
return {...data, frontMatter: {}} as DocMetadataBase;
}
const docsById: {[docId: string]: DocMetadataBase} = {
doc1: testDoc({
title: 'Doc 1',
permalink: '/doc1',
}),
doc2: testDoc({
title: 'Doc 1',
permalink: '/doc1',
}),
};
it('with doc items', () => {
expect(toNavigationLink({type: 'doc', id: 'doc1'}, docsById)).toEqual(
toDocNavigationLink(docsById.doc1),
);
expect(toNavigationLink({type: 'doc', id: 'doc2'}, docsById)).toEqual(
toDocNavigationLink(docsById.doc2),
);
expect(() =>
toNavigationLink({type: 'doc', id: 'doc3'}, docsById),
).toThrowErrorMatchingInlineSnapshot(
`"Can't create navigation link: no doc found with id=doc3"`,
);
});
it('with category item and doc link', () => {
expect(
toNavigationLink(
{
type: 'category',
label: 'Category',
items: [],
link: {
type: 'doc',
id: 'doc1',
},
collapsed: true,
collapsible: true,
},
docsById,
),
).toEqual(toDocNavigationLink(docsById.doc1));
expect(() =>
toNavigationLink(
{
type: 'category',
label: 'Category',
items: [],
link: {
type: 'doc',
id: 'doc3',
},
collapsed: true,
collapsible: true,
},
docsById,
),
).toThrowErrorMatchingInlineSnapshot(
`"Can't create navigation link: no doc found with id=doc3"`,
);
});
it('with category item and generated-index link', () => {
expect(
toNavigationLink(
{
type: 'category',
label: 'Category',
items: [],
link: {
type: 'generated-index',
slug: 'slug',
permalink: 'generated-index-permalink',
},
collapsed: true,
collapsible: true,
},
docsById,
),
).toEqual({title: 'Category', permalink: 'generated-index-permalink'});
});
});