mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-14 01:27:35 +02:00
feat(v2): docs versioning ❄️🔥 (#1983)
* wip: versioning * wip again * nits lint * refactor metadata code so that we can have inobject properties optimization, fix typing * remove buggy permalink code * modify versioned docs fixture such that foo/baz only exists in v1.0.0 * refactor metadata.ts so that there is less transformon object * more refactoring * reduce test fixtures, refactoring * refactoring readability * finish metadata part * refactor with readdir * first pass of implementation * fix mdx laoder * split generated routes by version for performance & smaller bundle * test data for demo * refactor with set * more tests * typo * fix typo * better temporary ui * stronger typing & docsVersion command * add 100% test coverage for docsVersion command * more test and delete manual docs cut * cut 2.0.0-alpha.35 docs * cut alpha.36 instead * copyright * delete versioned docs * stronger test on metadata * update typo
This commit is contained in:
parent
c413cff212
commit
9829f56b1e
45 changed files with 1852 additions and 395 deletions
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
custom_edit_url: https://github.com/customUrl/docs/lorem.md
|
||||
unrelated_frontmatter: won't be part of metadata
|
||||
---
|
||||
|
||||
Lorem ipsum.
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
id: permalink
|
||||
title: Permalink
|
||||
permalink: :baseUrl:docsUrl/endiliey/:id
|
||||
---
|
||||
|
||||
This has a different permalink
|
|
@ -11,6 +11,4 @@ module.exports = {
|
|||
url: 'https://your-docusaurus-test-site.com',
|
||||
baseUrl: '/',
|
||||
favicon: 'img/favicon.ico',
|
||||
organizationName: 'facebook', // Usually your GitHub org/user name.
|
||||
projectName: 'docusaurus', // Usually your repo name.
|
||||
};
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
This is `next` version of bar.
|
|
@ -0,0 +1 @@
|
|||
Hello `next` !
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
title: 'Versioned Site',
|
||||
tagline: 'The tagline of my site',
|
||||
url: 'https://your-docusaurus-test-site.com',
|
||||
baseUrl: '/',
|
||||
favicon: 'img/favicon.ico',
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
"foo/bar"
|
||||
],
|
||||
"Guides": [
|
||||
"hello"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
Bar `1.0.0` !
|
|
@ -0,0 +1 @@
|
|||
Baz `1.0.0` ! This will be deleted in next subsequent versions.
|
|
@ -0,0 +1 @@
|
|||
Hello `1.0.0` !
|
|
@ -0,0 +1 @@
|
|||
Bar `1.0.1` !
|
|
@ -0,0 +1 @@
|
|||
Hello `1.0.1` !
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version-1.0.0/docs": {
|
||||
"Test": [
|
||||
"version-1.0.0/foo/bar",
|
||||
"version-1.0.0/foo/baz"
|
||||
],
|
||||
"Guides": [
|
||||
"version-1.0.0/hello"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version-1.0.1/docs": {
|
||||
"Test": [
|
||||
"version-1.0.1/foo/bar"
|
||||
],
|
||||
"Guides": [
|
||||
"version-1.0.1/hello"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
[
|
||||
"1.0.1",
|
||||
"1.0.0"
|
||||
]
|
|
@ -58,16 +58,8 @@ Array [
|
|||
"docsMetadata": "@docusaurus-plugin-content-docs/docs-route-ff2.json",
|
||||
},
|
||||
"path": "/docs/:route",
|
||||
"priority": undefined,
|
||||
"routes": Array [
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/permalink.md",
|
||||
"metadata": "@docusaurus-plugin-content-docs/docs-endiliey-permalink-086.json",
|
||||
},
|
||||
"path": "/docs/endiliey/permalink",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
|
@ -108,3 +100,311 @@ Array [
|
|||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`versioned website content 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"component": "@theme/DocPage",
|
||||
"modules": Object {
|
||||
"docsMetadata": "@docusaurus-plugin-content-docs/docs-1-0-0-route-660.json",
|
||||
},
|
||||
"path": "/docs/1.0.0/:route",
|
||||
"priority": undefined,
|
||||
"routes": Array [
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-1.0.0/foo/bar.md",
|
||||
"metadata": "@docusaurus-plugin-content-docs/docs-1-0-0-foo-bar-568.json",
|
||||
},
|
||||
"path": "/docs/1.0.0/foo/bar",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-1.0.0/foo/baz.md",
|
||||
"metadata": "@docusaurus-plugin-content-docs/docs-1-0-0-foo-baz-5e1.json",
|
||||
},
|
||||
"path": "/docs/1.0.0/foo/baz",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-1.0.0/hello.md",
|
||||
"metadata": "@docusaurus-plugin-content-docs/docs-1-0-0-hello-1d0.json",
|
||||
},
|
||||
"path": "/docs/1.0.0/hello",
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocPage",
|
||||
"modules": Object {
|
||||
"docsMetadata": "@docusaurus-plugin-content-docs/docs-next-route-1c8.json",
|
||||
},
|
||||
"path": "/docs/next/:route",
|
||||
"priority": undefined,
|
||||
"routes": Array [
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/foo/bar.md",
|
||||
"metadata": "@docusaurus-plugin-content-docs/docs-next-foo-bar-09c.json",
|
||||
},
|
||||
"path": "/docs/next/foo/bar",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/hello.md",
|
||||
"metadata": "@docusaurus-plugin-content-docs/docs-next-hello-64c.json",
|
||||
},
|
||||
"path": "/docs/next/hello",
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocPage",
|
||||
"modules": Object {
|
||||
"docsMetadata": "@docusaurus-plugin-content-docs/docs-route-ff2.json",
|
||||
},
|
||||
"path": "/docs/:route",
|
||||
"priority": -1,
|
||||
"routes": Array [
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-1.0.1/foo/bar.md",
|
||||
"metadata": "@docusaurus-plugin-content-docs/docs-foo-bar-cef.json",
|
||||
},
|
||||
"path": "/docs/foo/bar",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-1.0.1/hello.md",
|
||||
"metadata": "@docusaurus-plugin-content-docs/docs-hello-da2.json",
|
||||
},
|
||||
"path": "/docs/hello",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`versioned website content: all sidebars 1`] = `
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/next/foo/bar",
|
||||
"label": "bar",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Test",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/next/hello",
|
||||
"label": "hello",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Guides",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
"version-1.0.0/docs": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/1.0.0/foo/bar",
|
||||
"label": "bar",
|
||||
"type": "link",
|
||||
},
|
||||
Object {
|
||||
"href": "/docs/1.0.0/foo/baz",
|
||||
"label": "baz",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Test",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/1.0.0/hello",
|
||||
"label": "hello",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Guides",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
"version-1.0.1/docs": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/foo/bar",
|
||||
"label": "bar",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Test",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/hello",
|
||||
"label": "hello",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Guides",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`versioned website content: base metadata for first version 1`] = `
|
||||
Object {
|
||||
"docsSidebars": Object {
|
||||
"version-1.0.0/docs": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/1.0.0/foo/bar",
|
||||
"label": "bar",
|
||||
"type": "link",
|
||||
},
|
||||
Object {
|
||||
"href": "/docs/1.0.0/foo/baz",
|
||||
"label": "baz",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Test",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/1.0.0/hello",
|
||||
"label": "hello",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Guides",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
},
|
||||
"permalinkToSidebar": Object {
|
||||
"/docs/1.0.0/foo/bar": "version-1.0.0/docs",
|
||||
"/docs/1.0.0/foo/baz": "version-1.0.0/docs",
|
||||
"/docs/1.0.0/hello": "version-1.0.0/docs",
|
||||
},
|
||||
"version": "1.0.0",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`versioned website content: base metadata for latest version 1`] = `
|
||||
Object {
|
||||
"docsSidebars": Object {
|
||||
"version-1.0.1/docs": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/foo/bar",
|
||||
"label": "bar",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Test",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/hello",
|
||||
"label": "hello",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Guides",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
},
|
||||
"permalinkToSidebar": Object {
|
||||
"/docs/foo/bar": "version-1.0.1/docs",
|
||||
"/docs/hello": "version-1.0.1/docs",
|
||||
},
|
||||
"version": "1.0.1",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`versioned website content: base metadata for next version 1`] = `
|
||||
Object {
|
||||
"docsSidebars": Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/next/foo/bar",
|
||||
"label": "bar",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Test",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/next/hello",
|
||||
"label": "hello",
|
||||
"type": "link",
|
||||
},
|
||||
],
|
||||
"label": "Guides",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
},
|
||||
"permalinkToSidebar": Object {
|
||||
"/docs/next/foo/bar": "docs",
|
||||
"/docs/next/hello": "docs",
|
||||
},
|
||||
"version": "next",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`versioned website content: sidebars needed for each version 1`] = `
|
||||
Object {
|
||||
"1.0.0": Set {
|
||||
"version-1.0.0/docs",
|
||||
},
|
||||
"1.0.1": Set {
|
||||
"version-1.0.1/docs",
|
||||
},
|
||||
"next": Set {
|
||||
"docs",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`docsVersion first time versioning 1`] = `
|
||||
Object {
|
||||
"version-1.0.0/docs": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "version-1.0.0/foo/bar",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"id": "version-1.0.0/foo/baz",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "foo",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"href": "https://github.com",
|
||||
"label": "Github",
|
||||
"type": "link",
|
||||
},
|
||||
Object {
|
||||
"id": "version-1.0.0/hello",
|
||||
"type": "ref",
|
||||
},
|
||||
],
|
||||
"label": "Test",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "version-1.0.0/hello",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "Guides",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`docsVersion not the first time versioning 1`] = `
|
||||
Object {
|
||||
"version-2.0.0/docs": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "version-2.0.0/foo/bar",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "Test",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "version-2.0.0/hello",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "Guides",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* 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';
|
||||
|
||||
describe('loadEnv', () => {
|
||||
test('website with versioning disabled', () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'simple-site');
|
||||
const env = loadEnv(siteDir);
|
||||
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);
|
||||
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']);
|
||||
});
|
||||
|
||||
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);
|
||||
expect(env.versioning.enabled).toBe(false);
|
||||
mock.mockRestore();
|
||||
});
|
||||
});
|
|
@ -8,19 +8,31 @@
|
|||
import path from 'path';
|
||||
import {validate} from 'webpack';
|
||||
import {isMatch} from 'picomatch';
|
||||
import commander from 'commander';
|
||||
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';
|
||||
import {posixPath} from '@docusaurus/utils';
|
||||
import {sortConfig} from '@docusaurus/core/src/server/plugins';
|
||||
|
||||
const createFakeActions = (routeConfigs: RouteConfig[], contentDir) => {
|
||||
import * as version from '../version';
|
||||
|
||||
const createFakeActions = (
|
||||
routeConfigs: RouteConfig[],
|
||||
contentDir,
|
||||
dataContainer?,
|
||||
) => {
|
||||
return {
|
||||
addRoute: (config: RouteConfig) => {
|
||||
routeConfigs.push(config);
|
||||
},
|
||||
createData: async (name, _content) => {
|
||||
createData: async (name, content) => {
|
||||
if (dataContainer) {
|
||||
dataContainer[name] = content;
|
||||
}
|
||||
return path.join(contentDir, name);
|
||||
},
|
||||
};
|
||||
|
@ -84,6 +96,18 @@ describe('simple website', () => {
|
|||
});
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
|
||||
test('extendCli - docsVersion', () => {
|
||||
const mock = jest.spyOn(version, 'docsVersion').mockImplementation();
|
||||
const cli = new commander.Command();
|
||||
plugin.extendCli(cli);
|
||||
cli.parse(['node', 'test', 'docs:version', '1.0.0']);
|
||||
expect(mock).toHaveBeenCalledWith('1.0.0', siteDir, {
|
||||
path: pluginPath,
|
||||
sidebarPath,
|
||||
});
|
||||
mock.mockRestore();
|
||||
});
|
||||
|
||||
test('getPathToWatch', () => {
|
||||
const pathToWatch = plugin.getPathsToWatch();
|
||||
const matchPattern = pathToWatch.map(filepath =>
|
||||
|
@ -126,7 +150,13 @@ describe('simple website', () => {
|
|||
|
||||
test('content', async () => {
|
||||
const content = await plugin.loadContent();
|
||||
const {docsMetadata, docsSidebars} = content;
|
||||
const {
|
||||
docsMetadata,
|
||||
docsSidebars,
|
||||
versionToSidebars,
|
||||
permalinkToSidebar,
|
||||
} = content;
|
||||
expect(versionToSidebars).toEqual({});
|
||||
expect(docsMetadata.hello).toEqual({
|
||||
id: 'hello',
|
||||
permalink: '/docs/hello',
|
||||
|
@ -156,13 +186,233 @@ describe('simple website', () => {
|
|||
expect(docsSidebars).toMatchSnapshot();
|
||||
|
||||
const routeConfigs = [];
|
||||
const actions = createFakeActions(routeConfigs, pluginContentDir);
|
||||
const dataContainer = {};
|
||||
const actions = createFakeActions(
|
||||
routeConfigs,
|
||||
pluginContentDir,
|
||||
dataContainer,
|
||||
);
|
||||
|
||||
await plugin.contentLoaded({
|
||||
content,
|
||||
actions,
|
||||
});
|
||||
|
||||
// There is only one nested docs route for simple site
|
||||
const baseMetadata = JSON.parse(dataContainer['docs-route-ff2.json']);
|
||||
expect(baseMetadata.docsSidebars).toEqual(docsSidebars);
|
||||
expect(baseMetadata.permalinkToSidebar).toEqual(permalinkToSidebar);
|
||||
|
||||
expect(routeConfigs).not.toEqual([]);
|
||||
expect(routeConfigs).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('versioned website', () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||
const context = loadContext(siteDir);
|
||||
const sidebarPath = path.join(siteDir, 'sidebars.json');
|
||||
const routeBasePath = 'docs';
|
||||
const plugin = pluginContentDocs(context, {
|
||||
routeBasePath,
|
||||
sidebarPath,
|
||||
});
|
||||
const env = loadEnv(siteDir);
|
||||
const {docsDir: versionedDir} = env.versioning;
|
||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||
|
||||
test('extendCli - docsVersion', () => {
|
||||
const mock = jest.spyOn(version, 'docsVersion').mockImplementation();
|
||||
const cli = new commander.Command();
|
||||
plugin.extendCli(cli);
|
||||
cli.parse(['node', 'test', 'docs:version', '2.0.0']);
|
||||
expect(mock).toHaveBeenCalledWith('2.0.0', siteDir, {
|
||||
path: routeBasePath,
|
||||
sidebarPath,
|
||||
});
|
||||
mock.mockRestore();
|
||||
});
|
||||
|
||||
test('getPathToWatch', () => {
|
||||
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}",
|
||||
"versioned_sidebars/version-1.0.1-sidebars.json",
|
||||
"versioned_sidebars/version-1.0.0-sidebars.json",
|
||||
"versioned_docs/version-1.0.1/**/*.{md,mdx}",
|
||||
"versioned_docs/version-1.0.0/**/*.{md,mdx}",
|
||||
"sidebars.json",
|
||||
]
|
||||
`);
|
||||
expect(isMatch('docs/hello.md', matchPattern)).toEqual(true);
|
||||
expect(isMatch('docs/hello.mdx', matchPattern)).toEqual(true);
|
||||
expect(isMatch('docs/foo/bar.md', matchPattern)).toEqual(true);
|
||||
expect(isMatch('sidebars.json', matchPattern)).toEqual(true);
|
||||
expect(
|
||||
isMatch('versioned_docs/version-1.0.0/hello.md', matchPattern),
|
||||
).toEqual(true);
|
||||
expect(
|
||||
isMatch('versioned_docs/version-1.0.0/foo/bar.md', matchPattern),
|
||||
).toEqual(true);
|
||||
expect(
|
||||
isMatch('versioned_sidebars/version-1.0.0-sidebars.json', matchPattern),
|
||||
).toEqual(true);
|
||||
|
||||
// Non existing version
|
||||
expect(
|
||||
isMatch('versioned_docs/version-2.0.0/foo/bar.md', matchPattern),
|
||||
).toEqual(false);
|
||||
expect(
|
||||
isMatch('versioned_docs/version-2.0.0/hello.md', matchPattern),
|
||||
).toEqual(false);
|
||||
expect(
|
||||
isMatch('versioned_sidebars/version-2.0.0-sidebars.json', matchPattern),
|
||||
).toEqual(false);
|
||||
|
||||
expect(isMatch('docs/hello.js', matchPattern)).toEqual(false);
|
||||
expect(isMatch('docs/super.mdl', matchPattern)).toEqual(false);
|
||||
expect(isMatch('docs/mdx', matchPattern)).toEqual(false);
|
||||
expect(isMatch('hello.md', matchPattern)).toEqual(false);
|
||||
expect(isMatch('super/docs/hello.md', matchPattern)).toEqual(false);
|
||||
});
|
||||
|
||||
test('content', async () => {
|
||||
const content = await plugin.loadContent();
|
||||
const {
|
||||
docsMetadata,
|
||||
docsSidebars,
|
||||
versionToSidebars,
|
||||
permalinkToSidebar,
|
||||
} = content;
|
||||
|
||||
// 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({
|
||||
id: 'foo/bar',
|
||||
permalink: '/docs/next/foo/bar',
|
||||
source: path.join('@site', routeBasePath, 'foo', 'bar.md'),
|
||||
title: 'bar',
|
||||
description: 'This is `next` version of bar.',
|
||||
version: 'next',
|
||||
sidebar: 'docs',
|
||||
next: {
|
||||
title: 'hello',
|
||||
permalink: '/docs/next/hello',
|
||||
},
|
||||
});
|
||||
expect(docsMetadata['hello']).toEqual({
|
||||
id: 'hello',
|
||||
permalink: '/docs/next/hello',
|
||||
source: path.join('@site', routeBasePath, 'hello.md'),
|
||||
title: 'hello',
|
||||
description: 'Hello `next` !',
|
||||
version: 'next',
|
||||
sidebar: 'docs',
|
||||
previous: {
|
||||
title: 'bar',
|
||||
permalink: '/docs/next/foo/bar',
|
||||
},
|
||||
});
|
||||
expect(docsMetadata['version-1.0.1/hello']).toEqual({
|
||||
id: 'version-1.0.1/hello',
|
||||
permalink: '/docs/hello',
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, versionedDir),
|
||||
'version-1.0.1',
|
||||
'hello.md',
|
||||
),
|
||||
title: 'hello',
|
||||
description: 'Hello `1.0.1` !',
|
||||
version: '1.0.1',
|
||||
sidebar: 'version-1.0.1/docs',
|
||||
previous: {
|
||||
title: 'bar',
|
||||
permalink: '/docs/foo/bar',
|
||||
},
|
||||
});
|
||||
expect(docsMetadata['version-1.0.0/foo/baz']).toEqual({
|
||||
id: 'version-1.0.0/foo/baz',
|
||||
permalink: '/docs/1.0.0/foo/baz',
|
||||
source: path.join(
|
||||
'@site',
|
||||
path.relative(siteDir, versionedDir),
|
||||
'version-1.0.0',
|
||||
'foo',
|
||||
'baz.md',
|
||||
),
|
||||
title: 'baz',
|
||||
description:
|
||||
'Baz `1.0.0` ! This will be deleted in next subsequent versions.',
|
||||
version: '1.0.0',
|
||||
sidebar: 'version-1.0.0/docs',
|
||||
next: {
|
||||
title: 'hello',
|
||||
permalink: '/docs/1.0.0/hello',
|
||||
},
|
||||
previous: {
|
||||
title: 'bar',
|
||||
permalink: '/docs/1.0.0/foo/bar',
|
||||
},
|
||||
});
|
||||
|
||||
expect(docsSidebars).toMatchSnapshot('all sidebars');
|
||||
expect(versionToSidebars).toMatchSnapshot(
|
||||
'sidebars needed for each version',
|
||||
);
|
||||
const routeConfigs = [];
|
||||
const dataContainer = {};
|
||||
const actions = createFakeActions(
|
||||
routeConfigs,
|
||||
pluginContentDir,
|
||||
dataContainer,
|
||||
);
|
||||
await plugin.contentLoaded({
|
||||
content,
|
||||
actions,
|
||||
});
|
||||
|
||||
// The created base metadata for each nested docs route is smartly chunked/ splitted across version
|
||||
const latestVersionBaseMetadata = JSON.parse(
|
||||
dataContainer['docs-route-ff2.json'],
|
||||
);
|
||||
expect(latestVersionBaseMetadata).toMatchSnapshot(
|
||||
'base metadata for latest version',
|
||||
);
|
||||
expect(latestVersionBaseMetadata.docsSidebars).not.toEqual(docsSidebars);
|
||||
expect(latestVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||
permalinkToSidebar,
|
||||
);
|
||||
const nextVersionBaseMetadata = JSON.parse(
|
||||
dataContainer['docs-next-route-1c8.json'],
|
||||
);
|
||||
expect(nextVersionBaseMetadata).toMatchSnapshot(
|
||||
'base metadata for next version',
|
||||
);
|
||||
expect(nextVersionBaseMetadata.docsSidebars).not.toEqual(docsSidebars);
|
||||
expect(nextVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||
permalinkToSidebar,
|
||||
);
|
||||
const firstVersionBaseMetadata = JSON.parse(
|
||||
dataContainer['docs-1-0-0-route-660.json'],
|
||||
);
|
||||
expect(firstVersionBaseMetadata).toMatchSnapshot(
|
||||
'base metadata for first version',
|
||||
);
|
||||
expect(nextVersionBaseMetadata.docsSidebars).not.toEqual(docsSidebars);
|
||||
expect(nextVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||
permalinkToSidebar,
|
||||
);
|
||||
|
||||
// Sort the route config like in src/server/plugins/index.ts for consistent snapshot ordering
|
||||
sortConfig(routeConfigs);
|
||||
|
||||
expect(routeConfigs).not.toEqual([]);
|
||||
expect(routeConfigs).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -6,96 +6,81 @@
|
|||
*/
|
||||
|
||||
import path from 'path';
|
||||
import {loadContext} from '@docusaurus/core/src/server/index';
|
||||
import processMetadata from '../metadata';
|
||||
import loadEnv from '../env';
|
||||
|
||||
describe('processMetadata', () => {
|
||||
const fixtureDir = path.join(__dirname, '__fixtures__');
|
||||
const fixtureDir = path.join(__dirname, '__fixtures__');
|
||||
|
||||
describe('simple site', () => {
|
||||
const simpleSiteDir = path.join(fixtureDir, 'simple-site');
|
||||
const siteConfig = {
|
||||
title: 'Hello',
|
||||
baseUrl: '/',
|
||||
url: 'https://docusaurus.io',
|
||||
};
|
||||
const pluginPath = 'docs';
|
||||
const docsDir = path.resolve(simpleSiteDir, pluginPath);
|
||||
const context = loadContext(simpleSiteDir);
|
||||
const routeBasePath = 'docs';
|
||||
const docsDir = path.resolve(simpleSiteDir, routeBasePath);
|
||||
|
||||
const env = loadEnv(simpleSiteDir);
|
||||
|
||||
test('normal docs', async () => {
|
||||
const sourceA = path.join('foo', 'bar.md');
|
||||
const sourceB = path.join('hello.md');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
||||
const [dataA, dataB] = await Promise.all([
|
||||
processMetadata({
|
||||
source: sourceA,
|
||||
docsDir,
|
||||
order: {},
|
||||
siteConfig,
|
||||
docsBasePath: pluginPath,
|
||||
siteDir: simpleSiteDir,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
processMetadata({
|
||||
source: sourceB,
|
||||
docsDir,
|
||||
order: {},
|
||||
siteConfig,
|
||||
docsBasePath: pluginPath,
|
||||
siteDir: simpleSiteDir,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(dataA).toEqual({
|
||||
id: 'foo/bar',
|
||||
permalink: '/docs/foo/bar',
|
||||
source: path.join('@site', pluginPath, sourceA),
|
||||
source: path.join('@site', routeBasePath, sourceA),
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
});
|
||||
expect(dataB).toEqual({
|
||||
id: 'hello',
|
||||
permalink: '/docs/hello',
|
||||
source: path.join('@site', pluginPath, sourceB),
|
||||
source: path.join('@site', routeBasePath, sourceB),
|
||||
title: 'Hello, World !',
|
||||
description: `Hi, Endilie here :)`,
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with custom permalink', async () => {
|
||||
const source = path.join('permalink.md');
|
||||
const data = await processMetadata({
|
||||
source,
|
||||
docsDir,
|
||||
order: {},
|
||||
siteConfig,
|
||||
docsBasePath: pluginPath,
|
||||
siteDir: simpleSiteDir,
|
||||
});
|
||||
|
||||
expect(data).toEqual({
|
||||
id: 'permalink',
|
||||
permalink: '/docs/endiliey/permalink',
|
||||
source: path.join('@site', pluginPath, source),
|
||||
title: 'Permalink',
|
||||
description: 'This has a different permalink',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with editUrl', async () => {
|
||||
const editUrl =
|
||||
'https://github.com/facebook/docusaurus/edit/master/website';
|
||||
const source = path.join('foo', 'baz.md');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
editUrl,
|
||||
};
|
||||
|
||||
const data = await processMetadata({
|
||||
source,
|
||||
docsDir,
|
||||
order: {},
|
||||
siteConfig,
|
||||
docsBasePath: pluginPath,
|
||||
siteDir: simpleSiteDir,
|
||||
editUrl,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
expect(data).toEqual({
|
||||
id: 'foo/baz',
|
||||
permalink: '/docs/foo/baz',
|
||||
source: path.join('@site', pluginPath, source),
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
title: 'baz',
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website/docs/foo/baz.md',
|
||||
|
@ -103,62 +88,73 @@ describe('processMetadata', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('docs with custom editUrl', async () => {
|
||||
test('docs with custom editUrl & unrelated frontmatter', async () => {
|
||||
const source = 'lorem.md';
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
||||
const data = await processMetadata({
|
||||
source,
|
||||
docsDir,
|
||||
order: {},
|
||||
siteConfig,
|
||||
docsBasePath: pluginPath,
|
||||
siteDir: simpleSiteDir,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
expect(data).toEqual({
|
||||
id: 'lorem',
|
||||
permalink: '/docs/lorem',
|
||||
source: path.join('@site', pluginPath, source),
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
title: 'lorem',
|
||||
editUrl: 'https://github.com/customUrl/docs/lorem.md',
|
||||
description: 'Lorem ipsum.',
|
||||
});
|
||||
|
||||
// unrelated frontmatter is not part of metadata
|
||||
expect(data['unrelated_frontmatter']).toBeUndefined();
|
||||
});
|
||||
|
||||
test('docs with last update time and author', async () => {
|
||||
const source = 'lorem.md';
|
||||
const data = await processMetadata({
|
||||
source,
|
||||
docsDir,
|
||||
order: {},
|
||||
siteConfig,
|
||||
docsBasePath: pluginPath,
|
||||
siteDir: simpleSiteDir,
|
||||
const options = {
|
||||
routeBasePath,
|
||||
showLastUpdateAuthor: true,
|
||||
showLastUpdateTime: true,
|
||||
};
|
||||
|
||||
const data = await processMetadata({
|
||||
source,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
expect(data).toEqual({
|
||||
id: 'lorem',
|
||||
permalink: '/docs/lorem',
|
||||
source: path.join('@site', pluginPath, source),
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
title: 'lorem',
|
||||
editUrl: 'https://github.com/customUrl/docs/lorem.md',
|
||||
description: 'Lorem ipsum.',
|
||||
lastUpdatedAt: '1539502055',
|
||||
lastUpdatedAt: 1539502055,
|
||||
lastUpdatedBy: 'Author',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with invalid id', async () => {
|
||||
const badSiteDir = path.join(fixtureDir, 'bad-site');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
||||
return processMetadata({
|
||||
source: 'invalid-id.md',
|
||||
docsDir: path.join(badSiteDir, 'docs'),
|
||||
order: {},
|
||||
siteConfig,
|
||||
docsBasePath: 'docs',
|
||||
siteDir: simpleSiteDir,
|
||||
refDir: path.join(badSiteDir, 'docs'),
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}).catch(e =>
|
||||
expect(e).toMatchInlineSnapshot(
|
||||
`[Error: Document id cannot include "/".]`,
|
||||
|
@ -166,3 +162,128 @@ describe('processMetadata', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
const {docsDir: versionedDir} = env.versioning;
|
||||
|
||||
test('master/next docs', async () => {
|
||||
const sourceA = path.join('foo', 'bar.md');
|
||||
const sourceB = path.join('hello.md');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
||||
const [dataA, dataB] = await Promise.all([
|
||||
processMetadata({
|
||||
source: sourceA,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
processMetadata({
|
||||
source: sourceB,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(dataA).toEqual({
|
||||
id: 'foo/bar',
|
||||
permalink: '/docs/next/foo/bar',
|
||||
source: path.join('@site', routeBasePath, sourceA),
|
||||
title: 'bar',
|
||||
description: 'This is `next` version of bar.',
|
||||
version: 'next',
|
||||
});
|
||||
expect(dataB).toEqual({
|
||||
id: 'hello',
|
||||
permalink: '/docs/next/hello',
|
||||
source: path.join('@site', routeBasePath, sourceB),
|
||||
title: 'hello',
|
||||
description: 'Hello `next` !',
|
||||
version: 'next',
|
||||
});
|
||||
});
|
||||
|
||||
test('versioned docs', async () => {
|
||||
const sourceA = path.join('version-1.0.0', 'foo', 'bar.md');
|
||||
const sourceB = path.join('version-1.0.0', 'hello.md');
|
||||
const sourceC = path.join('version-1.0.1', 'foo', 'bar.md');
|
||||
const sourceD = path.join('version-1.0.1', 'hello.md');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
||||
const [dataA, dataB, dataC, dataD] = await Promise.all([
|
||||
processMetadata({
|
||||
source: sourceA,
|
||||
refDir: versionedDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
processMetadata({
|
||||
source: sourceB,
|
||||
refDir: versionedDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
processMetadata({
|
||||
source: sourceC,
|
||||
refDir: versionedDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
processMetadata({
|
||||
source: sourceD,
|
||||
refDir: versionedDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(dataA).toEqual({
|
||||
id: 'version-1.0.0/foo/bar',
|
||||
permalink: '/docs/1.0.0/foo/bar',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceA),
|
||||
title: 'bar',
|
||||
description: 'Bar `1.0.0` !',
|
||||
version: '1.0.0',
|
||||
});
|
||||
expect(dataB).toEqual({
|
||||
id: 'version-1.0.0/hello',
|
||||
permalink: '/docs/1.0.0/hello',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceB),
|
||||
title: 'hello',
|
||||
description: 'Hello `1.0.0` !',
|
||||
version: '1.0.0',
|
||||
});
|
||||
expect(dataC).toEqual({
|
||||
id: 'version-1.0.1/foo/bar',
|
||||
permalink: '/docs/foo/bar',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceC),
|
||||
title: 'bar',
|
||||
description: 'Bar `1.0.1` !',
|
||||
version: '1.0.1',
|
||||
});
|
||||
expect(dataD).toEqual({
|
||||
id: 'version-1.0.1/hello',
|
||||
permalink: '/docs/hello',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceD),
|
||||
title: 'hello',
|
||||
description: 'Hello `1.0.1` !',
|
||||
version: '1.0.1',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -230,32 +230,6 @@ describe('createOrder', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('multiple sidebars with unknown sidebar item type', () => {
|
||||
expect(() =>
|
||||
createOrder({
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category1',
|
||||
items: [
|
||||
{type: 'endi', id: 'doc1'},
|
||||
{type: 'doc', id: 'doc2'},
|
||||
],
|
||||
},
|
||||
],
|
||||
otherDocs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category1',
|
||||
items: [{type: 'doc', id: 'doc5'}],
|
||||
},
|
||||
],
|
||||
}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Unknown item type: endi. Item: {\\"type\\":\\"endi\\",\\"id\\":\\"doc1\\"}"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('edge cases', () => {
|
||||
expect(createOrder({})).toEqual({});
|
||||
expect(createOrder(undefined)).toEqual({});
|
||||
|
|
|
@ -14,13 +14,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();
|
||||
});
|
||||
|
||||
|
@ -29,7 +29,9 @@ describe('loadSidebars', () => {
|
|||
fixtureDir,
|
||||
'sidebars-category-wrong-items.json',
|
||||
);
|
||||
expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() =>
|
||||
loadSidebars([sidebarPath]),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Error loading \\"Category Label\\" category. Category items must be array."`,
|
||||
);
|
||||
});
|
||||
|
@ -37,23 +39,29 @@ describe('loadSidebars', () => {
|
|||
test('sidebars with first level not a category', async () => {
|
||||
const sidebarPath = path.join(
|
||||
fixtureDir,
|
||||
'sidebars-first-level-not-category',
|
||||
'sidebars-first-level-not-category.js',
|
||||
);
|
||||
expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot(
|
||||
expect(() =>
|
||||
loadSidebars([sidebarPath]),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Error loading {\\"type\\":\\"doc\\",\\"id\\":\\"api\\"}. First level item of a sidebar must be a category"`,
|
||||
);
|
||||
});
|
||||
|
||||
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"`,
|
||||
);
|
||||
});
|
||||
|
||||
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\\"}"`,
|
||||
);
|
||||
});
|
||||
|
@ -62,10 +70,4 @@ describe('loadSidebars', () => {
|
|||
const result = loadSidebars(null);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
test('fake sidebars path', () => {
|
||||
expect(() => {
|
||||
loadSidebars('/fake/path');
|
||||
}).toThrowError();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* 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 {docsVersion} from '../version';
|
||||
import {PathOptions} from '../types';
|
||||
import fs from 'fs-extra';
|
||||
import {
|
||||
getVersionedDocsDir,
|
||||
getVersionsJSONFile,
|
||||
getVersionedSidebarsDir,
|
||||
} from '../env';
|
||||
|
||||
const fixtureDir = path.join(__dirname, '__fixtures__');
|
||||
|
||||
describe('docsVersion', () => {
|
||||
const simpleSiteDir = path.join(fixtureDir, 'simple-site');
|
||||
const versionedSiteDir = path.join(fixtureDir, 'versioned-site');
|
||||
const DEFAULT_OPTIONS: PathOptions = {
|
||||
path: 'docs',
|
||||
sidebarPath: '',
|
||||
};
|
||||
|
||||
test('no version tag provided', () => {
|
||||
expect(() =>
|
||||
docsVersion(null, simpleSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion(undefined, simpleSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion('', simpleSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('version tag should not have slash', () => {
|
||||
expect(() =>
|
||||
docsVersion('foo/bar', simpleSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Invalid version tag specified! Do not include slash (/) or (\\\\). Try something like: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion('foo\\bar', simpleSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Invalid version tag specified! Do not include slash (/) or (\\\\). Try something like: 1.0.0"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('version tag should not be too long', () => {
|
||||
expect(() =>
|
||||
docsVersion('a'.repeat(255), simpleSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Invalid version tag specified! Length must <= 32 characters. Try something like: 1.0.0"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('version tag should not be a dot or two dots', () => {
|
||||
expect(() =>
|
||||
docsVersion('..', simpleSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion('.', simpleSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('version tag should be a valid pathname', () => {
|
||||
expect(() =>
|
||||
docsVersion('<foo|bar>', simpleSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion('foo\x00bar', simpleSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
||||
);
|
||||
expect(() =>
|
||||
docsVersion('foo:bar', simpleSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('version tag already exist', () => {
|
||||
expect(() =>
|
||||
docsVersion('1.0.0', versionedSiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"This version already exists!. Use a version tag that does not already exist."`,
|
||||
);
|
||||
});
|
||||
|
||||
test('no docs file to version', () => {
|
||||
const emptySiteDir = path.join(fixtureDir, 'empty-site');
|
||||
expect(() =>
|
||||
docsVersion('1.0.0', emptySiteDir, DEFAULT_OPTIONS),
|
||||
).toThrowErrorMatchingInlineSnapshot(`"There is no docs to version !"`);
|
||||
});
|
||||
|
||||
test('first time versioning', () => {
|
||||
const copyMock = jest.spyOn(fs, 'copySync').mockImplementation();
|
||||
const ensureMock = jest.spyOn(fs, 'ensureDirSync').mockImplementation();
|
||||
const writeMock = jest.spyOn(fs, 'writeFileSync');
|
||||
let versionedSidebar;
|
||||
let versionedSidebarPath;
|
||||
writeMock.mockImplementationOnce((filepath, content) => {
|
||||
versionedSidebarPath = filepath;
|
||||
versionedSidebar = JSON.parse(content);
|
||||
});
|
||||
let versionsPath;
|
||||
let versions;
|
||||
writeMock.mockImplementationOnce((filepath, content) => {
|
||||
versionsPath = filepath;
|
||||
versions = JSON.parse(content);
|
||||
});
|
||||
const consoleMock = jest.spyOn(console, 'log').mockImplementation();
|
||||
const options = {
|
||||
path: 'docs',
|
||||
sidebarPath: path.join(simpleSiteDir, 'sidebars.json'),
|
||||
};
|
||||
docsVersion('1.0.0', simpleSiteDir, options);
|
||||
expect(copyMock).toHaveBeenCalledWith(
|
||||
path.join(simpleSiteDir, options.path),
|
||||
path.join(getVersionedDocsDir(simpleSiteDir), 'version-1.0.0'),
|
||||
);
|
||||
expect(versionedSidebar).toMatchSnapshot();
|
||||
expect(versionedSidebarPath).toEqual(
|
||||
path.join(
|
||||
getVersionedSidebarsDir(simpleSiteDir),
|
||||
'version-1.0.0-sidebars.json',
|
||||
),
|
||||
);
|
||||
expect(versionsPath).toEqual(getVersionsJSONFile(simpleSiteDir));
|
||||
expect(versions).toEqual(['1.0.0']);
|
||||
expect(consoleMock).toHaveBeenCalledWith('Version 1.0.0 created!');
|
||||
|
||||
copyMock.mockRestore();
|
||||
writeMock.mockRestore();
|
||||
consoleMock.mockRestore();
|
||||
ensureMock.mockRestore();
|
||||
});
|
||||
|
||||
test('not the first time versioning', () => {
|
||||
const copyMock = jest.spyOn(fs, 'copySync').mockImplementation();
|
||||
const ensureMock = jest.spyOn(fs, 'ensureDirSync').mockImplementation();
|
||||
const writeMock = jest.spyOn(fs, 'writeFileSync');
|
||||
let versionedSidebar;
|
||||
let versionedSidebarPath;
|
||||
writeMock.mockImplementationOnce((filepath, content) => {
|
||||
versionedSidebarPath = filepath;
|
||||
versionedSidebar = JSON.parse(content);
|
||||
});
|
||||
let versionsPath;
|
||||
let versions;
|
||||
writeMock.mockImplementationOnce((filepath, content) => {
|
||||
versionsPath = filepath;
|
||||
versions = JSON.parse(content);
|
||||
});
|
||||
const consoleMock = jest.spyOn(console, 'log').mockImplementation();
|
||||
const options = {
|
||||
path: 'docs',
|
||||
sidebarPath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||
};
|
||||
docsVersion('2.0.0', versionedSiteDir, options);
|
||||
expect(copyMock).toHaveBeenCalledWith(
|
||||
path.join(versionedSiteDir, options.path),
|
||||
path.join(getVersionedDocsDir(versionedSiteDir), 'version-2.0.0'),
|
||||
);
|
||||
expect(versionedSidebar).toMatchSnapshot();
|
||||
expect(versionedSidebarPath).toEqual(
|
||||
path.join(
|
||||
getVersionedSidebarsDir(versionedSiteDir),
|
||||
'version-2.0.0-sidebars.json',
|
||||
),
|
||||
);
|
||||
expect(versionsPath).toEqual(getVersionsJSONFile(versionedSiteDir));
|
||||
expect(versions).toEqual(['2.0.0', '1.0.1', '1.0.0']);
|
||||
expect(consoleMock).toHaveBeenCalledWith('Version 2.0.0 created!');
|
||||
|
||||
copyMock.mockRestore();
|
||||
writeMock.mockRestore();
|
||||
consoleMock.mockRestore();
|
||||
ensureMock.mockRestore();
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue