snapshot of https://github.com/toeverything/AFFiNE.git (canary, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Build & Test / Analyze (javascript, affine) (push) Failing after 4s
Build & Test / Analyze (typescript, affine) (push) Failing after 3s
Build & Test / Rust test filter (push) Failing after 4s
Build & Test / Check yarn binary (push) Failing after 3s
Build & Test / E2E BlockSuite Test (3) (push) Failing after 3s
Build & Test / Analyze (javascript, blocksuite) (push) Failing after 3s
Build & Test / Analyze (typescript, blocksuite) (push) Failing after 3s
Build & Test / Mobile native build filter (push) Failing after 3s
Build & Test / E2E BlockSuite Test (1) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (2) (push) Failing after 4s
Build & Test / E2E Mobile Test (1) (push) Failing after 3s
Build & Test / Unit Test (1) (push) Has been skipped
Build & Test / Unit Test (2) (push) Has been skipped
Build & Test / Unit Test (3) (push) Has been skipped
Build & Test / Unit Test (4) (push) Has been skipped
Build & Test / Unit Test (5) (push) Has been skipped
Build & Test / Native Unit Test (push) Has been skipped
Build & Test / E2E BlockSuite Test (4) (push) Failing after 3s
Build & Test / E2E BlockSuite Test (5) (push) Failing after 3s
Build & Test / E2E BlockSuite Cross Browser Test (push) Failing after 3s
Build & Test / E2E Mobile Test (2) (push) Failing after 3s
Build & Test / Build AFFiNE native (x86_64-unknown-linux-gnu) (push) Failing after 3s
Build & Test / Build Server native (push) Failing after 3s
Build & Test / Check Git Status (push) Has been skipped
Build & Test / Server Test (0, 4) (push) Has been skipped
Build & Test / Server Test (1, 4) (push) Has been skipped
Build & Test / Server Test (2, 4) (push) Has been skipped
Build & Test / Server Test (3, 4) (push) Has been skipped
Build & Test / Server Test with Elasticsearch (push) Has been skipped
Build & Test / Build @affine/electron renderer (push) Failing after 3s
Build & Test / Copilot test filter (push) Failing after 4s
Build & Test / Lint Rust (push) Has been skipped
Build & Test / Server Test with Embedded Search (push) Has been skipped
Build & Test / Server Test with Manticore Search (push) Has been skipped
Build & Test / Server E2E Test (push) Has been skipped
Build & Test / Cloud Desktop E2E Test (push) Has been skipped
Build & Test / Cloud E2E Test 1/2 (push) Has been skipped
Build & Test / Cloud E2E Test 2/2 (push) Has been skipped
Build & Test / Build Android app (push) Has been skipped
Build & Test / Test Android app (push) Has been skipped
Build & Test / Run native tests (push) Has been skipped
Build & Test / Server Copilot Api Test (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (1, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (2, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (3, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (4, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (5, 5) (push) Has been skipped
Release / Canary Gate (push) Has been skipped
Build & Test / Build AFFiNE native (aarch64-apple-darwin) (push) Has been cancelled
Build & Test / Lint (push) Has been cancelled
Build & Test / Typecheck (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-apple-darwin) (push) Has been cancelled
Build & Test / Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true) (push) Has been cancelled
Build & Test / Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true) (push) Has been cancelled
Build & Test / E2E Test (1) (push) Has been cancelled
Build & Test / E2E Test (2) (push) Has been cancelled
Build & Test / E2E Test (3) (push) Has been cancelled
Build & Test / E2E Test (4) (push) Has been cancelled
Build & Test / E2E Test (5) (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, x64, x86_64-apple-darwin, false) (push) Has been cancelled
Build & Test / 3, 2, 1 Launch (push) Has been cancelled
Build & Test / Build iOS app (push) Has been cancelled
Release / Prepare (push) Failing after 2s
Release / Release Cloud (push) Has been skipped
Release / Release Desktop (push) Has been skipped
Release / Release Docker Image (push) Has been skipped
Release / Release Mobile (push) Has been skipped
Copilot Test Automatically / Setup Test (push) Failing after 1s
Some checks failed
Build & Test / Analyze (javascript, affine) (push) Failing after 4s
Build & Test / Analyze (typescript, affine) (push) Failing after 3s
Build & Test / Rust test filter (push) Failing after 4s
Build & Test / Check yarn binary (push) Failing after 3s
Build & Test / E2E BlockSuite Test (3) (push) Failing after 3s
Build & Test / Analyze (javascript, blocksuite) (push) Failing after 3s
Build & Test / Analyze (typescript, blocksuite) (push) Failing after 3s
Build & Test / Mobile native build filter (push) Failing after 3s
Build & Test / E2E BlockSuite Test (1) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (2) (push) Failing after 4s
Build & Test / E2E Mobile Test (1) (push) Failing after 3s
Build & Test / Unit Test (1) (push) Has been skipped
Build & Test / Unit Test (2) (push) Has been skipped
Build & Test / Unit Test (3) (push) Has been skipped
Build & Test / Unit Test (4) (push) Has been skipped
Build & Test / Unit Test (5) (push) Has been skipped
Build & Test / Native Unit Test (push) Has been skipped
Build & Test / E2E BlockSuite Test (4) (push) Failing after 3s
Build & Test / E2E BlockSuite Test (5) (push) Failing after 3s
Build & Test / E2E BlockSuite Cross Browser Test (push) Failing after 3s
Build & Test / E2E Mobile Test (2) (push) Failing after 3s
Build & Test / Build AFFiNE native (x86_64-unknown-linux-gnu) (push) Failing after 3s
Build & Test / Build Server native (push) Failing after 3s
Build & Test / Check Git Status (push) Has been skipped
Build & Test / Server Test (0, 4) (push) Has been skipped
Build & Test / Server Test (1, 4) (push) Has been skipped
Build & Test / Server Test (2, 4) (push) Has been skipped
Build & Test / Server Test (3, 4) (push) Has been skipped
Build & Test / Server Test with Elasticsearch (push) Has been skipped
Build & Test / Build @affine/electron renderer (push) Failing after 3s
Build & Test / Copilot test filter (push) Failing after 4s
Build & Test / Lint Rust (push) Has been skipped
Build & Test / Server Test with Embedded Search (push) Has been skipped
Build & Test / Server Test with Manticore Search (push) Has been skipped
Build & Test / Server E2E Test (push) Has been skipped
Build & Test / Cloud Desktop E2E Test (push) Has been skipped
Build & Test / Cloud E2E Test 1/2 (push) Has been skipped
Build & Test / Cloud E2E Test 2/2 (push) Has been skipped
Build & Test / Build Android app (push) Has been skipped
Build & Test / Test Android app (push) Has been skipped
Build & Test / Run native tests (push) Has been skipped
Build & Test / Server Copilot Api Test (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (1, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (2, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (3, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (4, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (5, 5) (push) Has been skipped
Release / Canary Gate (push) Has been skipped
Build & Test / Build AFFiNE native (aarch64-apple-darwin) (push) Has been cancelled
Build & Test / Lint (push) Has been cancelled
Build & Test / Typecheck (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-apple-darwin) (push) Has been cancelled
Build & Test / Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true) (push) Has been cancelled
Build & Test / Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true) (push) Has been cancelled
Build & Test / E2E Test (1) (push) Has been cancelled
Build & Test / E2E Test (2) (push) Has been cancelled
Build & Test / E2E Test (3) (push) Has been cancelled
Build & Test / E2E Test (4) (push) Has been cancelled
Build & Test / E2E Test (5) (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, x64, x86_64-apple-darwin, false) (push) Has been cancelled
Build & Test / 3, 2, 1 Launch (push) Has been cancelled
Build & Test / Build iOS app (push) Has been cancelled
Release / Prepare (push) Failing after 2s
Release / Release Cloud (push) Has been skipped
Release / Release Desktop (push) Has been skipped
Release / Release Docker Image (push) Has been skipped
Release / Release Mobile (push) Has been skipped
Copilot Test Automatically / Setup Test (push) Failing after 1s
This commit is contained in:
458
tests/affine-local/e2e/blocksuite/toolbar.spec.ts
Normal file
458
tests/affine-local/e2e/blocksuite/toolbar.spec.ts
Normal file
@@ -0,0 +1,458 @@
|
||||
import { test } from '@affine-test/kit/playwright';
|
||||
import {
|
||||
clickEdgelessModeButton,
|
||||
dragView,
|
||||
locateToolbar,
|
||||
setEdgelessTool,
|
||||
} from '@affine-test/kit/utils/editor';
|
||||
import { importImage } from '@affine-test/kit/utils/image';
|
||||
import {
|
||||
selectAllByKeyboard,
|
||||
writeTextToClipboard,
|
||||
} from '@affine-test/kit/utils/keyboard';
|
||||
import { openHomePage } from '@affine-test/kit/utils/load-page';
|
||||
import {
|
||||
clickNewPageButton,
|
||||
type,
|
||||
waitForEmptyEditor,
|
||||
} from '@affine-test/kit/utils/page-logic';
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
function hexToRGB(hex: string) {
|
||||
hex = hex.replace(/^#/, '');
|
||||
const len = hex.length;
|
||||
let arr: string[] = [];
|
||||
|
||||
if (len === 3 || len === 4) {
|
||||
arr = hex.split('').map(s => s.repeat(2));
|
||||
} else if (len === 6 || len === 8) {
|
||||
arr = Array.from<number>({ length: len / 2 })
|
||||
.fill(0)
|
||||
.map((n, i) => n + i * 2)
|
||||
.map(n => hex.substring(n, n + 2));
|
||||
}
|
||||
|
||||
const values = arr
|
||||
.map(s => parseInt(s, 16))
|
||||
.map((n, i) => (i === 3 ? (n % 255) / 255 : n));
|
||||
|
||||
return `rgb${values.length === 4 ? 'a' : ''}(${values.join(', ')})`;
|
||||
}
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await openHomePage(page);
|
||||
await clickNewPageButton(page);
|
||||
await waitForEmptyEditor(page);
|
||||
});
|
||||
|
||||
test('should toggle toolbar when dragging page area', async ({ page }) => {
|
||||
await page.keyboard.press('Enter');
|
||||
await page.keyboard.type('Roman');
|
||||
await selectAllByKeyboard(page);
|
||||
|
||||
const toolbar = locateToolbar(page);
|
||||
|
||||
await expect(toolbar).toBeVisible();
|
||||
await expect(toolbar).toBeInViewport();
|
||||
|
||||
const paragraph = page.locator('affine-note affine-paragraph').nth(0);
|
||||
const bounds = await paragraph.boundingBox();
|
||||
|
||||
expect(bounds).toBeTruthy();
|
||||
const { x, y, width } = bounds!;
|
||||
|
||||
await page.mouse.move(x + width + 10, y - 10, { steps: 2 });
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(x + width - 10, y + 10, { steps: 2 });
|
||||
|
||||
await expect(toolbar).toBeHidden();
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
await expect(toolbar).toBeVisible();
|
||||
});
|
||||
|
||||
test.describe('Formatting', () => {
|
||||
test('should change text color', async ({ page }) => {
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await page.keyboard.type('hello world');
|
||||
await page.keyboard.press('Shift+ArrowLeft');
|
||||
await page.keyboard.press('Shift+ArrowLeft');
|
||||
await page.keyboard.press('Shift+ArrowLeft');
|
||||
|
||||
const toolbar = locateToolbar(page);
|
||||
const highlightButton = toolbar.locator('affine-highlight-duotone-icon');
|
||||
|
||||
await highlightButton.click();
|
||||
|
||||
const fgGreenButton = toolbar.locator('[data-testid="foreground-green"]');
|
||||
await fgGreenButton.click();
|
||||
const fgColor = await fgGreenButton
|
||||
.locator('affine-text-duotone-icon')
|
||||
.evaluate(e => window.getComputedStyle(e).getPropertyValue('--color'));
|
||||
|
||||
const paragraph = page.locator('affine-paragraph');
|
||||
const textSpan = paragraph
|
||||
.locator('affine-text:has-text("rld")')
|
||||
.locator('span')
|
||||
.first();
|
||||
|
||||
await expect(textSpan).toBeVisible();
|
||||
|
||||
await expect(textSpan).toHaveCSS('color', hexToRGB(fgColor));
|
||||
});
|
||||
|
||||
test('should change text background color', async ({ page }) => {
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await page.keyboard.type('hello world');
|
||||
await page.keyboard.press('Shift+ArrowLeft');
|
||||
await page.keyboard.press('Shift+ArrowLeft');
|
||||
await page.keyboard.press('Shift+ArrowLeft');
|
||||
|
||||
const toolbar = locateToolbar(page);
|
||||
const highlightButton = toolbar.locator('affine-highlight-duotone-icon');
|
||||
|
||||
await highlightButton.click();
|
||||
|
||||
const fgGreenButton = toolbar.locator('[data-testid="foreground-green"]');
|
||||
await fgGreenButton.click();
|
||||
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
const fgColor = await fgGreenButton
|
||||
.locator('affine-text-duotone-icon')
|
||||
.evaluate(e => window.getComputedStyle(e).getPropertyValue('--color'));
|
||||
|
||||
const paragraph = page.locator('affine-paragraph');
|
||||
const textSpan1 = paragraph
|
||||
.locator('affine-text:has-text("rld")')
|
||||
.locator('span')
|
||||
.first();
|
||||
|
||||
await expect(textSpan1).toHaveCSS('color', hexToRGB(fgColor));
|
||||
|
||||
await page.keyboard.press('ArrowRight');
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await page.keyboard.press('Shift+ArrowLeft');
|
||||
}
|
||||
|
||||
await highlightButton.click();
|
||||
|
||||
const yellow = 'var(--affine-text-highlight-yellow)';
|
||||
const bgYellowButton = toolbar.locator('[data-testid="background-yellow"]');
|
||||
await bgYellowButton.click();
|
||||
|
||||
const textSpan2 = paragraph
|
||||
.locator('affine-text:has-text("wo")')
|
||||
.locator('span')
|
||||
.first();
|
||||
|
||||
await expect(textSpan2).toBeVisible();
|
||||
|
||||
const bgColor1 = await textSpan1.evaluate(e => e.style.backgroundColor);
|
||||
const bgColor2 = await textSpan2.evaluate(e => e.style.backgroundColor);
|
||||
|
||||
expect(yellow).toBe(bgColor1);
|
||||
expect(yellow).toBe(bgColor2);
|
||||
|
||||
const bgColor = await bgYellowButton
|
||||
.locator('affine-text-duotone-icon')
|
||||
.evaluate(e =>
|
||||
window.getComputedStyle(e).getPropertyValue('--background')
|
||||
);
|
||||
|
||||
await expect(textSpan1).toHaveCSS('background-color', hexToRGB(bgColor));
|
||||
await expect(textSpan2).toHaveCSS('background-color', hexToRGB(bgColor));
|
||||
});
|
||||
});
|
||||
|
||||
test('should not show toolbar when releasing spacebar and elements have been deleted', async ({
|
||||
page,
|
||||
}) => {
|
||||
await clickEdgelessModeButton(page);
|
||||
|
||||
await setEdgelessTool(page, 'shape');
|
||||
await dragView(page, [100, 300], [200, 400]);
|
||||
|
||||
const toolbar = locateToolbar(page);
|
||||
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
await page.keyboard.down('Space');
|
||||
|
||||
await expect(toolbar).toBeHidden();
|
||||
|
||||
await page.keyboard.up('Space');
|
||||
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
await page.keyboard.press('Delete');
|
||||
|
||||
await expect(toolbar).toBeHidden();
|
||||
|
||||
await page.keyboard.down('Space');
|
||||
|
||||
await expect(toolbar).toBeHidden();
|
||||
|
||||
await page.keyboard.up('Space');
|
||||
|
||||
await expect(toolbar).toBeHidden();
|
||||
});
|
||||
|
||||
test('should not show inner toolbar of surface-ref in note under edgeless', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.keyboard.press('Enter');
|
||||
await page.keyboard.type('/frame');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
const toolbar = locateToolbar(page);
|
||||
|
||||
const surfaceRef = page.locator('affine-surface-ref');
|
||||
await surfaceRef.hover();
|
||||
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
await clickEdgelessModeButton(page);
|
||||
|
||||
const note = page.locator('affine-edgeless-note');
|
||||
await note.click();
|
||||
await note.click();
|
||||
|
||||
const edgelessSurfaceRef = note.locator('affine-edgeless-surface-ref');
|
||||
await edgelessSurfaceRef.hover();
|
||||
|
||||
await expect(toolbar).toBeHidden();
|
||||
|
||||
const dragHandler = page.locator('.affine-drag-handle-grabber');
|
||||
await dragHandler.hover();
|
||||
await dragHandler.click();
|
||||
|
||||
await expect(
|
||||
edgelessSurfaceRef.locator('.affine-edgeless-surface-ref-container')
|
||||
).toHaveClass(/focused$/);
|
||||
|
||||
await expect(toolbar).toBeHidden();
|
||||
});
|
||||
|
||||
test('should show toolbar when inline link is preceded by image or surface-ref', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await importImage(page, 'affine-preview.png');
|
||||
|
||||
const image = page.locator('affine-image');
|
||||
await image.click();
|
||||
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
const url = new URL(page.url());
|
||||
|
||||
await writeTextToClipboard(page, url.toString());
|
||||
|
||||
const toolbar = locateToolbar(page);
|
||||
|
||||
const inlineLink = page.locator('affine-reference');
|
||||
|
||||
await inlineLink.hover();
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
await toolbar.hover();
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
await image.hover();
|
||||
await expect(toolbar).toBeVisible();
|
||||
await expect(toolbar).toHaveAttribute('data-placement', 'inner');
|
||||
|
||||
await inlineLink.hover();
|
||||
await expect(toolbar).toBeVisible();
|
||||
await expect(toolbar).not.toHaveAttribute('data-placement', 'inner');
|
||||
});
|
||||
|
||||
test('should focus on input of popover on toolbar', async ({ page }) => {
|
||||
await clickEdgelessModeButton(page);
|
||||
|
||||
const toolbar = locateToolbar(page);
|
||||
|
||||
await expect(toolbar).toBeHidden();
|
||||
|
||||
const note = page.locator('affine-edgeless-note').first();
|
||||
|
||||
await note.click();
|
||||
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
const scaleMenu = toolbar.locator('.scale-menu');
|
||||
const scaleInput = scaleMenu.locator('input');
|
||||
const scaleButton = scaleMenu.getByLabel('Scale');
|
||||
|
||||
await expect(scaleInput).toBeHidden();
|
||||
await scaleButton.click();
|
||||
|
||||
await scaleInput.click();
|
||||
await expect(scaleInput).toBeFocused();
|
||||
|
||||
await scaleInput.fill('150');
|
||||
await expect(scaleInput).toBeFocused();
|
||||
|
||||
const scaleValue = await scaleInput.inputValue();
|
||||
expect(scaleValue).toBe('150');
|
||||
|
||||
const stylePanelButton = toolbar.locator('edgeless-note-style-panel');
|
||||
const cornersInput = stylePanelButton.locator(
|
||||
'.edgeless-note-corner-radius-panel input'
|
||||
);
|
||||
|
||||
await stylePanelButton.click();
|
||||
|
||||
await cornersInput.click();
|
||||
await expect(cornersInput).toBeFocused();
|
||||
|
||||
await cornersInput.fill('36');
|
||||
await expect(cornersInput).toBeFocused();
|
||||
|
||||
const cornersValue = await cornersInput.inputValue();
|
||||
expect(cornersValue).toBe('36');
|
||||
});
|
||||
|
||||
test('Dropdown menus should be closed automatically when toolbar is displayed', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.keyboard.press('Enter');
|
||||
await page.keyboard.type('/frame');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
const toolbar = locateToolbar(page);
|
||||
|
||||
const surfaceRef = page.locator('affine-surface-ref');
|
||||
await surfaceRef.hover();
|
||||
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
const moreMenuContainer = toolbar.getByLabel('More menu');
|
||||
const moreMenuButton = moreMenuContainer.getByLabel('More');
|
||||
const moreMenu = moreMenuContainer.getByRole('menu');
|
||||
|
||||
await expect(moreMenu).toBeHidden();
|
||||
|
||||
await moreMenuButton.click();
|
||||
|
||||
await expect(moreMenu).toBeVisible();
|
||||
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
await expect(toolbar).toBeHidden();
|
||||
|
||||
await surfaceRef.hover();
|
||||
|
||||
await expect(toolbar).toBeVisible();
|
||||
await expect(moreMenu).toBeHidden();
|
||||
});
|
||||
|
||||
test('should clear selection when switching doc mode', async ({ page }) => {
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await page.keyboard.type('hello world');
|
||||
await page.keyboard.press('Shift+ArrowLeft');
|
||||
await page.keyboard.press('Shift+ArrowLeft');
|
||||
await page.keyboard.press('Shift+ArrowLeft');
|
||||
|
||||
const toolbar = locateToolbar(page);
|
||||
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
await clickEdgelessModeButton(page);
|
||||
|
||||
await expect(toolbar).toBeHidden();
|
||||
});
|
||||
|
||||
test.describe('Toolbar More Actions', () => {
|
||||
test('should copy selected text as markdown', async ({ page }) => {
|
||||
await page.keyboard.press('Enter');
|
||||
await page.keyboard.type('toolbar-copy-as-markdown');
|
||||
await selectAllByKeyboard(page);
|
||||
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
await toolbar.getByLabel('More menu').click();
|
||||
await toolbar.getByLabel('Copy as Markdown').click();
|
||||
|
||||
const clipboardText = await (
|
||||
await page.evaluateHandle(() => navigator.clipboard.readText())
|
||||
).jsonValue();
|
||||
expect(clipboardText).toContain('toolbar-copy-as-markdown');
|
||||
});
|
||||
|
||||
test('should preserve heading syntax when copying as markdown from toolbar', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.keyboard.press('Enter');
|
||||
await type(page, '# toolbar-heading');
|
||||
await selectAllByKeyboard(page);
|
||||
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
await toolbar.getByLabel('More menu').click();
|
||||
await toolbar.getByLabel('Copy as Markdown').click();
|
||||
|
||||
const clipboardText = await (
|
||||
await page.evaluateHandle(() => navigator.clipboard.readText())
|
||||
).jsonValue();
|
||||
expect(clipboardText).toContain('# toolbar-heading');
|
||||
});
|
||||
|
||||
test('should preserve bulleted list syntax when copying as markdown from toolbar', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.keyboard.press('Enter');
|
||||
await type(page, '- toolbar-list-item');
|
||||
await selectAllByKeyboard(page);
|
||||
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
await toolbar.getByLabel('More menu').click();
|
||||
await toolbar.getByLabel('Copy as Markdown').click();
|
||||
|
||||
const clipboardText = await (
|
||||
await page.evaluateHandle(() => navigator.clipboard.readText())
|
||||
).jsonValue();
|
||||
expect(clipboardText).toMatch(/^\* toolbar-list-item/m);
|
||||
});
|
||||
|
||||
test('should duplicate block', async ({ page }) => {
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await importImage(page, 'large-image.png');
|
||||
const images = page.locator('affine-page-image');
|
||||
|
||||
const firstImage = images.first();
|
||||
const firstImageUrl = await firstImage.locator('img').getAttribute('src');
|
||||
|
||||
await firstImage.hover();
|
||||
|
||||
const toolbar = locateToolbar(page);
|
||||
const moreMenu = toolbar.getByLabel('More menu');
|
||||
await moreMenu.click();
|
||||
|
||||
const duplicateButton = toolbar.getByTestId('duplicate');
|
||||
await duplicateButton.click();
|
||||
|
||||
await expect(images).toHaveCount(2);
|
||||
|
||||
const secondImage = images.nth(1);
|
||||
const secondImageUrl = await secondImage.locator('img').getAttribute('src');
|
||||
|
||||
expect(firstImageUrl).not.toBeNull();
|
||||
expect(firstImageUrl!.startsWith('blob:')).toBe(true);
|
||||
|
||||
expect(secondImageUrl).not.toBeNull();
|
||||
expect(secondImageUrl!.startsWith('blob:')).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user