From 013ec5538aafa10573f69df1cdb16954dd9a0c31 Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Fri, 4 Sep 2026 18:27:38 +0800 Subject: [PATCH 1/2] fix(sidebar): complete loading when nested sidebar is missing --- src/core/fetch/index.js | 1 + src/core/render/compiler.js | 2 +- test/e2e/plugins.test.js | 81 +++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/core/fetch/index.js b/src/core/fetch/index.js index 3dcc0caf9d..fbd5b3d1b6 100644 --- a/src/core/fetch/index.js +++ b/src/core/fetch/index.js @@ -23,6 +23,7 @@ export function Fetch(Base) { path = getParentPath(path); if (!path) { + next(''); return; } diff --git a/src/core/render/compiler.js b/src/core/render/compiler.js index e81aaa81f8..d77a153645 100644 --- a/src/core/render/compiler.js +++ b/src/core/render/compiler.js @@ -206,7 +206,7 @@ export class Compiler { let html = ''; // compile sidebar from _sidebar.md - if (text) { + if (typeof text === 'string') { return this.compile(text); } // compile sidebar from content's headings toc diff --git a/test/e2e/plugins.test.js b/test/e2e/plugins.test.js index b1e53d729a..f1d07c9192 100644 --- a/test/e2e/plugins.test.js +++ b/test/e2e/plugins.test.js @@ -79,6 +79,87 @@ test.describe('Plugins', () => { expect(consoleMsgs).toEqual(expectedMsgs); }); + test('ready runs once when the initial sidebar is missing', async ({ + page, + }) => { + await docsifyInit({ + config: { + loadSidebar: true, + name: 'Docsify', + nameLink: '#/', + plugins: [ + function (hook) { + window.hookCalls = []; + + hook.doneEach(() => { + window.hookCalls.push('doneEach'); + }); + + hook.ready(() => { + window.hookCalls.push('ready'); + document + .querySelector('.sidebar-nav') + .addEventListener('click', event => { + const groupTitle = event.target.closest( + '.sidebar-nav > ul > li > p', + ); + + groupTitle?.parentElement.classList.toggle('plugin-collapse'); + }); + }); + }, + ], + }, + markdown: { + homepage: ` + # Home + + [Section](/section/) + `, + }, + routes: { + '/section/README.md': '# Section', + '/section/_sidebar.md': ` + - Group + - [Page](page) + `, + }, + }); + + await expect + .poll(() => page.evaluate(() => window.hookCalls)) + .toEqual(['doneEach', 'ready']); + await expect(page.locator('.sidebar-nav')).toBeEmpty(); + + await page.locator('a[href="#/section/"]').click(); + + const group = page.locator('.sidebar-nav > ul > li').first(); + await expect(group.locator(':scope > p')).toHaveText('Group'); + + await group.locator(':scope > p').click(); + await expect(group).toHaveClass(/plugin-collapse/); + await expect + .poll(() => page.evaluate(() => window.hookCalls)) + .toEqual(['doneEach', 'ready', 'doneEach']); + + await page.locator('.app-name-link').click(); + + await expect(page.locator('#main h1')).toHaveText('Home'); + await expect(page.locator('.sidebar-nav')).toBeEmpty(); + await expect + .poll(() => page.evaluate(() => window.hookCalls)) + .toEqual(['doneEach', 'ready', 'doneEach', 'doneEach']); + + await page.locator('a[href="#/section/"]').click(); + + await expect(group.locator(':scope > p')).toHaveText('Group'); + await group.locator(':scope > p').click(); + await expect(group).toHaveClass(/plugin-collapse/); + await expect + .poll(() => page.evaluate(() => window.hookCalls)) + .toEqual(['doneEach', 'ready', 'doneEach', 'doneEach', 'doneEach']); + }); + test.describe('beforeEach()', () => { test('return value', async ({ page }) => { await docsifyInit({ From 5086ea142ec1b53fc15c4e5e25b3c051fb64e540 Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Mon, 7 Sep 2026 12:09:26 +0800 Subject: [PATCH 2/2] fix(tests): handle missing sidebar in initial load test --- test/e2e/plugins.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/e2e/plugins.test.js b/test/e2e/plugins.test.js index f1d07c9192..53e2b96e0a 100644 --- a/test/e2e/plugins.test.js +++ b/test/e2e/plugins.test.js @@ -82,6 +82,8 @@ test.describe('Plugins', () => { test('ready runs once when the initial sidebar is missing', async ({ page, }) => { + await page.route('_sidebar.md', route => route.fulfill({ status: 404 })); + await docsifyInit({ config: { loadSidebar: true,