diff --git a/jest.config.mjs b/jest.config.mjs
index 7163875c41..479ebd5948 100644
--- a/jest.config.mjs
+++ b/jest.config.mjs
@@ -25,6 +25,7 @@ const ignorePatterns = [
'/packages/docusaurus-theme-classic/lib-next',
'/packages/docusaurus-theme-common/lib',
'/packages/docusaurus-migrate/lib',
+ '/jest',
];
export default {
diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap
index 97a8976893..bca094fc9e 100644
--- a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap
+++ b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap
@@ -74,7 +74,20 @@ bbbbb",
}
`;
-exports[`parseLines respects language 1`] = `
+exports[`parseLines respects language: html 1`] = `
+{
+ "code": "aaaa
+{/* highlight-next-line */}
+bbbbb
+dddd",
+ "highlightLines": [
+ 0,
+ 3,
+ ],
+}
+`;
+
+exports[`parseLines respects language: js 1`] = `
{
"code": "# highlight-next-line
aaaaa
@@ -83,31 +96,47 @@ bbbbb",
}
`;
-exports[`parseLines respects language 2`] = `
+exports[`parseLines respects language: jsx 1`] = `
{
- "code": "/* highlight-next-line */
-aaaaa
-bbbbb",
- "highlightLines": [],
-}
-`;
-
-exports[`parseLines respects language 3`] = `
-{
- "code": "// highlight-next-line
-aaaa
-/* highlight-next-line */
+ "code": "aaaa
bbbbb
-ccccc
dddd",
"highlightLines": [
- 4,
+ 0,
+ 1,
],
}
`;
-exports[`parseLines respects language 4`] = `
+exports[`parseLines respects language: md 1`] = `
+{
+ "code": "---
+aaa: boo
+---
+
+aaaa
+
+
+foo
+
+
+bbbbb
+dddd
+
+\`\`\`js
+// highlight-next-line
+console.log(\\"preserved\\");
+\`\`\`",
+ "highlightLines": [
+ 1,
+ 7,
+ 11,
+ ],
+}
+`;
+
+exports[`parseLines respects language: none 1`] = `
{
"code": "aaaa
bbbbb
@@ -121,3 +150,27 @@ dddd",
],
}
`;
+
+exports[`parseLines respects language: py 1`] = `
+{
+ "code": "/* highlight-next-line */
+aaaaa
+bbbbb",
+ "highlightLines": [],
+}
+`;
+
+exports[`parseLines respects language: py 2`] = `
+{
+ "code": "// highlight-next-line
+aaaa
+/* highlight-next-line */
+bbbbb
+ccccc
+
+dddd",
+ "highlightLines": [
+ 4,
+ ],
+}
+`;
diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts
index bc4e77b0d1..f2ddc02bb6 100644
--- a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts
+++ b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts
@@ -140,7 +140,7 @@ bbbbb`,
'',
'js',
),
- ).toMatchSnapshot();
+ ).toMatchSnapshot('js');
expect(
parseLines(
`/* highlight-next-line */
@@ -149,7 +149,7 @@ bbbbb`,
'',
'py',
),
- ).toMatchSnapshot();
+ ).toMatchSnapshot('py');
expect(
parseLines(
`// highlight-next-line
@@ -163,7 +163,7 @@ dddd`,
'',
'py',
),
- ).toMatchSnapshot();
+ ).toMatchSnapshot('py');
expect(
parseLines(
`// highlight-next-line
@@ -177,6 +177,57 @@ dddd`,
'',
'',
),
- ).toMatchSnapshot();
+ ).toMatchSnapshot('none');
+ expect(
+ parseLines(
+ `// highlight-next-line
+aaaa
+{/* highlight-next-line */}
+bbbbb
+
+dddd`,
+ '',
+ 'jsx',
+ ),
+ ).toMatchSnapshot('jsx');
+ expect(
+ parseLines(
+ `// highlight-next-line
+aaaa
+{/* highlight-next-line */}
+bbbbb
+
+dddd`,
+ '',
+ 'html',
+ ),
+ ).toMatchSnapshot('html');
+ expect(
+ parseLines(
+ `---
+# highlight-next-line
+aaa: boo
+---
+
+aaaa
+
+
+{/* highlight-next-line */}
+foo
+
+
+bbbbb
+
+dddd
+
+\`\`\`js
+// highlight-next-line
+console.log("preserved");
+\`\`\`
+`,
+ '',
+ 'md',
+ ),
+ ).toMatchSnapshot('md');
});
});
diff --git a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts
index cc28c5d21f..46277defbf 100644
--- a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts
+++ b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts
@@ -141,29 +141,29 @@ export function parseLines(
for (let lineNumber = 0; lineNumber < lines.length; ) {
const line = lines[lineNumber]!;
const match = line.match(directiveRegex);
- if (match !== null) {
- const directive = match.slice(1).find((item) => item !== undefined);
- switch (directive) {
- case 'highlight-next-line':
- highlightRange += `${lineNumber},`;
- break;
-
- case 'highlight-start':
- highlightBlockStart = lineNumber;
- break;
-
- case 'highlight-end':
- highlightRange += `${highlightBlockStart!}-${lineNumber - 1},`;
- break;
-
- default:
- break;
- }
- lines.splice(lineNumber, 1);
- } else {
+ if (!match) {
// lines without directives are unchanged
lineNumber += 1;
+ continue;
}
+ const directive = match.slice(1).find((item) => item !== undefined);
+ switch (directive) {
+ case 'highlight-next-line':
+ highlightRange += `${lineNumber},`;
+ break;
+
+ case 'highlight-start':
+ highlightBlockStart = lineNumber;
+ break;
+
+ case 'highlight-end':
+ highlightRange += `${highlightBlockStart!}-${lineNumber - 1},`;
+ break;
+
+ default:
+ break;
+ }
+ lines.splice(lineNumber, 1);
}
const highlightLines = rangeParser(highlightRange);
code = lines.join('\n');
diff --git a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts
index e5f975abb9..236d9c224d 100644
--- a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts
+++ b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts
@@ -11,7 +11,7 @@ import path from 'path';
import fs from 'fs-extra';
describe('readOutputHTMLFile', () => {
- it('trailing slash undefined', async () => {
+ it('reads both files with trailing slash undefined', async () => {
await expect(
readOutputHTMLFile(
'/file',
@@ -41,7 +41,7 @@ describe('readOutputHTMLFile', () => {
).then(String),
).resolves.toBe('folder\n');
});
- it('trailing slash true', async () => {
+ it('reads only folder with trailing slash true', async () => {
await expect(
readOutputHTMLFile(
'/folder',
@@ -57,7 +57,7 @@ describe('readOutputHTMLFile', () => {
).then(String),
).resolves.toBe('folder\n');
});
- it('trailing slash false', async () => {
+ it('reads only file trailing slash false', async () => {
await expect(
readOutputHTMLFile(
'/file',
@@ -73,6 +73,18 @@ describe('readOutputHTMLFile', () => {
).then(String),
).resolves.toBe('file\n');
});
+ // Can it ever happen?
+ it('throws if file does not exist', async () => {
+ await expect(
+ readOutputHTMLFile(
+ '/nonExistent',
+ path.join(__dirname, '__fixtures__/build-snap'),
+ undefined,
+ ).then(String),
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
+ `"Expected output HTML file to be found at /packages/docusaurus-utils/src/__tests__/__fixtures__/build-snap/nonExistent/index.html."`,
+ );
+ });
});
describe('generate', () => {
diff --git a/packages/docusaurus-utils/src/emitUtils.ts b/packages/docusaurus-utils/src/emitUtils.ts
index 89680f92ad..b0c9a3ab27 100644
--- a/packages/docusaurus-utils/src/emitUtils.ts
+++ b/packages/docusaurus-utils/src/emitUtils.ts
@@ -83,18 +83,16 @@ export async function readOutputHTMLFile(
outDir,
`${permalink.replace(/\/$/, '')}.html`,
);
- if (trailingSlash) {
- return fs.readFile(withTrailingSlashPath);
- } else if (trailingSlash === false) {
- return fs.readFile(withoutTrailingSlashPath);
- }
const HTMLPath = await findAsyncSequential(
- [withTrailingSlashPath, withoutTrailingSlashPath],
+ [
+ trailingSlash !== false && withTrailingSlashPath,
+ trailingSlash !== true && withoutTrailingSlashPath,
+ ].filter((p): p is string => Boolean(p)),
fs.pathExists,
);
if (!HTMLPath) {
throw new Error(
- `Expected output HTML file to be found at ${withTrailingSlashPath}`,
+ `Expected output HTML file to be found at ${withTrailingSlashPath}.`,
);
}
return fs.readFile(HTMLPath);
diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/configs/configAsync.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/configAsync.config.js
similarity index 100%
rename from packages/docusaurus/src/server/__tests__/__fixtures__/configs/configAsync.config.js
rename to packages/docusaurus/src/server/__tests__/__fixtures__/config/configAsync.config.js
diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfig.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfig.config.js
similarity index 100%
rename from packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfig.config.js
rename to packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfig.config.js
diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfigAsync.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfigAsync.config.js
similarity index 100%
rename from packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfigAsync.config.js
rename to packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfigAsync.config.js
diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/bad-site/docusaurus.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/incomplete.config.js
similarity index 100%
rename from packages/docusaurus/src/server/__tests__/__fixtures__/bad-site/docusaurus.config.js
rename to packages/docusaurus/src/server/__tests__/__fixtures__/config/incomplete.config.js
diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/wrong-site/docusaurus.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/config/wrong.config.js
similarity index 100%
rename from packages/docusaurus/src/server/__tests__/__fixtures__/wrong-site/docusaurus.config.js
rename to packages/docusaurus/src/server/__tests__/__fixtures__/config/wrong.config.js
diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js b/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js
index 994e27fa63..a67a70d528 100644
--- a/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js
+++ b/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/docusaurus.config.js
@@ -22,4 +22,7 @@ module.exports = {
],
'@docusaurus/plugin-content-pages',
],
+ clientModules: [
+ 'foo.js'
+ ]
};
diff --git a/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/i18n/en/code.json b/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/i18n/en/code.json
new file mode 100644
index 0000000000..768c5072a6
--- /dev/null
+++ b/packages/docusaurus/src/server/__tests__/__fixtures__/simple-site/i18n/en/code.json
@@ -0,0 +1,6 @@
+{
+ "foo": {
+ "message": "bar",
+ "description": "foo for bar"
+ }
+}
diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap
index 914b41fe1c..abaaab349c 100644
--- a/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap
+++ b/packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap
@@ -34,7 +34,7 @@ exports[`loadSiteConfig website with valid async config 1`] = `
"titleDelimiter": "|",
"url": "https://docusaurus.io",
},
- "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/configs/configAsync.config.js",
+ "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/configAsync.config.js",
}
`;
@@ -72,7 +72,7 @@ exports[`loadSiteConfig website with valid async config creator function 1`] = `
"titleDelimiter": "|",
"url": "https://docusaurus.io",
},
- "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfigAsync.config.js",
+ "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfigAsync.config.js",
}
`;
@@ -110,7 +110,7 @@ exports[`loadSiteConfig website with valid config creator function 1`] = `
"titleDelimiter": "|",
"url": "https://docusaurus.io",
},
- "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/configs/createConfig.config.js",
+ "siteConfigPath": "/packages/docusaurus/src/server/__tests__/__fixtures__/config/createConfig.config.js",
}
`;
@@ -119,7 +119,9 @@ exports[`loadSiteConfig website with valid siteConfig 1`] = `
"siteConfig": {
"baseUrl": "/",
"baseUrlIssueBanner": true,
- "clientModules": [],
+ "clientModules": [
+ "foo.js",
+ ],
"customFields": {},
"favicon": "img/docusaurus.ico",
"i18n": {
diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/siteMetadata.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/siteMetadata.test.ts.snap
new file mode 100644
index 0000000000..667dc1216a
--- /dev/null
+++ b/packages/docusaurus/src/server/__tests__/__snapshots__/siteMetadata.test.ts.snap
@@ -0,0 +1,15 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`loadSiteMetadata warns about plugin version mismatch 1`] = `
+{
+ "docusaurusVersion": "",
+ "pluginVersions": {
+ "docusaurus-plugin-content-docs": {
+ "name": "@docusaurus/plugin-content-docs",
+ "type": "package",
+ "version": "1.0.0",
+ },
+ },
+ "siteVersion": "random-version",
+}
+`;
diff --git a/packages/docusaurus/src/server/__tests__/config.test.ts b/packages/docusaurus/src/server/__tests__/config.test.ts
index 7c3fb39b80..12b4be6415 100644
--- a/packages/docusaurus/src/server/__tests__/config.test.ts
+++ b/packages/docusaurus/src/server/__tests__/config.test.ts
@@ -9,7 +9,7 @@ import path from 'path';
import {loadSiteConfig} from '../config';
describe('loadSiteConfig', () => {
- const siteDir = path.join(__dirname, '__fixtures__', 'configs');
+ const siteDir = path.join(__dirname, '__fixtures__', 'config');
it('website with valid siteConfig', async () => {
const config = await loadSiteConfig({
@@ -49,7 +49,8 @@ describe('loadSiteConfig', () => {
it('website with incomplete siteConfig', async () => {
await expect(
loadSiteConfig({
- siteDir: path.join(__dirname, '__fixtures__', 'bad-site'),
+ siteDir,
+ customConfigFilePath: 'incomplete.config.js',
}),
).rejects.toThrowErrorMatchingInlineSnapshot(`
"\\"url\\" is required
@@ -60,7 +61,8 @@ describe('loadSiteConfig', () => {
it('website with useless field (wrong field) in siteConfig', async () => {
await expect(
loadSiteConfig({
- siteDir: path.join(__dirname, '__fixtures__', 'wrong-site'),
+ siteDir,
+ customConfigFilePath: 'wrong.config.js',
}),
).rejects.toThrowErrorMatchingInlineSnapshot(`
"These field(s) (\\"useLessField\\",) are not recognized in docusaurus.config.js.
@@ -72,10 +74,11 @@ describe('loadSiteConfig', () => {
it('website with no siteConfig', async () => {
await expect(
loadSiteConfig({
- siteDir: path.join(__dirname, '__fixtures__', 'nonExisting'),
+ siteDir,
+ customConfigFilePath: 'nonExistent.config.js',
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
- `"Config file at \\"/packages/docusaurus/src/server/__tests__/__fixtures__/nonExisting/docusaurus.config.js\\" not found."`,
+ `"Config file at \\"/packages/docusaurus/src/server/__tests__/__fixtures__/config/nonExistent.config.js\\" not found."`,
);
});
});
diff --git a/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts b/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts
index b12e0a7e17..12c62dcd54 100644
--- a/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts
+++ b/packages/docusaurus/src/server/__tests__/siteMetadata.test.ts
@@ -5,7 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/
-import {getPluginVersion} from '../siteMetadata';
+import {jest} from '@jest/globals';
+import {getPluginVersion, loadSiteMetadata} from '../siteMetadata';
import path from 'path';
describe('getPluginVersion', () => {
@@ -33,3 +34,32 @@ describe('getPluginVersion', () => {
await expect(getPluginVersion('/', '/')).resolves.toEqual({type: 'local'});
});
});
+
+describe('loadSiteMetadata', () => {
+ it('warns about plugin version mismatch', async () => {
+ const consoleMock = jest
+ .spyOn(console, 'error')
+ .mockImplementation(() => {});
+ await expect(
+ loadSiteMetadata({
+ plugins: [
+ {
+ name: 'docusaurus-plugin-content-docs',
+ version: {
+ type: 'package',
+ version: '1.0.0',
+ name: '@docusaurus/plugin-content-docs',
+ },
+ },
+ ],
+ siteDir: path.join(__dirname, '__fixtures__/siteMetadata'),
+ }),
+ ).resolves.toMatchSnapshot();
+ // cSpell:ignore mdocusaurus
+ expect(consoleMock.mock.calls[0][0]).toMatchInlineSnapshot(`
+ "[31m[1m[ERROR][22m Invalid [34m[1mdocusaurus-plugin-content-docs[22m[39m[31m version [33m1.0.0[39m[31m.[39m
+ [31mAll official @docusaurus/* packages should have the exact same version as @docusaurus/core ([33m[39m[31m).[39m
+ [31mMaybe you want to check, or regenerate your yarn.lock or package-lock.json file?[39m"
+ `);
+ });
+});