mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-23 14:06:59 +02:00
refactor(v2): docs plugin refactor (#3245)
* safe refactorings * safe refactors * add code to read versions more generically * refactor docs plugin * refactors * stable docs refactor * progress on refactor * stable docs refactor * stable docs refactor * stable docs refactor * attempt to fix admonition :( * configureWebpack docs: better typing * more refactors * rename cli * refactor docs metadata processing => move to pure function * stable docs refactor * stable docs refactor * named exports * basic sidebars refactor * add getElementsAround utils * refactor sidebar + ordering/navigation logic * stable retrocompatible refactor * add proper versions metadata tests * fix docs metadata tests * fix docs tests * fix test due to absolute path * fix webpack tests * refactor linkify + add broken markdown links warning * fix DOM warning due to forwarding legacy prop to div element * add todo
This commit is contained in:
parent
d17df954b5
commit
a4c8a7f55b
54 changed files with 3219 additions and 2724 deletions
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"version-1.0.1/docs": {
|
||||
"Test": ["version-withSlugs/rootAbsoluteSlug"]
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -6,14 +6,14 @@
|
|||
*/
|
||||
|
||||
import path from 'path';
|
||||
import {docsVersion} from '../version';
|
||||
import {cliDocsVersionCommand} from '../cli';
|
||||
import {PathOptions} from '../types';
|
||||
import fs from 'fs-extra';
|
||||
import {
|
||||
getVersionedDocsDir,
|
||||
getVersionsJSONFile,
|
||||
getVersionedSidebarsDir,
|
||||
} from '../env';
|
||||
getVersionedDocsDirPath,
|
||||
getVersionsFilePath,
|
||||
getVersionedSidebarsDirPath,
|
||||
} from '../versions';
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||
|
||||
const fixtureDir = path.join(__dirname, '__fixtures__');
|
||||
|
@ -28,17 +28,32 @@ describe('docsVersion', () => {
|
|||
|
||||
test('no version tag provided', () => {
|
||||
expect(() =>
|
||||
docsVersion(null, simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||
cliDocsVersionCommand(
|
||||
null,
|
||||
simpleSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
DEFAULT_OPTIONS,
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[docs] No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion(undefined, simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||
cliDocsVersionCommand(
|
||||
undefined,
|
||||
simpleSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
DEFAULT_OPTIONS,
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[docs] No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion('', simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||
cliDocsVersionCommand(
|
||||
'',
|
||||
simpleSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
DEFAULT_OPTIONS,
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[docs] No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
||||
);
|
||||
|
@ -46,12 +61,17 @@ describe('docsVersion', () => {
|
|||
|
||||
test('version tag should not have slash', () => {
|
||||
expect(() =>
|
||||
docsVersion('foo/bar', simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||
cliDocsVersionCommand(
|
||||
'foo/bar',
|
||||
simpleSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
DEFAULT_OPTIONS,
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[docs] Invalid version tag specified! Do not include slash (/) or (\\\\). Try something like: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion(
|
||||
cliDocsVersionCommand(
|
||||
'foo\\bar',
|
||||
simpleSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
|
@ -64,7 +84,7 @@ describe('docsVersion', () => {
|
|||
|
||||
test('version tag should not be too long', () => {
|
||||
expect(() =>
|
||||
docsVersion(
|
||||
cliDocsVersionCommand(
|
||||
'a'.repeat(255),
|
||||
simpleSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
|
@ -77,12 +97,22 @@ describe('docsVersion', () => {
|
|||
|
||||
test('version tag should not be a dot or two dots', () => {
|
||||
expect(() =>
|
||||
docsVersion('..', simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||
cliDocsVersionCommand(
|
||||
'..',
|
||||
simpleSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
DEFAULT_OPTIONS,
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[docs] Invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion('.', simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||
cliDocsVersionCommand(
|
||||
'.',
|
||||
simpleSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
DEFAULT_OPTIONS,
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[docs] Invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0"`,
|
||||
);
|
||||
|
@ -90,7 +120,7 @@ describe('docsVersion', () => {
|
|||
|
||||
test('version tag should be a valid pathname', () => {
|
||||
expect(() =>
|
||||
docsVersion(
|
||||
cliDocsVersionCommand(
|
||||
'<foo|bar>',
|
||||
simpleSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
|
@ -100,7 +130,7 @@ describe('docsVersion', () => {
|
|||
`"[docs] Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion(
|
||||
cliDocsVersionCommand(
|
||||
'foo\x00bar',
|
||||
simpleSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
|
@ -110,7 +140,12 @@ describe('docsVersion', () => {
|
|||
`"[docs] Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion('foo:bar', simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||
cliDocsVersionCommand(
|
||||
'foo:bar',
|
||||
simpleSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
DEFAULT_OPTIONS,
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[docs] Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
||||
);
|
||||
|
@ -118,7 +153,7 @@ describe('docsVersion', () => {
|
|||
|
||||
test('version tag already exist', () => {
|
||||
expect(() =>
|
||||
docsVersion(
|
||||
cliDocsVersionCommand(
|
||||
'1.0.0',
|
||||
versionedSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
|
@ -132,7 +167,12 @@ describe('docsVersion', () => {
|
|||
test('no docs file to version', () => {
|
||||
const emptySiteDir = path.join(fixtureDir, 'empty-site');
|
||||
expect(() =>
|
||||
docsVersion('1.0.0', emptySiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||
cliDocsVersionCommand(
|
||||
'1.0.0',
|
||||
emptySiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
DEFAULT_OPTIONS,
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"[docs] There is no docs to version !"`,
|
||||
);
|
||||
|
@ -159,23 +199,23 @@ describe('docsVersion', () => {
|
|||
path: 'docs',
|
||||
sidebarPath: path.join(simpleSiteDir, 'sidebars.json'),
|
||||
};
|
||||
docsVersion('1.0.0', simpleSiteDir, DEFAULT_PLUGIN_ID, options);
|
||||
cliDocsVersionCommand('1.0.0', simpleSiteDir, DEFAULT_PLUGIN_ID, options);
|
||||
expect(copyMock).toHaveBeenCalledWith(
|
||||
path.join(simpleSiteDir, options.path),
|
||||
path.join(
|
||||
getVersionedDocsDir(simpleSiteDir, DEFAULT_PLUGIN_ID),
|
||||
getVersionedDocsDirPath(simpleSiteDir, DEFAULT_PLUGIN_ID),
|
||||
'version-1.0.0',
|
||||
),
|
||||
);
|
||||
expect(versionedSidebar).toMatchSnapshot();
|
||||
expect(versionedSidebarPath).toEqual(
|
||||
path.join(
|
||||
getVersionedSidebarsDir(simpleSiteDir, DEFAULT_PLUGIN_ID),
|
||||
getVersionedSidebarsDirPath(simpleSiteDir, DEFAULT_PLUGIN_ID),
|
||||
'version-1.0.0-sidebars.json',
|
||||
),
|
||||
);
|
||||
expect(versionsPath).toEqual(
|
||||
getVersionsJSONFile(simpleSiteDir, DEFAULT_PLUGIN_ID),
|
||||
getVersionsFilePath(simpleSiteDir, DEFAULT_PLUGIN_ID),
|
||||
);
|
||||
expect(versions).toEqual(['1.0.0']);
|
||||
expect(consoleMock).toHaveBeenCalledWith('[docs] Version 1.0.0 created!');
|
||||
|
@ -207,23 +247,28 @@ describe('docsVersion', () => {
|
|||
path: 'docs',
|
||||
sidebarPath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||
};
|
||||
docsVersion('2.0.0', versionedSiteDir, DEFAULT_PLUGIN_ID, options);
|
||||
cliDocsVersionCommand(
|
||||
'2.0.0',
|
||||
versionedSiteDir,
|
||||
DEFAULT_PLUGIN_ID,
|
||||
options,
|
||||
);
|
||||
expect(copyMock).toHaveBeenCalledWith(
|
||||
path.join(versionedSiteDir, options.path),
|
||||
path.join(
|
||||
getVersionedDocsDir(versionedSiteDir, DEFAULT_PLUGIN_ID),
|
||||
getVersionedDocsDirPath(versionedSiteDir, DEFAULT_PLUGIN_ID),
|
||||
'version-2.0.0',
|
||||
),
|
||||
);
|
||||
expect(versionedSidebar).toMatchSnapshot();
|
||||
expect(versionedSidebarPath).toEqual(
|
||||
path.join(
|
||||
getVersionedSidebarsDir(versionedSiteDir, DEFAULT_PLUGIN_ID),
|
||||
getVersionedSidebarsDirPath(versionedSiteDir, DEFAULT_PLUGIN_ID),
|
||||
'version-2.0.0-sidebars.json',
|
||||
),
|
||||
);
|
||||
expect(versionsPath).toEqual(
|
||||
getVersionsJSONFile(versionedSiteDir, DEFAULT_PLUGIN_ID),
|
||||
getVersionsFilePath(versionedSiteDir, DEFAULT_PLUGIN_ID),
|
||||
);
|
||||
expect(versions).toEqual(['2.0.0', '1.0.1', '1.0.0', 'withSlugs']);
|
||||
expect(consoleMock).toHaveBeenCalledWith('[docs] Version 2.0.0 created!');
|
||||
|
@ -257,23 +302,23 @@ describe('docsVersion', () => {
|
|||
path: 'community',
|
||||
sidebarPath: path.join(versionedSiteDir, 'community_sidebars.json'),
|
||||
};
|
||||
docsVersion('2.0.0', versionedSiteDir, pluginId, options);
|
||||
cliDocsVersionCommand('2.0.0', versionedSiteDir, pluginId, options);
|
||||
expect(copyMock).toHaveBeenCalledWith(
|
||||
path.join(versionedSiteDir, options.path),
|
||||
path.join(
|
||||
getVersionedDocsDir(versionedSiteDir, pluginId),
|
||||
getVersionedDocsDirPath(versionedSiteDir, pluginId),
|
||||
'version-2.0.0',
|
||||
),
|
||||
);
|
||||
expect(versionedSidebar).toMatchSnapshot();
|
||||
expect(versionedSidebarPath).toEqual(
|
||||
path.join(
|
||||
getVersionedSidebarsDir(versionedSiteDir, pluginId),
|
||||
getVersionedSidebarsDirPath(versionedSiteDir, pluginId),
|
||||
'version-2.0.0-sidebars.json',
|
||||
),
|
||||
);
|
||||
expect(versionsPath).toEqual(
|
||||
getVersionsJSONFile(versionedSiteDir, pluginId),
|
||||
getVersionsFilePath(versionedSiteDir, pluginId),
|
||||
);
|
||||
expect(versions).toEqual(['2.0.0', '1.0.0']);
|
||||
expect(consoleMock).toHaveBeenCalledWith(
|
|
@ -1,361 +0,0 @@
|
|||
/**
|
||||
* 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 {
|
||||
ActivePlugin,
|
||||
getActivePlugin,
|
||||
getLatestVersion,
|
||||
getActiveDocContext,
|
||||
getActiveVersion,
|
||||
getDocVersionSuggestions,
|
||||
} from '../../client/docsClientUtils';
|
||||
import {GlobalPluginData, GlobalVersion} from '../../types';
|
||||
import {shuffle} from 'lodash';
|
||||
|
||||
describe('docsClientUtils', () => {
|
||||
test('getActivePlugin', () => {
|
||||
const data: Record<string, GlobalPluginData> = {
|
||||
pluginIosId: {
|
||||
path: '/ios',
|
||||
latestVersionName: 'xyz',
|
||||
versions: [],
|
||||
},
|
||||
pluginAndroidId: {
|
||||
path: '/android',
|
||||
latestVersionName: 'xyz',
|
||||
versions: [],
|
||||
},
|
||||
};
|
||||
|
||||
expect(getActivePlugin(data, '/')).toEqual(undefined);
|
||||
expect(getActivePlugin(data, '/xyz')).toEqual(undefined);
|
||||
|
||||
const activePluginIos: ActivePlugin = {
|
||||
pluginId: 'pluginIosId',
|
||||
pluginData: data.pluginIosId,
|
||||
};
|
||||
expect(getActivePlugin(data, '/ios')).toEqual(activePluginIos);
|
||||
expect(getActivePlugin(data, '/ios/')).toEqual(activePluginIos);
|
||||
expect(getActivePlugin(data, '/ios/abc/def')).toEqual(activePluginIos);
|
||||
|
||||
const activePluginAndroid: ActivePlugin = {
|
||||
pluginId: 'pluginAndroidId',
|
||||
pluginData: data.pluginAndroidId,
|
||||
};
|
||||
expect(getActivePlugin(data, '/android')).toEqual(activePluginAndroid);
|
||||
expect(getActivePlugin(data, '/android/')).toEqual(activePluginAndroid);
|
||||
expect(getActivePlugin(data, '/android/ijk')).toEqual(activePluginAndroid);
|
||||
});
|
||||
|
||||
test('getLatestVersion', () => {
|
||||
const versions: GlobalVersion[] = [
|
||||
{
|
||||
name: 'version1',
|
||||
path: '/???',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
{
|
||||
name: 'version2',
|
||||
path: '/???',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
{
|
||||
name: 'version3',
|
||||
path: '/???',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
];
|
||||
|
||||
expect(
|
||||
getLatestVersion({
|
||||
path: '???',
|
||||
latestVersionName: 'does not exist',
|
||||
versions,
|
||||
}),
|
||||
).toEqual(undefined);
|
||||
expect(
|
||||
getLatestVersion({
|
||||
path: '???',
|
||||
latestVersionName: 'version1',
|
||||
versions,
|
||||
})?.name,
|
||||
).toEqual('version1');
|
||||
expect(
|
||||
getLatestVersion({
|
||||
path: '???',
|
||||
latestVersionName: 'version2',
|
||||
versions,
|
||||
})?.name,
|
||||
).toEqual('version2');
|
||||
expect(
|
||||
getLatestVersion({
|
||||
path: '???',
|
||||
latestVersionName: 'version3',
|
||||
versions,
|
||||
})?.name,
|
||||
).toEqual('version3');
|
||||
});
|
||||
|
||||
test('getActiveVersion', () => {
|
||||
const data: GlobalPluginData = {
|
||||
path: 'docs',
|
||||
latestVersionName: 'version2',
|
||||
versions: [
|
||||
{
|
||||
name: 'next',
|
||||
path: '/docs/next',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
{
|
||||
name: 'version2',
|
||||
path: '/docs',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
{
|
||||
name: 'version1',
|
||||
path: '/docs/version1',
|
||||
docs: [],
|
||||
mainDocId: '???',
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(getActiveVersion(data, '/docs/next')?.name).toEqual('next');
|
||||
expect(getActiveVersion(data, '/docs/next/')?.name).toEqual('next');
|
||||
expect(getActiveVersion(data, '/docs/next/someDoc')?.name).toEqual('next');
|
||||
|
||||
expect(getActiveVersion(data, '/docs')?.name).toEqual('version2');
|
||||
expect(getActiveVersion(data, '/docs/')?.name).toEqual('version2');
|
||||
expect(getActiveVersion(data, '/docs/someDoc')?.name).toEqual('version2');
|
||||
|
||||
expect(getActiveVersion(data, '/docs/version1')?.name).toEqual('version1');
|
||||
expect(getActiveVersion(data, '/docs/version1')?.name).toEqual('version1');
|
||||
expect(getActiveVersion(data, '/docs/version1/someDoc')?.name).toEqual(
|
||||
'version1',
|
||||
);
|
||||
});
|
||||
|
||||
test('getActiveDocContext', () => {
|
||||
const versionNext: GlobalVersion = {
|
||||
name: 'next',
|
||||
path: '/docs/next',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/next/',
|
||||
},
|
||||
{
|
||||
id: 'doc2',
|
||||
path: '/docs/next/doc2',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const version2: GlobalVersion = {
|
||||
name: 'version2',
|
||||
path: '/docs',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/',
|
||||
},
|
||||
{
|
||||
id: 'doc2',
|
||||
path: '/docs/doc2',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const version1: GlobalVersion = {
|
||||
name: 'version1',
|
||||
path: '/docs/version1',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/version1/',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// shuffle, because order shouldn't matter
|
||||
const versions: GlobalVersion[] = shuffle([
|
||||
versionNext,
|
||||
version2,
|
||||
version1,
|
||||
]);
|
||||
|
||||
const data: GlobalPluginData = {
|
||||
path: 'docs',
|
||||
latestVersionName: 'version2',
|
||||
versions,
|
||||
};
|
||||
|
||||
expect(getActiveDocContext(data, '/doesNotExist')).toEqual({
|
||||
activeVersion: undefined,
|
||||
activeDoc: undefined,
|
||||
alternateDocVersions: {},
|
||||
});
|
||||
|
||||
expect(getActiveDocContext(data, '/docs/next/doesNotExist')).toEqual({
|
||||
activeVersion: versionNext,
|
||||
activeDoc: undefined,
|
||||
alternateDocVersions: {},
|
||||
});
|
||||
|
||||
expect(getActiveDocContext(data, '/docs/next')).toEqual({
|
||||
activeVersion: versionNext,
|
||||
activeDoc: versionNext.docs[0],
|
||||
alternateDocVersions: {
|
||||
next: versionNext.docs[0],
|
||||
version2: version2.docs[0],
|
||||
version1: version1.docs[0],
|
||||
},
|
||||
});
|
||||
expect(getActiveDocContext(data, '/docs/next/doc2')).toEqual({
|
||||
activeVersion: versionNext,
|
||||
activeDoc: versionNext.docs[1],
|
||||
alternateDocVersions: {
|
||||
next: versionNext.docs[1],
|
||||
version2: version2.docs[1],
|
||||
version1: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
expect(getActiveDocContext(data, '/docs/')).toEqual({
|
||||
activeVersion: version2,
|
||||
activeDoc: version2.docs[0],
|
||||
alternateDocVersions: {
|
||||
next: versionNext.docs[0],
|
||||
version2: version2.docs[0],
|
||||
version1: version1.docs[0],
|
||||
},
|
||||
});
|
||||
expect(getActiveDocContext(data, '/docs/doc2')).toEqual({
|
||||
activeVersion: version2,
|
||||
activeDoc: version2.docs[1],
|
||||
alternateDocVersions: {
|
||||
next: versionNext.docs[1],
|
||||
version2: version2.docs[1],
|
||||
version1: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
expect(getActiveDocContext(data, '/docs/version1')).toEqual({
|
||||
activeVersion: version1,
|
||||
activeDoc: version1.docs[0],
|
||||
alternateDocVersions: {
|
||||
next: versionNext.docs[0],
|
||||
version2: version2.docs[0],
|
||||
version1: version1.docs[0],
|
||||
},
|
||||
});
|
||||
expect(getActiveDocContext(data, '/docs/version1/doc2')).toEqual({
|
||||
activeVersion: version1,
|
||||
activeDoc: undefined,
|
||||
alternateDocVersions: {},
|
||||
});
|
||||
});
|
||||
|
||||
test('getDocVersionSuggestions', () => {
|
||||
const versionNext: GlobalVersion = {
|
||||
name: 'next',
|
||||
path: '/docs/next',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/next/',
|
||||
},
|
||||
{
|
||||
id: 'doc2',
|
||||
path: '/docs/next/doc2',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const version2: GlobalVersion = {
|
||||
name: 'version2',
|
||||
path: '/docs',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/',
|
||||
},
|
||||
{
|
||||
id: 'doc2',
|
||||
path: '/docs/doc2',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const version1: GlobalVersion = {
|
||||
name: 'version1',
|
||||
path: '/docs/version1',
|
||||
mainDocId: 'doc1',
|
||||
docs: [
|
||||
{
|
||||
id: 'doc1',
|
||||
path: '/docs/version1/',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// shuffle, because order shouldn't matter
|
||||
const versions: GlobalVersion[] = shuffle([
|
||||
versionNext,
|
||||
version2,
|
||||
version1,
|
||||
]);
|
||||
|
||||
const data: GlobalPluginData = {
|
||||
path: 'docs',
|
||||
latestVersionName: 'version2',
|
||||
versions,
|
||||
};
|
||||
|
||||
expect(getDocVersionSuggestions(data, '/doesNotExist')).toEqual({
|
||||
latestDocSuggestion: undefined,
|
||||
latestVersionSuggestion: version2,
|
||||
});
|
||||
|
||||
expect(getDocVersionSuggestions(data, '/docs/next')).toEqual({
|
||||
latestDocSuggestion: version2.docs[0],
|
||||
latestVersionSuggestion: version2,
|
||||
});
|
||||
expect(getDocVersionSuggestions(data, '/docs/next/doc2')).toEqual({
|
||||
latestDocSuggestion: version2.docs[1],
|
||||
latestVersionSuggestion: version2,
|
||||
});
|
||||
|
||||
// nothing to suggest, we are already on latest version
|
||||
expect(getDocVersionSuggestions(data, '/docs/')).toEqual({
|
||||
latestDocSuggestion: undefined,
|
||||
latestVersionSuggestion: undefined,
|
||||
});
|
||||
expect(getDocVersionSuggestions(data, '/docs/doc2')).toEqual({
|
||||
latestDocSuggestion: undefined,
|
||||
latestVersionSuggestion: undefined,
|
||||
});
|
||||
|
||||
expect(getDocVersionSuggestions(data, '/docs/version1/')).toEqual({
|
||||
latestDocSuggestion: version2.docs[0],
|
||||
latestVersionSuggestion: version2,
|
||||
});
|
||||
expect(getDocVersionSuggestions(data, '/docs/version1/doc2')).toEqual({
|
||||
latestDocSuggestion: undefined, // because /docs/version1/doc2 does not exist
|
||||
latestVersionSuggestion: version2,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,529 @@
|
|||
/**
|
||||
* 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 path from 'path';
|
||||
import {loadContext} from '@docusaurus/core/src/server/index';
|
||||
import {processDocMetadata, readVersionDocs, readDocFile} from '../docs';
|
||||
import {readVersionsMetadata} from '../versions';
|
||||
import {
|
||||
DocFile,
|
||||
DocMetadataBase,
|
||||
MetadataOptions,
|
||||
VersionMetadata,
|
||||
} from '../types';
|
||||
import {LoadContext} from '@docusaurus/types';
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||
import {DEFAULT_OPTIONS} from '../options';
|
||||
import {Optional} from 'utility-types';
|
||||
|
||||
const fixtureDir = path.join(__dirname, '__fixtures__');
|
||||
|
||||
const createFakeDocFile = ({
|
||||
source,
|
||||
frontmatter = {},
|
||||
markdown = 'some markdown content',
|
||||
}: {
|
||||
source: string;
|
||||
frontmatter?: Record<string, string>;
|
||||
markdown?: string;
|
||||
}): DocFile => {
|
||||
const content = `---
|
||||
${Object.entries(frontmatter)
|
||||
.map(([key, value]) => `${key}: ${value}`)
|
||||
.join('\n')}
|
||||
---
|
||||
${markdown}
|
||||
`;
|
||||
return {
|
||||
source,
|
||||
content,
|
||||
lastUpdate: {},
|
||||
};
|
||||
};
|
||||
|
||||
function createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
versionMetadata,
|
||||
options,
|
||||
}: {
|
||||
siteDir: string;
|
||||
context: LoadContext;
|
||||
versionMetadata: VersionMetadata;
|
||||
options: MetadataOptions;
|
||||
}) {
|
||||
async function readDoc(docFileSource: string) {
|
||||
return readDocFile(versionMetadata.docsDirPath, docFileSource, options);
|
||||
}
|
||||
function processDocFile(docFile: DocFile) {
|
||||
return processDocMetadata({
|
||||
docFile,
|
||||
versionMetadata,
|
||||
options,
|
||||
context,
|
||||
});
|
||||
}
|
||||
async function testMeta(
|
||||
docFileSource: string,
|
||||
expectedMetadata: Optional<
|
||||
DocMetadataBase,
|
||||
'source' | 'lastUpdatedBy' | 'lastUpdatedAt' | 'sidebar_label' | 'editUrl'
|
||||
>,
|
||||
) {
|
||||
const docFile = await readDoc(docFileSource);
|
||||
const metadata = await processDocMetadata({
|
||||
docFile,
|
||||
versionMetadata,
|
||||
context,
|
||||
options,
|
||||
});
|
||||
expect(metadata).toEqual({
|
||||
lastUpdatedBy: undefined,
|
||||
lastUpdatedAt: undefined,
|
||||
sidebar_label: undefined,
|
||||
editUrl: undefined,
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, versionMetadata.docsDirPath),
|
||||
docFileSource,
|
||||
),
|
||||
...expectedMetadata,
|
||||
});
|
||||
}
|
||||
|
||||
async function testSlug(docFileSource: string, expectedPermalink: string) {
|
||||
const docFile = await readDoc(docFileSource);
|
||||
const metadata = await processDocMetadata({
|
||||
docFile,
|
||||
versionMetadata,
|
||||
context,
|
||||
options,
|
||||
});
|
||||
expect(metadata.permalink).toEqual(expectedPermalink);
|
||||
}
|
||||
|
||||
return {processDocFile, testMeta, testSlug};
|
||||
}
|
||||
|
||||
describe('simple site', () => {
|
||||
const siteDir = path.join(fixtureDir, 'simple-site');
|
||||
const context = loadContext(siteDir);
|
||||
const options = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
};
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
context,
|
||||
options: {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
},
|
||||
});
|
||||
expect(versionsMetadata.length).toEqual(1);
|
||||
const [currentVersion] = versionsMetadata;
|
||||
|
||||
const defaultTestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
|
||||
test('readVersionDocs', async () => {
|
||||
const docs = await readVersionDocs(currentVersion, options);
|
||||
expect(docs.map((doc) => doc.source)).toMatchObject([
|
||||
'hello.md',
|
||||
'ipsum.md',
|
||||
'lorem.md',
|
||||
'rootAbsoluteSlug.md',
|
||||
'rootRelativeSlug.md',
|
||||
'rootResolvedSlug.md',
|
||||
'rootTryToEscapeSlug.md',
|
||||
'foo/bar.md',
|
||||
'foo/baz.md',
|
||||
'slugs/absoluteSlug.md',
|
||||
'slugs/relativeSlug.md',
|
||||
'slugs/resolvedSlug.md',
|
||||
'slugs/tryToEscapeSlug.md',
|
||||
]);
|
||||
});
|
||||
|
||||
test('normal docs', async () => {
|
||||
await defaultTestUtils.testMeta(path.join('foo', 'bar.md'), {
|
||||
version: 'current',
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bar',
|
||||
slug: '/foo/bar',
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
});
|
||||
await defaultTestUtils.testMeta(path.join('hello.md'), {
|
||||
version: 'current',
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/hello',
|
||||
slug: '/hello',
|
||||
title: 'Hello, World !',
|
||||
description: `Hi, Endilie here :)`,
|
||||
});
|
||||
});
|
||||
|
||||
test('homePageId doc', async () => {
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options: {...options, homePageId: 'hello'},
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
|
||||
await testUtilsLocal.testMeta(path.join('hello.md'), {
|
||||
version: 'current',
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/',
|
||||
slug: '/',
|
||||
title: 'Hello, World !',
|
||||
description: `Hi, Endilie here :)`,
|
||||
});
|
||||
});
|
||||
|
||||
test('homePageId doc nested', async () => {
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options: {...options, homePageId: 'foo/bar'},
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
|
||||
await testUtilsLocal.testMeta(path.join('foo', 'bar.md'), {
|
||||
version: 'current',
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/',
|
||||
slug: '/',
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with editUrl', async () => {
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options: {
|
||||
...options,
|
||||
editUrl: 'https://github.com/facebook/docusaurus/edit/master/website',
|
||||
},
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
|
||||
await testUtilsLocal.testMeta(path.join('foo', 'baz.md'), {
|
||||
version: 'current',
|
||||
id: 'foo/baz',
|
||||
unversionedId: 'foo/baz',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bazSlug.html',
|
||||
slug: '/foo/bazSlug.html',
|
||||
title: 'baz',
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website/docs/foo/baz.md',
|
||||
description: 'Images',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with custom editUrl & unrelated frontmatter', async () => {
|
||||
await defaultTestUtils.testMeta('lorem.md', {
|
||||
version: 'current',
|
||||
id: 'lorem',
|
||||
unversionedId: 'lorem',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/lorem',
|
||||
slug: '/lorem',
|
||||
title: 'lorem',
|
||||
editUrl: 'https://github.com/customUrl/docs/lorem.md',
|
||||
description: 'Lorem ipsum.',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with last update time and author', async () => {
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options: {
|
||||
...options,
|
||||
showLastUpdateAuthor: true,
|
||||
showLastUpdateTime: true,
|
||||
},
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
|
||||
await testUtilsLocal.testMeta('lorem.md', {
|
||||
version: 'current',
|
||||
id: 'lorem',
|
||||
unversionedId: 'lorem',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/lorem',
|
||||
slug: '/lorem',
|
||||
title: 'lorem',
|
||||
editUrl: 'https://github.com/customUrl/docs/lorem.md',
|
||||
description: 'Lorem ipsum.',
|
||||
lastUpdatedAt: 1539502055,
|
||||
lastUpdatedBy: 'Author',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with slugs', async () => {
|
||||
await defaultTestUtils.testSlug(
|
||||
path.join('rootRelativeSlug.md'),
|
||||
'/docs/rootRelativeSlug',
|
||||
);
|
||||
await defaultTestUtils.testSlug(
|
||||
path.join('rootAbsoluteSlug.md'),
|
||||
'/docs/rootAbsoluteSlug',
|
||||
);
|
||||
await defaultTestUtils.testSlug(
|
||||
path.join('rootResolvedSlug.md'),
|
||||
'/docs/hey/rootResolvedSlug',
|
||||
);
|
||||
await defaultTestUtils.testSlug(
|
||||
path.join('rootTryToEscapeSlug.md'),
|
||||
'/docs/rootTryToEscapeSlug',
|
||||
);
|
||||
|
||||
await defaultTestUtils.testSlug(
|
||||
path.join('slugs', 'absoluteSlug.md'),
|
||||
'/docs/absoluteSlug',
|
||||
);
|
||||
await defaultTestUtils.testSlug(
|
||||
path.join('slugs', 'relativeSlug.md'),
|
||||
'/docs/slugs/relativeSlug',
|
||||
);
|
||||
await defaultTestUtils.testSlug(
|
||||
path.join('slugs', 'resolvedSlug.md'),
|
||||
'/docs/slugs/hey/resolvedSlug',
|
||||
);
|
||||
await defaultTestUtils.testSlug(
|
||||
path.join('slugs', 'tryToEscapeSlug.md'),
|
||||
'/docs/tryToEscapeSlug',
|
||||
);
|
||||
});
|
||||
|
||||
test('docs with invalid id', () => {
|
||||
expect(() => {
|
||||
defaultTestUtils.processDocFile(
|
||||
createFakeDocFile({
|
||||
source: 'some/fake/path',
|
||||
frontmatter: {
|
||||
id: 'Hello/world',
|
||||
},
|
||||
}),
|
||||
);
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Document id [Hello/world] cannot include \\"/\\"."`,
|
||||
);
|
||||
});
|
||||
|
||||
test('docs with slug on doc home', async () => {
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options: {
|
||||
...options,
|
||||
homePageId: 'homePageId',
|
||||
},
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
expect(() => {
|
||||
testUtilsLocal.processDocFile(
|
||||
createFakeDocFile({
|
||||
source: 'homePageId',
|
||||
frontmatter: {
|
||||
slug: '/x/y',
|
||||
},
|
||||
}),
|
||||
);
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
`"The docs homepage (homePageId=homePageId) is not allowed to have a frontmatter slug=/x/y => you have to chooser either homePageId or slug, not both"`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('versioned site', () => {
|
||||
const siteDir = path.join(fixtureDir, 'versioned-site');
|
||||
const context = loadContext(siteDir);
|
||||
const options = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
};
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
context,
|
||||
options: {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
},
|
||||
});
|
||||
expect(versionsMetadata.length).toEqual(4);
|
||||
const [
|
||||
currentVersion,
|
||||
version101,
|
||||
version100,
|
||||
versionWithSlugs,
|
||||
] = versionsMetadata;
|
||||
|
||||
const currentVersionTestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
const version101TestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: version101,
|
||||
});
|
||||
|
||||
const version100TestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: version100,
|
||||
});
|
||||
|
||||
const versionWithSlugsTestUtils = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: versionWithSlugs,
|
||||
});
|
||||
|
||||
test('next docs', async () => {
|
||||
await currentVersionTestUtils.testMeta(path.join('foo', 'bar.md'), {
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/next/foo/barSlug',
|
||||
slug: '/foo/barSlug',
|
||||
title: 'bar',
|
||||
description: 'This is next version of bar.',
|
||||
version: 'current',
|
||||
});
|
||||
await currentVersionTestUtils.testMeta(path.join('hello.md'), {
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/next/hello',
|
||||
slug: '/hello',
|
||||
title: 'hello',
|
||||
description: 'Hello next !',
|
||||
version: 'current',
|
||||
});
|
||||
});
|
||||
|
||||
test('versioned docs', async () => {
|
||||
await version100TestUtils.testMeta(path.join('foo', 'bar.md'), {
|
||||
id: 'version-1.0.0/foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/1.0.0/foo/barSlug',
|
||||
slug: '/foo/barSlug',
|
||||
title: 'bar',
|
||||
description: 'Bar 1.0.0 !',
|
||||
version: '1.0.0',
|
||||
});
|
||||
await version100TestUtils.testMeta(path.join('hello.md'), {
|
||||
id: 'version-1.0.0/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/1.0.0/hello',
|
||||
slug: '/hello',
|
||||
title: 'hello',
|
||||
description: 'Hello 1.0.0 !',
|
||||
version: '1.0.0',
|
||||
});
|
||||
await version101TestUtils.testMeta(path.join('foo', 'bar.md'), {
|
||||
id: 'version-1.0.1/foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bar',
|
||||
slug: '/foo/bar',
|
||||
title: 'bar',
|
||||
description: 'Bar 1.0.1 !',
|
||||
version: '1.0.1',
|
||||
});
|
||||
await version101TestUtils.testMeta(path.join('hello.md'), {
|
||||
id: 'version-1.0.1/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/hello',
|
||||
slug: '/hello',
|
||||
title: 'hello',
|
||||
description: 'Hello 1.0.1 !',
|
||||
version: '1.0.1',
|
||||
});
|
||||
});
|
||||
|
||||
test('next doc slugs', async () => {
|
||||
await currentVersionTestUtils.testSlug(
|
||||
path.join('slugs', 'absoluteSlug.md'),
|
||||
'/docs/next/absoluteSlug',
|
||||
);
|
||||
await currentVersionTestUtils.testSlug(
|
||||
path.join('slugs', 'relativeSlug.md'),
|
||||
'/docs/next/slugs/relativeSlug',
|
||||
);
|
||||
await currentVersionTestUtils.testSlug(
|
||||
path.join('slugs', 'resolvedSlug.md'),
|
||||
'/docs/next/slugs/hey/resolvedSlug',
|
||||
);
|
||||
await currentVersionTestUtils.testSlug(
|
||||
path.join('slugs', 'tryToEscapeSlug.md'),
|
||||
'/docs/next/tryToEscapeSlug',
|
||||
);
|
||||
});
|
||||
|
||||
test('versioned doc slugs', async () => {
|
||||
await versionWithSlugsTestUtils.testSlug(
|
||||
path.join('rootAbsoluteSlug.md'),
|
||||
'/docs/withSlugs/rootAbsoluteSlug',
|
||||
);
|
||||
await versionWithSlugsTestUtils.testSlug(
|
||||
path.join('rootRelativeSlug.md'),
|
||||
'/docs/withSlugs/rootRelativeSlug',
|
||||
);
|
||||
await versionWithSlugsTestUtils.testSlug(
|
||||
path.join('rootResolvedSlug.md'),
|
||||
'/docs/withSlugs/hey/rootResolvedSlug',
|
||||
);
|
||||
await versionWithSlugsTestUtils.testSlug(
|
||||
path.join('rootTryToEscapeSlug.md'),
|
||||
'/docs/withSlugs/rootTryToEscapeSlug',
|
||||
);
|
||||
|
||||
await versionWithSlugsTestUtils.testSlug(
|
||||
path.join('slugs', 'absoluteSlug.md'),
|
||||
'/docs/withSlugs/absoluteSlug',
|
||||
);
|
||||
await versionWithSlugsTestUtils.testSlug(
|
||||
path.join('slugs', 'relativeSlug.md'),
|
||||
'/docs/withSlugs/slugs/relativeSlug',
|
||||
);
|
||||
await versionWithSlugsTestUtils.testSlug(
|
||||
path.join('slugs', 'resolvedSlug.md'),
|
||||
'/docs/withSlugs/slugs/hey/resolvedSlug',
|
||||
);
|
||||
await versionWithSlugsTestUtils.testSlug(
|
||||
path.join('slugs', 'tryToEscapeSlug.md'),
|
||||
'/docs/withSlugs/tryToEscapeSlug',
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
* 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 path from 'path';
|
||||
import loadEnv from '../env';
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||
|
||||
describe('loadEnv', () => {
|
||||
test('website with versioning disabled', () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'simple-site');
|
||||
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||
expect(env.versioning.enabled).toBe(false);
|
||||
expect(env.versioning.versions).toStrictEqual([]);
|
||||
});
|
||||
|
||||
test('website with versioning enabled', () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||
expect(env.versioning.enabled).toBe(true);
|
||||
expect(env.versioning.latestVersion).toBe('1.0.1');
|
||||
expect(env.versioning.versions).toStrictEqual([
|
||||
'1.0.1',
|
||||
'1.0.0',
|
||||
'withSlugs',
|
||||
]);
|
||||
});
|
||||
|
||||
test('website with versioning enabled, 2nd docs plugin instance', () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||
const env = loadEnv(siteDir, 'community');
|
||||
expect(env.versioning.enabled).toBe(true);
|
||||
expect(env.versioning.latestVersion).toBe('1.0.0');
|
||||
expect(env.versioning.versions).toStrictEqual(['1.0.0']);
|
||||
});
|
||||
|
||||
test('website with versioning but disabled', () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID, {disableVersioning: true});
|
||||
expect(env.versioning.enabled).toBe(false);
|
||||
expect(env.versioning.versions).toStrictEqual([]);
|
||||
});
|
||||
|
||||
test('website with invalid versions.json file', () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||
const mock = jest.spyOn(JSON, 'parse').mockImplementationOnce(() => {
|
||||
return {
|
||||
invalid: 'json',
|
||||
};
|
||||
});
|
||||
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||
expect(env.versioning.enabled).toBe(false);
|
||||
mock.mockRestore();
|
||||
});
|
||||
});
|
|
@ -6,12 +6,12 @@
|
|||
*/
|
||||
|
||||
import path from 'path';
|
||||
import {validate} from 'webpack';
|
||||
import {isMatch} from 'picomatch';
|
||||
import commander from 'commander';
|
||||
import {kebabCase} from 'lodash';
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import pluginContentDocs from '../index';
|
||||
import loadEnv from '../env';
|
||||
import {loadContext} from '@docusaurus/core/src/server/index';
|
||||
import {applyConfigureWebpack} from '@docusaurus/core/src/webpack/utils';
|
||||
import {RouteConfig} from '@docusaurus/types';
|
||||
|
@ -19,9 +19,26 @@ import {posixPath} from '@docusaurus/utils';
|
|||
import {sortConfig} from '@docusaurus/core/src/server/plugins';
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||
|
||||
import * as version from '../version';
|
||||
import {PluginOptionSchema} from '../pluginOptionSchema';
|
||||
import * as cliDocs from '../cli';
|
||||
import {OptionsSchema} from '../options';
|
||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||
import {DocMetadata, LoadedVersion} from '../types';
|
||||
import {toSidebarsProp} from '../props';
|
||||
|
||||
// @ts-expect-error: TODO typedefs missing?
|
||||
import {validate} from 'webpack';
|
||||
|
||||
function findDocById(version: LoadedVersion, unversionedId: string) {
|
||||
return version.docs.find((item) => item.unversionedId === unversionedId);
|
||||
}
|
||||
const defaultDocMetadata: Partial<DocMetadata> = {
|
||||
next: undefined,
|
||||
previous: undefined,
|
||||
editUrl: undefined,
|
||||
lastUpdatedAt: undefined,
|
||||
lastUpdatedBy: undefined,
|
||||
sidebar_label: undefined,
|
||||
};
|
||||
|
||||
const createFakeActions = (contentDir: string) => {
|
||||
const routeConfigs: RouteConfig[] = [];
|
||||
|
@ -41,20 +58,34 @@ const createFakeActions = (contentDir: string) => {
|
|||
},
|
||||
};
|
||||
|
||||
// query by prefix, because files have a hash at the end
|
||||
// so it's not convenient to query by full filename
|
||||
const getCreatedDataByPrefix = (prefix: string) => {
|
||||
const entry = Object.entries(dataContainer).find(([key]) =>
|
||||
key.startsWith(prefix),
|
||||
);
|
||||
if (!entry) {
|
||||
throw new Error(`No created entry found for prefix=[${prefix}]
|
||||
Entries created:
|
||||
- ${Object.keys(dataContainer).join('\n- ')}
|
||||
`);
|
||||
}
|
||||
return JSON.parse(entry[1] as string);
|
||||
};
|
||||
|
||||
// Extra fns useful for tests!
|
||||
const utils = {
|
||||
getGlobalData: () => globalDataContainer,
|
||||
getRouteConfigs: () => routeConfigs,
|
||||
// query by prefix, because files have a hash at the end
|
||||
// so it's not convenient to query by full filename
|
||||
getCreatedDataByPrefix: (prefix: string) => {
|
||||
const entry = Object.entries(dataContainer).find(([key]) =>
|
||||
key.startsWith(prefix),
|
||||
|
||||
checkVersionMetadataPropCreated: (version: LoadedVersion) => {
|
||||
const versionMetadataProp = getCreatedDataByPrefix(
|
||||
`version-${kebabCase(version.versionName)}-metadata-prop`,
|
||||
);
|
||||
expect(versionMetadataProp.docsSidebars).toEqual(toSidebarsProp(version));
|
||||
expect(versionMetadataProp.permalinkToSidebar).toEqual(
|
||||
version.permalinkToSidebar,
|
||||
);
|
||||
if (!entry) {
|
||||
throw new Error(`No entry found for prefix=${prefix}`);
|
||||
}
|
||||
return JSON.parse(entry[1] as string);
|
||||
},
|
||||
|
||||
expectSnapshot: () => {
|
||||
|
@ -79,11 +110,11 @@ test('site with wrong sidebar file', async () => {
|
|||
const sidebarPath = path.join(siteDir, 'wrong-sidebars.json');
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(PluginOptionSchema, {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
sidebarPath,
|
||||
}),
|
||||
);
|
||||
await expect(plugin.loadContent()).rejects.toThrowErrorMatchingSnapshot();
|
||||
await expect(plugin.loadContent!()).rejects.toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
|
||||
describe('empty/no docs website', () => {
|
||||
|
@ -94,33 +125,26 @@ describe('empty/no docs website', () => {
|
|||
await fs.ensureDir(path.join(siteDir, 'docs'));
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(PluginOptionSchema, {}),
|
||||
normalizePluginOptions(OptionsSchema, {}),
|
||||
);
|
||||
await expect(
|
||||
plugin.loadContent!(),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"Docs version current has no docs! At least one doc should exist at path=[docs]"`,
|
||||
);
|
||||
const content = await plugin.loadContent();
|
||||
const {docsMetadata, docsSidebars} = content;
|
||||
expect(docsMetadata).toMatchInlineSnapshot(`Object {}`);
|
||||
expect(docsSidebars).toMatchInlineSnapshot(`Object {}`);
|
||||
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
const {actions, utils} = createFakeActions(pluginContentDir);
|
||||
|
||||
await plugin.contentLoaded({
|
||||
content,
|
||||
actions,
|
||||
});
|
||||
|
||||
expect(utils.getRouteConfigs()).toEqual([]);
|
||||
});
|
||||
|
||||
test('docs folder does not exist', async () => {
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(PluginOptionSchema, {
|
||||
path: '/path/does/not/exist/',
|
||||
}),
|
||||
expect(() =>
|
||||
pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: '/path/does/not/exist/',
|
||||
}),
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"The docs folder does not exist for version [current]. A docs folder is expected to be found at /path/does/not/exist"`,
|
||||
);
|
||||
const content = await plugin.loadContent();
|
||||
expect(content).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -128,11 +152,10 @@ describe('simple website', () => {
|
|||
const siteDir = path.join(__dirname, '__fixtures__', 'simple-site');
|
||||
const context = loadContext(siteDir);
|
||||
const sidebarPath = path.join(siteDir, 'sidebars.json');
|
||||
const pluginPath = 'docs';
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(PluginOptionSchema, {
|
||||
path: pluginPath,
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: 'docs',
|
||||
sidebarPath,
|
||||
homePageId: 'hello',
|
||||
}),
|
||||
|
@ -140,27 +163,31 @@ describe('simple website', () => {
|
|||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
|
||||
test('extendCli - docsVersion', () => {
|
||||
const mock = jest.spyOn(version, 'docsVersion').mockImplementation();
|
||||
const mock = jest
|
||||
.spyOn(cliDocs, 'cliDocsVersionCommand')
|
||||
.mockImplementation();
|
||||
const cli = new commander.Command();
|
||||
plugin.extendCli(cli);
|
||||
// @ts-expect-error: TODO annoying type incompatibility
|
||||
plugin.extendCli!(cli);
|
||||
cli.parse(['node', 'test', 'docs:version', '1.0.0']);
|
||||
expect(mock).toHaveBeenCalledTimes(1);
|
||||
expect(mock).toHaveBeenCalledWith('1.0.0', siteDir, DEFAULT_PLUGIN_ID, {
|
||||
path: pluginPath,
|
||||
path: 'docs',
|
||||
sidebarPath,
|
||||
});
|
||||
mock.mockRestore();
|
||||
});
|
||||
|
||||
test('getPathToWatch', () => {
|
||||
const pathToWatch = plugin.getPathsToWatch();
|
||||
const pathToWatch = plugin.getPathsToWatch!();
|
||||
const matchPattern = pathToWatch.map((filepath) =>
|
||||
posixPath(path.relative(siteDir, filepath)),
|
||||
);
|
||||
expect(matchPattern).not.toEqual([]);
|
||||
expect(matchPattern).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"docs/**/*.{md,mdx}",
|
||||
"sidebars.json",
|
||||
"docs/**/*.{md,mdx}",
|
||||
]
|
||||
`);
|
||||
expect(isMatch('docs/hello.md', matchPattern)).toEqual(true);
|
||||
|
@ -192,15 +219,13 @@ describe('simple website', () => {
|
|||
});
|
||||
|
||||
test('content', async () => {
|
||||
const content = await plugin.loadContent();
|
||||
const {
|
||||
docsMetadata,
|
||||
docsSidebars,
|
||||
versionToSidebars,
|
||||
permalinkToSidebar,
|
||||
} = content;
|
||||
expect(versionToSidebars).toEqual({});
|
||||
expect(docsMetadata.hello).toEqual({
|
||||
const content = await plugin.loadContent!();
|
||||
expect(content.loadedVersions.length).toEqual(1);
|
||||
const [currentVersion] = content.loadedVersions;
|
||||
|
||||
expect(findDocById(currentVersion, 'hello')).toEqual({
|
||||
...defaultDocMetadata,
|
||||
version: 'current',
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: true,
|
||||
|
@ -211,12 +236,18 @@ describe('simple website', () => {
|
|||
permalink: '/docs/foo/bazSlug.html',
|
||||
},
|
||||
sidebar: 'docs',
|
||||
source: path.join('@site', pluginPath, 'hello.md'),
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, currentVersion.docsDirPath),
|
||||
'hello.md',
|
||||
),
|
||||
title: 'Hello, World !',
|
||||
description: 'Hi, Endilie here :)',
|
||||
});
|
||||
|
||||
expect(docsMetadata['foo/bar']).toEqual({
|
||||
expect(findDocById(currentVersion, 'foo/bar')).toEqual({
|
||||
...defaultDocMetadata,
|
||||
version: 'current',
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
|
@ -227,26 +258,30 @@ describe('simple website', () => {
|
|||
permalink: '/docs/foo/bar',
|
||||
slug: '/foo/bar',
|
||||
sidebar: 'docs',
|
||||
source: path.join('@site', pluginPath, 'foo', 'bar.md'),
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, currentVersion.docsDirPath),
|
||||
'foo',
|
||||
'bar.md',
|
||||
),
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
});
|
||||
|
||||
expect(docsSidebars).toMatchSnapshot();
|
||||
expect(currentVersion.sidebars).toMatchSnapshot();
|
||||
|
||||
const {actions, utils} = createFakeActions(pluginContentDir);
|
||||
|
||||
await plugin.contentLoaded({
|
||||
await plugin.contentLoaded!({
|
||||
content,
|
||||
actions,
|
||||
allContent: {},
|
||||
});
|
||||
|
||||
// There is only one nested docs route for simple site
|
||||
const baseMetadata = utils.getCreatedDataByPrefix('docs-route-');
|
||||
expect(baseMetadata.docsSidebars).toEqual(docsSidebars);
|
||||
expect(baseMetadata.permalinkToSidebar).toEqual(permalinkToSidebar);
|
||||
utils.checkVersionMetadataPropCreated(currentVersion);
|
||||
|
||||
utils.expectSnapshot();
|
||||
|
||||
expect(utils.getGlobalData()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -258,25 +293,24 @@ describe('versioned website', () => {
|
|||
const routeBasePath = 'docs';
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(PluginOptionSchema, {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
homePageId: 'hello',
|
||||
}),
|
||||
);
|
||||
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||
const {docsDir: versionedDir} = env.versioning;
|
||||
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
|
||||
test('isVersioned', () => {
|
||||
expect(env.versioning.enabled).toEqual(true);
|
||||
});
|
||||
|
||||
test('extendCli - docsVersion', () => {
|
||||
const mock = jest.spyOn(version, 'docsVersion').mockImplementation();
|
||||
const mock = jest
|
||||
.spyOn(cliDocs, 'cliDocsVersionCommand')
|
||||
.mockImplementation();
|
||||
const cli = new commander.Command();
|
||||
plugin.extendCli(cli);
|
||||
// @ts-expect-error: TODO annoying type incompatibility
|
||||
plugin.extendCli!(cli);
|
||||
cli.parse(['node', 'test', 'docs:version', '2.0.0']);
|
||||
expect(mock).toHaveBeenCalledTimes(1);
|
||||
expect(mock).toHaveBeenCalledWith('2.0.0', siteDir, DEFAULT_PLUGIN_ID, {
|
||||
path: routeBasePath,
|
||||
sidebarPath,
|
||||
|
@ -285,21 +319,21 @@ describe('versioned website', () => {
|
|||
});
|
||||
|
||||
test('getPathToWatch', () => {
|
||||
const pathToWatch = plugin.getPathsToWatch();
|
||||
const pathToWatch = plugin.getPathsToWatch!();
|
||||
const matchPattern = pathToWatch.map((filepath) =>
|
||||
posixPath(path.relative(siteDir, filepath)),
|
||||
);
|
||||
expect(matchPattern).not.toEqual([]);
|
||||
expect(matchPattern).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"sidebars.json",
|
||||
"docs/**/*.{md,mdx}",
|
||||
"versioned_sidebars/version-1.0.1-sidebars.json",
|
||||
"versioned_sidebars/version-1.0.0-sidebars.json",
|
||||
"versioned_sidebars/version-withSlugs-sidebars.json",
|
||||
"versioned_docs/version-1.0.1/**/*.{md,mdx}",
|
||||
"versioned_sidebars/version-1.0.0-sidebars.json",
|
||||
"versioned_docs/version-1.0.0/**/*.{md,mdx}",
|
||||
"versioned_sidebars/version-withSlugs-sidebars.json",
|
||||
"versioned_docs/version-withSlugs/**/*.{md,mdx}",
|
||||
"sidebars.json",
|
||||
]
|
||||
`);
|
||||
expect(isMatch('docs/hello.md', matchPattern)).toEqual(true);
|
||||
|
@ -335,50 +369,65 @@ describe('versioned website', () => {
|
|||
});
|
||||
|
||||
test('content', async () => {
|
||||
const content = await plugin.loadContent();
|
||||
const {
|
||||
docsMetadata,
|
||||
docsSidebars,
|
||||
versionToSidebars,
|
||||
permalinkToSidebar,
|
||||
} = content;
|
||||
const content = await plugin.loadContent!();
|
||||
expect(content.loadedVersions.length).toEqual(4);
|
||||
const [
|
||||
currentVersion,
|
||||
version101,
|
||||
version100,
|
||||
versionWithSlugs,
|
||||
] = content.loadedVersions;
|
||||
|
||||
// foo/baz.md only exists in version -1.0.0
|
||||
expect(docsMetadata['foo/baz']).toBeUndefined();
|
||||
expect(docsMetadata['version-1.0.1/foo/baz']).toBeUndefined();
|
||||
expect(docsMetadata['foo/bar']).toEqual({
|
||||
expect(findDocById(currentVersion, 'foo/baz')).toBeUndefined();
|
||||
expect(findDocById(version101, 'foo/baz')).toBeUndefined();
|
||||
expect(findDocById(versionWithSlugs, 'foo/baz')).toBeUndefined();
|
||||
|
||||
expect(findDocById(currentVersion, 'foo/bar')).toEqual({
|
||||
...defaultDocMetadata,
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/next/foo/barSlug',
|
||||
slug: '/foo/barSlug',
|
||||
source: path.join('@site', routeBasePath, 'foo', 'bar.md'),
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, currentVersion.docsDirPath),
|
||||
'foo',
|
||||
'bar.md',
|
||||
),
|
||||
title: 'bar',
|
||||
description: 'This is next version of bar.',
|
||||
version: 'next',
|
||||
version: 'current',
|
||||
sidebar: 'docs',
|
||||
next: {
|
||||
title: 'hello',
|
||||
permalink: '/docs/next/',
|
||||
},
|
||||
});
|
||||
expect(docsMetadata.hello).toEqual({
|
||||
expect(findDocById(currentVersion, 'hello')).toEqual({
|
||||
...defaultDocMetadata,
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/next/',
|
||||
slug: '/',
|
||||
source: path.join('@site', routeBasePath, 'hello.md'),
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, currentVersion.docsDirPath),
|
||||
'hello.md',
|
||||
),
|
||||
title: 'hello',
|
||||
description: 'Hello next !',
|
||||
version: 'next',
|
||||
version: 'current',
|
||||
sidebar: 'docs',
|
||||
previous: {
|
||||
title: 'bar',
|
||||
permalink: '/docs/next/foo/barSlug',
|
||||
},
|
||||
});
|
||||
expect(docsMetadata['version-1.0.1/hello']).toEqual({
|
||||
expect(findDocById(version101, 'hello')).toEqual({
|
||||
...defaultDocMetadata,
|
||||
id: 'version-1.0.1/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: true,
|
||||
|
@ -386,8 +435,7 @@ describe('versioned website', () => {
|
|||
slug: '/',
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, versionedDir),
|
||||
'version-1.0.1',
|
||||
path.relative(siteDir, version101.docsDirPath),
|
||||
'hello.md',
|
||||
),
|
||||
title: 'hello',
|
||||
|
@ -399,7 +447,8 @@ describe('versioned website', () => {
|
|||
permalink: '/docs/foo/bar',
|
||||
},
|
||||
});
|
||||
expect(docsMetadata['version-1.0.0/foo/baz']).toEqual({
|
||||
expect(findDocById(version100, 'foo/baz')).toEqual({
|
||||
...defaultDocMetadata,
|
||||
id: 'version-1.0.0/foo/baz',
|
||||
unversionedId: 'foo/baz',
|
||||
isDocsHomePage: false,
|
||||
|
@ -407,8 +456,7 @@ describe('versioned website', () => {
|
|||
slug: '/foo/baz',
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, versionedDir),
|
||||
'version-1.0.0',
|
||||
path.relative(siteDir, version100.docsDirPath),
|
||||
'foo',
|
||||
'baz.md',
|
||||
),
|
||||
|
@ -427,47 +475,24 @@ describe('versioned website', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(docsSidebars).toMatchSnapshot('all sidebars');
|
||||
expect(versionToSidebars).toMatchSnapshot(
|
||||
'sidebars needed for each version',
|
||||
expect(currentVersion.sidebars).toMatchSnapshot('current version sidebars');
|
||||
expect(version101.sidebars).toMatchSnapshot('101 version sidebars');
|
||||
expect(version100.sidebars).toMatchSnapshot('100 version sidebars');
|
||||
expect(versionWithSlugs.sidebars).toMatchSnapshot(
|
||||
'withSlugs version sidebars',
|
||||
);
|
||||
|
||||
const {actions, utils} = createFakeActions(pluginContentDir);
|
||||
await plugin.contentLoaded({
|
||||
await plugin.contentLoaded!({
|
||||
content,
|
||||
actions,
|
||||
allContent: {},
|
||||
});
|
||||
|
||||
// The created base metadata for each nested docs route is smartly chunked/ splitted across version
|
||||
const latestVersionBaseMetadata = utils.getCreatedDataByPrefix(
|
||||
'docs-route-',
|
||||
);
|
||||
expect(latestVersionBaseMetadata).toMatchSnapshot(
|
||||
'base metadata for latest version',
|
||||
);
|
||||
expect(latestVersionBaseMetadata.docsSidebars).not.toEqual(docsSidebars);
|
||||
expect(latestVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||
permalinkToSidebar,
|
||||
);
|
||||
const nextVersionBaseMetadata = utils.getCreatedDataByPrefix(
|
||||
'docs-next-route-',
|
||||
);
|
||||
expect(nextVersionBaseMetadata).toMatchSnapshot(
|
||||
'base metadata for next version',
|
||||
);
|
||||
expect(nextVersionBaseMetadata.docsSidebars).not.toEqual(docsSidebars);
|
||||
expect(nextVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||
permalinkToSidebar,
|
||||
);
|
||||
const firstVersionBaseMetadata = utils.getCreatedDataByPrefix(
|
||||
'docs-1-0-0-route-',
|
||||
);
|
||||
expect(firstVersionBaseMetadata).toMatchSnapshot(
|
||||
'base metadata for first version',
|
||||
);
|
||||
expect(nextVersionBaseMetadata.docsSidebars).not.toEqual(docsSidebars);
|
||||
expect(nextVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||
permalinkToSidebar,
|
||||
);
|
||||
utils.checkVersionMetadataPropCreated(currentVersion);
|
||||
utils.checkVersionMetadataPropCreated(version101);
|
||||
utils.checkVersionMetadataPropCreated(version100);
|
||||
utils.checkVersionMetadataPropCreated(versionWithSlugs);
|
||||
|
||||
utils.expectSnapshot();
|
||||
});
|
||||
|
@ -481,26 +506,24 @@ describe('versioned website (community)', () => {
|
|||
const pluginId = 'community';
|
||||
const plugin = pluginContentDocs(
|
||||
context,
|
||||
normalizePluginOptions(PluginOptionSchema, {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
id: 'community',
|
||||
path: 'community',
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
}),
|
||||
);
|
||||
const env = loadEnv(siteDir, pluginId);
|
||||
const {docsDir: versionedDir} = env.versioning;
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
|
||||
test('isVersioned', () => {
|
||||
expect(env.versioning.enabled).toEqual(true);
|
||||
});
|
||||
|
||||
test('extendCli - docsVersion', () => {
|
||||
const mock = jest.spyOn(version, 'docsVersion').mockImplementation();
|
||||
const mock = jest
|
||||
.spyOn(cliDocs, 'cliDocsVersionCommand')
|
||||
.mockImplementation();
|
||||
const cli = new commander.Command();
|
||||
plugin.extendCli(cli);
|
||||
// @ts-expect-error: TODO annoying type incompatibility
|
||||
plugin.extendCli!(cli);
|
||||
cli.parse(['node', 'test', `docs:version:${pluginId}`, '2.0.0']);
|
||||
expect(mock).toHaveBeenCalledTimes(1);
|
||||
expect(mock).toHaveBeenCalledWith('2.0.0', siteDir, pluginId, {
|
||||
path: routeBasePath,
|
||||
sidebarPath,
|
||||
|
@ -509,17 +532,17 @@ describe('versioned website (community)', () => {
|
|||
});
|
||||
|
||||
test('getPathToWatch', () => {
|
||||
const pathToWatch = plugin.getPathsToWatch();
|
||||
const pathToWatch = plugin.getPathsToWatch!();
|
||||
const matchPattern = pathToWatch.map((filepath) =>
|
||||
posixPath(path.relative(siteDir, filepath)),
|
||||
);
|
||||
expect(matchPattern).not.toEqual([]);
|
||||
expect(matchPattern).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"community_sidebars.json",
|
||||
"community/**/*.{md,mdx}",
|
||||
"community_versioned_sidebars/version-1.0.0-sidebars.json",
|
||||
"community_versioned_docs/version-1.0.0/**/*.{md,mdx}",
|
||||
"community_sidebars.json",
|
||||
]
|
||||
`);
|
||||
expect(isMatch('community/team.md', matchPattern)).toEqual(true);
|
||||
|
@ -545,27 +568,29 @@ describe('versioned website (community)', () => {
|
|||
});
|
||||
|
||||
test('content', async () => {
|
||||
const content = await plugin.loadContent();
|
||||
const {
|
||||
docsMetadata,
|
||||
docsSidebars,
|
||||
versionToSidebars,
|
||||
permalinkToSidebar,
|
||||
} = content;
|
||||
const content = await plugin.loadContent!();
|
||||
expect(content.loadedVersions.length).toEqual(2);
|
||||
const [currentVersion, version100] = content.loadedVersions;
|
||||
|
||||
expect(docsMetadata.team).toEqual({
|
||||
expect(findDocById(currentVersion, 'team')).toEqual({
|
||||
...defaultDocMetadata,
|
||||
id: 'team',
|
||||
unversionedId: 'team',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/community/next/team',
|
||||
slug: '/team',
|
||||
source: path.join('@site', routeBasePath, 'team.md'),
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, currentVersion.docsDirPath),
|
||||
'team.md',
|
||||
),
|
||||
title: 'team',
|
||||
description: 'Team current version',
|
||||
version: 'next',
|
||||
version: 'current',
|
||||
sidebar: 'community',
|
||||
});
|
||||
expect(docsMetadata['version-1.0.0/team']).toEqual({
|
||||
expect(findDocById(version100, 'team')).toEqual({
|
||||
...defaultDocMetadata,
|
||||
id: 'version-1.0.0/team',
|
||||
unversionedId: 'team',
|
||||
isDocsHomePage: false,
|
||||
|
@ -573,8 +598,7 @@ describe('versioned website (community)', () => {
|
|||
slug: '/team',
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, versionedDir),
|
||||
'version-1.0.0',
|
||||
path.relative(siteDir, version100.docsDirPath),
|
||||
'team.md',
|
||||
),
|
||||
title: 'team',
|
||||
|
@ -583,38 +607,18 @@ describe('versioned website (community)', () => {
|
|||
sidebar: 'version-1.0.0/community',
|
||||
});
|
||||
|
||||
expect(docsSidebars).toMatchSnapshot('all sidebars');
|
||||
expect(versionToSidebars).toMatchSnapshot(
|
||||
'sidebars needed for each version',
|
||||
);
|
||||
expect(currentVersion.sidebars).toMatchSnapshot('current version sidebars');
|
||||
expect(version100.sidebars).toMatchSnapshot('100 version sidebars');
|
||||
|
||||
const {actions, utils} = createFakeActions(pluginContentDir);
|
||||
await plugin.contentLoaded({
|
||||
await plugin.contentLoaded!({
|
||||
content,
|
||||
actions,
|
||||
allContent: {},
|
||||
});
|
||||
|
||||
// The created base metadata for each nested docs route is smartly chunked/ splitted across version
|
||||
const latestVersionBaseMetadata = utils.getCreatedDataByPrefix(
|
||||
'community-route-',
|
||||
);
|
||||
expect(latestVersionBaseMetadata).toMatchSnapshot(
|
||||
'base metadata for latest version',
|
||||
);
|
||||
expect(latestVersionBaseMetadata.docsSidebars).not.toEqual(docsSidebars);
|
||||
expect(latestVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||
permalinkToSidebar,
|
||||
);
|
||||
const nextVersionBaseMetadata = utils.getCreatedDataByPrefix(
|
||||
'community-next-route-',
|
||||
);
|
||||
expect(nextVersionBaseMetadata).toMatchSnapshot(
|
||||
'base metadata for next version',
|
||||
);
|
||||
expect(nextVersionBaseMetadata.docsSidebars).not.toEqual(docsSidebars);
|
||||
expect(nextVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||
permalinkToSidebar,
|
||||
);
|
||||
utils.checkVersionMetadataPropCreated(currentVersion);
|
||||
utils.checkVersionMetadataPropCreated(version100);
|
||||
|
||||
utils.expectSnapshot();
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ import fs from 'fs';
|
|||
import path from 'path';
|
||||
import shell from 'shelljs';
|
||||
|
||||
import lastUpdate from '../lastUpdate';
|
||||
import {getFileLastUpdate} from '../lastUpdate';
|
||||
|
||||
describe('lastUpdate', () => {
|
||||
const existingFilePath = path.join(
|
||||
|
@ -17,7 +17,7 @@ describe('lastUpdate', () => {
|
|||
'__fixtures__/simple-site/docs/hello.md',
|
||||
);
|
||||
test('existing test file in repository with Git timestamp', async () => {
|
||||
const lastUpdateData = await lastUpdate(existingFilePath);
|
||||
const lastUpdateData = await getFileLastUpdate(existingFilePath);
|
||||
expect(lastUpdateData).not.toBeNull();
|
||||
|
||||
const {author, timestamp} = lastUpdateData;
|
||||
|
@ -36,29 +36,29 @@ describe('lastUpdate', () => {
|
|||
'__fixtures__',
|
||||
'.nonExisting',
|
||||
);
|
||||
expect(await lastUpdate(nonExistingFilePath)).toBeNull();
|
||||
expect(await getFileLastUpdate(nonExistingFilePath)).toBeNull();
|
||||
expect(consoleMock).toHaveBeenCalledTimes(1);
|
||||
expect(consoleMock).toHaveBeenCalledWith(
|
||||
new Error(
|
||||
`Command failed with exit code 128: git log -1 --format=%ct, %an ${nonExistingFilePath}`,
|
||||
),
|
||||
);
|
||||
expect(await lastUpdate(null)).toBeNull();
|
||||
expect(await lastUpdate(undefined)).toBeNull();
|
||||
expect(await getFileLastUpdate(null)).toBeNull();
|
||||
expect(await getFileLastUpdate(undefined)).toBeNull();
|
||||
consoleMock.mockRestore();
|
||||
});
|
||||
|
||||
test('temporary created file that has no git timestamp', async () => {
|
||||
const tempFilePath = path.join(__dirname, '__fixtures__', '.temp');
|
||||
fs.writeFileSync(tempFilePath, 'Lorem ipsum :)');
|
||||
expect(await lastUpdate(tempFilePath)).toBeNull();
|
||||
expect(await getFileLastUpdate(tempFilePath)).toBeNull();
|
||||
fs.unlinkSync(tempFilePath);
|
||||
});
|
||||
|
||||
test('Git does not exist', async () => {
|
||||
const mock = jest.spyOn(shell, 'which').mockImplementationOnce(() => null);
|
||||
const consoleMock = jest.spyOn(console, 'warn').mockImplementation();
|
||||
const lastUpdateData = await lastUpdate(existingFilePath);
|
||||
const lastUpdateData = await getFileLastUpdate(existingFilePath);
|
||||
expect(lastUpdateData).toBeNull();
|
||||
expect(consoleMock).toHaveBeenLastCalledWith(
|
||||
'Sorry, the docs plugin last update options require Git.',
|
||||
|
|
|
@ -1,464 +0,0 @@
|
|||
/**
|
||||
* 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 path from 'path';
|
||||
import {loadContext} from '@docusaurus/core/src/server/index';
|
||||
import processMetadata from '../metadata';
|
||||
import loadEnv from '../env';
|
||||
import {MetadataRaw, Env, MetadataOptions} from '../types';
|
||||
import {LoadContext} from '@docusaurus/types';
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||
|
||||
const fixtureDir = path.join(__dirname, '__fixtures__');
|
||||
|
||||
function createTestHelpers({
|
||||
siteDir,
|
||||
context,
|
||||
env,
|
||||
options,
|
||||
}: {
|
||||
siteDir: string;
|
||||
context: LoadContext;
|
||||
env: Env;
|
||||
options: MetadataOptions;
|
||||
}) {
|
||||
async function testMeta(
|
||||
refDir: string,
|
||||
source: string,
|
||||
expectedMetadata: Omit<MetadataRaw, 'source'>,
|
||||
) {
|
||||
const metadata = await processMetadata({
|
||||
source,
|
||||
refDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
expect(metadata).toEqual({
|
||||
...expectedMetadata,
|
||||
source: path.join('@site', path.relative(siteDir, refDir), source),
|
||||
});
|
||||
}
|
||||
|
||||
async function testSlug(
|
||||
refDir: string,
|
||||
source: string,
|
||||
expectedPermalink: string,
|
||||
) {
|
||||
const metadata = await processMetadata({
|
||||
source,
|
||||
refDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
expect(metadata.permalink).toEqual(expectedPermalink);
|
||||
}
|
||||
|
||||
return {testMeta, testSlug};
|
||||
}
|
||||
|
||||
describe('simple site', () => {
|
||||
const siteDir = path.join(fixtureDir, 'simple-site');
|
||||
const context = loadContext(siteDir);
|
||||
const routeBasePath = 'docs';
|
||||
const docsDir = path.resolve(siteDir, routeBasePath);
|
||||
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||
const options = {routeBasePath};
|
||||
|
||||
const {testMeta, testSlug} = createTestHelpers({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
test('normal docs', async () => {
|
||||
await testMeta(docsDir, path.join('foo', 'bar.md'), {
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bar',
|
||||
slug: '/foo/bar',
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
});
|
||||
await testMeta(docsDir, path.join('hello.md'), {
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/hello',
|
||||
slug: '/hello',
|
||||
title: 'Hello, World !',
|
||||
description: `Hi, Endilie here :)`,
|
||||
});
|
||||
});
|
||||
|
||||
test('homePageId doc', async () => {
|
||||
const {testMeta: testMetaLocal} = createTestHelpers({
|
||||
siteDir,
|
||||
options: {
|
||||
routeBasePath,
|
||||
homePageId: 'hello',
|
||||
},
|
||||
context,
|
||||
env,
|
||||
});
|
||||
|
||||
await testMetaLocal(docsDir, path.join('hello.md'), {
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/',
|
||||
slug: '/',
|
||||
title: 'Hello, World !',
|
||||
description: `Hi, Endilie here :)`,
|
||||
});
|
||||
});
|
||||
|
||||
test('homePageId doc nested', async () => {
|
||||
const {testMeta: testMetaLocal} = createTestHelpers({
|
||||
siteDir,
|
||||
options: {
|
||||
routeBasePath,
|
||||
homePageId: 'foo/bar',
|
||||
},
|
||||
context,
|
||||
env,
|
||||
});
|
||||
|
||||
await testMetaLocal(docsDir, path.join('foo', 'bar.md'), {
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/',
|
||||
slug: '/',
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with editUrl', async () => {
|
||||
const {testMeta: testMetaLocal} = createTestHelpers({
|
||||
siteDir,
|
||||
options: {
|
||||
routeBasePath,
|
||||
editUrl: 'https://github.com/facebook/docusaurus/edit/master/website',
|
||||
},
|
||||
context,
|
||||
env,
|
||||
});
|
||||
|
||||
await testMetaLocal(docsDir, path.join('foo', 'baz.md'), {
|
||||
id: 'foo/baz',
|
||||
unversionedId: 'foo/baz',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bazSlug.html',
|
||||
slug: '/foo/bazSlug.html',
|
||||
title: 'baz',
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website/docs/foo/baz.md',
|
||||
description: 'Images',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with custom editUrl & unrelated frontmatter', async () => {
|
||||
await testMeta(docsDir, 'lorem.md', {
|
||||
id: 'lorem',
|
||||
unversionedId: 'lorem',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/lorem',
|
||||
slug: '/lorem',
|
||||
title: 'lorem',
|
||||
editUrl: 'https://github.com/customUrl/docs/lorem.md',
|
||||
description: 'Lorem ipsum.',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with last update time and author', async () => {
|
||||
const {testMeta: testMetaLocal} = createTestHelpers({
|
||||
siteDir,
|
||||
options: {
|
||||
routeBasePath,
|
||||
showLastUpdateAuthor: true,
|
||||
showLastUpdateTime: true,
|
||||
},
|
||||
context,
|
||||
env,
|
||||
});
|
||||
|
||||
await testMetaLocal(docsDir, 'lorem.md', {
|
||||
id: 'lorem',
|
||||
unversionedId: 'lorem',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/lorem',
|
||||
slug: '/lorem',
|
||||
title: 'lorem',
|
||||
editUrl: 'https://github.com/customUrl/docs/lorem.md',
|
||||
description: 'Lorem ipsum.',
|
||||
lastUpdatedAt: 1539502055,
|
||||
lastUpdatedBy: 'Author',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with null custom_edit_url', async () => {
|
||||
const {testMeta: testMetaLocal} = createTestHelpers({
|
||||
siteDir,
|
||||
options: {
|
||||
routeBasePath,
|
||||
showLastUpdateAuthor: true,
|
||||
showLastUpdateTime: true,
|
||||
},
|
||||
context,
|
||||
env,
|
||||
});
|
||||
|
||||
await testMetaLocal(docsDir, 'ipsum.md', {
|
||||
id: 'ipsum',
|
||||
unversionedId: 'ipsum',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/ipsum',
|
||||
slug: '/ipsum',
|
||||
title: 'ipsum',
|
||||
editUrl: null,
|
||||
description: 'Lorem ipsum.',
|
||||
lastUpdatedAt: 1539502055,
|
||||
lastUpdatedBy: 'Author',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with slugs', async () => {
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('rootRelativeSlug.md'),
|
||||
'/docs/rootRelativeSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('rootAbsoluteSlug.md'),
|
||||
'/docs/rootAbsoluteSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('rootResolvedSlug.md'),
|
||||
'/docs/hey/rootResolvedSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('rootTryToEscapeSlug.md'),
|
||||
'/docs/rootTryToEscapeSlug',
|
||||
);
|
||||
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'absoluteSlug.md'),
|
||||
'/docs/absoluteSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'relativeSlug.md'),
|
||||
'/docs/slugs/relativeSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'resolvedSlug.md'),
|
||||
'/docs/slugs/hey/resolvedSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'tryToEscapeSlug.md'),
|
||||
'/docs/tryToEscapeSlug',
|
||||
);
|
||||
});
|
||||
|
||||
test('docs with invalid id', async () => {
|
||||
const badSiteDir = path.join(fixtureDir, 'bad-id-site');
|
||||
|
||||
await expect(
|
||||
processMetadata({
|
||||
source: 'invalid-id.md',
|
||||
refDir: path.join(badSiteDir, 'docs'),
|
||||
context,
|
||||
options: {
|
||||
routeBasePath,
|
||||
},
|
||||
env,
|
||||
}),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"Document id cannot include \\"/\\"."`,
|
||||
);
|
||||
});
|
||||
|
||||
test('docs with slug on doc home', async () => {
|
||||
const badSiteDir = path.join(fixtureDir, 'bad-slug-on-doc-home-site');
|
||||
|
||||
await expect(
|
||||
processMetadata({
|
||||
source: 'docWithSlug.md',
|
||||
refDir: path.join(badSiteDir, 'docs'),
|
||||
context,
|
||||
options: {
|
||||
routeBasePath,
|
||||
homePageId: 'docWithSlug',
|
||||
},
|
||||
env,
|
||||
}),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"The docs homepage (homePageId=docWithSlug) is not allowed to have a frontmatter slug=docWithSlug.html => you have to chooser either homePageId or slug, not both"`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('versioned site', () => {
|
||||
const siteDir = path.join(fixtureDir, 'versioned-site');
|
||||
const context = loadContext(siteDir);
|
||||
const routeBasePath = 'docs';
|
||||
const docsDir = path.resolve(siteDir, routeBasePath);
|
||||
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||
const {docsDir: versionedDir} = env.versioning;
|
||||
const options = {routeBasePath};
|
||||
|
||||
const {testMeta, testSlug} = createTestHelpers({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
test('next docs', async () => {
|
||||
await testMeta(docsDir, path.join('foo', 'bar.md'), {
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/next/foo/barSlug',
|
||||
slug: '/foo/barSlug',
|
||||
title: 'bar',
|
||||
description: 'This is next version of bar.',
|
||||
version: 'next',
|
||||
});
|
||||
await testMeta(docsDir, path.join('hello.md'), {
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/next/hello',
|
||||
slug: '/hello',
|
||||
title: 'hello',
|
||||
description: 'Hello next !',
|
||||
version: 'next',
|
||||
});
|
||||
});
|
||||
|
||||
test('versioned docs', async () => {
|
||||
await testMeta(versionedDir, path.join('version-1.0.0', 'foo', 'bar.md'), {
|
||||
id: 'version-1.0.0/foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/1.0.0/foo/barSlug',
|
||||
slug: '/foo/barSlug',
|
||||
title: 'bar',
|
||||
description: 'Bar 1.0.0 !',
|
||||
version: '1.0.0',
|
||||
});
|
||||
await testMeta(versionedDir, path.join('version-1.0.0', 'hello.md'), {
|
||||
id: 'version-1.0.0/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/1.0.0/hello',
|
||||
slug: '/hello',
|
||||
title: 'hello',
|
||||
description: 'Hello 1.0.0 !',
|
||||
version: '1.0.0',
|
||||
});
|
||||
await testMeta(versionedDir, path.join('version-1.0.1', 'foo', 'bar.md'), {
|
||||
id: 'version-1.0.1/foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bar',
|
||||
slug: '/foo/bar',
|
||||
title: 'bar',
|
||||
description: 'Bar 1.0.1 !',
|
||||
version: '1.0.1',
|
||||
});
|
||||
await testMeta(versionedDir, path.join('version-1.0.1', 'hello.md'), {
|
||||
id: 'version-1.0.1/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/hello',
|
||||
slug: '/hello',
|
||||
title: 'hello',
|
||||
description: 'Hello 1.0.1 !',
|
||||
version: '1.0.1',
|
||||
});
|
||||
});
|
||||
|
||||
test('next doc slugs', async () => {
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'absoluteSlug.md'),
|
||||
'/docs/next/absoluteSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'relativeSlug.md'),
|
||||
'/docs/next/slugs/relativeSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'resolvedSlug.md'),
|
||||
'/docs/next/slugs/hey/resolvedSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'tryToEscapeSlug.md'),
|
||||
'/docs/next/tryToEscapeSlug',
|
||||
);
|
||||
});
|
||||
|
||||
test('versioned doc slugs', async () => {
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'rootAbsoluteSlug.md'),
|
||||
'/docs/withSlugs/rootAbsoluteSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'rootRelativeSlug.md'),
|
||||
'/docs/withSlugs/rootRelativeSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'rootResolvedSlug.md'),
|
||||
'/docs/withSlugs/hey/rootResolvedSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'rootTryToEscapeSlug.md'),
|
||||
'/docs/withSlugs/rootTryToEscapeSlug',
|
||||
);
|
||||
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'slugs', 'absoluteSlug.md'),
|
||||
'/docs/withSlugs/absoluteSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'slugs', 'relativeSlug.md'),
|
||||
'/docs/withSlugs/slugs/relativeSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'slugs', 'resolvedSlug.md'),
|
||||
'/docs/withSlugs/slugs/hey/resolvedSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'slugs', 'tryToEscapeSlug.md'),
|
||||
'/docs/withSlugs/tryToEscapeSlug',
|
||||
);
|
||||
});
|
||||
});
|
|
@ -5,7 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema';
|
||||
import {OptionsSchema, DEFAULT_OPTIONS} from '../options';
|
||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||
|
||||
// the type of remark/rehype plugins is function
|
||||
|
@ -14,7 +14,7 @@ const markdownPluginsObjectStub = {};
|
|||
|
||||
describe('normalizeDocsPluginOptions', () => {
|
||||
test('should return default options for undefined user options', async () => {
|
||||
const {value, error} = await PluginOptionSchema.validate({});
|
||||
const {value, error} = await OptionsSchema.validate({});
|
||||
expect(value).toEqual(DEFAULT_OPTIONS);
|
||||
expect(error).toBe(undefined);
|
||||
});
|
||||
|
@ -34,9 +34,10 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
showLastUpdateAuthor: true,
|
||||
admonitions: {},
|
||||
excludeNextVersionDocs: true,
|
||||
includeCurrentVersion: false,
|
||||
disableVersioning: true,
|
||||
};
|
||||
const {value, error} = await PluginOptionSchema.validate(userOptions);
|
||||
const {value, error} = await OptionsSchema.validate(userOptions);
|
||||
expect(value).toEqual(userOptions);
|
||||
expect(error).toBe(undefined);
|
||||
});
|
||||
|
@ -50,14 +51,14 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
[markdownPluginsFunctionStub, {option1: '42'}],
|
||||
],
|
||||
};
|
||||
const {value, error} = await PluginOptionSchema.validate(userOptions);
|
||||
const {value, error} = await OptionsSchema.validate(userOptions);
|
||||
expect(value).toEqual(userOptions);
|
||||
expect(error).toBe(undefined);
|
||||
});
|
||||
|
||||
test('should reject invalid remark plugin options', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(PluginOptionSchema, {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
remarkPlugins: [[{option1: '42'}, markdownPluginsFunctionStub]],
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
|
@ -67,7 +68,7 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
|
||||
test('should reject invalid rehype plugin options', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(PluginOptionSchema, {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
rehypePlugins: [
|
||||
[
|
||||
markdownPluginsFunctionStub,
|
||||
|
@ -83,7 +84,7 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
|
||||
test('should reject bad path inputs', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(PluginOptionSchema, {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
path: 2,
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(`"\\"path\\" must be a string"`);
|
||||
|
@ -91,7 +92,7 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
|
||||
test('should reject bad include inputs', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(PluginOptionSchema, {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
include: '**/*.{md,mdx}',
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(`"\\"include\\" must be an array"`);
|
||||
|
@ -99,7 +100,7 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
|
||||
test('should reject bad showLastUpdateTime inputs', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(PluginOptionSchema, {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
showLastUpdateTime: 'true',
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
|
@ -109,7 +110,7 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
|
||||
test('should reject bad remarkPlugins input', () => {
|
||||
expect(() => {
|
||||
normalizePluginOptions(PluginOptionSchema, {
|
||||
normalizePluginOptions(OptionsSchema, {
|
||||
remarkPlugins: 'remark-math',
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
|
@ -1,240 +0,0 @@
|
|||
/**
|
||||
* 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 createOrder from '../order';
|
||||
|
||||
describe('createOrder', () => {
|
||||
test('multiple sidebars with subcategory', () => {
|
||||
const result = createOrder({
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category1',
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Subcategory 1',
|
||||
items: [{type: 'doc', id: 'doc1'}],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Subcategory 2',
|
||||
items: [{type: 'doc', id: 'doc2'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category2',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc3'},
|
||||
{type: 'doc', id: 'doc4'},
|
||||
],
|
||||
},
|
||||
],
|
||||
otherDocs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category1',
|
||||
items: [{type: 'doc', id: 'doc5'}],
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toEqual({
|
||||
doc1: {
|
||||
next: 'doc2',
|
||||
previous: undefined,
|
||||
sidebar: 'docs',
|
||||
},
|
||||
doc2: {
|
||||
next: 'doc3',
|
||||
previous: 'doc1',
|
||||
sidebar: 'docs',
|
||||
},
|
||||
doc3: {
|
||||
next: 'doc4',
|
||||
previous: 'doc2',
|
||||
sidebar: 'docs',
|
||||
},
|
||||
doc4: {
|
||||
next: undefined,
|
||||
previous: 'doc3',
|
||||
sidebar: 'docs',
|
||||
},
|
||||
doc5: {
|
||||
next: undefined,
|
||||
previous: undefined,
|
||||
sidebar: 'otherDocs',
|
||||
},
|
||||
});
|
||||
});
|
||||
test('multiple sidebars without subcategory', () => {
|
||||
const result = createOrder({
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category1',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc1'},
|
||||
{type: 'doc', id: 'doc2'},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category2',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc3'},
|
||||
{type: 'doc', id: 'doc4'},
|
||||
],
|
||||
},
|
||||
],
|
||||
otherDocs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category1',
|
||||
items: [{type: 'doc', id: 'doc5'}],
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toEqual({
|
||||
doc1: {
|
||||
next: 'doc2',
|
||||
previous: undefined,
|
||||
sidebar: 'docs',
|
||||
},
|
||||
doc2: {
|
||||
next: 'doc3',
|
||||
previous: 'doc1',
|
||||
sidebar: 'docs',
|
||||
},
|
||||
doc3: {
|
||||
next: 'doc4',
|
||||
previous: 'doc2',
|
||||
sidebar: 'docs',
|
||||
},
|
||||
doc4: {
|
||||
next: undefined,
|
||||
previous: 'doc3',
|
||||
sidebar: 'docs',
|
||||
},
|
||||
doc5: {
|
||||
next: undefined,
|
||||
previous: undefined,
|
||||
sidebar: 'otherDocs',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('versioned sidebars', () => {
|
||||
const result = createOrder({
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category1',
|
||||
items: [{type: 'doc', id: 'doc1'}],
|
||||
},
|
||||
],
|
||||
'version-1.2.3-docs': [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category1',
|
||||
items: [{type: 'doc', id: 'version-1.2.3-doc2'}],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category2',
|
||||
items: [{type: 'doc', id: 'version-1.2.3-doc1'}],
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toEqual({
|
||||
doc1: {
|
||||
next: undefined,
|
||||
previous: undefined,
|
||||
sidebar: 'docs',
|
||||
},
|
||||
'version-1.2.3-doc1': {
|
||||
next: undefined,
|
||||
previous: 'version-1.2.3-doc2',
|
||||
sidebar: 'version-1.2.3-docs',
|
||||
},
|
||||
'version-1.2.3-doc2': {
|
||||
next: 'version-1.2.3-doc1',
|
||||
previous: undefined,
|
||||
sidebar: 'version-1.2.3-docs',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('multiple sidebars with subcategories, refs and external links', () => {
|
||||
const result = createOrder({
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category1',
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Subcategory 1',
|
||||
items: [{type: 'link', href: '//example.com', label: 'bar'}],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Subcategory 2',
|
||||
items: [{type: 'doc', id: 'doc2'}],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Subcategory 1',
|
||||
items: [{type: 'link', href: '//example2.com', label: 'baz'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category2',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc3'},
|
||||
{type: 'ref', id: 'doc4'},
|
||||
],
|
||||
},
|
||||
],
|
||||
otherDocs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category1',
|
||||
items: [{type: 'doc', id: 'doc5'}],
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result).toEqual({
|
||||
doc2: {
|
||||
next: 'doc3',
|
||||
previous: undefined,
|
||||
sidebar: 'docs',
|
||||
},
|
||||
doc3: {
|
||||
next: undefined,
|
||||
previous: 'doc2',
|
||||
sidebar: 'docs',
|
||||
},
|
||||
doc5: {
|
||||
next: undefined,
|
||||
previous: undefined,
|
||||
sidebar: 'otherDocs',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('edge cases', () => {
|
||||
expect(createOrder({})).toEqual({});
|
||||
expect(createOrder(undefined)).toEqual({});
|
||||
expect(() => createOrder(null)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Cannot convert undefined or null to object"`,
|
||||
);
|
||||
});
|
||||
});
|
|
@ -6,7 +6,13 @@
|
|||
*/
|
||||
|
||||
import path from 'path';
|
||||
import loadSidebars from '../sidebars';
|
||||
import {
|
||||
loadSidebars,
|
||||
collectSidebarDocItems,
|
||||
collectSidebarsDocIds,
|
||||
createSidebarsUtils,
|
||||
} from '../sidebars';
|
||||
import {Sidebar, Sidebars} from '../types';
|
||||
|
||||
/* eslint-disable global-require, import/no-dynamic-require */
|
||||
|
||||
|
@ -14,13 +20,13 @@ describe('loadSidebars', () => {
|
|||
const fixtureDir = path.join(__dirname, '__fixtures__', 'sidebars');
|
||||
test('sidebars with known sidebar item type', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars.json');
|
||||
const result = loadSidebars([sidebarPath]);
|
||||
const result = loadSidebars(sidebarPath);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('sidebars with deep level of category', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-category.js');
|
||||
const result = loadSidebars([sidebarPath]);
|
||||
const result = loadSidebars(sidebarPath);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -30,8 +36,8 @@ describe('loadSidebars', () => {
|
|||
fixtureDir,
|
||||
'sidebars-category-shorthand.js',
|
||||
);
|
||||
const sidebar1 = loadSidebars([sidebarPath1]);
|
||||
const sidebar2 = loadSidebars([sidebarPath2]);
|
||||
const sidebar1 = loadSidebars(sidebarPath1);
|
||||
const sidebar2 = loadSidebars(sidebarPath2);
|
||||
expect(sidebar1).toEqual(sidebar2);
|
||||
});
|
||||
|
||||
|
@ -40,9 +46,7 @@ describe('loadSidebars', () => {
|
|||
fixtureDir,
|
||||
'sidebars-category-wrong-items.json',
|
||||
);
|
||||
expect(() =>
|
||||
loadSidebars([sidebarPath]),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Error loading {\\"type\\":\\"category\\",\\"label\\":\\"Category Label\\",\\"items\\":\\"doc1\\"}. \\"items\\" must be an array."`,
|
||||
);
|
||||
});
|
||||
|
@ -52,9 +56,7 @@ describe('loadSidebars', () => {
|
|||
fixtureDir,
|
||||
'sidebars-category-wrong-label.json',
|
||||
);
|
||||
expect(() =>
|
||||
loadSidebars([sidebarPath]),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Error loading {\\"type\\":\\"category\\",\\"label\\":true,\\"items\\":[\\"doc1\\"]}. \\"label\\" must be a string."`,
|
||||
);
|
||||
});
|
||||
|
@ -64,9 +66,7 @@ describe('loadSidebars', () => {
|
|||
fixtureDir,
|
||||
'sidebars-doc-id-not-string.json',
|
||||
);
|
||||
expect(() =>
|
||||
loadSidebars([sidebarPath]),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Error loading {\\"type\\":\\"doc\\",\\"id\\":[\\"doc1\\"]}. \\"id\\" must be a string."`,
|
||||
);
|
||||
});
|
||||
|
@ -76,60 +76,75 @@ describe('loadSidebars', () => {
|
|||
fixtureDir,
|
||||
'sidebars-first-level-not-category.js',
|
||||
);
|
||||
const result = loadSidebars([sidebarPath]);
|
||||
const result = loadSidebars(sidebarPath);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('sidebars link', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-link.json');
|
||||
const result = loadSidebars([sidebarPath]);
|
||||
const result = loadSidebars(sidebarPath);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('sidebars link wrong label', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-link-wrong-label.json');
|
||||
expect(() =>
|
||||
loadSidebars([sidebarPath]),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Error loading {\\"type\\":\\"link\\",\\"label\\":false,\\"href\\":\\"https://github.com\\"}. \\"label\\" must be a string."`,
|
||||
);
|
||||
});
|
||||
|
||||
test('sidebars link wrong href', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-link-wrong-href.json');
|
||||
expect(() =>
|
||||
loadSidebars([sidebarPath]),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Error loading {\\"type\\":\\"link\\",\\"label\\":\\"GitHub\\",\\"href\\":[\\"example.com\\"]}. \\"href\\" must be a string."`,
|
||||
);
|
||||
});
|
||||
|
||||
test('sidebars with unknown sidebar item type', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-unknown-type.json');
|
||||
expect(() =>
|
||||
loadSidebars([sidebarPath]),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Unknown sidebar item type [superman]. Sidebar item={\\"type\\":\\"superman\\"} "`,
|
||||
);
|
||||
});
|
||||
|
||||
test('sidebars with known sidebar item type but wrong field', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-wrong-field.json');
|
||||
expect(() =>
|
||||
loadSidebars([sidebarPath]),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Unknown sidebar item keys: href. Item: {\\"type\\":\\"category\\",\\"label\\":\\"category\\",\\"href\\":\\"https://github.com\\"}"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('no sidebars', () => {
|
||||
const result = loadSidebars(null);
|
||||
expect(result).toEqual({});
|
||||
test('unexisting path', () => {
|
||||
expect(() => loadSidebars('badpath')).toThrowErrorMatchingInlineSnapshot(
|
||||
`"No sidebar file exist at path: badpath"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('undefined path', () => {
|
||||
expect(() =>
|
||||
loadSidebars(
|
||||
// @ts-expect-error: bad arg
|
||||
undefined,
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"sidebarFilePath not provided: undefined"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('null path', () => {
|
||||
expect(() =>
|
||||
loadSidebars(
|
||||
// @ts-expect-error: bad arg
|
||||
null,
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"sidebarFilePath not provided: null"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('sidebars with category.collapsed property', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-collapsed.json');
|
||||
const result = loadSidebars([sidebarPath]);
|
||||
const result = loadSidebars(sidebarPath);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -138,7 +153,177 @@ describe('loadSidebars', () => {
|
|||
fixtureDir,
|
||||
'sidebars-collapsed-first-level.json',
|
||||
);
|
||||
const result = loadSidebars([sidebarPath]);
|
||||
const result = loadSidebars(sidebarPath);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('collectSidebarDocItems', () => {
|
||||
test('can collect recursively', async () => {
|
||||
const sidebar: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Category1',
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Subcategory 1',
|
||||
items: [{type: 'doc', id: 'doc1'}],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Subcategory 2',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc2'},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Sub sub category 1',
|
||||
items: [{type: 'doc', id: 'doc3'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
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('collectSidebarsDocItems', () => {
|
||||
test('can collect sidebars doc items', async () => {
|
||||
const sidebar1: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Category1',
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Subcategory 1',
|
||||
items: [{type: 'doc', id: 'doc1'}],
|
||||
},
|
||||
{type: 'doc', id: 'doc2'},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const sidebar2: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
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('createSidebarsUtils', () => {
|
||||
const sidebar1: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Category1',
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Subcategory 1',
|
||||
items: [{type: 'doc', id: 'doc1'}],
|
||||
},
|
||||
{type: 'doc', id: 'doc2'},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const sidebar2: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
label: 'Category2',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc3'},
|
||||
{type: 'doc', id: 'doc4'},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const sidebars: Sidebars = {sidebar1, sidebar2};
|
||||
|
||||
const {
|
||||
getFirstDocIdOfFirstSidebar,
|
||||
getSidebarNameByDocId,
|
||||
getDocNavigation,
|
||||
} = createSidebarsUtils(sidebars);
|
||||
|
||||
test('getSidebarNameByDocId', async () => {
|
||||
expect(getFirstDocIdOfFirstSidebar()).toEqual('doc1');
|
||||
});
|
||||
|
||||
test('getSidebarNameByDocId', async () => {
|
||||
expect(getSidebarNameByDocId('doc1')).toEqual('sidebar1');
|
||||
expect(getSidebarNameByDocId('doc2')).toEqual('sidebar1');
|
||||
expect(getSidebarNameByDocId('doc3')).toEqual('sidebar2');
|
||||
expect(getSidebarNameByDocId('doc4')).toEqual('sidebar2');
|
||||
expect(getSidebarNameByDocId('doc5')).toEqual(undefined);
|
||||
expect(getSidebarNameByDocId('doc6')).toEqual(undefined);
|
||||
});
|
||||
|
||||
test('getDocNavigation', async () => {
|
||||
expect(getDocNavigation('doc1')).toEqual({
|
||||
sidebarName: 'sidebar1',
|
||||
previousId: undefined,
|
||||
nextId: 'doc2',
|
||||
});
|
||||
expect(getDocNavigation('doc2')).toEqual({
|
||||
sidebarName: 'sidebar1',
|
||||
previousId: 'doc1',
|
||||
nextId: undefined,
|
||||
});
|
||||
|
||||
expect(getDocNavigation('doc3')).toEqual({
|
||||
sidebarName: 'sidebar2',
|
||||
previousId: undefined,
|
||||
nextId: 'doc4',
|
||||
});
|
||||
expect(getDocNavigation('doc4')).toEqual({
|
||||
sidebarName: 'sidebar2',
|
||||
previousId: 'doc3',
|
||||
nextId: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
/**
|
||||
* 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 path from 'path';
|
||||
import {
|
||||
getVersionsFilePath,
|
||||
getVersionedDocsDirPath,
|
||||
getVersionedSidebarsDirPath,
|
||||
readVersionsMetadata,
|
||||
} from '../versions';
|
||||
import {DEFAULT_OPTIONS} from '../options';
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||
import {VersionMetadata} from '../types';
|
||||
|
||||
describe('version paths', () => {
|
||||
test('getVersionedDocsDirPath', () => {
|
||||
expect(getVersionsFilePath('someSiteDir', DEFAULT_PLUGIN_ID)).toBe(
|
||||
'someSiteDir/versions.json',
|
||||
);
|
||||
expect(getVersionsFilePath('otherSite/dir', 'pluginId')).toBe(
|
||||
'otherSite/dir/pluginId_versions.json',
|
||||
);
|
||||
});
|
||||
|
||||
test('getVersionedDocsDirPath', () => {
|
||||
expect(getVersionedDocsDirPath('someSiteDir', DEFAULT_PLUGIN_ID)).toBe(
|
||||
'someSiteDir/versioned_docs',
|
||||
);
|
||||
expect(getVersionedDocsDirPath('otherSite/dir', 'pluginId')).toBe(
|
||||
'otherSite/dir/pluginId_versioned_docs',
|
||||
);
|
||||
});
|
||||
|
||||
test('getVersionedSidebarsDirPath', () => {
|
||||
expect(getVersionedSidebarsDirPath('someSiteDir', DEFAULT_PLUGIN_ID)).toBe(
|
||||
'someSiteDir/versioned_sidebars',
|
||||
);
|
||||
expect(getVersionedSidebarsDirPath('otherSite/dir', 'pluginId')).toBe(
|
||||
'otherSite/dir/pluginId_versioned_sidebars',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('simple site', () => {
|
||||
const simpleSiteDir = path.resolve(
|
||||
path.join(__dirname, '__fixtures__', 'simple-site'),
|
||||
);
|
||||
const defaultOptions = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
};
|
||||
const defaultContext = {
|
||||
siteDir: simpleSiteDir,
|
||||
baseUrl: '/',
|
||||
};
|
||||
|
||||
const vCurrent: VersionMetadata = {
|
||||
docsDirPath: path.join(simpleSiteDir, 'docs'),
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
sidebarFilePath: path.join(simpleSiteDir, 'sidebars.json'),
|
||||
versionLabel: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/docs',
|
||||
};
|
||||
|
||||
test('readVersionsMetadata simple site', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: defaultOptions,
|
||||
context: defaultContext,
|
||||
});
|
||||
|
||||
expect(versionsMetadata).toEqual([vCurrent]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with base url', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: defaultOptions,
|
||||
context: {
|
||||
...defaultContext,
|
||||
baseUrl: '/myBaseUrl',
|
||||
},
|
||||
});
|
||||
|
||||
expect(versionsMetadata).toEqual([
|
||||
{
|
||||
...vCurrent,
|
||||
versionPath: '/myBaseUrl/docs',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with base url', () => {
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {...defaultOptions, disableVersioning: true},
|
||||
context: defaultContext,
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Docs: using disableVersioning=true option on a non-versioned site does not make sense"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata simple site with base url', () => {
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {...defaultOptions, includeCurrentVersion: false},
|
||||
context: defaultContext,
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"It is not possible to use docs without any version. Please check the configuration of these options: includeCurrentVersion=false disableVersioning=false"`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('versioned site, pluginId=default', () => {
|
||||
const versionedSiteDir = path.resolve(
|
||||
path.join(__dirname, '__fixtures__', 'versioned-site'),
|
||||
);
|
||||
const defaultOptions = {
|
||||
id: DEFAULT_PLUGIN_ID,
|
||||
...DEFAULT_OPTIONS,
|
||||
};
|
||||
const defaultContext = {
|
||||
siteDir: versionedSiteDir,
|
||||
baseUrl: '/',
|
||||
};
|
||||
|
||||
const vCurrent: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'docs'),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||
versionLabel: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/docs/next',
|
||||
};
|
||||
|
||||
const v101: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.1'),
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
sidebarFilePath: path.join(
|
||||
versionedSiteDir,
|
||||
'versioned_sidebars/version-1.0.1-sidebars.json',
|
||||
),
|
||||
versionLabel: '1.0.1',
|
||||
versionName: '1.0.1',
|
||||
versionPath: '/docs',
|
||||
};
|
||||
|
||||
const v100: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'versioned_docs/version-1.0.0'),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(
|
||||
versionedSiteDir,
|
||||
'versioned_sidebars/version-1.0.0-sidebars.json',
|
||||
),
|
||||
versionLabel: '1.0.0',
|
||||
versionName: '1.0.0',
|
||||
versionPath: '/docs/1.0.0',
|
||||
};
|
||||
|
||||
const vwithSlugs: VersionMetadata = {
|
||||
docsDirPath: path.join(
|
||||
versionedSiteDir,
|
||||
'versioned_docs/version-withSlugs',
|
||||
),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(
|
||||
versionedSiteDir,
|
||||
'versioned_sidebars/version-withSlugs-sidebars.json',
|
||||
),
|
||||
versionLabel: 'withSlugs',
|
||||
versionName: 'withSlugs',
|
||||
versionPath: '/docs/withSlugs',
|
||||
};
|
||||
|
||||
test('readVersionsMetadata versioned site', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: defaultOptions,
|
||||
context: defaultContext,
|
||||
});
|
||||
|
||||
expect(versionsMetadata).toEqual([vCurrent, v101, v100, vwithSlugs]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with includeCurrentVersion=false', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {...defaultOptions, includeCurrentVersion: false},
|
||||
context: defaultContext,
|
||||
});
|
||||
|
||||
expect(versionsMetadata).toEqual([
|
||||
// vCurrent removed
|
||||
v101,
|
||||
v100,
|
||||
vwithSlugs,
|
||||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with disableVersioning', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {...defaultOptions, disableVersioning: true},
|
||||
context: defaultContext,
|
||||
});
|
||||
|
||||
expect(versionsMetadata).toEqual([
|
||||
{...vCurrent, isLast: true, routePriority: -1, versionPath: '/docs'},
|
||||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with all versions disabled', () => {
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {
|
||||
...defaultOptions,
|
||||
includeCurrentVersion: false,
|
||||
disableVersioning: true,
|
||||
},
|
||||
context: defaultContext,
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"It is not possible to use docs without any version. Please check the configuration of these options: includeCurrentVersion=false disableVersioning=true"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site with invalid versions.json file', () => {
|
||||
const mock = jest.spyOn(JSON, 'parse').mockImplementationOnce(() => {
|
||||
return {
|
||||
invalid: 'json',
|
||||
};
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
readVersionsMetadata({
|
||||
options: defaultOptions,
|
||||
context: defaultContext,
|
||||
});
|
||||
}).toThrowErrorMatchingInlineSnapshot(
|
||||
`"The versions file should contain an array of versions! Found content={\\"invalid\\":\\"json\\"}"`,
|
||||
);
|
||||
mock.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('versioned site, pluginId=community', () => {
|
||||
const versionedSiteDir = path.resolve(
|
||||
path.join(__dirname, '__fixtures__', 'versioned-site'),
|
||||
);
|
||||
const defaultOptions = {
|
||||
...DEFAULT_OPTIONS,
|
||||
id: 'community',
|
||||
path: 'community',
|
||||
routeBasePath: 'communityBasePath',
|
||||
};
|
||||
const defaultContext = {
|
||||
siteDir: versionedSiteDir,
|
||||
baseUrl: '/',
|
||||
};
|
||||
|
||||
const vCurrent: VersionMetadata = {
|
||||
docsDirPath: path.join(versionedSiteDir, 'community'),
|
||||
isLast: false,
|
||||
routePriority: undefined,
|
||||
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||
versionLabel: 'Next',
|
||||
versionName: 'current',
|
||||
versionPath: '/communityBasePath/next',
|
||||
};
|
||||
|
||||
const v100: VersionMetadata = {
|
||||
docsDirPath: path.join(
|
||||
versionedSiteDir,
|
||||
'community_versioned_docs/version-1.0.0',
|
||||
),
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
sidebarFilePath: path.join(
|
||||
versionedSiteDir,
|
||||
'community_versioned_sidebars/version-1.0.0-sidebars.json',
|
||||
),
|
||||
versionLabel: '1.0.0',
|
||||
versionName: '1.0.0',
|
||||
versionPath: '/communityBasePath',
|
||||
};
|
||||
|
||||
test('readVersionsMetadata versioned site (community)', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: defaultOptions,
|
||||
context: defaultContext,
|
||||
});
|
||||
|
||||
expect(versionsMetadata).toEqual([vCurrent, v100]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site (community) with includeCurrentVersion=false', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {...defaultOptions, includeCurrentVersion: false},
|
||||
context: defaultContext,
|
||||
});
|
||||
|
||||
expect(versionsMetadata).toEqual([
|
||||
// vCurrent removed
|
||||
v100,
|
||||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site (community) with disableVersioning', () => {
|
||||
const versionsMetadata = readVersionsMetadata({
|
||||
options: {...defaultOptions, disableVersioning: true},
|
||||
context: defaultContext,
|
||||
});
|
||||
|
||||
expect(versionsMetadata).toEqual([
|
||||
{
|
||||
...vCurrent,
|
||||
isLast: true,
|
||||
routePriority: -1,
|
||||
versionPath: '/communityBasePath',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('readVersionsMetadata versioned site (community) with all versions disabled', () => {
|
||||
expect(() =>
|
||||
readVersionsMetadata({
|
||||
options: {
|
||||
...defaultOptions,
|
||||
includeCurrentVersion: false,
|
||||
disableVersioning: true,
|
||||
},
|
||||
context: defaultContext,
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"It is not possible to use docs without any version. Please check the configuration of these options: includeCurrentVersion=false disableVersioning=true"`,
|
||||
);
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue