mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-17 19:16:58 +02:00
test: improve test coverage (#6387)
* test: improve test coverage * fix * use posixPath
This commit is contained in:
parent
a9810db1cc
commit
62223ee556
24 changed files with 463 additions and 60 deletions
|
@ -1,4 +1,3 @@
|
|||
__fixtures__
|
||||
build
|
||||
coverage
|
||||
examples/
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* stylelint-disable docusaurus/copyright-header, declaration-block-no-duplicate-custom-properties */
|
||||
:root {
|
||||
--color-primary: red;
|
||||
--color-secondary: green;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* stylelint-disable docusaurus/copyright-header, declaration-block-no-duplicate-custom-properties */
|
||||
:root {
|
||||
--color-primary: red;
|
||||
--color-primary: red;
|
||||
|
@ -5,3 +6,8 @@
|
|||
--color-primary: blue;
|
||||
--color-header: gray;
|
||||
}
|
||||
|
||||
.non-root {
|
||||
--color-primary: red;
|
||||
--color-primary: red;
|
||||
}
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`remove-overridden-custom-properties overridden custom properties should be removed 1`] = `
|
||||
":root {
|
||||
"/* stylelint-disable docusaurus/copyright-header, declaration-block-no-duplicate-custom-properties */
|
||||
:root {
|
||||
--color-secondary: green;
|
||||
--color-primary: blue;
|
||||
--color-header: gray;
|
||||
}
|
||||
|
||||
.non-root {
|
||||
--color-primary: red;
|
||||
--color-primary: red;
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`remove-overridden-custom-properties overridden custom properties with \`!important\` rule should not be removed 1`] = `
|
||||
":root {
|
||||
"/* stylelint-disable docusaurus/copyright-header, declaration-block-no-duplicate-custom-properties */
|
||||
:root {
|
||||
--color-primary: blue;
|
||||
--color-header: gray !important;
|
||||
--color-secondary: yellow !important;
|
||||
|
|
|
@ -22,8 +22,9 @@ module.exports = function creator() {
|
|||
return;
|
||||
}
|
||||
|
||||
const sameProperties =
|
||||
decl.parent.nodes.filter((n) => n.prop === decl.prop) || [];
|
||||
const sameProperties = decl.parent.nodes.filter(
|
||||
(n) => n.prop === decl.prop,
|
||||
);
|
||||
const hasImportantProperties = sameProperties.some((p) =>
|
||||
Object.prototype.hasOwnProperty.call(p, 'important'),
|
||||
);
|
||||
|
|
|
@ -260,6 +260,25 @@ describe('collectRedirects', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('should allow returning string / undefined', () => {
|
||||
expect(
|
||||
collectRedirects(
|
||||
createTestPluginContext(
|
||||
{
|
||||
createRedirects: (routePath) => {
|
||||
if (routePath === '/') {
|
||||
return `${routePath}foo`;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
['/', '/testpath', '/otherPath.html'],
|
||||
),
|
||||
undefined,
|
||||
),
|
||||
).toEqual([{from: '/foo', to: '/'}]);
|
||||
});
|
||||
|
||||
test('should throw if redirect creator creates invalid redirects', () => {
|
||||
expect(() =>
|
||||
collectRedirects(
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
---
|
||||
slug: /hey/my super path/héllô
|
||||
title: Complex Slug
|
||||
date: 2020-08-16
|
||||
# This date is not YAML date, but we can still use it.
|
||||
date: 2020/08/16
|
||||
---
|
||||
|
||||
complex url slug
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`blogFeed atom shows feed item for each post 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"build/blog/atom.xml",
|
||||
"<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>
|
||||
<feed xmlns=\\"http://www.w3.org/2005/Atom\\">
|
||||
<id>https://docusaurus.io/myBaseUrl/blog</id>
|
||||
|
@ -83,10 +86,15 @@ exports[`blogFeed atom shows feed item for each post 1`] = `
|
|||
<name>Sébastien Lorber (translated)</name>
|
||||
</author>
|
||||
</entry>
|
||||
</feed>"
|
||||
</feed>",
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`blogFeed json shows feed item for each post 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"build/blog/feed.json",
|
||||
"{
|
||||
\\"version\\": \\"https://jsonfeed.org/version/1\\",
|
||||
\\"title\\": \\"Hello Blog\\",
|
||||
|
@ -163,10 +171,15 @@ exports[`blogFeed json shows feed item for each post 1`] = `
|
|||
}
|
||||
}
|
||||
]
|
||||
}"
|
||||
}",
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`blogFeed rss shows feed item for each post 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"build/blog/rss.xml",
|
||||
"<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>
|
||||
<rss version=\\"2.0\\" xmlns:dc=\\"http://purl.org/dc/elements/1.1/\\" xmlns:content=\\"http://purl.org/rss/1.0/modules/content/\\">
|
||||
<channel>
|
||||
|
@ -240,5 +253,7 @@ exports[`blogFeed rss shows feed item for each post 1`] = `
|
|||
<content:encoded><![CDATA[<p>Happy birthday! (translated)</p>]]></content:encoded>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>"
|
||||
</rss>",
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
|
|
@ -5,7 +5,24 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {parseBlogFileName} from '../blogUtils';
|
||||
import {truncate, parseBlogFileName} from '../blogUtils';
|
||||
|
||||
describe('truncate', () => {
|
||||
test('truncates texts', () => {
|
||||
expect(
|
||||
truncate('aaa\n<!-- truncate -->\nbbb\nccc', /<!-- truncate -->/),
|
||||
).toEqual('aaa\n');
|
||||
expect(
|
||||
truncate('\n<!-- truncate -->\nbbb\nccc', /<!-- truncate -->/),
|
||||
).toEqual('\n');
|
||||
});
|
||||
test('leaves texts without markers', () => {
|
||||
expect(truncate('aaa\nbbb\nccc', /<!-- truncate -->/)).toEqual(
|
||||
'aaa\nbbb\nccc',
|
||||
);
|
||||
expect(truncate('', /<!-- truncate -->/)).toEqual('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseBlogFileName', () => {
|
||||
test('parse file', () => {
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
*/
|
||||
|
||||
import path from 'path';
|
||||
import {generateBlogFeed} from '../feed';
|
||||
import fs from 'fs-extra';
|
||||
import {createBlogFeedFiles} from '../feed';
|
||||
import type {LoadContext, I18n} from '@docusaurus/types';
|
||||
import type {BlogContentPaths} from '../types';
|
||||
import {DEFAULT_OPTIONS} from '../pluginOptionSchema';
|
||||
import {generateBlogPosts} from '../blogUtils';
|
||||
import type {Feed} from 'feed';
|
||||
import type {PluginOptions} from '@docusaurus/plugin-content-blog';
|
||||
|
||||
const DefaultI18N: I18n = {
|
||||
|
@ -36,23 +36,26 @@ function getBlogContentPaths(siteDir: string): BlogContentPaths {
|
|||
async function testGenerateFeeds(
|
||||
context: LoadContext,
|
||||
options: PluginOptions,
|
||||
): Promise<Feed | null> {
|
||||
): Promise<void> {
|
||||
const blogPosts = await generateBlogPosts(
|
||||
getBlogContentPaths(context.siteDir),
|
||||
context,
|
||||
options,
|
||||
);
|
||||
|
||||
return generateBlogFeed({
|
||||
await createBlogFeedFiles({
|
||||
blogPosts,
|
||||
options,
|
||||
siteConfig: context.siteConfig,
|
||||
outDir: 'build',
|
||||
});
|
||||
}
|
||||
|
||||
describe('blogFeed', () => {
|
||||
(['atom', 'rss', 'json'] as const).forEach((feedType) => {
|
||||
describe(`${feedType}`, () => {
|
||||
const fsMock = jest.spyOn(fs, 'outputFile').mockImplementation(() => {});
|
||||
|
||||
test('should not show feed without posts', async () => {
|
||||
const siteDir = __dirname;
|
||||
const siteConfig = {
|
||||
|
@ -62,7 +65,7 @@ describe('blogFeed', () => {
|
|||
favicon: 'image/favicon.ico',
|
||||
};
|
||||
|
||||
const feed = await testGenerateFeeds(
|
||||
await testGenerateFeeds(
|
||||
{
|
||||
siteDir,
|
||||
siteConfig,
|
||||
|
@ -83,7 +86,8 @@ describe('blogFeed', () => {
|
|||
} as PluginOptions,
|
||||
);
|
||||
|
||||
expect(feed).toEqual(null);
|
||||
expect(fsMock).toBeCalledTimes(0);
|
||||
fsMock.mockClear();
|
||||
});
|
||||
|
||||
test('shows feed item for each post', async () => {
|
||||
|
@ -96,7 +100,7 @@ describe('blogFeed', () => {
|
|||
favicon: 'image/favicon.ico',
|
||||
};
|
||||
|
||||
const feed = await testGenerateFeeds(
|
||||
await testGenerateFeeds(
|
||||
{
|
||||
siteDir,
|
||||
siteConfig,
|
||||
|
@ -119,22 +123,8 @@ describe('blogFeed', () => {
|
|||
} as PluginOptions,
|
||||
);
|
||||
|
||||
let feedContent = '';
|
||||
switch (feedType) {
|
||||
case 'rss':
|
||||
feedContent = feed.rss2();
|
||||
break;
|
||||
case 'json':
|
||||
feedContent = feed.json1();
|
||||
break;
|
||||
case 'atom':
|
||||
feedContent = feed.atom1();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
expect(feedContent).toMatchSnapshot();
|
||||
expect(fsMock.mock.calls).toMatchSnapshot();
|
||||
fsMock.mockClear();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -204,7 +204,7 @@ describe('loadBlog', () => {
|
|||
date: new Date('2020-08-16'),
|
||||
formattedDate: 'August 16, 2020',
|
||||
frontMatter: {
|
||||
date: new Date('2020-08-16'),
|
||||
date: '2020/08/16',
|
||||
slug: '/hey/my super path/héllô',
|
||||
title: 'Complex Slug',
|
||||
},
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import {Feed, type Author as FeedAuthor, type Item as FeedItem} from 'feed';
|
||||
import type {BlogPost} from './types';
|
||||
import {normalizeUrl, mdxToHtml} from '@docusaurus/utils';
|
||||
import {normalizeUrl, mdxToHtml, posixPath} from '@docusaurus/utils';
|
||||
import type {DocusaurusConfig} from '@docusaurus/types';
|
||||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
|
@ -30,7 +30,7 @@ function mdxToFeedContent(mdxContent: string): string | undefined {
|
|||
}
|
||||
}
|
||||
|
||||
export async function generateBlogFeed({
|
||||
async function generateBlogFeed({
|
||||
blogPosts,
|
||||
options,
|
||||
siteConfig,
|
||||
|
@ -47,9 +47,7 @@ export async function generateBlogFeed({
|
|||
const {url: siteUrl, baseUrl, title, favicon} = siteConfig;
|
||||
const blogBaseUrl = normalizeUrl([siteUrl, baseUrl, routeBasePath]);
|
||||
|
||||
const updated =
|
||||
(blogPosts[0] && blogPosts[0].metadata.date) ||
|
||||
new Date('2015-10-25T16:29:00.000-07:00'); // weird legacy magic date
|
||||
const updated = blogPosts[0] && blogPosts[0].metadata.date;
|
||||
|
||||
const feed = new Feed({
|
||||
id: blogBaseUrl,
|
||||
|
@ -118,7 +116,10 @@ async function createBlogFeedFile({
|
|||
}
|
||||
})();
|
||||
try {
|
||||
await fs.outputFile(path.join(generatePath, feedPath), feedContent);
|
||||
await fs.outputFile(
|
||||
posixPath(path.join(generatePath, feedPath)),
|
||||
feedContent,
|
||||
);
|
||||
} catch (err) {
|
||||
throw new Error(`Generating ${feedType} feed failed: ${err}.`);
|
||||
}
|
||||
|
|
|
@ -201,7 +201,9 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
source: 'guide1.md',
|
||||
sourceDirName: '02-Guides',
|
||||
sidebarPosition: 1,
|
||||
frontMatter: {},
|
||||
frontMatter: {
|
||||
sidebar_class_name: 'foo',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'nested-guide',
|
||||
|
@ -250,7 +252,7 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
id: 'guides-index',
|
||||
},
|
||||
items: [
|
||||
{type: 'doc', id: 'guide1'},
|
||||
{type: 'doc', id: 'guide1', className: 'foo'},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'SubGuides (metadata file label)',
|
||||
|
@ -278,12 +280,17 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
'subfolder/subsubfolder/subsubsubfolder2/_category_.yml': {
|
||||
position: 2,
|
||||
label: 'subsubsubfolder2 (_category_.yml label)',
|
||||
className: 'bar',
|
||||
},
|
||||
'subfolder/subsubfolder/subsubsubfolder3/_category_.json': {
|
||||
position: 1,
|
||||
label: 'subsubsubfolder3 (_category_.json label)',
|
||||
collapsible: false,
|
||||
collapsed: false,
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'doc1', // This is a "fully-qualified" ID that can't be found locally
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -367,6 +374,10 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
label: 'subsubsubfolder3 (_category_.json label)',
|
||||
collapsed: false,
|
||||
collapsible: false,
|
||||
link: {
|
||||
id: 'doc1',
|
||||
type: 'doc',
|
||||
},
|
||||
items: [
|
||||
{type: 'doc', id: 'doc8'},
|
||||
{type: 'doc', id: 'doc7'},
|
||||
|
@ -377,6 +388,7 @@ describe('DefaultSidebarItemsGenerator', () => {
|
|||
label: 'subsubsubfolder2 (_category_.yml label)',
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
className: 'bar',
|
||||
items: [{type: 'doc', id: 'doc6'}],
|
||||
},
|
||||
{type: 'doc', id: 'doc1'},
|
||||
|
|
|
@ -102,8 +102,8 @@ describe('processSidebars', () => {
|
|||
slug: 'category-generated-index-slug',
|
||||
permalink: 'category-generated-index-permalink',
|
||||
},
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
collapsed: true, // A suspicious bad config that will be normalized
|
||||
collapsible: false,
|
||||
items: [
|
||||
{type: 'doc', id: 'doc2'},
|
||||
{type: 'autogenerated', dirName: 'dir1'},
|
||||
|
@ -172,7 +172,7 @@ describe('processSidebars', () => {
|
|||
permalink: 'category-generated-index-permalink',
|
||||
},
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
collapsible: false,
|
||||
items: [{type: 'doc', id: 'doc2'}, ...StaticGeneratedSidebarSlice],
|
||||
},
|
||||
{type: 'link', href: 'https://facebook.com', label: 'FB'},
|
||||
|
|
|
@ -96,6 +96,14 @@ describe('createSidebarsUtils', () => {
|
|||
];
|
||||
|
||||
const sidebar4: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
items: [
|
||||
{type: 'link', href: 'https://facebook.com'},
|
||||
{type: 'link', href: 'https://reactjs.org'},
|
||||
{type: 'link', href: 'https://docusaurus.io'},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {parseCodeBlockTitle} from '../codeBlockUtils';
|
||||
import {
|
||||
parseCodeBlockTitle,
|
||||
parseLanguage,
|
||||
parseLines,
|
||||
} from '../codeBlockUtils';
|
||||
|
||||
describe('parseCodeBlockTitle', () => {
|
||||
test('should parse double quote delimited title', () => {
|
||||
|
@ -52,3 +56,227 @@ describe('parseCodeBlockTitle', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseLanguage', () => {
|
||||
test('behaves correctly', () => {
|
||||
expect(parseLanguage('language-foo xxx yyy')).toEqual('foo');
|
||||
expect(parseLanguage('xxxxx language-foo yyy')).toEqual('foo');
|
||||
expect(parseLanguage('xx-language-foo yyyy')).toBeUndefined();
|
||||
expect(parseLanguage('xxx yyy zzz')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseLines', () => {
|
||||
test('does not parse content with metastring', () => {
|
||||
expect(parseLines('aaaaa\nbbbbb', '{1}', 'js')).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"code": "aaaaa
|
||||
bbbbb",
|
||||
"highlightLines": Array [
|
||||
0,
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(
|
||||
parseLines(
|
||||
`// highlight-next-line
|
||||
aaaaa
|
||||
bbbbb`,
|
||||
'{1}',
|
||||
'js',
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"code": "// highlight-next-line
|
||||
aaaaa
|
||||
bbbbb",
|
||||
"highlightLines": Array [
|
||||
0,
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(
|
||||
parseLines(
|
||||
`aaaaa
|
||||
bbbbb`,
|
||||
'{1}',
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"code": "aaaaa
|
||||
bbbbb",
|
||||
"highlightLines": Array [
|
||||
0,
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
test('does not parse content with no language', () => {
|
||||
expect(
|
||||
parseLines(
|
||||
`// highlight-next-line
|
||||
aaaaa
|
||||
bbbbb`,
|
||||
'',
|
||||
undefined,
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"code": "// highlight-next-line
|
||||
aaaaa
|
||||
bbbbb",
|
||||
"highlightLines": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
test('removes lines correctly', () => {
|
||||
expect(
|
||||
parseLines(
|
||||
`// highlight-next-line
|
||||
aaaaa
|
||||
bbbbb`,
|
||||
'',
|
||||
'js',
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"code": "aaaaa
|
||||
bbbbb",
|
||||
"highlightLines": Array [
|
||||
0,
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(
|
||||
parseLines(
|
||||
`// highlight-start
|
||||
aaaaa
|
||||
// highlight-end
|
||||
bbbbb`,
|
||||
'',
|
||||
'js',
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"code": "aaaaa
|
||||
bbbbb",
|
||||
"highlightLines": Array [
|
||||
0,
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(
|
||||
parseLines(
|
||||
`// highlight-start
|
||||
// highlight-next-line
|
||||
aaaaa
|
||||
bbbbbbb
|
||||
// highlight-next-line
|
||||
// highlight-end
|
||||
bbbbb`,
|
||||
'',
|
||||
'js',
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"code": "aaaaa
|
||||
bbbbbbb
|
||||
bbbbb",
|
||||
"highlightLines": Array [
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
test('respects language', () => {
|
||||
expect(
|
||||
parseLines(
|
||||
`# highlight-next-line
|
||||
aaaaa
|
||||
bbbbb`,
|
||||
'',
|
||||
'js',
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"code": "# highlight-next-line
|
||||
aaaaa
|
||||
bbbbb",
|
||||
"highlightLines": Array [],
|
||||
}
|
||||
`);
|
||||
expect(
|
||||
parseLines(
|
||||
`/* highlight-next-line */
|
||||
aaaaa
|
||||
bbbbb`,
|
||||
'',
|
||||
'py',
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"code": "/* highlight-next-line */
|
||||
aaaaa
|
||||
bbbbb",
|
||||
"highlightLines": Array [],
|
||||
}
|
||||
`);
|
||||
expect(
|
||||
parseLines(
|
||||
`// highlight-next-line
|
||||
aaaa
|
||||
/* highlight-next-line */
|
||||
bbbbb
|
||||
# highlight-next-line
|
||||
ccccc
|
||||
<!-- highlight-next-line -->
|
||||
dddd`,
|
||||
'',
|
||||
'py',
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"code": "// highlight-next-line
|
||||
aaaa
|
||||
/* highlight-next-line */
|
||||
bbbbb
|
||||
ccccc
|
||||
<!-- highlight-next-line -->
|
||||
dddd",
|
||||
"highlightLines": Array [
|
||||
4,
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(
|
||||
parseLines(
|
||||
`// highlight-next-line
|
||||
aaaa
|
||||
/* highlight-next-line */
|
||||
bbbbb
|
||||
# highlight-next-line
|
||||
ccccc
|
||||
<!-- highlight-next-line -->
|
||||
dddd`,
|
||||
'',
|
||||
'',
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"code": "aaaa
|
||||
bbbbb
|
||||
ccccc
|
||||
dddd",
|
||||
"highlightLines": Array [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,27 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {uniq} from '../jsUtils';
|
||||
import {uniq, duplicates} from '../jsUtils';
|
||||
|
||||
describe('duplicates', () => {
|
||||
test('gets duplicate values', () => {
|
||||
expect(duplicates(['a', 'b', 'c', 'd'])).toEqual([]);
|
||||
expect(duplicates(['a', 'b', 'b', 'b'])).toEqual(['b', 'b']);
|
||||
expect(duplicates(['c', 'b', 'b', 'c'])).toEqual(['b', 'c']);
|
||||
expect(duplicates([{a: 1}, {a: 1}, {a: 1}])).toEqual([]);
|
||||
});
|
||||
test('accepts custom comparator', () => {
|
||||
expect(duplicates([{a: 1}, {a: 1}, {a: 1}], (a, b) => a.a === b.a)).toEqual(
|
||||
[{a: 1}, {a: 1}],
|
||||
);
|
||||
expect(duplicates(['a', 'b', 'c', 'd'], (a, b) => a !== b)).toEqual([
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('uniq', () => {
|
||||
test('remove duplicate primitives', () => {
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* 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 {isRegexpStringMatch} from '../regexpUtils';
|
||||
|
||||
describe('isRegexpStringMatch', () => {
|
||||
test('behaves correctly', () => {
|
||||
expect(isRegexpStringMatch(undefined, 'foo')).toEqual(false);
|
||||
expect(isRegexpStringMatch('bar', undefined)).toEqual(false);
|
||||
expect(isRegexpStringMatch('foo', 'bar')).toEqual(false);
|
||||
expect(isRegexpStringMatch('foo', 'foo')).toEqual(true);
|
||||
expect(isRegexpStringMatch('fooooooooooo', 'foo')).toEqual(false);
|
||||
expect(isRegexpStringMatch('foo', 'fooooooo')).toEqual(true);
|
||||
expect(isRegexpStringMatch('f.*o', 'fggo')).toEqual(true);
|
||||
expect(isRegexpStringMatch('FOO', 'foo')).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* 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 {docVersionSearchTag} from '../searchUtils';
|
||||
|
||||
describe('docVersionSearchTag', () => {
|
||||
test('behaves correctly', () => {
|
||||
expect(docVersionSearchTag('foo', 'bar')).toEqual('docs-foo-bar');
|
||||
});
|
||||
});
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Utility to convert an optional string into a Regex case sensitive and global
|
||||
* Utility to convert an optional string into a Regex case insensitive and global
|
||||
*/
|
||||
export function isRegexpStringMatch(
|
||||
regexAsString?: string,
|
||||
|
|
|
@ -14,13 +14,26 @@ import {
|
|||
|
||||
describe('codeTranslationLocalesToTry', () => {
|
||||
test('should return appropriate locale lists', () => {
|
||||
expect(codeTranslationLocalesToTry('fr')).toEqual(['fr', 'fr-FR']);
|
||||
expect(codeTranslationLocalesToTry('fr')).toEqual([
|
||||
'fr',
|
||||
'fr-FR',
|
||||
'fr-Latn',
|
||||
]);
|
||||
expect(codeTranslationLocalesToTry('fr-FR')).toEqual(['fr-FR', 'fr']);
|
||||
// Note: "pt" is expanded into "pt-BR", not "pt-PT", as "pt-BR" is more widely used!
|
||||
// See https://github.com/facebook/docusaurus/pull/4536#issuecomment-810088783
|
||||
expect(codeTranslationLocalesToTry('pt')).toEqual(['pt', 'pt-BR']);
|
||||
expect(codeTranslationLocalesToTry('pt')).toEqual([
|
||||
'pt',
|
||||
'pt-BR',
|
||||
'pt-Latn',
|
||||
]);
|
||||
expect(codeTranslationLocalesToTry('pt-BR')).toEqual(['pt-BR', 'pt']);
|
||||
expect(codeTranslationLocalesToTry('pt-PT')).toEqual(['pt-PT', 'pt']);
|
||||
expect(codeTranslationLocalesToTry('zh')).toEqual([
|
||||
'zh',
|
||||
'zh-CN',
|
||||
'zh-Hans',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -123,4 +136,17 @@ describe('readDefaultCodeTranslationMessages', () => {
|
|||
}),
|
||||
).resolves.toEqual(await readAsJSON('en'));
|
||||
});
|
||||
|
||||
test('default locale', async () => {
|
||||
await expect(
|
||||
readDefaultCodeTranslationMessages({
|
||||
locale: 'zh',
|
||||
name: 'plugin-pwa',
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
'theme.PwaReloadPopup.closeButtonAriaLabel': '关闭',
|
||||
'theme.PwaReloadPopup.info': '有可用的新版本',
|
||||
'theme.PwaReloadPopup.refreshButtonText': '刷新',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,16 +14,17 @@ function getDefaultLocalesDirPath(): string {
|
|||
|
||||
// Return an ordered list of locales we should try
|
||||
export function codeTranslationLocalesToTry(locale: string): string[] {
|
||||
const intlLocale = Intl.Locale ? new Intl.Locale(locale) : undefined;
|
||||
if (!intlLocale) {
|
||||
return [locale];
|
||||
}
|
||||
const intlLocale = new Intl.Locale(locale);
|
||||
// if locale is just a simple language like "pt", we want to fallback to pt-BR (not pt-PT!)
|
||||
// see https://github.com/facebook/docusaurus/pull/4536#issuecomment-810088783
|
||||
if (intlLocale.language === locale) {
|
||||
const maximizedLocale = intlLocale.maximize(); // pt-Latn-BR`
|
||||
// ["pt","pt-BR"]
|
||||
return [locale, `${maximizedLocale.language}-${maximizedLocale.region}`];
|
||||
// ["pt","pt-BR"]; ["zh", "zh-Hans"]
|
||||
return [
|
||||
locale,
|
||||
`${maximizedLocale.language}-${maximizedLocale.region}`,
|
||||
`${maximizedLocale.language}-${maximizedLocale.script}`,
|
||||
];
|
||||
}
|
||||
// if locale is like "pt-BR", we want to fallback to "pt"
|
||||
else {
|
||||
|
|
|
@ -35,6 +35,8 @@ describe('normalizeLocation', () => {
|
|||
});
|
||||
|
||||
test('untouched pathnames', () => {
|
||||
const replaceMock = jest.spyOn(String.prototype, 'replace');
|
||||
|
||||
expect(
|
||||
normalizeLocation({
|
||||
pathname: '/docs/introduction',
|
||||
|
@ -47,6 +49,20 @@ describe('normalizeLocation', () => {
|
|||
hash: '#features',
|
||||
});
|
||||
|
||||
// For the sake of testing memoization
|
||||
expect(
|
||||
normalizeLocation({
|
||||
pathname: '/docs/introduction',
|
||||
search: '',
|
||||
hash: '#features',
|
||||
}),
|
||||
).toEqual({
|
||||
pathname: '/docs/introduction',
|
||||
search: '',
|
||||
hash: '#features',
|
||||
});
|
||||
expect(replaceMock).toBeCalledTimes(1);
|
||||
|
||||
expect(
|
||||
normalizeLocation({
|
||||
pathname: '/docs/introduction/foo.html',
|
||||
|
|
|
@ -23,7 +23,7 @@ export default function loadPresets(context: LoadContext): {
|
|||
// declares the dependency on these presets.
|
||||
const presetRequire = createRequire(context.siteConfigPath);
|
||||
|
||||
const presets: PresetConfig[] = (context.siteConfig || {}).presets || [];
|
||||
const presets: PresetConfig[] = context.siteConfig.presets || [];
|
||||
const unflatPlugins: PluginConfig[][] = [];
|
||||
const unflatThemes: PluginConfig[][] = [];
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue