diff --git a/blocksuite/framework/std/src/inline/consts.ts b/blocksuite/framework/std/src/inline/consts.ts index 81568c1a02..37057e1739 100644 --- a/blocksuite/framework/std/src/inline/consts.ts +++ b/blocksuite/framework/std/src/inline/consts.ts @@ -1,7 +1,5 @@ -import { IS_SAFARI } from '@blocksuite/global/env'; - -export const ZERO_WIDTH_SPACE = IS_SAFARI ? '\u200C' : '\u200B'; +export const ZERO_WIDTH_SPACE = '\u200C'; // see https://en.wikipedia.org/wiki/Zero-width_non-joiner -export const ZERO_WIDTH_NON_JOINER = '\u200C'; +export const ZERO_WIDTH_NON_JOINER = '\u200B'; export const INLINE_ROOT_ATTR = 'data-v-root'; diff --git a/tests/affine-local/e2e/blocksuite/edgeless/note.spec.ts b/tests/affine-local/e2e/blocksuite/edgeless/note.spec.ts index 6ef1014f22..99042eeca6 100644 --- a/tests/affine-local/e2e/blocksuite/edgeless/note.spec.ts +++ b/tests/affine-local/e2e/blocksuite/edgeless/note.spec.ts @@ -1,5 +1,6 @@ import { test } from '@affine-test/kit/playwright'; import { + assertTitle, clickEdgelessModeButton, clickView, createEdgelessNoteBlock, @@ -162,7 +163,7 @@ test.describe('edgeless page block', () => { const note = page.locator('affine-edgeless-note'); const docTitle = note.locator('edgeless-page-block-title'); await expect(docTitle).toBeVisible(); - await expect(docTitle).toHaveText(title); + await assertTitle(page, title); await note.dblclick(); await docTitle.click(); @@ -170,11 +171,11 @@ test.describe('edgeless page block', () => { // clear the title await selectAllByKeyboard(page); await pressBackspace(page); - await expect(docTitle).toHaveText(''); + await assertTitle(page, ''); // type new title await type(page, 'New Title'); - await expect(docTitle).toHaveText('New Title'); + await assertTitle(page, 'New Title'); // cursor could move between doc title and note content await page.keyboard.press('ArrowDown'); @@ -186,10 +187,10 @@ test.describe('edgeless page block', () => { await page.keyboard.press('ArrowUp'); await type(page, 'yy'); - await expect(docTitle).toHaveText('yyNew Title'); + await assertTitle(page, 'yyNew Title'); await pressEnter(page); - await expect(docTitle).toHaveText('yy'); + await assertTitle(page, 'yy'); await expect(paragraphs).toHaveCount(numParagraphs + 1); await expect(paragraphs.nth(0)).toHaveText('New Title'); await expect(paragraphs.nth(1)).toHaveText('xxHello'); diff --git a/tests/blocksuite/e2e/inline/inline-editor.spec.ts b/tests/blocksuite/e2e/inline/inline-editor.spec.ts index 6762f30d1a..e086163273 100644 --- a/tests/blocksuite/e2e/inline/inline-editor.spec.ts +++ b/tests/blocksuite/e2e/inline/inline-editor.spec.ts @@ -2,6 +2,13 @@ import type { InlineEditor, InlineRange } from '@blocksuite/affine/std/inline'; import type { DeltaInsert } from '@blocksuite/affine/store'; import { expect, type Page, test } from '@playwright/test'; +import { pressArrowLeft, pressEnter } from '../utils/actions/keyboard.js'; +import { + enterPlaygroundRoom, + focusRichText, + initEmptyParagraphState, +} from '../utils/actions/misc.js'; +import { assertRichTextInlineDeltas } from '../utils/asserts.js'; import { ZERO_WIDTH_SPACE } from '../utils/inline-editor.js'; // FIXME(mirone): copy paste from framework/inline/__tests__/utils.ts const defaultPlaygroundURL = new URL( @@ -1124,3 +1131,41 @@ test('triple click to select line', async ({ page }) => { await press(page, 'Backspace'); expect(await editorA.innerText()).toBe('abc\n' + ZERO_WIDTH_SPACE + '\nabc'); }); + +test('caret should move correctly when inline elements are exist', async ({ + page, +}) => { + await enterPlaygroundRoom(page); + await initEmptyParagraphState(page); + await focusRichText(page, 0); + + // hello 'link doc' world + await type(page, 'hello '); + await press(page, '@'); + await type(page, 'link doc'); + await pressEnter(page); + await type(page, ' world'); + + await pressArrowLeft(page, ' world'.length); + await pressArrowLeft(page); // on 'linked doc' + await pressArrowLeft(page); // on the left side of 'linked doc' + await type(page, 'test'); + + await assertRichTextInlineDeltas(page, [ + { + insert: 'hello test', + }, + { + attributes: { + reference: { + pageId: '3', + type: 'LinkedPage', + }, + }, + insert: ' ', + }, + { + insert: ' world', + }, + ]); +}); diff --git a/tests/blocksuite/e2e/utils/actions/misc.ts b/tests/blocksuite/e2e/utils/actions/misc.ts index 20bc9ce438..9b02a1df11 100644 --- a/tests/blocksuite/e2e/utils/actions/misc.ts +++ b/tests/blocksuite/e2e/utils/actions/misc.ts @@ -14,6 +14,7 @@ import { expect } from '@playwright/test'; import stringify from 'json-stable-stringify'; import lz from 'lz-string'; +import { ZERO_WIDTH_SPACE } from '../inline-editor.js'; import { currentEditorIndex } from '../multiple-editor.js'; import { pressArrowRight, @@ -1053,7 +1054,7 @@ export async function getIndexCoordinate( } export function inlineEditorInnerTextToString(innerText: string): string { - return innerText.replace('\u200B', '').trim(); + return innerText.replace(ZERO_WIDTH_SPACE, '').trim(); } export async function focusTitle(page: Page) { diff --git a/tests/blocksuite/e2e/utils/inline-editor.ts b/tests/blocksuite/e2e/utils/inline-editor.ts index ae625ac78c..93e84cb399 100644 --- a/tests/blocksuite/e2e/utils/inline-editor.ts +++ b/tests/blocksuite/e2e/utils/inline-editor.ts @@ -22,8 +22,4 @@ export async function getStringFromRichText( } // Why? we can't import from `@blocksuite/affine/std/inline` because playwright will throw an error -export const ZERO_WIDTH_SPACE = /Apple Computer/.test( - globalThis.navigator?.vendor -) - ? '\u200C' - : '\u200B'; +export const ZERO_WIDTH_SPACE = '\u200C'; diff --git a/tests/kit/src/utils/editor.ts b/tests/kit/src/utils/editor.ts index a048c1bd79..a45437ac17 100644 --- a/tests/kit/src/utils/editor.ts +++ b/tests/kit/src/utils/editor.ts @@ -5,6 +5,11 @@ import { expect, type Locator, type Page } from '@playwright/test'; declare type _GLOBAL_ = typeof BlocksuiteEffects; const EDGELESS_TOOLBAR_WIDGET = 'edgeless-toolbar-widget'; +export const ZERO_WIDTH_SPACE = '\u200C'; + +export function inlineEditorInnerTextToString(innerText: string): string { + return innerText.replace(ZERO_WIDTH_SPACE, '').trim(); +} export function locateModeSwitchButton( page: Page, @@ -62,6 +67,13 @@ export async function focusDocTitle(page: Page, editorIndex = 0) { await locateDocTitle(page, editorIndex).locator('.inline-editor').focus(); } +export async function assertTitle(page: Page, text: string) { + const title = locateDocTitle(page); + const inlineEditor = title.locator('.doc-title-container').first(); + const vText = inlineEditorInnerTextToString(await inlineEditor.innerText()); + expect(vText).toBe(text); +} + export function locateToolbar(page: Page, editorIndex = 0) { return locateEditorContainer(page, editorIndex).locator( 'affine-toolbar-widget editor-toolbar'