import docsifyInit from '../helpers/docsify-init.js'; import { test, expect } from './fixtures/docsify-init-fixture.js'; // Suite // ----------------------------------------------------------------------------- test.describe('Sidebar Tests', () => { // Tests // --------------------------------------------------------------------------- test('Active Test', async ({ page }) => { const docsifyInitConfig = { markdown: { sidebar: ` - [Test Space](test%20space) - [Test _](test_foo) - [Test -](test-foo) - [Test .](test.foo) - [Test >](test>foo) - [Test](test) `, }, routes: { '/test space.md': ` # Test Space `, '/test_foo.md': ` # Test _ `, '/test-foo.md': ` # Test - `, '/test.foo.md': ` # Test . `, '/test>foo.md': ` # Test > `, '/test.md': ` # Test page `, }, }; const activeLinkElm = page.locator('.sidebar-nav li[class=active]'); await docsifyInit(docsifyInitConfig); await page.click('a[href="#/test"]'); await expect(activeLinkElm).toHaveText('Test'); expect(page.url()).toMatch(/\/test$/); await page.click('a[href="#/test%20space"]'); await expect(activeLinkElm).toHaveText('Test Space'); expect(page.url()).toMatch(/\/test%20space$/); await page.click('a[href="#/test_foo"]'); await expect(activeLinkElm).toHaveText('Test _'); expect(page.url()).toMatch(/\/test_foo$/); await page.click('a[href="#/test-foo"]'); await expect(activeLinkElm).toHaveText('Test -'); expect(page.url()).toMatch(/\/test-foo$/); await page.click('a[href="#/test.foo"]'); await expect(activeLinkElm).toHaveText('Test .'); expect(page.url()).toMatch(/\/test.foo$/); await page.click('a[href="#/test>foo"]'); await expect(activeLinkElm).toHaveText('Test >'); expect(page.url()).toMatch(/\/test%3Efoo$/); }); test('does not collapse root sidebar groups by default', async ({ page }) => { await docsifyInit({ config: { collapseSidebarGroups: true, }, styleURLs: ['/dist/themes/core.css'], html: `
`, markdown: { sidebar: ` - Getting started - [Quick start](quickstart) `, }, routes: { '/quickstart.md': '# Quick start', }, }); const group = page.locator('.sidebar-nav > ul > li.group'); const groupTitle = group.locator(':scope > p'); const childLink = group.locator(':scope > ul > li > a'); await expect(group).not.toHaveClass(/collapse/); await expect(groupTitle).not.toHaveClass(/group-toggle/); await expect(groupTitle).not.toHaveAttribute('role'); await expect(groupTitle).not.toHaveAttribute('tabindex'); await expect(groupTitle).not.toHaveAttribute('aria-expanded'); await expect(groupTitle).not.toHaveAttribute('data-group-id'); await expect(groupTitle).toHaveCSS('background-image', 'none'); await expect(groupTitle).toHaveCSS('cursor', 'auto'); await expect(childLink).toBeVisible(); await groupTitle.click(); await expect(group).not.toHaveClass(/collapse/); await expect(childLink).toBeVisible(); }); test('collapses root sidebar groups when configured', async ({ page }) => { await docsifyInit({ config: { collapsibleSidebarGroups: true, }, styleURLs: ['/dist/themes/core.css'], markdown: { sidebar: ` - Getting started - [Quick start](quickstart) - Customization - [Configuration](configuration) - Standalone - [Linked group](linked) - [Linked child](linked-child) `, }, routes: { '/quickstart.md': '# Quick start', '/configuration.md': '# Configuration', '/linked.md': '# Linked group', '/linked-child.md': '# Linked child', }, }); const group = page.locator('.sidebar-nav > ul > li').first(); const groupTitle = group.locator(':scope > p.group-toggle'); const childLink = group.locator(':scope > ul > li > a'); await expect(groupTitle).toHaveAttribute('role', 'button'); await expect(groupTitle).toHaveAttribute('tabindex', '0'); await expect(groupTitle).toHaveAttribute('aria-expanded', 'true'); await expect(childLink).toBeVisible(); const standalone = page.locator('.sidebar-nav > ul > li').nth(2); await expect(standalone).not.toHaveClass(/group/); await expect(standalone.locator('[role="button"]')).toHaveCount(0); const linkedGroup = page.locator('.sidebar-nav > ul > li').nth(3); const linkedGroupLink = linkedGroup.locator('a').first(); await expect(linkedGroupLink).toHaveAttribute('href', '#/linked'); await groupTitle.click(); await expect(group).toHaveClass(/collapse/); await expect(groupTitle).toHaveAttribute('aria-expanded', 'false'); await expect(childLink).toBeHidden(); await linkedGroupLink.click(); expect(page.url()).toMatch(/\/linked$/); await expect(group).toHaveClass(/collapse/); await expect(groupTitle).toHaveAttribute('aria-expanded', 'false'); await expect(childLink).toBeHidden(); await groupTitle.press('Enter'); await expect(group).not.toHaveClass(/collapse/); await expect(groupTitle).toHaveAttribute('aria-expanded', 'true'); await expect(childLink).toBeVisible(); await groupTitle.press('Space'); await expect(group).toHaveClass(/collapse/); await groupTitle.press('Space'); await expect(group).not.toHaveClass(/collapse/); }); for (const viewport of [ { name: 'desktop', width: 1280, height: 720, prepareSidebar: async () => {}, }, { name: 'mobile', width: 390, height: 500, prepareSidebar: async (page, sidebar) => { await page.locator('.sidebar-toggle-button').click(); await sidebar.evaluate(element => Promise.all( element.getAnimations().map(animation => animation.finished), ), ); }, }, ]) { test(`keeps sidebar content aligned when a root group removes the scrollbar on ${viewport.name}`, async ({ page, }) => { await page.setViewportSize(viewport); const childLinks = Array.from( { length: 40 }, (_, index) => ` - [Page ${index + 1}](page-${index + 1})`, ).join('\n'); await docsifyInit({ config: { collapsibleSidebarGroups: true, }, styleURLs: ['/dist/themes/core.css'], markdown: { homepage: '# Home', sidebar: `- Root\n${childLinks}`, }, }); const sidebar = page.locator('.sidebar'); const group = page.locator('.sidebar-nav > ul > li.group'); const groupTitle = group.locator(':scope > .group-toggle'); await viewport.prepareSidebar(page, sidebar); await expect(sidebar).toHaveCSS('overflow-y', 'scroll'); const expandedLayout = await page.evaluate(() => { const sidebar = document.querySelector('.sidebar'); const groupTitle = document.querySelector('.group-toggle'); return { hasScrollbar: sidebar.scrollHeight > sidebar.clientHeight, titleRight: groupTitle.getBoundingClientRect().right, url: location.href, }; }); expect(expandedLayout.hasScrollbar).toBe(true); await groupTitle.click(); await expect(group).toHaveClass(/collapse/); const collapsedLayout = await page.evaluate(() => { const sidebar = document.querySelector('.sidebar'); const groupTitle = document.querySelector('.group-toggle'); return { hasScrollbar: sidebar.scrollHeight > sidebar.clientHeight, titleRight: groupTitle.getBoundingClientRect().right, url: location.href, }; }); expect(collapsedLayout.hasScrollbar).toBe(false); expect(collapsedLayout.titleRight).toBe(expandedLayout.titleRight); expect(collapsedLayout.url).toBe(expandedLayout.url); }); } test('initially collapses root sidebar groups when configured', async ({ page, }) => { await docsifyInit({ config: { collapseSidebarGroups: true, collapsibleSidebarGroups: true, }, styleURLs: ['/dist/themes/core.css'], markdown: { sidebar: ` - Getting started - [Quick start](quickstart) - Customization - [Configuration](configuration) - [Standalone](standalone) `, }, routes: { '/quickstart.md': '# Quick start', '/configuration.md': '# Configuration', '/standalone.md': '# Standalone', }, }); const groups = page.locator('.sidebar-nav > ul > li.group'); const firstGroup = groups.first(); const firstGroupTitle = firstGroup.locator(':scope > .group-toggle'); const firstGroupLink = firstGroup.locator(':scope > ul > li > a'); const secondGroup = groups.nth(1); await expect(groups).toHaveCount(2); await expect(firstGroup).toHaveClass(/collapse/); await expect(secondGroup).toHaveClass(/collapse/); await expect(firstGroupTitle).toHaveAttribute('aria-expanded', 'false'); await expect(firstGroupLink).toBeHidden(); await firstGroupTitle.click(); await expect(firstGroup).not.toHaveClass(/collapse/); await firstGroupLink.click(); expect(page.url()).toMatch(/\/quickstart$/); await expect(firstGroup).not.toHaveClass(/collapse/); await expect(firstGroupTitle).toHaveAttribute('aria-expanded', 'true'); await expect(secondGroup).toHaveClass(/collapse/); }); test('supports chevrons on collapsible root groups', async ({ page }) => { await docsifyInit({ config: { collapsibleSidebarGroups: true, }, styleURLs: ['/dist/themes/core.css'], style: ` :root:has(body[class*='sidebar-chevron']) { --sidebar-chevron-collapsed-color: rgb(1, 2, 3); --sidebar-chevron-expanded-color: rgb(4, 5, 6); --sidebar-group-title-font-weight: 700; } `, html: `
`, markdown: { sidebar: ` - Getting started - [Quick start](quickstart) - [Standalone](standalone) 1. Styled group - [Styled child](styled-child) `, }, routes: { '/quickstart.md': '# Quick start', '/styled-child.md': '# Styled child', '/standalone.md': '# Standalone', }, }); const groupTitle = page .locator('.group-toggle[role="button"]') .filter({ hasText: 'Getting started' }); const styledGroupTitle = page .locator('.group-title.group-toggle') .filter({ hasText: 'Styled group' }); const standaloneLink = page.locator('a[href="#/standalone"]'); const background = await groupTitle.evaluate( element => getComputedStyle(element).backgroundImage, ); const [groupTitleBox, standaloneLinkBox] = await Promise.all([ groupTitle.boundingBox(), standaloneLink.boundingBox(), ]); const [groupTitleFontWeight, standaloneLinkFontWeight] = await Promise.all([ groupTitle.evaluate(element => getComputedStyle(element).fontWeight), standaloneLink.evaluate(element => getComputedStyle(element).fontWeight), ]); expect(background).not.toBe('none'); expect(background).toMatch(/rgb\(1,\s*2,\s*3\)/); expect(background).not.toMatch(/rgb\(4,\s*5,\s*6\)/); await expect(groupTitle).not.toHaveClass(/group-title/); expect(groupTitleFontWeight).toBe(standaloneLinkFontWeight); await expect(styledGroupTitle).not.toHaveCSS('background-image', 'none'); await expect(styledGroupTitle).toHaveCSS('font-weight', '700'); expect(groupTitleBox?.x + groupTitleBox?.width).toBe( standaloneLinkBox?.x + standaloneLinkBox?.width, ); await groupTitle.click(); await expect(groupTitle).toHaveAttribute('aria-expanded', 'false'); const collapsedBackground = await groupTitle.evaluate( element => getComputedStyle(element).backgroundImage, ); expect(collapsedBackground).not.toBe(background); expect(collapsedBackground).toMatch(/rgb\(1,\s*2,\s*3\)/); expect(collapsedBackground).not.toMatch(/rgb\(4,\s*5,\s*6\)/); }); test('normalizes loose-list page links and shows expanded chevrons', async ({ page, }) => { await docsifyInit({ config: { subMaxLevel: 2, }, styleURLs: ['/dist/themes/core.css'], style: ` :root:has(body[class*='sidebar-chevron']) { --sidebar-chevron-collapsed-color: rgb(1, 2, 3); --sidebar-chevron-expanded-color: rgb(4, 5, 6); --sidebar-link-color-active: rgb(7, 8, 9); } `, html: `
`, markdown: { homepage: '# Home', sidebar: ` * [Test](test.md) + [Quick start](quickstart.md) - [Adding pages](adding-pages.md) - Getting started - [Cover page](cover.md) `, }, routes: { '/test.md': '# Test', '/quickstart.md': '# Quick start\n\n## Installation', '/adding-pages.md': '# Adding pages\n\n## Sidebar', '/cover.md': '# Cover page', }, }); const quickStartLink = page.locator('a[href="#/quickstart"]'); const addingPagesLink = page.locator('a[href="#/adding-pages"]'); const quickStartItem = page.locator( '.sidebar-nav li:has(> a[href="#/quickstart"])', ); const addingPagesItem = page.locator( '.sidebar-nav li:has(> a[href="#/adding-pages"])', ); await expect(page.locator('.sidebar-nav li > p > a')).toHaveCount(0); await quickStartLink.click(); await expect( quickStartItem.locator(':scope > .app-sub-sidebar'), ).toBeVisible(); const quickStartBackground = await quickStartLink.evaluate( element => getComputedStyle(element).backgroundImage, ); await addingPagesLink.click(); await expect( addingPagesItem.locator(':scope > .app-sub-sidebar'), ).toBeVisible(); const addingPagesBackground = await addingPagesLink.evaluate( element => getComputedStyle(element).backgroundImage, ); expect(addingPagesBackground).toBe(quickStartBackground); expect(addingPagesBackground).toMatch(/rgb\(4,\s*5,\s*6\)/); await expect(addingPagesLink).toHaveCSS('color', 'rgb(7, 8, 9)'); await addingPagesLink.click(); await expect(addingPagesItem).toHaveClass(/collapse/); const collapsedBackground = await addingPagesLink.evaluate( element => getComputedStyle(element).backgroundImage, ); expect(collapsedBackground).not.toBe(addingPagesBackground); }); test('hides root chevrons when configured by body class', async ({ page, }) => { await docsifyInit({ config: { collapsibleSidebarGroups: true, subMaxLevel: 2, }, styleURLs: ['/dist/themes/core.css'], html: `
`, markdown: { homepage: '# Home', sidebar: ` + [Direct root page](direct.md) - [Loose root page](loose.md) - Getting started - [Nested page](nested.md) `, }, routes: { '/direct.md': '# Direct root page', '/loose.md': '# Loose root page\n\n## Child heading', '/nested.md': '# Nested page', }, }); const directRootLink = page.locator('a[href="#/direct"]'); const looseRootLink = page.locator('a[href="#/loose"]'); const nestedLink = page.locator('a[href="#/nested"]'); const groupTitle = page.locator('.group-toggle[role="button"]'); const looseRootItem = page.locator( '.sidebar-nav li:has(> a[href="#/loose"])', ); for (const rootLink of [directRootLink, looseRootLink]) { await expect(rootLink).toHaveCSS('background-image', 'none'); } await expect(nestedLink).not.toHaveCSS('background-image', 'none'); await expect(groupTitle).toHaveCSS('background-image', 'none'); await groupTitle.click(); await expect(groupTitle).toHaveAttribute('aria-expanded', 'false'); await expect(groupTitle).toHaveCSS('background-image', 'none'); await looseRootLink.click(); await expect( looseRootItem.locator(':scope > .app-sub-sidebar'), ).toBeVisible(); await expect(looseRootLink).toHaveCSS('background-image', 'none'); await looseRootLink.click(); await expect(looseRootItem).toHaveClass(/collapse/); await expect(looseRootLink).toHaveCSS('background-image', 'none'); }); test('keeps group border spacing when the last group collapses', async ({ page, }) => { await docsifyInit({ config: { collapsibleSidebarGroups: true, }, styleURLs: ['/dist/themes/core.css'], html: `
`, markdown: { sidebar: ` - Upgrading - [v4 to v5](upgrade) * [Awesome docsify](awesome) `, }, routes: { '/upgrade.md': '# v4 to v5', '/awesome.md': '# Awesome docsify', }, }); const upgradingGroup = page.locator( '.sidebar-nav > ul:first-of-type > li:last-child', ); const groupTitle = upgradingGroup.locator(':scope > .group-toggle'); await groupTitle.click(); const spacing = await page.evaluate(() => { const title = document.querySelector('.group-toggle'); const group = title.closest('li'); const awesome = document.querySelector('a[href="#/awesome"]'); const titleBox = title.getBoundingClientRect(); const groupBox = group.getBoundingClientRect(); const awesomeBox = awesome.getBoundingClientRect(); return { borderToAwesome: awesomeBox.top - groupBox.bottom, titleToBorder: groupBox.bottom - titleBox.bottom, }; }); expect(spacing.titleToBorder).toBeGreaterThan(spacing.borderToAwesome); }); test('keeps a normalized loose-list page link visible when collapsed', async ({ page, }) => { await docsifyInit({ config: { subMaxLevel: 2, }, markdown: { homepage: '# Home', sidebar: ` - Getting started - [Introduction](introduction.md) - [Quick start](quickstart.md) `, }, routes: { '/quickstart.md': ` # Quick start ## Installation `, }, styleURLs: ['/dist/themes/core.css'], }); const quickStartLink = page.locator('.sidebar-nav a[href="#/quickstart"]'); await quickStartLink.click(); const quickStartItem = page.locator( '.sidebar-nav li:has(> a[href="#/quickstart"])', ); const subSidebar = quickStartItem.locator(':scope > .app-sub-sidebar'); await expect(subSidebar).toBeVisible(); await quickStartLink.click(); await expect(quickStartItem).toHaveClass(/collapse/); await expect(subSidebar).toBeHidden(); await expect(quickStartLink).toBeVisible(); }); test('exposes the expanded state of page links that toggle a sub-sidebar', async ({ page, }) => { await docsifyInit({ config: { subMaxLevel: 2, }, markdown: { homepage: '# Home', sidebar: ` - [Quick start](quickstart.md) - [Adding pages](adding-pages.md) `, }, routes: { '/quickstart.md': ` # Quick start ## Installation `, '/adding-pages.md': '# Adding pages', }, styleURLs: ['/dist/themes/core.css'], }); const quickStartLink = page.locator('.sidebar-nav a[href="#/quickstart"]'); const addingPagesLink = page.locator( '.sidebar-nav a[href="#/adding-pages"]', ); const subSidebar = page.locator('.sidebar-nav .app-sub-sidebar'); await expect(quickStartLink).not.toHaveAttribute('aria-expanded'); await quickStartLink.click(); await expect(subSidebar).toBeVisible(); await expect(quickStartLink).toHaveAttribute('aria-expanded', 'true'); await quickStartLink.click(); await expect(subSidebar).toBeHidden(); await expect(quickStartLink).toHaveAttribute('aria-expanded', 'false'); await quickStartLink.press('Enter'); await expect(subSidebar).toBeVisible(); await expect(quickStartLink).toHaveAttribute('aria-expanded', 'true'); // Pages without headings have no sub-sidebar to toggle await addingPagesLink.click(); await expect(quickStartLink).not.toHaveAttribute('aria-expanded'); await expect(addingPagesLink).not.toHaveAttribute('aria-expanded'); }); }); test.describe('Mobile sidebar toggle', () => { test('moves focus to content after sidebar navigation', async ({ page }) => { await page.setViewportSize({ width: 390, height: 844 }); await docsifyInit({ markdown: { homepage: '# Home', sidebar: ` - [Home](/) - [Guide](guide) `, }, routes: { '/guide.md': '# Guide', }, styleURLs: ['/dist/themes/core.css'], }); await page.locator('.sidebar-toggle-button').click(); const guideLinkElm = page .locator('.sidebar-nav') .getByRole('link', { name: 'Guide' }); await guideLinkElm.focus(); await page.keyboard.press('Enter'); await expect(page.locator('#guide')).toBeVisible(); await expect(page.locator('#guide')).toBeFocused(); await expect(page.locator('.sidebar')).not.toHaveClass(/show/); }); test('wraps long links without causing horizontal overflow', async ({ page, }) => { await page.setViewportSize({ width: 390, height: 844 }); const longUrl = `https://example.com/${'a'.repeat(240)}`; const content = Array.from( { length: 80 }, (_, index) => `## Section ${index + 1}\n\nLong content for scrolling.`, ).join('\n\n'); await docsifyInit({ config: { loadSidebar: '_sidebar.md', }, markdown: { homepage: `# Mobile scrolling\n\n${content}\n\n[${longUrl}](${longUrl})`, sidebar: '- [Mobile scrolling](README.md)', }, styleURLs: ['/dist/themes/core.css'], }); await expect .poll(() => page.evaluate(() => document.documentElement.scrollWidth)) .toBe(page.viewportSize().width); await page.mouse.wheel(0, 1200); await expect .poll(() => page.evaluate(() => window.scrollY)) .toBeGreaterThan(0); await page.mouse.wheel(0, -1200); await expect.poll(() => page.evaluate(() => window.scrollY)).toBe(0); }); }); test('keeps focus on activated sidebar page links', async ({ page }) => { const docsifyInitConfig = { config: { name: 'Docsify', nameLink: '#/', }, markdown: { homepage: ` # Home `, sidebar: ` - [Home](/) - [Guide](guide) `, }, routes: { '/guide.md': ` # Guide `, }, }; await docsifyInit(docsifyInitConfig); const guideLinkElm = page.locator('.sidebar-nav a[href="#/guide"]'); await guideLinkElm.focus(); await page.keyboard.press('Enter'); await expect(page).toHaveURL(/#\/guide$/); await expect(page.locator('#guide')).toBeVisible(); await expect(guideLinkElm).toBeFocused(); const homeLinkElm = page.locator('.sidebar-nav a[href="#/"]'); await homeLinkElm.focus(); await page.keyboard.press('Enter'); await expect(page).toHaveURL(/#\/$/); await expect(page.locator('#home')).toBeVisible(); await expect(homeLinkElm).toBeFocused(); await expect(page.locator('.app-name-link')).not.toBeFocused(); }); test('keeps focus on activated app name and section links', async ({ page, }) => { await docsifyInit({ config: { name: 'Docsify', nameLink: '#/guide', subMaxLevel: 2, }, markdown: { homepage: '# Home', sidebar: ` - [Home](/) - [Guide](guide) `, }, routes: { '/guide.md': ` # Guide ## Details `, }, }); const appNameLinkElm = page.locator('.app-name-link'); await appNameLinkElm.focus(); await page.keyboard.press('Enter'); await expect(page).toHaveURL(/#\/guide$/); await expect(page.locator('#guide')).toBeVisible(); await expect(appNameLinkElm).toBeFocused(); const sectionLinkElm = page .locator('.sidebar-nav') .getByRole('link', { name: 'Details' }); await sectionLinkElm.focus(); await page.keyboard.press('Enter'); await expect(page).toHaveURL(/#\/guide\?id=details$/); await expect(sectionLinkElm).toBeFocused(); }); test('restores sidebar focus for encoded URLs', async ({ page }) => { await docsifyInit({ markdown: { homepage: '# Home', sidebar: '- [Quoted path](say%22hi)', }, routes: { '/say%22hi.md': '# Quoted path', }, }); const quotedLinkElm = page .locator('.sidebar-nav') .getByRole('link', { name: 'Quoted path' }); await quotedLinkElm.focus(); await page.keyboard.press('Enter'); await expect(page.locator('#quoted-path')).toBeVisible(); await expect(quotedLinkElm).toBeFocused(); }); test('does not reuse focus from a cancelled sidebar navigation', async ({ page, }) => { await docsifyInit({ markdown: { homepage: '# Home', sidebar: ` - [Guide](guide) - [Other](other) `, }, routes: { '/guide.md': '# Guide', '/other.md': '# Other', }, }); const guideLinkElm = page.getByRole('link', { name: 'Guide' }); await guideLinkElm.evaluate(linkElm => { linkElm.addEventListener('click', event => event.preventDefault(), { once: true, }); }); await guideLinkElm.focus(); await page.keyboard.press('Enter'); await expect(page).toHaveURL(/#\/$/); await page.evaluate(() => { location.hash = '#/other'; }); await expect(page).toHaveURL(/#\/other$/); await expect(page.locator('#other')).toBeVisible(); await expect(page.getByRole('link', { name: 'Guide' })).not.toBeFocused(); }); test('keeps focus on sidebar page links in history mode', async ({ page }) => { await docsifyInit({ config: { name: 'Docsify', nameLink: '/guide', routerMode: 'history', }, markdown: { homepage: '# Home', sidebar: '- [Guide](guide)', }, routes: { '/guide.md': '# Guide', }, waitForSelector: '.sidebar-nav a[href="/guide"]', }); const guideLinkElm = page.locator('.sidebar-nav a[href="/guide"]'); await guideLinkElm.focus(); await page.keyboard.press('Enter'); await expect(page).toHaveURL(/\/guide$/); await expect(page.locator('#guide')).toBeVisible(); await expect(guideLinkElm).toBeFocused(); await expect(page.locator('.app-name-link')).not.toBeFocused(); }); test.describe('Configuration: autoHeader', () => { test('autoHeader=false', async ({ page }) => { const docsifyInitConfig = { config: { loadSidebar: '_sidebar.md', autoHeader: false, }, markdown: { sidebar: ` - [QuickStartAutoHeader](quickstart.md) `, }, routes: { '/quickstart.md': ` the content of quickstart space ## In the main content there is no h1 `, }, }; await docsifyInit(docsifyInitConfig); await page.click('a[href="#/quickstart"]'); expect(page.url()).toMatch(/\/quickstart$/); // not heading await expect(page.locator('#quickstart')).toBeHidden(); }); test('autoHeader=true', async ({ page }) => { const docsifyInitConfig = { config: { loadSidebar: '_sidebar.md', autoHeader: true, }, markdown: { sidebar: ` - [QuickStartAutoHeader](quickstart.md ) `, }, routes: { '/quickstart.md': ` the content of quickstart space ## In the main content there is no h1 `, }, }; await docsifyInit(docsifyInitConfig); await page.click('a[href="#/quickstart"]'); expect(page.url()).toMatch(/\/quickstart$/); // auto generate default heading id const autoHeader = page.locator('#quickstartautoheader'); expect(await autoHeader.innerText()).toContain('QuickStartAutoHeader'); }); test('autoHeader=true and custom headingId', async ({ page }) => { const docsifyInitConfig = { config: { loadSidebar: '_sidebar.md', autoHeader: true, }, markdown: { sidebar: ` - [QuickStartAutoHeader](quickstart.md ":id=quickstartId") `, }, routes: { '/quickstart.md': ` the content of quickstart space ## In the main content there is no h1 `, }, }; await docsifyInit(docsifyInitConfig); await page.click('a[href="#/quickstart"]'); expect(page.url()).toMatch(/\/quickstart$/); // auto generate custom heading id const autoHeader = page.locator('#quickstartId'); expect(await autoHeader.innerText()).toContain('QuickStartAutoHeader'); }); });