Files
AFFiNE-Mirror/blocksuite/tests-legacy/fragments/outline/toc-viewer.spec.ts
2024-12-20 11:08:21 +00:00

209 lines
6.0 KiB
TypeScript

import { noop } from '@blocksuite/global/utils';
import type { OutlineViewer } from '@blocksuite/presets';
import { expect, type Page } from '@playwright/test';
import { addNote, switchEditorMode } from 'utils/actions/edgeless.js';
import { pressEnter, type } from 'utils/actions/keyboard.js';
import {
enterPlaygroundRoom,
focusRichTextEnd,
focusTitle,
getEditorLocator,
initEmptyEdgelessState,
initEmptyParagraphState,
waitNextFrame,
} from 'utils/actions/misc.js';
import { test } from '../../utils/playwright.js';
import {
createHeadingsWithGap,
getVerticalCenterFromLocator,
} from './utils.js';
test.describe('toc-viewer', () => {
async function toggleTocViewer(page: Page) {
await page.click('sl-button:text("Test Operations")');
await page.click('sl-menu-item:text("Enable Outline Viewer")');
await waitNextFrame(page);
const viewer = page.locator('affine-outline-viewer');
return viewer;
}
function getIndicators(page: Page) {
return page.locator('affine-outline-viewer .outline-viewer-indicator');
}
test('should display highlight indicators when non-empty headings exists', async ({
page,
}) => {
await enterPlaygroundRoom(page);
await initEmptyParagraphState(page);
await toggleTocViewer(page);
await focusRichTextEnd(page);
const indicators = getIndicators(page);
// heading 1 to 6
for (let i = 1; i <= 6; i++) {
await type(page, `${'#'.repeat(i)} `);
await type(page, `Heading ${i}`);
await pressEnter(page);
await expect(indicators.nth(i - 1)).toBeVisible();
}
});
test('should be hidden when only empty headings exists', async ({ page }) => {
await enterPlaygroundRoom(page);
await initEmptyParagraphState(page);
await toggleTocViewer(page);
await focusTitle(page);
await type(page, 'Title');
await focusRichTextEnd(page);
const indicators = getIndicators(page);
// heading 1 to 6
for (let i = 1; i <= 6; i++) {
await type(page, `${'#'.repeat(i)} `);
await pressEnter(page);
await expect(indicators).toHaveCount(0);
}
});
test('should display outline content when hovering over indicators', async ({
page,
}) => {
await enterPlaygroundRoom(page);
await initEmptyParagraphState(page);
await toggleTocViewer(page);
await focusRichTextEnd(page);
await type(page, '# Heading 1');
await pressEnter(page);
const indicator = getIndicators(page).first();
await indicator.hover({ force: true });
const items = page.locator('.outline-viewer-item');
await expect(items).toHaveCount(2);
await expect(items.nth(0)).toContainText(['Table of Contents']);
await expect(items.nth(1)).toContainText(['Heading 1']);
});
test('should highlight indicator when scrolling', async ({ page }) => {
await enterPlaygroundRoom(page);
await initEmptyParagraphState(page);
await toggleTocViewer(page);
await focusRichTextEnd(page);
const editor = getEditorLocator(page);
const indicators = getIndicators(page);
const headings = await createHeadingsWithGap(page);
await editor.locator('.inline-editor').first().scrollIntoViewIfNeeded();
const viewportCenter = await getVerticalCenterFromLocator(
page.locator('body')
);
for (let i = 0; i < headings.length; i++) {
const lastHeadingCenter = await getVerticalCenterFromLocator(headings[i]);
await page.mouse.wheel(0, lastHeadingCenter - viewportCenter + 50);
await expect(indicators.nth(i)).toHaveClass(/active/);
}
});
test('should highlight indicator when click item in outline panel', async ({
page,
}) => {
await enterPlaygroundRoom(page);
await initEmptyParagraphState(page);
const viewer = await toggleTocViewer(page);
await focusRichTextEnd(page);
const headings = await createHeadingsWithGap(page);
const indicators = getIndicators(page);
await indicators.first().hover({ force: true });
const headingsInPanel = Array.from({ length: 6 }, (_, i) =>
viewer.locator(`.h${i + 1} > span`)
);
await headingsInPanel[2].click();
await expect(headings[2]).toBeVisible();
await expect(indicators.nth(2)).toHaveClass(/active/);
});
test('should hide in edgeless mode', async ({ page }) => {
await enterPlaygroundRoom(page);
await initEmptyEdgelessState(page);
await toggleTocViewer(page);
const indicators = getIndicators(page);
await focusRichTextEnd(page);
await type(page, '# Heading 1');
await pressEnter(page);
await expect(indicators).toHaveCount(1);
await switchEditorMode(page);
await expect(indicators).toHaveCount(0);
});
test('should hide edgeless-only note headings', async ({ page }) => {
await enterPlaygroundRoom(page);
await initEmptyEdgelessState(page);
const viewer = await toggleTocViewer(page);
await focusRichTextEnd(page);
await type(page, '# Heading 1');
await pressEnter(page);
await type(page, '## Heading 2');
await pressEnter(page);
await switchEditorMode(page);
await addNote(page, '# Edgeless', 300, 300);
await switchEditorMode(page);
const indicators = getIndicators(page);
await expect(indicators).toHaveCount(2);
await indicators.first().hover({ force: true });
await expect(viewer).toBeVisible();
const hiddenTitle = viewer.locator('.hidden-title');
await expect(hiddenTitle).toBeHidden();
});
test('outline panel toggle button', async ({ page }) => {
await enterPlaygroundRoom(page);
await initEmptyParagraphState(page);
const viewer = await toggleTocViewer(page);
await focusRichTextEnd(page);
await createHeadingsWithGap(page);
const toggleButton = viewer.locator(
'[data-testid="toggle-outline-panel-button"]'
);
await expect(toggleButton).toHaveCount(0);
await viewer.evaluate((el: OutlineViewer) => {
el.toggleOutlinePanel = () => {
noop();
};
});
await waitNextFrame(page);
await expect(toggleButton).toHaveCount(1);
await expect(toggleButton).toBeVisible();
});
});