mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-06 08:50:50 +08:00
chore: migrate blocksuite test (#9222)
This commit is contained in:
@@ -0,0 +1,409 @@
|
||||
import '../utils/declare-test-window.js';
|
||||
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
import {
|
||||
captureHistory,
|
||||
copyByKeyboard,
|
||||
dragBetweenCoords,
|
||||
dragOverTitle,
|
||||
enterPlaygroundRoom,
|
||||
focusRichText,
|
||||
focusTitle,
|
||||
getClipboardHTML,
|
||||
getClipboardSnapshot,
|
||||
getClipboardText,
|
||||
getCurrentEditorDocId,
|
||||
getEditorLocator,
|
||||
getPageSnapshot,
|
||||
initEmptyParagraphState,
|
||||
mockParseDocUrlService,
|
||||
pasteByKeyboard,
|
||||
pasteContent,
|
||||
pressEnter,
|
||||
pressShiftTab,
|
||||
pressTab,
|
||||
resetHistory,
|
||||
setInlineRangeInSelectedRichText,
|
||||
setSelection,
|
||||
SHORT_KEY,
|
||||
type,
|
||||
undoByClick,
|
||||
waitNextFrame,
|
||||
} from '../utils/actions/index.js';
|
||||
import {
|
||||
assertBlockTypes,
|
||||
assertClipItems,
|
||||
assertExists,
|
||||
assertRichTexts,
|
||||
assertText,
|
||||
assertTitle,
|
||||
} from '../utils/asserts.js';
|
||||
import { scoped, test } from '../utils/playwright.js';
|
||||
|
||||
test(scoped`clipboard copy paste`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
await type(page, 'test');
|
||||
await setInlineRangeInSelectedRichText(page, 0, 3);
|
||||
await waitNextFrame(page);
|
||||
await copyByKeyboard(page);
|
||||
await focusRichText(page);
|
||||
await page.keyboard.press(`${SHORT_KEY}+v`);
|
||||
await assertText(page, 'testtes');
|
||||
});
|
||||
|
||||
test(scoped`clipboard copy paste title`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusTitle(page);
|
||||
|
||||
await type(page, 'test');
|
||||
await dragOverTitle(page);
|
||||
await waitNextFrame(page);
|
||||
await copyByKeyboard(page);
|
||||
await focusTitle(page);
|
||||
await page.keyboard.press(`${SHORT_KEY}+v`);
|
||||
await assertTitle(page, 'testtest');
|
||||
});
|
||||
|
||||
test(scoped`clipboard paste html`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
// set up clipboard data using html
|
||||
const clipData = {
|
||||
'text/html': `<span>aaa</span><span>bbb</span><span>ccc</span><bdi>ddd</bdi>`,
|
||||
};
|
||||
await waitNextFrame(page);
|
||||
await page.evaluate(
|
||||
({ clipData }) => {
|
||||
const dT = new DataTransfer();
|
||||
const e = new ClipboardEvent('paste', { clipboardData: dT });
|
||||
Object.defineProperty(e, 'target', {
|
||||
writable: false,
|
||||
value: document,
|
||||
});
|
||||
e.clipboardData?.setData('text/html', clipData['text/html']);
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
{ clipData }
|
||||
);
|
||||
await assertText(page, 'aaabbbcccddd');
|
||||
});
|
||||
|
||||
test(scoped`split block when paste`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
await resetHistory(page);
|
||||
|
||||
const clipData = {
|
||||
'text/plain': `# text
|
||||
# h1
|
||||
`,
|
||||
};
|
||||
await type(page, 'abc');
|
||||
await captureHistory(page);
|
||||
|
||||
await setInlineRangeInSelectedRichText(page, 1, 1);
|
||||
await pasteContent(page, clipData);
|
||||
await waitNextFrame(page);
|
||||
|
||||
await assertRichTexts(page, ['atext', 'h1c']);
|
||||
|
||||
await undoByClick(page);
|
||||
await assertRichTexts(page, ['abc']);
|
||||
|
||||
await type(page, 'aa');
|
||||
await pressEnter(page);
|
||||
await type(page, 'bb');
|
||||
const topLeft123 = await getEditorLocator(page)
|
||||
.locator('[data-block-id="2"] .inline-editor')
|
||||
.boundingBox();
|
||||
const bottomRight789 = await getEditorLocator(page)
|
||||
.locator('[data-block-id="4"] .inline-editor')
|
||||
.boundingBox();
|
||||
assertExists(topLeft123);
|
||||
assertExists(bottomRight789);
|
||||
await dragBetweenCoords(page, topLeft123, bottomRight789);
|
||||
|
||||
// FIXME see https://github.com/toeverything/blocksuite/pull/878
|
||||
// await pasteContent(page, clipData);
|
||||
// await assertRichTexts(page, ['aaa', 'bbc', 'text', 'h1']);
|
||||
});
|
||||
|
||||
test(scoped`copy clipItems format`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
await captureHistory(page);
|
||||
|
||||
const clipData = `
|
||||
- aa
|
||||
- bb
|
||||
- cc
|
||||
- dd
|
||||
`;
|
||||
|
||||
await pasteContent(page, { 'text/plain': clipData });
|
||||
await page.waitForTimeout(100);
|
||||
await setSelection(page, 4, 1, 5, 1);
|
||||
assertClipItems(page, 'text/plain', 'bc');
|
||||
assertClipItems(page, 'text/html', '<ul><li>b<ul><li>c</li></ul></li></ul>');
|
||||
await undoByClick(page);
|
||||
await assertRichTexts(page, ['']);
|
||||
});
|
||||
|
||||
test(scoped`copy partially selected text`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
await type(page, '123 456 789');
|
||||
|
||||
// select 456
|
||||
await setInlineRangeInSelectedRichText(page, 4, 3);
|
||||
await copyByKeyboard(page);
|
||||
assertClipItems(page, 'text/plain', '456');
|
||||
|
||||
// move to line end
|
||||
await setInlineRangeInSelectedRichText(page, 11, 0);
|
||||
await pressEnter(page);
|
||||
await pasteByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
|
||||
await assertRichTexts(page, ['123 456 789', '456']);
|
||||
});
|
||||
|
||||
test(scoped`copy & paste outside editor`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await page.evaluate(() => {
|
||||
const input = document.createElement('input');
|
||||
input.setAttribute('id', 'input-test');
|
||||
input.value = '123';
|
||||
document.body.querySelector('#app')?.append(input);
|
||||
});
|
||||
await page.focus('#input-test');
|
||||
await page.dblclick('#input-test');
|
||||
await copyByKeyboard(page);
|
||||
await focusRichText(page);
|
||||
await pasteByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
await assertRichTexts(page, ['123']);
|
||||
});
|
||||
|
||||
test('should keep first line format when pasted into a new line', async ({
|
||||
page,
|
||||
}) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
const clipData = `
|
||||
- [ ] aaa
|
||||
`;
|
||||
|
||||
await pasteContent(page, { 'text/plain': clipData });
|
||||
await waitNextFrame(page);
|
||||
await assertRichTexts(page, ['aaa']);
|
||||
await assertBlockTypes(page, ['todo']);
|
||||
});
|
||||
|
||||
test(scoped`auto identify url`, async ({ page }, testInfo) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
// set up clipboard data using html
|
||||
const clipData = {
|
||||
'text/plain': `test https://www.google.com`,
|
||||
};
|
||||
await waitNextFrame(page);
|
||||
await page.evaluate(
|
||||
({ clipData }) => {
|
||||
const dT = new DataTransfer();
|
||||
const e = new ClipboardEvent('paste', { clipboardData: dT });
|
||||
Object.defineProperty(e, 'target', {
|
||||
writable: false,
|
||||
value: document,
|
||||
});
|
||||
e.clipboardData?.setData('text/plain', clipData['text/plain']);
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
{ clipData }
|
||||
);
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_final.json`
|
||||
);
|
||||
});
|
||||
|
||||
test(scoped`pasting internal url`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusTitle(page);
|
||||
await type(page, 'test page');
|
||||
|
||||
await focusRichText(page);
|
||||
const docId = await getCurrentEditorDocId(page);
|
||||
await mockParseDocUrlService(page, {
|
||||
'http://workspace/doc-id': docId,
|
||||
});
|
||||
await pasteContent(page, {
|
||||
'text/plain': 'http://workspace/doc-id',
|
||||
});
|
||||
await expect(page.locator('affine-reference')).toContainText('test page');
|
||||
});
|
||||
|
||||
test(scoped`pasting internal url with params`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusTitle(page);
|
||||
await type(page, 'test page');
|
||||
|
||||
await focusRichText(page);
|
||||
const docId = await getCurrentEditorDocId(page);
|
||||
await mockParseDocUrlService(page, {
|
||||
'http://workspace/doc-id?mode=page&blockIds=rL2_GXbtLU2SsJVfCSmh_': docId,
|
||||
});
|
||||
await pasteContent(page, {
|
||||
'text/plain':
|
||||
'http://workspace/doc-id?mode=page&blockIds=rL2_GXbtLU2SsJVfCSmh_',
|
||||
});
|
||||
await expect(page.locator('affine-reference')).toContainText('test page');
|
||||
});
|
||||
|
||||
test(
|
||||
scoped`pasting an external URL from clipboard to automatically creating a link from selection`,
|
||||
async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusTitle(page);
|
||||
await type(page, 'test page');
|
||||
|
||||
await focusRichText(page);
|
||||
await type(page, 'title alias');
|
||||
await setSelection(page, 1, 6, 1, 11);
|
||||
|
||||
await pasteContent(page, {
|
||||
'text/plain': 'https://affine.pro/',
|
||||
});
|
||||
await expect(page.locator('affine-link')).toContainText('alias');
|
||||
}
|
||||
);
|
||||
|
||||
test(
|
||||
scoped`pasting an internal URL from clipboard to automatically creating a link from selection`,
|
||||
async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusTitle(page);
|
||||
await type(page, 'test page');
|
||||
|
||||
await focusRichText(page);
|
||||
await type(page, 'title alias');
|
||||
await setSelection(page, 1, 6, 1, 11);
|
||||
|
||||
const docId = await getCurrentEditorDocId(page);
|
||||
await mockParseDocUrlService(page, {
|
||||
'http://workspace/doc-id': docId,
|
||||
});
|
||||
await pasteContent(page, {
|
||||
'text/plain': 'http://workspace/doc-id',
|
||||
});
|
||||
await expect(page.locator('affine-reference')).toContainText('alias');
|
||||
}
|
||||
);
|
||||
|
||||
test(scoped`paste parent block`, async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/toeverything/blocksuite/issues/3153',
|
||||
});
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
await type(page, 'This is parent');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.keyboard.press('Tab');
|
||||
await type(page, 'This is child 1');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.keyboard.press('Tab');
|
||||
await type(page, 'This is child 2');
|
||||
await setInlineRangeInSelectedRichText(page, 0, 3);
|
||||
await copyByKeyboard(page);
|
||||
await focusRichText(page, 2);
|
||||
await page.keyboard.press(`${SHORT_KEY}+v`);
|
||||
await assertRichTexts(page, [
|
||||
'This is parent',
|
||||
'This is child 1',
|
||||
'This is child 2Thi',
|
||||
]);
|
||||
});
|
||||
|
||||
test(scoped`clipboard copy multi selection`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
await type(page, 'abc');
|
||||
await pressEnter(page);
|
||||
await type(page, 'def');
|
||||
await setSelection(page, 2, 1, 3, 1);
|
||||
await waitNextFrame(page);
|
||||
await copyByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
await focusRichText(page, 1);
|
||||
await pasteByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
await type(page, 'cursor');
|
||||
await waitNextFrame(page);
|
||||
await assertRichTexts(page, ['abc', 'defbc', 'dcursor']);
|
||||
});
|
||||
|
||||
test(scoped`clipboard copy nested items`, async ({ page }, testInfo) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
await type(page, 'abc');
|
||||
await pressEnter(page);
|
||||
await pressTab(page);
|
||||
await type(page, 'def');
|
||||
await pressEnter(page);
|
||||
await pressTab(page);
|
||||
await type(page, 'ghi');
|
||||
await pressEnter(page);
|
||||
await pressShiftTab(page);
|
||||
await pressShiftTab(page);
|
||||
await type(page, 'jkl');
|
||||
await setSelection(page, 2, 1, 3, 1);
|
||||
await waitNextFrame(page);
|
||||
await copyByKeyboard(page);
|
||||
|
||||
const text = await getClipboardText(page);
|
||||
const html = await getClipboardHTML(page);
|
||||
const snapshot = await getClipboardSnapshot(page);
|
||||
expect(text).toMatchSnapshot(`${testInfo.title}-clipboard.md`);
|
||||
expect(JSON.stringify(snapshot.snapshot.content, null, 2)).toMatchSnapshot(
|
||||
`${testInfo.title}-clipboard.json`
|
||||
);
|
||||
expect(html).toMatchSnapshot(`${testInfo.title}-clipboard.html`);
|
||||
|
||||
await setSelection(page, 4, 1, 5, 1);
|
||||
await waitNextFrame(page);
|
||||
await copyByKeyboard(page);
|
||||
|
||||
const text2 = await getClipboardText(page);
|
||||
const html2 = await getClipboardHTML(page);
|
||||
const snapshot2 = await getClipboardSnapshot(page);
|
||||
expect(text2).toMatchSnapshot(`${testInfo.title}-clipboard2.md`);
|
||||
expect(JSON.stringify(snapshot2.snapshot.content, null, 2)).toMatchSnapshot(
|
||||
`${testInfo.title}-clipboard2.json`
|
||||
);
|
||||
expect(html2).toMatchSnapshot(`${testInfo.title}-clipboard2.html`);
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
import {
|
||||
enterPlaygroundRoom,
|
||||
focusRichText,
|
||||
initEmptyParagraphState,
|
||||
pasteContent,
|
||||
pressArrowDown,
|
||||
pressArrowUp,
|
||||
pressEscape,
|
||||
waitEmbedLoaded,
|
||||
} from '../utils/actions/index.js';
|
||||
import { assertRichImage, assertText } from '../utils/asserts.js';
|
||||
import { scoped, test } from '../utils/playwright.js';
|
||||
|
||||
test(
|
||||
scoped`clipboard paste end with image, the cursor should be controlled by up/down keys`,
|
||||
async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/toeverything/blocksuite/issues/3639',
|
||||
});
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
// set up clipboard data using html
|
||||
const clipData = {
|
||||
'text/html': `<p>Lorem Ipsum placeholder text.</p>
|
||||
<figure ><img src='https://placehold.co/600x400' /></figure>
|
||||
`,
|
||||
};
|
||||
await page.evaluate(
|
||||
({ clipData }) => {
|
||||
const dT = new DataTransfer();
|
||||
const e = new ClipboardEvent('paste', { clipboardData: dT });
|
||||
Object.defineProperty(e, 'target', {
|
||||
writable: false,
|
||||
value: document,
|
||||
});
|
||||
e.clipboardData?.setData('text/html', clipData['text/html']);
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
{ clipData }
|
||||
);
|
||||
const str = 'Lorem Ipsum placeholder text.';
|
||||
await waitEmbedLoaded(page);
|
||||
await assertRichImage(page, 1);
|
||||
await pressEscape(page);
|
||||
await pressArrowUp(page, 1);
|
||||
await pasteContent(page, clipData);
|
||||
await assertRichImage(page, 2);
|
||||
await assertText(page, str + str);
|
||||
await pressArrowDown(page, 1);
|
||||
await pressEscape(page);
|
||||
await pasteContent(page, clipData);
|
||||
await assertRichImage(page, 3);
|
||||
await assertText(page, 'Lorem Ipsum placeholder text.', 1);
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,714 @@
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
import { initDatabaseColumn } from '../database/actions.js';
|
||||
import {
|
||||
activeNoteInEdgeless,
|
||||
changeEdgelessNoteBackground,
|
||||
copyByKeyboard,
|
||||
createShapeElement,
|
||||
cutByKeyboard,
|
||||
dragBetweenCoords,
|
||||
enterPlaygroundRoom,
|
||||
focusRichText,
|
||||
getAllNoteIds,
|
||||
getClipboardHTML,
|
||||
getClipboardSnapshot,
|
||||
getClipboardText,
|
||||
getEdgelessSelectedRectModel,
|
||||
getInlineSelectionIndex,
|
||||
getInlineSelectionText,
|
||||
getPageSnapshot,
|
||||
getRichTextBoundingBox,
|
||||
initDatabaseDynamicRowWithData,
|
||||
initEmptyDatabaseWithParagraphState,
|
||||
initEmptyEdgelessState,
|
||||
initEmptyParagraphState,
|
||||
initThreeParagraphs,
|
||||
pasteByKeyboard,
|
||||
pasteContent,
|
||||
pressArrowLeft,
|
||||
pressArrowRight,
|
||||
pressEnter,
|
||||
pressEscape,
|
||||
pressShiftTab,
|
||||
pressSpace,
|
||||
pressTab,
|
||||
selectAllByKeyboard,
|
||||
selectNoteInEdgeless,
|
||||
setInlineRangeInSelectedRichText,
|
||||
SHORT_KEY,
|
||||
switchEditorMode,
|
||||
toViewCoord,
|
||||
triggerComponentToolbarAction,
|
||||
type,
|
||||
undoByKeyboard,
|
||||
waitForInlineEditorStateUpdated,
|
||||
waitNextFrame,
|
||||
} from '../utils/actions/index.js';
|
||||
import {
|
||||
assertBlockTypes,
|
||||
assertEdgelessNoteBackground,
|
||||
assertEdgelessSelectedModelRect,
|
||||
assertExists,
|
||||
assertRichTextModelType,
|
||||
assertRichTexts,
|
||||
assertStoreMatchJSX,
|
||||
assertText,
|
||||
} from '../utils/asserts.js';
|
||||
import { scoped, test } from '../utils/playwright.js';
|
||||
|
||||
test('paste a non-nested list to a non-nested list', async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
const clipData = {
|
||||
'text/plain': `
|
||||
- a
|
||||
`,
|
||||
};
|
||||
await type(page, '-');
|
||||
await pressSpace(page);
|
||||
await type(page, '123');
|
||||
await page.keyboard.press('Control+ArrowLeft');
|
||||
|
||||
// paste on start
|
||||
await waitNextFrame(page);
|
||||
await pasteContent(page, clipData);
|
||||
await pressArrowLeft(page);
|
||||
await assertRichTexts(page, ['a123']);
|
||||
|
||||
// paste in middle
|
||||
await pressArrowRight(page, 2);
|
||||
await pasteContent(page, clipData);
|
||||
await pressArrowRight(page);
|
||||
await assertRichTexts(page, ['a1a23']);
|
||||
|
||||
// paste on end
|
||||
await pressArrowRight(page);
|
||||
await pasteContent(page, clipData);
|
||||
await waitNextFrame(page);
|
||||
await assertRichTexts(page, ['a1a23a']);
|
||||
|
||||
await assertBlockTypes(page, ['bulleted']);
|
||||
});
|
||||
|
||||
test('copy a nested list by clicking button, the clipboard data should be complete', async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
const clipData = {
|
||||
'text/plain': `
|
||||
- aaa
|
||||
- bbb
|
||||
- ccc
|
||||
`,
|
||||
};
|
||||
await pasteContent(page, clipData);
|
||||
|
||||
const rootListBound = await page.locator('affine-list').first().boundingBox();
|
||||
assertExists(rootListBound);
|
||||
|
||||
// use drag element to test.
|
||||
await dragBetweenCoords(
|
||||
page,
|
||||
{ x: rootListBound.x + 1, y: rootListBound.y - 1 },
|
||||
{ x: rootListBound.x + 1, y: rootListBound.y + rootListBound.height - 1 }
|
||||
);
|
||||
await copyByKeyboard(page);
|
||||
|
||||
const text = await getClipboardText(page);
|
||||
const html = await getClipboardHTML(page);
|
||||
const snapshot = await getClipboardSnapshot(page);
|
||||
expect(text).toMatchSnapshot(`${testInfo.title}-clipboard.md`);
|
||||
expect(JSON.stringify(snapshot.snapshot.content, null, 2)).toMatchSnapshot(
|
||||
`${testInfo.title}-clipboard.json`
|
||||
);
|
||||
expect(html).toMatchSnapshot(`${testInfo.title}-clipboard.html`);
|
||||
});
|
||||
|
||||
test('paste a nested list to a nested list', async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
const clipData = {
|
||||
'text/plain': `
|
||||
- aaa
|
||||
- bbb
|
||||
- ccc
|
||||
`,
|
||||
};
|
||||
await pasteContent(page, clipData);
|
||||
await focusRichText(page, 1);
|
||||
|
||||
// paste on start
|
||||
await page.keyboard.press('Control+ArrowLeft');
|
||||
|
||||
/**
|
||||
* - aaa
|
||||
* - |bbb
|
||||
* - ccc
|
||||
*/
|
||||
await pasteContent(page, clipData);
|
||||
/**
|
||||
* - aaa
|
||||
* - aaa
|
||||
* - bbb
|
||||
* - ccc|bbb
|
||||
* -ccc
|
||||
*/
|
||||
|
||||
await assertRichTexts(page, ['aaa', 'aaa', 'bbb', 'cccbbb', 'ccc']);
|
||||
expect(await getInlineSelectionText(page)).toEqual('cccbbb');
|
||||
expect(await getInlineSelectionIndex(page)).toEqual(3);
|
||||
|
||||
// paste in middle
|
||||
await undoByKeyboard(page);
|
||||
await pressArrowRight(page);
|
||||
|
||||
/**
|
||||
* - aaa
|
||||
* - b|bb
|
||||
* - ccc
|
||||
*/
|
||||
await pasteContent(page, clipData);
|
||||
/**
|
||||
* - aaa
|
||||
* - baaa
|
||||
* - bbb
|
||||
* - ccc|bb
|
||||
* - ccc
|
||||
*/
|
||||
|
||||
await assertRichTexts(page, ['aaa', 'baaa', 'bbb', 'cccbb', 'ccc']);
|
||||
expect(await getInlineSelectionText(page)).toEqual('cccbb');
|
||||
expect(await getInlineSelectionIndex(page)).toEqual(3);
|
||||
|
||||
// paste on end
|
||||
await undoByKeyboard(page);
|
||||
await page.keyboard.press('Control+ArrowRight');
|
||||
|
||||
/**
|
||||
* - aaa
|
||||
* - bbb|
|
||||
* - ccc
|
||||
*/
|
||||
await pasteContent(page, clipData);
|
||||
/**
|
||||
* - aaa
|
||||
* - bbbaaa
|
||||
* - bbb
|
||||
* - ccc|
|
||||
* - ccc
|
||||
*/
|
||||
|
||||
await assertRichTexts(page, ['aaa', 'bbbaaa', 'bbb', 'ccc', 'ccc']);
|
||||
expect(await getInlineSelectionText(page)).toEqual('ccc');
|
||||
expect(await getInlineSelectionIndex(page)).toEqual(3);
|
||||
});
|
||||
|
||||
test('paste nested lists to a nested list', async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
const clipData = {
|
||||
'text/plain': `
|
||||
- aaa
|
||||
- bbb
|
||||
- ccc
|
||||
`,
|
||||
};
|
||||
await pasteContent(page, clipData);
|
||||
await focusRichText(page, 1);
|
||||
|
||||
const clipData2 = {
|
||||
'text/plain': `
|
||||
- 111
|
||||
- 222
|
||||
- 111
|
||||
- 222
|
||||
`,
|
||||
};
|
||||
|
||||
// paste on start
|
||||
await page.keyboard.press('Control+ArrowLeft');
|
||||
|
||||
/**
|
||||
* - aaa
|
||||
* - |bbb
|
||||
* - ccc
|
||||
*/
|
||||
await pasteContent(page, clipData2);
|
||||
/**
|
||||
* - aaa
|
||||
* - 111
|
||||
* - 222
|
||||
* - 111
|
||||
* - 222|bbb
|
||||
* - ccc
|
||||
*/
|
||||
|
||||
await assertRichTexts(page, ['aaa', '111', '222', '111', '222bbb', 'ccc']);
|
||||
expect(await getInlineSelectionText(page)).toEqual('222bbb');
|
||||
expect(await getInlineSelectionIndex(page)).toEqual(3);
|
||||
|
||||
// paste in middle
|
||||
await undoByKeyboard(page);
|
||||
await pressArrowRight(page);
|
||||
|
||||
/**
|
||||
* - aaa
|
||||
* - b|bb
|
||||
* - ccc
|
||||
*/
|
||||
await pasteContent(page, clipData2);
|
||||
/**
|
||||
* - aaa
|
||||
* - b111
|
||||
* - 222
|
||||
* - 111
|
||||
* - 222|bb
|
||||
* - ccc
|
||||
*/
|
||||
|
||||
await assertRichTexts(page, ['aaa', 'b111', '222', '111', '222bb', 'ccc']);
|
||||
expect(await getInlineSelectionText(page)).toEqual('222bb');
|
||||
expect(await getInlineSelectionIndex(page)).toEqual(3);
|
||||
|
||||
// paste on end
|
||||
await undoByKeyboard(page);
|
||||
await page.keyboard.press('Control+ArrowRight');
|
||||
|
||||
/**
|
||||
* - aaa
|
||||
* - bbb|
|
||||
* - ccc
|
||||
*/
|
||||
await pasteContent(page, clipData2);
|
||||
/**
|
||||
* - aaa
|
||||
* - bbb111
|
||||
* - 222
|
||||
* - 111
|
||||
* - 222|
|
||||
* - ccc
|
||||
*/
|
||||
|
||||
await assertRichTexts(page, ['aaa', 'bbb111', '222', '111', '222', 'ccc']);
|
||||
expect(await getInlineSelectionText(page)).toEqual('222');
|
||||
expect(await getInlineSelectionIndex(page)).toEqual(3);
|
||||
});
|
||||
|
||||
test('paste non-nested lists to a nested list', async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
const clipData = {
|
||||
'text/plain': `
|
||||
- aaa
|
||||
- bbb
|
||||
`,
|
||||
};
|
||||
await pasteContent(page, clipData);
|
||||
await focusRichText(page, 0);
|
||||
|
||||
const clipData2 = {
|
||||
'text/plain': `
|
||||
- 123
|
||||
- 456
|
||||
`,
|
||||
};
|
||||
|
||||
// paste on start
|
||||
await page.keyboard.press('Control+ArrowLeft');
|
||||
|
||||
/**
|
||||
* - |aaa
|
||||
* - bbb
|
||||
*/
|
||||
await pasteContent(page, clipData2);
|
||||
/**
|
||||
* - 123
|
||||
* - 456|aaa
|
||||
* - bbb
|
||||
*/
|
||||
|
||||
await assertRichTexts(page, ['123', '456aaa', 'bbb']);
|
||||
expect(await getInlineSelectionText(page)).toEqual('456aaa');
|
||||
expect(await getInlineSelectionIndex(page)).toEqual(3);
|
||||
});
|
||||
|
||||
test(scoped`cut should work for multi-block selection`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
await type(page, 'a');
|
||||
await pressEnter(page);
|
||||
await type(page, 'b');
|
||||
await pressEnter(page);
|
||||
await type(page, 'c');
|
||||
await selectAllByKeyboard(page);
|
||||
await selectAllByKeyboard(page);
|
||||
await selectAllByKeyboard(page);
|
||||
await cutByKeyboard(page);
|
||||
await page.locator('.affine-page-viewport').click();
|
||||
await waitNextFrame(page);
|
||||
await assertText(page, '');
|
||||
});
|
||||
|
||||
test(
|
||||
scoped`pasting into empty list should not convert the list into paragraph`,
|
||||
async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
await type(page, 'test');
|
||||
await setInlineRangeInSelectedRichText(page, 0, 4);
|
||||
await copyByKeyboard(page);
|
||||
await type(page, '- ');
|
||||
await page.keyboard.press(`${SHORT_KEY}+v`);
|
||||
await assertRichTexts(page, ['test']);
|
||||
await assertRichTextModelType(page, 'bulleted');
|
||||
}
|
||||
);
|
||||
|
||||
test('cut will delete all content, and copy will reappear content', async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
await type(page, '-');
|
||||
await pressSpace(page);
|
||||
await type(page, '1');
|
||||
await pressEnter(page);
|
||||
await pressTab(page);
|
||||
await type(page, '2');
|
||||
await pressEnter(page);
|
||||
await type(page, '3');
|
||||
await pressEnter(page);
|
||||
await pressShiftTab(page);
|
||||
await type(page, '4');
|
||||
|
||||
const box123 = await getRichTextBoundingBox(page, '1');
|
||||
const inside123 = { x: box123.left + 1, y: box123.top + 1 };
|
||||
|
||||
const box789 = await getRichTextBoundingBox(page, '6');
|
||||
const inside789 = { x: box789.right - 1, y: box789.bottom - 1 };
|
||||
// from top to bottom
|
||||
await dragBetweenCoords(page, inside123, inside789);
|
||||
|
||||
await cutByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_after-cut.json`
|
||||
);
|
||||
await waitNextFrame(page);
|
||||
await focusRichText(page);
|
||||
|
||||
await pasteByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_after-paste.json`
|
||||
);
|
||||
});
|
||||
|
||||
test(scoped`should copy and paste of database work`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyDatabaseWithParagraphState(page);
|
||||
|
||||
// init database columns and rows
|
||||
await initDatabaseColumn(page);
|
||||
await initDatabaseDynamicRowWithData(page, 'abc', true);
|
||||
await pressEscape(page);
|
||||
await focusRichText(page, 1);
|
||||
await selectAllByKeyboard(page);
|
||||
await selectAllByKeyboard(page);
|
||||
await copyByKeyboard(page);
|
||||
await pressEnter(page);
|
||||
await pasteByKeyboard(page);
|
||||
await page.waitForTimeout(100);
|
||||
|
||||
await assertStoreMatchJSX(
|
||||
page,
|
||||
/*xml*/ `
|
||||
<affine:page>
|
||||
<affine:note
|
||||
prop:background="--affine-note-background-white"
|
||||
prop:displayMode="both"
|
||||
prop:edgeless={
|
||||
Object {
|
||||
"style": Object {
|
||||
"borderRadius": 8,
|
||||
"borderSize": 4,
|
||||
"borderStyle": "none",
|
||||
"shadowType": "--affine-note-shadow-box",
|
||||
},
|
||||
}
|
||||
}
|
||||
prop:hidden={false}
|
||||
prop:index="a0"
|
||||
prop:lockedBySelf={false}
|
||||
>
|
||||
<affine:database
|
||||
prop:columns="Array [2]"
|
||||
prop:title="Database 1"
|
||||
prop:views="Array [1]"
|
||||
>
|
||||
<affine:paragraph
|
||||
prop:collapsed={false}
|
||||
prop:type="text"
|
||||
/>
|
||||
</affine:database>
|
||||
<affine:database
|
||||
prop:columns="Array [2]"
|
||||
prop:title="Database 1"
|
||||
prop:views="Array [1]"
|
||||
>
|
||||
<affine:paragraph
|
||||
prop:collapsed={false}
|
||||
prop:type="text"
|
||||
/>
|
||||
</affine:database>
|
||||
<affine:paragraph
|
||||
prop:collapsed={false}
|
||||
prop:type="text"
|
||||
/>
|
||||
</affine:note>
|
||||
</affine:page>`
|
||||
);
|
||||
|
||||
await undoByKeyboard(page);
|
||||
await assertStoreMatchJSX(
|
||||
page,
|
||||
/*xml*/ `
|
||||
<affine:page>
|
||||
<affine:note
|
||||
prop:background="--affine-note-background-white"
|
||||
prop:displayMode="both"
|
||||
prop:edgeless={
|
||||
Object {
|
||||
"style": Object {
|
||||
"borderRadius": 8,
|
||||
"borderSize": 4,
|
||||
"borderStyle": "none",
|
||||
"shadowType": "--affine-note-shadow-box",
|
||||
},
|
||||
}
|
||||
}
|
||||
prop:hidden={false}
|
||||
prop:index="a0"
|
||||
prop:lockedBySelf={false}
|
||||
>
|
||||
<affine:database
|
||||
prop:columns="Array [2]"
|
||||
prop:title="Database 1"
|
||||
prop:views="Array [1]"
|
||||
>
|
||||
<affine:paragraph
|
||||
prop:collapsed={false}
|
||||
prop:type="text"
|
||||
/>
|
||||
</affine:database>
|
||||
<affine:paragraph
|
||||
prop:collapsed={false}
|
||||
prop:type="text"
|
||||
/>
|
||||
</affine:note>
|
||||
</affine:page>`
|
||||
);
|
||||
});
|
||||
|
||||
test(`copy canvas element and text note in edgeless mode`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyEdgelessState(page);
|
||||
await switchEditorMode(page);
|
||||
await initThreeParagraphs(page);
|
||||
await createShapeElement(page, [0, 0], [100, 100]);
|
||||
await selectAllByKeyboard(page);
|
||||
const bound = await getEdgelessSelectedRectModel(page);
|
||||
await copyByKeyboard(page);
|
||||
const coord = await toViewCoord(page, [
|
||||
bound[0] + bound[2] / 2,
|
||||
bound[1] + bound[3] / 2 + 200,
|
||||
]);
|
||||
await page.mouse.move(coord[0], coord[1]);
|
||||
await page.waitForTimeout(300);
|
||||
await pasteByKeyboard(page, false);
|
||||
bound[1] = bound[1] + 200;
|
||||
await assertEdgelessSelectedModelRect(page, bound);
|
||||
});
|
||||
|
||||
test(scoped`copy when text note active in edgeless`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
const ids = await initEmptyEdgelessState(page);
|
||||
await focusRichText(page);
|
||||
await type(page, '1234');
|
||||
|
||||
await switchEditorMode(page);
|
||||
|
||||
await activeNoteInEdgeless(page, ids.noteId);
|
||||
await waitForInlineEditorStateUpdated(page);
|
||||
await setInlineRangeInSelectedRichText(page, 0, 4);
|
||||
await copyByKeyboard(page);
|
||||
await pressArrowRight(page);
|
||||
await type(page, '555');
|
||||
await pasteByKeyboard(page, false);
|
||||
await assertText(page, '12345551234');
|
||||
});
|
||||
|
||||
test(scoped`paste note block with background`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
const ids = await initEmptyEdgelessState(page);
|
||||
await focusRichText(page);
|
||||
await type(page, '1234');
|
||||
|
||||
await switchEditorMode(page);
|
||||
await selectNoteInEdgeless(page, ids.noteId);
|
||||
|
||||
await triggerComponentToolbarAction(page, 'changeNoteColor');
|
||||
const color = '--affine-note-background-grey';
|
||||
await changeEdgelessNoteBackground(page, color);
|
||||
await assertEdgelessNoteBackground(page, ids.noteId, color);
|
||||
|
||||
await copyByKeyboard(page);
|
||||
|
||||
await page.mouse.move(0, 0);
|
||||
await pasteByKeyboard(page, false);
|
||||
const noteIds = await getAllNoteIds(page);
|
||||
for (const noteId of noteIds) {
|
||||
await assertEdgelessNoteBackground(page, noteId, color);
|
||||
}
|
||||
});
|
||||
|
||||
test(scoped`copy and paste to selection block selection`, async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/toeverything/blocksuite/issues/2265',
|
||||
});
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
await type(page, '1234');
|
||||
|
||||
await selectAllByKeyboard(page);
|
||||
await copyByKeyboard(page);
|
||||
await pressArrowRight(page);
|
||||
await pasteByKeyboard(page, false);
|
||||
await waitNextFrame(page);
|
||||
await assertRichTexts(page, ['12341234']);
|
||||
});
|
||||
|
||||
test(
|
||||
scoped`should keep paragraph block's type when pasting at the start of empty paragraph block except type text`,
|
||||
async ({ page }, testInfo) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/toeverything/blocksuite/issues/2336',
|
||||
});
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
await focusRichText(page);
|
||||
await type(page, '>');
|
||||
await page.keyboard.press('Space', { delay: 50 });
|
||||
|
||||
await page.evaluate(() => {
|
||||
const input = document.createElement('input');
|
||||
input.setAttribute('id', 'input-test');
|
||||
input.value = '123';
|
||||
document.body.querySelector('#app')?.append(input);
|
||||
});
|
||||
await page.focus('#input-test');
|
||||
await page.dblclick('#input-test');
|
||||
await copyByKeyboard(page);
|
||||
await focusRichText(page);
|
||||
await pasteByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_after-paste-1.json`
|
||||
);
|
||||
|
||||
await pressEnter(page);
|
||||
await waitNextFrame(page);
|
||||
await pressEnter(page);
|
||||
await waitNextFrame(page);
|
||||
await pasteByKeyboard(page, false);
|
||||
await waitNextFrame(page);
|
||||
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_after-paste-2.json`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
test(scoped`paste from FeiShu list format`, async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/toeverything/blocksuite/issues/2438',
|
||||
});
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
// set up clipboard data using html
|
||||
const clipData = {
|
||||
'text/html': `<div><li><div><span>aaaa</span></div></li></div>`,
|
||||
};
|
||||
await waitNextFrame(page);
|
||||
await page.evaluate(
|
||||
({ clipData }) => {
|
||||
const dT = new DataTransfer();
|
||||
const e = new ClipboardEvent('paste', { clipboardData: dT });
|
||||
Object.defineProperty(e, 'target', {
|
||||
writable: false,
|
||||
value: document,
|
||||
});
|
||||
e.clipboardData?.setData('text/html', clipData['text/html']);
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
{ clipData }
|
||||
);
|
||||
await assertText(page, 'aaaa');
|
||||
await assertBlockTypes(page, ['bulleted']);
|
||||
});
|
||||
|
||||
test(scoped`paste in list format`, async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/toeverything/blocksuite/issues/2281',
|
||||
});
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
await type(page, '- test');
|
||||
await focusRichText(page);
|
||||
|
||||
const clipData = {
|
||||
'text/html': `<ul><li>111<ul><li>222</li></ul></li></ul>`,
|
||||
};
|
||||
await waitNextFrame(page);
|
||||
await page.evaluate(
|
||||
({ clipData }) => {
|
||||
const dT = new DataTransfer();
|
||||
const e = new ClipboardEvent('paste', { clipboardData: dT });
|
||||
Object.defineProperty(e, 'target', {
|
||||
writable: false,
|
||||
value: document,
|
||||
});
|
||||
e.clipboardData?.setData('text/html', clipData['text/html']);
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
{ clipData }
|
||||
);
|
||||
await assertRichTexts(page, ['test111', '222']);
|
||||
});
|
||||
@@ -0,0 +1,170 @@
|
||||
import {
|
||||
enterPlaygroundRoom,
|
||||
focusRichText,
|
||||
initEmptyParagraphState,
|
||||
pasteContent,
|
||||
resetHistory,
|
||||
undoByClick,
|
||||
waitEmbedLoaded,
|
||||
waitNextFrame,
|
||||
} from '../utils/actions/index.js';
|
||||
import {
|
||||
assertBlockTypes,
|
||||
assertRichImage,
|
||||
assertRichTexts,
|
||||
assertTextFormats,
|
||||
} from '../utils/asserts.js';
|
||||
import { scoped, test } from '../utils/playwright.js';
|
||||
|
||||
test(scoped`markdown format parse`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
await resetHistory(page);
|
||||
|
||||
let clipData = {
|
||||
'text/plain': `# h1
|
||||
|
||||
## h2
|
||||
|
||||
### h3
|
||||
|
||||
#### h4
|
||||
|
||||
##### h5
|
||||
|
||||
###### h6
|
||||
|
||||
- [ ] todo
|
||||
|
||||
- [ ] todo
|
||||
|
||||
- [x] todo
|
||||
|
||||
* bulleted
|
||||
|
||||
- bulleted
|
||||
|
||||
1. numbered
|
||||
|
||||
> quote
|
||||
`,
|
||||
};
|
||||
await waitNextFrame(page);
|
||||
await pasteContent(page, clipData);
|
||||
await page.waitForTimeout(200);
|
||||
await assertBlockTypes(page, [
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'todo',
|
||||
'todo',
|
||||
'todo',
|
||||
'bulleted',
|
||||
'bulleted',
|
||||
'numbered',
|
||||
'quote',
|
||||
]);
|
||||
await assertRichTexts(page, [
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'todo',
|
||||
'todo',
|
||||
'todo',
|
||||
'bulleted',
|
||||
'bulleted',
|
||||
'numbered',
|
||||
'quote',
|
||||
]);
|
||||
await undoByClick(page);
|
||||
await assertRichTexts(page, ['']);
|
||||
await focusRichText(page);
|
||||
|
||||
clipData = {
|
||||
'text/plain': `# ***bolditalic***
|
||||
# **bold**
|
||||
|
||||
*italic*
|
||||
|
||||
~~strikethrough~~
|
||||
|
||||
[link](linktest)
|
||||
|
||||
\`code\`
|
||||
`,
|
||||
};
|
||||
await waitNextFrame(page);
|
||||
await pasteContent(page, clipData);
|
||||
await page.waitForTimeout(200);
|
||||
await assertTextFormats(page, [
|
||||
{ bold: true, italic: true },
|
||||
{ bold: true },
|
||||
{ italic: true },
|
||||
{ strike: true },
|
||||
{ link: 'linktest' },
|
||||
{ code: true },
|
||||
]);
|
||||
await undoByClick(page);
|
||||
await assertRichTexts(page, ['']);
|
||||
});
|
||||
|
||||
test(scoped`import markdown`, async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
await resetHistory(page);
|
||||
const clipData = `# text
|
||||
# h1
|
||||
`;
|
||||
await pasteContent(page, { 'text/plain': clipData });
|
||||
await page.waitForTimeout(100);
|
||||
await assertRichTexts(page, ['text', 'h1']);
|
||||
await undoByClick(page);
|
||||
await assertRichTexts(page, ['']);
|
||||
});
|
||||
|
||||
test(
|
||||
scoped`clipboard paste HTML containing markdown syntax code and image `,
|
||||
async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/toeverything/blocksuite/issues/2855',
|
||||
});
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
|
||||
// set up clipboard data using html
|
||||
const clipData = {
|
||||
'text/html': `<p>符合 Markdown 格式的 URL 放到笔记中,此时需要的格式如下:</p>
|
||||
<pre><code>md [任务管理这件事 - 少数派](https://sspai.com/post/61092)</code></pre>
|
||||
<p>(将一段文字包裹在<code >[[]]</code>中)此时需要的格式如下:</p>
|
||||
<figure ><img src="https://placehold.co/600x400"></figure>
|
||||
<p>上图中,当我们处在 Obsidian 的「预览模式」时,点击这个「双向链接」</p>
|
||||
`,
|
||||
};
|
||||
await page.evaluate(
|
||||
({ clipData }) => {
|
||||
const dT = new DataTransfer();
|
||||
const e = new ClipboardEvent('paste', { clipboardData: dT });
|
||||
Object.defineProperty(e, 'target', {
|
||||
writable: false,
|
||||
value: document,
|
||||
});
|
||||
e.clipboardData?.setData('text/html', clipData['text/html']);
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
{ clipData }
|
||||
);
|
||||
await waitEmbedLoaded(page);
|
||||
// await page.waitForTimeout(500);
|
||||
await assertRichImage(page, 1);
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user