From e53ced3c66ce0785c40521bdea6932a6427b709c Mon Sep 17 00:00:00 2001
From: umaranis
-
- hm
-
-
+
+ hm
+
+
-
- alert
-
-
- (
-
-
- 1
-
-
- )
-
-
- ;
-
-
- `,
- );
+ test.beforeEach(({isCollab, page}) => initialize({isCollab, page}));
+ test.fixme(
+ 'Can create code block with markdown',
+ async ({page, isRichText}) => {
+ await focusEditor(page);
+ await page.keyboard.type('``` alert(1);');
+ if (isRichText) {
+ await assertSelection(page, {
+ anchorOffset: 1,
+ anchorPath: [0, 4, 0],
+ focusOffset: 1,
+ focusPath: [0, 4, 0],
+ });
+ await assertHTML(
+ page,
+ html`
+
+
+ alert
+
+
+ (
+
+
+ 1
+
+
+ )
+
+
+ ;
+
+
+ `,
+ );
- // Remove code block (back to a normal paragraph) and check that highlights are converted into regular text
- await moveToEditorBeginning(page);
- await page.keyboard.press('Backspace');
- await assertHTML(
- page,
- html`
- - alert(1); -
- `, - ); - } else { - await assertHTML( - page, - html` -- \`\`\` alert(1); -
- `, - ); - } - }); + // Remove code block (back to a normal paragraph) and check that highlights are converted into regular text + await moveToEditorBeginning(page); + await page.keyboard.press('Backspace'); + await assertHTML( + page, + html` ++ alert(1); +
+ `, + ); + } else { + await assertHTML( + page, + html` ++ \`\`\` alert(1); +
+ `, + ); + } + }, + ); - test.fixme('Can create code block with markdown and wrap existing text', async ({ - page, - isRichText, - }) => { - await focusEditor(page); - await page.keyboard.type('alert(1);'); - await moveToEditorBeginning(page); - await page.keyboard.type('``` '); - if (isRichText) { - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 0, 0], - focusOffset: 0, - focusPath: [0, 0, 0], - }); - await assertHTML( - page, - html` -
-
- alert
-
-
- (
-
-
- 1
-
-
- )
-
-
- ;
-
-
- `,
- );
- } else {
- await assertHTML(
- page,
- html`
- - \`\`\` alert(1); -
- `, - ); - } - }); + test.fixme( + 'Can create code block with markdown and wrap existing text', + async ({page, isRichText}) => { + await focusEditor(page); + await page.keyboard.type('alert(1);'); + await moveToEditorBeginning(page); + await page.keyboard.type('``` '); + if (isRichText) { + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 0, 0], + focusOffset: 0, + focusPath: [0, 0, 0], + }); + await assertHTML( + page, + html` +
+
+ alert
+
+
+ (
+
+
+ 1
+
+
+ )
+
+
+ ;
+
+
+ `,
+ );
+ } else {
+ await assertHTML(
+ page,
+ html`
+ + \`\`\` alert(1); +
+ `, + ); + } + }, + ); test('Can select multiple paragraphs and convert to code block', async ({ page, @@ -240,13 +243,89 @@ test.describe('CodeBlock', () => { ); }); - test.fixme('Can switch highlighting language in a toolbar', async ({ - page, - isRichText, - }) => { - await focusEditor(page); - await page.keyboard.type('``` select * from users'); - if (isRichText) { + test.fixme( + 'Can switch highlighting language in a toolbar', + async ({page, isRichText}) => { + await focusEditor(page); + await page.keyboard.type('``` select * from users'); + if (isRichText) { + await assertHTML( + page, + html` +
+ select
+
+ *
+
+ from users
+
+ `,
+ );
+ await click(page, '.toolbar-item.code-language');
+ await click(page, 'button:has-text("SQL")');
+ await assertHTML(
+ page,
+ html`
+
+
+ select
+
+
+
+ *
+
+
+
+ from
+
+ users
+
+ `,
+ );
+ } else {
+ await assertHTML(
+ page,
+ html`
+ + \`\`\` select * from users +
+ `, + ); + } + }, + ); + + test.fixme( + 'Can maintain indent when creating new lines', + async ({page, isRichText, isPlainText}) => { + test.skip(isPlainText); + await focusEditor(page); + await page.keyboard.type('``` alert(1);'); + await page.keyboard.press('Enter'); + await click(page, '.toolbar-item.alignment'); + await click(page, 'button:has-text("Indent")'); + await page.keyboard.type('alert(2);'); + await page.keyboard.press('Enter'); await assertHTML( page, html` @@ -254,20 +333,81 @@ test.describe('CodeBlock', () => { class="PlaygroundEditorTheme__code PlaygroundEditorTheme__ltr" spellcheck="false" dir="ltr" - data-gutter="1" + data-gutter="123" data-highlight-language="javascript"> - select + alert + + - * + ( - from users + + 1 + + + ) + + + ; + +
+
+
+ if
+
+
+
+ (
+
+ x
+
+ )
+
+
+
+ {
+
+
+
+
+ x
+
+
+ (
+
+
+ )
+
+
+ ;
+
+
+
+
+ }
+
+
+ `,
+ );
+ await page.keyboard.down('Shift');
+ await click(page, '.toolbar-item.alignment');
+ await click(page, 'button:has-text("Outdent")');
+ await page.keyboard.up('Shift');
+ await assertHTML(
+ page,
+ html`
+
- from
+ if
+
+
+
+ (
+
+ x
+
+ )
+
+
+
+ {
+
+
+
+
+ x
+
+
+ (
+
+
+ )
+
+
+ ;
+
+
+
+
+ }
- users
`,
);
- } else {
+ await click(page, '.toolbar-item.alignment');
+ await click(page, 'button:has-text("Outdent")');
+ await click(page, '.toolbar-item.alignment');
+ await click(page, 'button:has-text("Outdent")');
await assertHTML(
page,
html`
- - \`\`\` select * from users -
+
+
+ if
+
+
+
+ (
+
+ x
+
+ )
+
+
+
+ {
+
+
+
+ x
+
+
+ (
+
+
+ )
+
+
+ ;
+
+
+
+ }
+
+
`,
);
- }
- });
+ },
+ );
- test.fixme('Can maintain indent when creating new lines', async ({
- page,
- isRichText,
- isPlainText,
- }) => {
- test.skip(isPlainText);
- await focusEditor(page);
- await page.keyboard.type('``` alert(1);');
- await page.keyboard.press('Enter');
- await click(page, '.toolbar-item.alignment');
- await click(page, 'button:has-text("Indent")');
- await page.keyboard.type('alert(2);');
- await page.keyboard.press('Enter');
- await assertHTML(
- page,
- html`
+ test.fixme(
+ 'Can move around lines with option+arrow keys',
+ async ({page, isPlainText}) => {
+ test.skip(isPlainText);
+ const abcHTML = html`
{
- alert
+ a
(
-
- 1
-
@@ -360,22 +714,16 @@ test.describe('CodeBlock', () => {
;
-
- alert
+ b
(
-
- 2
-
@@ -387,65 +735,10 @@ test.describe('CodeBlock', () => {
;
-
-
- `,
- );
- });
-
- test.fixme('Can (un)indent multiple lines at once', async ({
- page,
- isRichText,
- isPlainText,
- }) => {
- test.skip(isPlainText);
- await focusEditor(page);
- await page.keyboard.type('``` if (x) {');
- await page.keyboard.press('Enter');
- await click(page, '.toolbar-item.alignment');
- await click(page, 'button:has-text("Indent")');
- await page.keyboard.type('x();');
- await page.keyboard.press('Enter');
- await page.keyboard.press('Backspace');
- await page.keyboard.type('}');
- await assertHTML(
- page,
- html`
-
-
- if
-
-
-
- (
-
- x
-
- )
-
-
-
- {
-
-
-
- x
+ c
{
data-lexical-text="true">
;
-
-
- }
-
- `,
- );
- await page.keyboard.down('Shift');
- await page.keyboard.press('ArrowUp');
- await page.keyboard.press('ArrowUp');
- await page.keyboard.up('Shift');
- await click(page, '.toolbar-item.alignment');
- await click(page, 'button:has-text("Indent")');
- await click(page, '.toolbar-item.alignment');
- await click(page, 'button:has-text("Indent")');
- await assertHTML(
- page,
- html`
+ `;
+ const bcaHTML = html`
-
-
- if
-
-
-
- (
-
- x
-
- )
-
-
-
- {
-
-
-
- x
+ b
{
;
-
-
- }
-
-
- `,
- );
- await page.keyboard.down('Shift');
- await click(page, '.toolbar-item.alignment');
- await click(page, 'button:has-text("Outdent")');
- await page.keyboard.up('Shift');
- await assertHTML(
- page,
- html`
-
-
-
- if
-
-
-
- (
-
- x
-
- )
-
-
-
- {
-
-
-
- x
+ c
{
;
-
-
- }
-
-
- `,
- );
- await click(page, '.toolbar-item.alignment');
- await click(page, 'button:has-text("Outdent")');
- await click(page, '.toolbar-item.alignment');
- await click(page, 'button:has-text("Outdent")');
- await assertHTML(
- page,
- html`
-
-
- if
-
-
-
- (
-
- x
-
- )
-
-
-
- {
-
-
- x
+ a
{
data-lexical-text="true">
;
-
-
- }
-
- `,
- );
- });
-
- test.fixme('Can move around lines with option+arrow keys', async ({
- page,
- isPlainText,
- }) => {
- test.skip(isPlainText);
- const abcHTML = html`
-
-
- a
-
-
- (
-
-
- )
-
-
- ;
-
-
-
- b
-
-
- (
-
-
- )
-
-
- ;
-
-
-
- c
-
-
- (
-
-
- )
-
-
- ;
-
-
- `;
- const bcaHTML = html`
-
-
- b
-
-
- (
-
-
- )
-
-
- ;
-
-
-
- c
-
-
- (
-
-
- )
-
-
- ;
-
-
-
- a
-
-
- (
-
-
- )
-
-
- ;
-
-
- `;
- const endOfFirstLine = {
- anchorOffset: 1,
- anchorPath: [0, 3, 0],
- focusOffset: 1,
- focusPath: [0, 3, 0],
- };
- const endOfLastLine = {
- anchorOffset: 1,
- anchorPath: [0, 13, 0],
- focusOffset: 1,
- focusPath: [0, 13, 0],
- };
- await focusEditor(page);
- await page.keyboard.type('``` a();\nb();\nc();');
- await assertHTML(page, abcHTML);
- await assertSelection(page, endOfLastLine);
- await page.keyboard.press('ArrowUp');
- await page.keyboard.press('ArrowUp');
- // Workaround for #1173: just insert and remove a space to fix Firefox losing the selection
- await page.keyboard.type(' ');
- await page.keyboard.press('Backspace');
- await assertSelection(page, endOfFirstLine);
- // End workaround
- // Ensure attempting to move a line up at the top of a codeblock no-ops
- await page.keyboard.down('Alt');
- await page.keyboard.press('ArrowUp');
- await assertSelection(page, endOfFirstLine);
- await assertHTML(page, abcHTML);
- await page.keyboard.press('ArrowDown');
- await page.keyboard.press('ArrowDown');
- await assertSelection(page, endOfLastLine);
- // Can't move a line down and out of codeblock
- await assertHTML(page, bcaHTML);
- await page.keyboard.press('ArrowDown');
- await assertSelection(page, endOfLastLine);
- await assertHTML(page, bcaHTML);
- });
+ `;
+ const endOfFirstLine = {
+ anchorOffset: 1,
+ anchorPath: [0, 3, 0],
+ focusOffset: 1,
+ focusPath: [0, 3, 0],
+ };
+ const endOfLastLine = {
+ anchorOffset: 1,
+ anchorPath: [0, 13, 0],
+ focusOffset: 1,
+ focusPath: [0, 13, 0],
+ };
+ await focusEditor(page);
+ await page.keyboard.type('``` a();\nb();\nc();');
+ await assertHTML(page, abcHTML);
+ await assertSelection(page, endOfLastLine);
+ await page.keyboard.press('ArrowUp');
+ await page.keyboard.press('ArrowUp');
+ // Workaround for #1173: just insert and remove a space to fix Firefox losing the selection
+ await page.keyboard.type(' ');
+ await page.keyboard.press('Backspace');
+ await assertSelection(page, endOfFirstLine);
+ // End workaround
+ // Ensure attempting to move a line up at the top of a codeblock no-ops
+ await page.keyboard.down('Alt');
+ await page.keyboard.press('ArrowUp');
+ await assertSelection(page, endOfFirstLine);
+ await assertHTML(page, abcHTML);
+ await page.keyboard.press('ArrowDown');
+ await page.keyboard.press('ArrowDown');
+ await assertSelection(page, endOfLastLine);
+ // Can't move a line down and out of codeblock
+ await assertHTML(page, bcaHTML);
+ await page.keyboard.press('ArrowDown');
+ await assertSelection(page, endOfLastLine);
+ await assertHTML(page, bcaHTML);
+ },
+ );
/**
* Code example for tests:
@@ -1056,24 +1057,23 @@ test.describe('CodeBlock', () => {
});
});
- test.fixme('When pressing CMD/Ctrl + Left, CMD/Ctrl + Right, the cursor should go to the start of the code', async ({
- page,
- isPlainText,
- }) => {
- test.skip(isPlainText);
- await focusEditor(page);
- await page.keyboard.type('``` ');
- await page.keyboard.press('Space');
- await click(page, '.toolbar-item.alignment');
- await click(page, 'button:has-text("Indent")');
- await page.keyboard.type('a b');
- await page.keyboard.press('Space');
- await page.keyboard.press('Enter');
- await page.keyboard.type('c d');
- await page.keyboard.press('Space');
- await assertHTML(
- page,
- `
+ test.fixme(
+ 'When pressing CMD/Ctrl + Left, CMD/Ctrl + Right, the cursor should go to the start of the code',
+ async ({page, isPlainText}) => {
+ test.skip(isPlainText);
+ await focusEditor(page);
+ await page.keyboard.type('``` ');
+ await page.keyboard.press('Space');
+ await click(page, '.toolbar-item.alignment');
+ await click(page, 'button:has-text("Indent")');
+ await page.keyboard.type('a b');
+ await page.keyboard.press('Space');
+ await page.keyboard.press('Enter');
+ await page.keyboard.type('c d');
+ await page.keyboard.press('Space');
+ await assertHTML(
+ page,
+ `
{
c d
`,
- );
+ );
- await selectCharacters(page, 'left', 13);
- await assertSelection(page, {
- anchorOffset: 6,
- anchorPath: [0, 2, 0],
- focusOffset: 0,
- focusPath: [0, 0, 0],
- });
+ await selectCharacters(page, 'left', 13);
+ await assertSelection(page, {
+ anchorOffset: 6,
+ anchorPath: [0, 2, 0],
+ focusOffset: 0,
+ focusPath: [0, 0, 0],
+ });
- await moveToStart(page);
- await assertSelection(page, {
- anchorOffset: 2,
- anchorPath: [0, 0, 0],
- focusOffset: 2,
- focusPath: [0, 0, 0],
- });
+ await moveToStart(page);
+ await assertSelection(page, {
+ anchorOffset: 2,
+ anchorPath: [0, 0, 0],
+ focusOffset: 2,
+ focusPath: [0, 0, 0],
+ });
- await moveToEnd(page);
- await assertSelection(page, {
- anchorOffset: 5,
- anchorPath: [0, 0, 0],
- focusOffset: 5,
- focusPath: [0, 0, 0],
- });
+ await moveToEnd(page);
+ await assertSelection(page, {
+ anchorOffset: 5,
+ anchorPath: [0, 0, 0],
+ focusOffset: 5,
+ focusPath: [0, 0, 0],
+ });
- await moveToStart(page);
- await assertSelection(page, {
- anchorOffset: 2,
- anchorPath: [0, 0, 0],
- focusOffset: 2,
- focusPath: [0, 0, 0],
- });
+ await moveToStart(page);
+ await assertSelection(page, {
+ anchorOffset: 2,
+ anchorPath: [0, 0, 0],
+ focusOffset: 2,
+ focusPath: [0, 0, 0],
+ });
- await selectCharacters(page, 'right', 11);
- await assertSelection(page, {
- anchorOffset: 2,
- anchorPath: [0, 0, 0],
- focusOffset: 6,
- focusPath: [0, 2, 0],
- });
+ await selectCharacters(page, 'right', 11);
+ await assertSelection(page, {
+ anchorOffset: 2,
+ anchorPath: [0, 0, 0],
+ focusOffset: 6,
+ focusPath: [0, 2, 0],
+ });
- await moveToEnd(page);
- await assertSelection(page, {
- anchorOffset: 5,
- anchorPath: [0, 2, 0],
- focusOffset: 5,
- focusPath: [0, 2, 0],
- });
+ await moveToEnd(page);
+ await assertSelection(page, {
+ anchorOffset: 5,
+ anchorPath: [0, 2, 0],
+ focusOffset: 5,
+ focusPath: [0, 2, 0],
+ });
- await page.pause();
- });
+ await page.pause();
+ },
+ );
});
diff --git a/demos/playground/src/__tests__/e2e/Composition.spec.mjs b/demos/playground/src/__tests__/e2e/Composition.spec.mjs
index 2802c5fd..aa0d86e9 100644
--- a/demos/playground/src/__tests__/e2e/Composition.spec.mjs
+++ b/demos/playground/src/__tests__/e2e/Composition.spec.mjs
@@ -625,100 +625,102 @@ test.describe('Composition', () => {
});
});
- test.fixme('Can type, delete and cancel Hiragana via IME', async ({
- page,
- browserName,
- }) => {
- // We don't yet support FF.
- test.skip(browserName === 'firefox');
-
- await focusEditor(page);
- await enableCompositionKeyEvents(page);
-
- await page.keyboard.imeSetComposition('s', 1, 1);
- await page.keyboard.imeSetComposition('す', 1, 1);
- await page.keyboard.imeSetComposition('すs', 2, 2);
- await page.keyboard.imeSetComposition('すsh', 3, 3);
- await page.keyboard.imeSetComposition('すし', 2, 2);
- await page.keyboard.imeSetComposition('す', 1, 1);
- await page.keyboard.imeSetComposition('', 0, 0);
- // Escape would fire here
- await page.keyboard.insertText('');
-
- await assertHTML(
- page,
- html`
- - -
- `, - ); - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 0, 0], - focusOffset: 0, - focusPath: [0, 0, 0], - }); - }); + await assertHTML( + page, + html` ++ +
+ `, + ); + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 0, 0], + focusOffset: 0, + focusPath: [0, 0, 0], + }); + }, + ); - test.fixme('Floating toolbar should not be displayed when using IME', async ({ - page, - browserName, - isPlainText, - }) => { - test.skip(isPlainText); - // We don't yet support FF. - test.skip(browserName === 'firefox'); + test.fixme( + 'Floating toolbar should not be displayed when using IME', + async ({page, browserName, isPlainText}) => { + test.skip(isPlainText); + // We don't yet support FF. + test.skip(browserName === 'firefox'); - await focusEditor(page); - await enableCompositionKeyEvents(page); + await focusEditor(page); + await enableCompositionKeyEvents(page); - await page.keyboard.imeSetComposition('s', 0, 1); - await page.keyboard.imeSetComposition('す', 0, 1); - await page.keyboard.imeSetComposition('すs', 0, 2); - await page.keyboard.imeSetComposition('すsh', 0, 3); - await page.keyboard.imeSetComposition('すsh', 0, 4); + await page.keyboard.imeSetComposition('s', 0, 1); + await page.keyboard.imeSetComposition('す', 0, 1); + await page.keyboard.imeSetComposition('すs', 0, 2); + await page.keyboard.imeSetComposition('すsh', 0, 3); + await page.keyboard.imeSetComposition('すsh', 0, 4); - const isFloatingToolbarDisplayedWhenUseIME = await evaluate(page, () => { - return !!document.querySelector('.floating-text-format-popup'); - }); + const isFloatingToolbarDisplayedWhenUseIME = await evaluate( + page, + () => { + return !!document.querySelector('.floating-text-format-popup'); + }, + ); - expect(isFloatingToolbarDisplayedWhenUseIME).toEqual(false); + expect(isFloatingToolbarDisplayedWhenUseIME).toEqual(false); - await page.keyboard.insertText('すsh'); - await selectCharacters(page, 'left', 3); + await page.keyboard.insertText('すsh'); + await selectCharacters(page, 'left', 3); - const isFloatingToolbarDisplayed = await evaluate(page, () => { - return !!document.querySelector('.floating-text-format-popup'); - }); + const isFloatingToolbarDisplayed = await evaluate(page, () => { + return !!document.querySelector('.floating-text-format-popup'); + }); - expect(isFloatingToolbarDisplayed).toEqual(true); - }); + expect(isFloatingToolbarDisplayed).toEqual(true); + }, + ); }); }); diff --git a/demos/playground/src/__tests__/e2e/CopyAndPaste.spec.mjs b/demos/playground/src/__tests__/e2e/CopyAndPaste.spec.mjs index 52c41821..4cc7a1e7 100644 --- a/demos/playground/src/__tests__/e2e/CopyAndPaste.spec.mjs +++ b/demos/playground/src/__tests__/e2e/CopyAndPaste.spec.mjs @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * */ -import { expect } from '@playwright/test'; +import {expect} from '@playwright/test'; import { extendToNextWord, @@ -42,8 +42,8 @@ import { } from '../utils/index.mjs'; test.describe('CopyAndPaste', () => { - test.beforeEach(({ isCollab, page }) => initialize({ isCollab, page })); - test('Basic copy + paste', async ({ isRichText, page, browserName }) => { + test.beforeEach(({isCollab, page}) => initialize({isCollab, page})); + test('Basic copy + paste', async ({isRichText, page, browserName}) => { await focusEditor(page); // Add paragraph @@ -256,7 +256,7 @@ test.describe('CopyAndPaste', () => { test.fixme( `Copy and paste heading`, - async ({ isPlainText, page, browserName }) => { + async ({isPlainText, page, browserName}) => { test.skip(isPlainText); await focusEditor(page); @@ -309,7 +309,7 @@ test.describe('CopyAndPaste', () => { test.fixme( `Copy and paste between sections`, - async ({ isRichText, page, browserName }) => { + async ({isRichText, page, browserName}) => { await focusEditor(page); await page.keyboard.type('Hello world #foobar test #foobar2 when #not'); @@ -789,7 +789,7 @@ test.describe('CopyAndPaste', () => { test.fixme( 'Copy and paste of partial list items into an empty editor', - async ({ page, isPlainText }) => { + async ({page, isPlainText}) => { test.skip(isPlainText); await focusEditor(page); @@ -869,7 +869,7 @@ test.describe('CopyAndPaste', () => { test.fixme( 'Copy and paste of partial list items into the list', - async ({ page, isPlainText, isCollab, browserName }) => { + async ({page, isPlainText, isCollab, browserName}) => { test.skip(isPlainText); await focusEditor(page); @@ -1045,7 +1045,7 @@ test.describe('CopyAndPaste', () => { test.fixme( 'Copy list items and paste back into list', - async ({ page, isPlainText, isCollab }) => { + async ({page, isPlainText, isCollab}) => { test.skip(isPlainText); await focusEditor(page); @@ -1112,7 +1112,7 @@ test.describe('CopyAndPaste', () => { test.fixme( 'Copy list items and paste into list', - async ({ page, isPlainText, isCollab }) => { + async ({page, isPlainText, isCollab}) => { test.skip(isPlainText); await focusEditor(page); @@ -1298,7 +1298,7 @@ test.describe('CopyAndPaste', () => { test.fixme( 'Copy and paste of list items and paste back into list on an existing item', - async ({ page, isPlainText, isCollab }) => { + async ({page, isPlainText, isCollab}) => { test.skip(isPlainText); await focusEditor(page); @@ -1363,171 +1363,170 @@ test.describe('CopyAndPaste', () => { }, ); - test.fixme('Copy list of a different type and paste into list on an existing item - should merge the lists.', async ({ - page, - isPlainText, - isCollab, - }) => { - test.skip(isPlainText); + test.fixme( + 'Copy list of a different type and paste into list on an existing item - should merge the lists.', + async ({page, isPlainText, isCollab}) => { + test.skip(isPlainText); - await focusEditor(page); + await focusEditor(page); - await page.keyboard.type('- one'); - await page.keyboard.press('Enter'); - await page.keyboard.type('two'); - await page.keyboard.press('Tab'); - await page.keyboard.press('Enter'); - await page.keyboard.type('a'); + await page.keyboard.type('- one'); + await page.keyboard.press('Enter'); + await page.keyboard.type('two'); + await page.keyboard.press('Tab'); + await page.keyboard.press('Enter'); + await page.keyboard.type('a'); - await page.keyboard.press('Enter'); - await page.keyboard.press('Enter'); - await page.keyboard.press('Enter'); - await page.keyboard.press('Enter'); + await page.keyboard.press('Enter'); + await page.keyboard.press('Enter'); + await page.keyboard.press('Enter'); + await page.keyboard.press('Enter'); - await page.keyboard.type('1. four'); - await page.keyboard.press('Enter'); - await page.keyboard.type('five'); - await page.keyboard.press('Tab'); + await page.keyboard.type('1. four'); + await page.keyboard.press('Enter'); + await page.keyboard.type('five'); + await page.keyboard.press('Tab'); - await page.keyboard.press('ArrowUp'); + await page.keyboard.press('ArrowUp'); - await moveToLineBeginning(page); - await page.keyboard.down('Shift'); - await page.keyboard.press('ArrowDown'); - await page.keyboard.press('ArrowDown'); - await page.keyboard.up('Shift'); + await moveToLineBeginning(page); + await page.keyboard.down('Shift'); + await page.keyboard.press('ArrowDown'); + await page.keyboard.press('ArrowDown'); + await page.keyboard.up('Shift'); - await assertHTML( - page, - html` -Hello!
' }; + const clipboard = {'text/html': '
Hello!
'}; await pasteFromClipboard(page, clipboard); @@ -1754,7 +1753,7 @@ test.describe('CopyAndPaste', () => { }); }); - test('HTML Copy + paste an anchor element', async ({ page, isPlainText }) => { + test('HTML Copy + paste an anchor element', async ({page, isPlainText}) => { test.skip(isPlainText); await focusEditor(page); @@ -1821,12 +1820,12 @@ test.describe('CopyAndPaste', () => { ); }); - test('HTML Copy + paste a list element', async ({ page, isPlainText }) => { + test('HTML Copy + paste a list element', async ({page, isPlainText}) => { test.skip(isPlainText); await focusEditor(page); - const clipboard = { 'text/html': '
My document
`; + clipboard['text/html'] = + `My document
`; await pasteFromClipboard(page, clipboard); @@ -2802,7 +2800,7 @@ test.describe('CopyAndPaste', () => { ); }); - test('HTML Copy + paste a checklist', async ({ page, isPlainText }) => { + test('HTML Copy + paste a checklist', async ({page, isPlainText}) => { test.skip(isPlainText); await focusEditor(page); @@ -2843,9 +2841,8 @@ test.describe('CopyAndPaste', () => { await focusEditor(page); // Ensure we preserve checked status. - clipboard[ - 'text/html' - ] = `Text between HRs
' }; + clipboard = {'text/html': 'Text between HRs
'}; await pasteFromClipboard(page, clipboard); await assertHTML( @@ -3213,7 +3210,7 @@ test.describe('CopyAndPaste', () => { test.fixme( 'Paste top level element in the middle of paragraph', - async ({ page, isPlainText, isCollab }) => { + async ({page, isPlainText, isCollab}) => { test.skip(isPlainText || isCollab); await focusEditor(page); await page.keyboard.type('Hello world'); @@ -3243,7 +3240,7 @@ test.describe('CopyAndPaste', () => { test.fixme( 'Paste top level element in the middle of list', - async ({ page, isPlainText, isCollab }) => { + async ({page, isPlainText, isCollab}) => { test.skip(isPlainText || isCollab); await focusEditor(page); // Add three list items diff --git a/demos/playground/src/__tests__/e2e/Hashtags.spec.mjs b/demos/playground/src/__tests__/e2e/Hashtags.spec.mjs index 9ec9a4dc..d85e9066 100644 --- a/demos/playground/src/__tests__/e2e/Hashtags.spec.mjs +++ b/demos/playground/src/__tests__/e2e/Hashtags.spec.mjs @@ -24,8 +24,8 @@ import { } from '../utils/index.mjs'; test.describe('Hashtags', () => { - test.beforeEach(({ isCollab, page }) => initialize({ isCollab, page })); - test(`Can handle a single hashtag`, async ({ page }) => { + test.beforeEach(({isCollab, page}) => initialize({isCollab, page})); + test(`Can handle a single hashtag`, async ({page}) => { await focusEditor(page); await page.keyboard.type('#yolo'); @@ -91,7 +91,7 @@ test.describe('Hashtags', () => { }); }); - test(`Can handle adjacent hashtags`, async ({ page, browserName }) => { + test(`Can handle adjacent hashtags`, async ({page, browserName}) => { await focusEditor(page); await page.keyboard.type('#hello world'); @@ -280,7 +280,7 @@ test.describe('Hashtags', () => { }); }); - test('Hashtag inherits format', async ({ page, isPlainText }) => { + test('Hashtag inherits format', async ({page, isPlainText}) => { test.skip(isPlainText); await focusEditor(page); await page.keyboard.type('Hello '); diff --git a/demos/playground/src/__tests__/e2e/Headings.spec.mjs b/demos/playground/src/__tests__/e2e/Headings.spec.mjs index 58a5eeb2..00aa0cbf 100644 --- a/demos/playground/src/__tests__/e2e/Headings.spec.mjs +++ b/demos/playground/src/__tests__/e2e/Headings.spec.mjs @@ -6,7 +6,7 @@ * */ -import { moveRight, moveToEditorBeginning } from '../keyboardShortcuts/index.mjs'; +import {moveRight, moveToEditorBeginning} from '../keyboardShortcuts/index.mjs'; import { assertHTML, click, @@ -14,14 +14,14 @@ import { html, initialize, test, - IS_WINDOWS + IS_WINDOWS, } from '../utils/index.mjs'; test.describe('Headings', () => { - test.beforeEach(({ isPlainText, isCollab, browserName, page }) => { + test.beforeEach(({isPlainText, isCollab, browserName, page}) => { test.fixme(IS_WINDOWS && browserName === 'firefox' && isCollab); test.skip(isPlainText); - initialize({ isCollab, page }); + initialize({isCollab, page}); }); test('Stays as a heading when you backspace at the start of a heading with no previous sibling nodes present', async ({ @@ -113,7 +113,7 @@ test.describe('Headings', () => { test('Changes to a paragraph when you press enter at the end of a heading', async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); diff --git a/demos/playground/src/__tests__/e2e/HorizontalRule.spec.mjs b/demos/playground/src/__tests__/e2e/HorizontalRule.spec.mjs index c7b66bf2..a9ea3492 100644 --- a/demos/playground/src/__tests__/e2e/HorizontalRule.spec.mjs +++ b/demos/playground/src/__tests__/e2e/HorizontalRule.spec.mjs @@ -27,7 +27,7 @@ import { } from '../utils/index.mjs'; test.describe('HorizontalRule', () => { - test.beforeEach(({ isCollab, page }) => initialize({ isCollab, page })); + test.beforeEach(({isCollab, page}) => initialize({isCollab, page})); test('Can create a horizontal rule and move selection around it', async ({ page, isCollab, @@ -149,7 +149,6 @@ test.describe('HorizontalRule', () => { focusOffset: 0, focusPath: [], }); - }); test('Will add a horizontal rule at the end of a current TextNode and move selection to the new ParagraphNode.', async ({ @@ -270,7 +269,12 @@ test.describe('HorizontalRule', () => { }); }); - test('Can copy and paste a horizontal rule', async ({ page, isPlainText, browserName, isCollab }) => { + test('Can copy and paste a horizontal rule', async ({ + page, + isPlainText, + browserName, + isCollab, + }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); } diff --git a/demos/playground/src/__tests__/e2e/Keywords.spec.mjs b/demos/playground/src/__tests__/e2e/Keywords.spec.mjs index daeec862..01b5a024 100644 --- a/demos/playground/src/__tests__/e2e/Keywords.spec.mjs +++ b/demos/playground/src/__tests__/e2e/Keywords.spec.mjs @@ -22,7 +22,7 @@ import { } from '../utils/index.mjs'; test.describe('Keywords', () => { - test.beforeEach(({ isCollab, page }) => initialize({ isCollab, page })); + test.beforeEach(({isCollab, page}) => initialize({isCollab, page})); test(`Can create a decorator and move selection around it`, async ({ page, browserName, @@ -199,7 +199,7 @@ test.describe('Keywords', () => { }); }); - test('Can type congrats[Team]!', async ({ page }) => { + test('Can type congrats[Team]!', async ({page}) => { await focusEditor(page); await page.keyboard.type('congrats[Team]!'); @@ -368,245 +368,245 @@ test.describe('Keywords', () => { } }); - test.fixme('Can type "Everyone congrats!" where "Everyone " and "!" are bold', async ({ - page, - isPlainText, - }) => { - test.skip(isPlainText); - await focusEditor(page); - - await toggleBold(page); - await page.keyboard.type('Everyone '); - - await assertHTML( - page, - html` -- - Everyone - -
- `, - ); - await assertSelection(page, { - anchorOffset: 9, - anchorPath: [0, 0, 0], - focusOffset: 9, - focusPath: [0, 0, 0], - }); - - await toggleBold(page); - - await page.keyboard.type('congrats'); - - await assertHTML( - page, - html` -- - Everyone - - - congrats - -
- `, - ); - await assertSelection(page, { - anchorOffset: 8, - anchorPath: [0, 1, 0], - focusOffset: 8, - focusPath: [0, 1, 0], - }); - - await page.keyboard.type('!'); - - await assertHTML( - page, - html` -- - Everyone - - - congrats - - ! -
- `, - ); - await assertSelection(page, { - anchorOffset: 1, - anchorPath: [0, 2, 0], - focusOffset: 1, - focusPath: [0, 2, 0], - }); - - await page.keyboard.press('Backspace'); - - await assertHTML( - page, - html` -- - Everyone - - - congrats - -
- `, - ); - await assertSelection(page, { - anchorOffset: 8, - anchorPath: [0, 1, 0], - focusOffset: 8, - focusPath: [0, 1, 0], - }); - - await toggleBold(page); - - await page.keyboard.type('!'); - - await assertHTML( - page, - html` -- - Everyone - - - congrats - - - ! - -
- `, - ); - await assertSelection(page, { - anchorOffset: 1, - anchorPath: [0, 2, 0], - focusOffset: 1, - focusPath: [0, 2, 0], - }); + test.fixme( + 'Can type "Everyone congrats!" where "Everyone " and "!" are bold', + async ({page, isPlainText}) => { + test.skip(isPlainText); + await focusEditor(page); + + await toggleBold(page); + await page.keyboard.type('Everyone '); + + await assertHTML( + page, + html` ++ + Everyone + +
+ `, + ); + await assertSelection(page, { + anchorOffset: 9, + anchorPath: [0, 0, 0], + focusOffset: 9, + focusPath: [0, 0, 0], + }); - await page.keyboard.press('Backspace'); + await toggleBold(page); + + await page.keyboard.type('congrats'); + + await assertHTML( + page, + html` ++ + Everyone + + + congrats + +
+ `, + ); + await assertSelection(page, { + anchorOffset: 8, + anchorPath: [0, 1, 0], + focusOffset: 8, + focusPath: [0, 1, 0], + }); - await assertHTML( - page, - html` -- - Everyone - - - congrats - -
- `, - ); - await assertSelection(page, { - anchorOffset: 8, - anchorPath: [0, 1, 0], - focusOffset: 8, - focusPath: [0, 1, 0], - }); + await page.keyboard.type('!'); + + await assertHTML( + page, + html` ++ + Everyone + + + congrats + + ! +
+ `, + ); + await assertSelection(page, { + anchorOffset: 1, + anchorPath: [0, 2, 0], + focusOffset: 1, + focusPath: [0, 2, 0], + }); - await moveToPrevWord(page); + await page.keyboard.press('Backspace'); + + await assertHTML( + page, + html` ++ + Everyone + + + congrats + +
+ `, + ); + await assertSelection(page, { + anchorOffset: 8, + anchorPath: [0, 1, 0], + focusOffset: 8, + focusPath: [0, 1, 0], + }); - await page.keyboard.press('Backspace'); + await toggleBold(page); + + await page.keyboard.type('!'); + + await assertHTML( + page, + html` ++ + Everyone + + + congrats + + + ! + +
+ `, + ); + await assertSelection(page, { + anchorOffset: 1, + anchorPath: [0, 2, 0], + focusOffset: 1, + focusPath: [0, 2, 0], + }); - await assertHTML( - page, - html` -- - Everyone - - congrats -
- `, - ); - await assertSelection(page, { - anchorOffset: 8, - anchorPath: [0, 0, 0], - focusOffset: 8, - focusPath: [0, 0, 0], - }); + await page.keyboard.press('Backspace'); + + await assertHTML( + page, + html` ++ + Everyone + + + congrats + +
+ `, + ); + await assertSelection(page, { + anchorOffset: 8, + anchorPath: [0, 1, 0], + focusOffset: 8, + focusPath: [0, 1, 0], + }); - await page.keyboard.press('Space'); + await moveToPrevWord(page); + + await page.keyboard.press('Backspace'); + + await assertHTML( + page, + html` ++ + Everyone + + congrats +
+ `, + ); + await assertSelection(page, { + anchorOffset: 8, + anchorPath: [0, 0, 0], + focusOffset: 8, + focusPath: [0, 0, 0], + }); - await assertHTML( - page, - html` -- - Everyone - - - congrats - -
- `, - ); - await assertSelection(page, { - anchorOffset: 9, - anchorPath: [0, 0, 0], - focusOffset: 9, - focusPath: [0, 0, 0], - }); - }); + await page.keyboard.press('Space'); + + await assertHTML( + page, + html` ++ + Everyone + + + congrats + +
+ `, + ); + await assertSelection(page, { + anchorOffset: 9, + anchorPath: [0, 0, 0], + focusOffset: 9, + focusPath: [0, 0, 0], + }); + }, + ); }); diff --git a/demos/playground/src/__tests__/e2e/List.spec.mjs b/demos/playground/src/__tests__/e2e/List.spec.mjs index 97707ef5..49f58dfd 100644 --- a/demos/playground/src/__tests__/e2e/List.spec.mjs +++ b/demos/playground/src/__tests__/e2e/List.spec.mjs @@ -6,7 +6,7 @@ * */ -import { expect } from '@playwright/test'; +import {expect} from '@playwright/test'; import { moveLeft, @@ -34,7 +34,7 @@ import { selectFromFormatDropdown, test, waitForSelector, - IS_WINDOWS + IS_WINDOWS, } from '../utils/index.mjs'; async function toggleBulletList(page) { @@ -64,13 +64,13 @@ async function clickOutdentButton(page, times = 1) { } } -test.beforeEach(({ isPlainText }) => { +test.beforeEach(({isPlainText}) => { test.skip(isPlainText); }); test.describe('Nested List', () => { - test.beforeEach(({ isCollab, page }) => initialize({ isCollab, page })); - test(`Can toggle an empty list on/off`, async ({ page }) => { + test.beforeEach(({isCollab, page}) => initialize({isCollab, page})); + test(`Can toggle an empty list on/off`, async ({page}) => { await focusEditor(page); await assertHTML( @@ -97,7 +97,7 @@ test.describe('Nested List', () => { ); }); - test.fixme(`Can create a list and indent/outdent it`, async ({ page }) => { + test.fixme(`Can create a list and indent/outdent it`, async ({page}) => { await focusEditor(page); await toggleBulletList(page); await assertHTML( @@ -208,7 +208,7 @@ test.describe('Nested List', () => { test('Should outdent if indented when the backspace key is pressed', async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -244,7 +244,7 @@ test.describe('Nested List', () => { test(`Can indent/outdent mutliple list nodes in a list with multiple levels of indentation`, async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -374,7 +374,7 @@ test.describe('Nested List', () => { `, undefined, - { ignoreClasses: true }, + {ignoreClasses: true}, ); }); @@ -539,87 +539,88 @@ test.describe('Nested List', () => { ); }); - test.fixme(`Can create a list containing inline blocks and then toggle it back to original state.`, async ({ - page, - }) => { - await focusEditor(page); - - await assertHTML( - page, - html` -- One two three -
- `, - ); - - await moveLeft(page, 6); - await selectCharacters(page, 'left', 3); - - // link - await click(page, '.link'); - - await assertHTML( - page, - html` - - `, - ); - - // move to end of paragraph to close the floating link bar - await moveToParagraphEnd(page); - - await toggleBulletList(page); - - await assertHTML( - page, - '- One - One two three +
+ `, + ); + + await moveLeft(page, 6); + await selectCharacters(page, 'left', 3); + + // link + await click(page, '.link'); + + await assertHTML( + page, + html` +- two - - three -
- `, - ); - }); + One + + two + + three + + `, + ); + + // move to end of paragraph to close the floating link bar + await moveToParagraphEnd(page); + + await toggleBulletList(page); + + await assertHTML( + page, + '+ One + + two + + three +
+ `, + ); + }, + ); test(`Can create mutliple bullet lists and then toggle off the list.`, async ({ page, @@ -709,7 +710,7 @@ test.describe('Nested List', () => { test(`Can create an unordered list and convert it to an ordered list `, async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -743,7 +744,7 @@ test.describe('Nested List', () => { test(`Can create a single item unordered list with text and convert it to an ordered list `, async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -772,7 +773,7 @@ test.describe('Nested List', () => { test(`Can create a multi-line unordered list and convert it to an ordered list `, async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -814,7 +815,7 @@ test.describe('Nested List', () => { test(`Can create a multi-line unordered list and convert it to an ordered list when no nodes are in the selection`, async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -855,7 +856,7 @@ test.describe('Nested List', () => { test(`Can create an indented multi-line unordered list and convert it to an ordered list `, async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -903,7 +904,7 @@ test.describe('Nested List', () => { test(`Can create an indented multi-line unordered list and convert individual lists in the nested structure to a numbered list. `, async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -1055,7 +1056,7 @@ test.describe('Nested List', () => { test(`Should NOT merge selected nodes into existing list siblings of a different type when formatting to a list`, async ({ page, isCollab, - browserName + browserName, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -1106,38 +1107,42 @@ test.describe('Nested List', () => { ); }); - test.fixme(`Should create list with start number markdown`, async ({ - page, - isCollab, - }) => { - await focusEditor(page); - // Trigger markdown using 321 digits followed by "." and a trigger of " ". - await page.keyboard.type('321. '); - - // forward case is the normal case. - // undo case is when the user presses undo. + test.fixme( + `Should create list with start number markdown`, + async ({page, isCollab}) => { + await focusEditor(page); + // Trigger markdown using 321 digits followed by "." and a trigger of " ". + await page.keyboard.type('321. '); - const forwardHTML = - '- 321. -
- `; + const forwardHTML = + '+ 321. +
+ `; + + await assertHTML(page, forwardHTML); + if (isCollab) { + // Collab uses its own undo/redo + return; + } + await undo(page); + await assertHTML(page, undoHTML); + await redo(page); + await assertHTML(page, forwardHTML); + }, + ); + + test(`Should not process paragraph markdown inside list.`, async ({ + page, + browserName, + isCollab, + }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); } @@ -1154,7 +1159,7 @@ test.describe('Nested List', () => { test(`Un-indents list empty list items when the user presses enter`, async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -1185,7 +1190,7 @@ test.describe('Nested List', () => { test(`Converts a List with one ListItem to a Paragraph when Normal is selected in the format menu`, async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -1203,7 +1208,7 @@ test.describe('Nested List', () => { `, undefined, - { ignoreClasses: true }, + {ignoreClasses: true}, ); await selectFromFormatDropdown(page, '.paragraph'); await assertHTML( @@ -1212,14 +1217,14 @@ test.describe('Nested List', () => {a
`, undefined, - { ignoreClasses: true }, + {ignoreClasses: true}, ); }); test(`Converts the last ListItem in a List with multiple ListItem to a Paragraph when Normal is selected in the format menu`, async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -1242,7 +1247,7 @@ test.describe('Nested List', () => { `, undefined, - { ignoreClasses: true }, + {ignoreClasses: true}, ); await selectFromFormatDropdown(page, '.paragraph'); await assertHTML( @@ -1256,14 +1261,14 @@ test.describe('Nested List', () => {b
`, undefined, - { ignoreClasses: true }, + {ignoreClasses: true}, ); }); test(`Converts the middle ListItem in a List with multiple ListItem to a Paragraph when Normal is selected in the format menu`, async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -1292,7 +1297,7 @@ test.describe('Nested List', () => { `, undefined, - { ignoreClasses: true }, + {ignoreClasses: true}, ); await selectFromFormatDropdown(page, '.paragraph'); await assertHTML( @@ -1311,14 +1316,14 @@ test.describe('Nested List', () => { `, undefined, - { ignoreClasses: true }, + {ignoreClasses: true}, ); }); test('Can create check list, toggle it to bullet-list and back', async ({ page, browserName, - isCollab + isCollab, }) => { if (IS_WINDOWS && browserName === 'firefox' && isCollab) { test.fixme(); @@ -1327,7 +1332,7 @@ test.describe('Nested List', () => { await toggleCheckList(page); await page.keyboard.type('a'); await click(page, '.PlaygroundEditorTheme__listItemUnchecked', { - position: { x: 10, y: 10 }, + position: {x: 10, y: 10}, }); await page.keyboard.press('Enter'); await page.keyboard.type('b'); @@ -1360,7 +1365,8 @@ test.describe('Nested List', () => {${escapedText}
`, - undefined, - {ignoreClasses: true}, - ); - await redo(page); + test.fixme( + `can convert "${testCase.text}" shortcut`, + async ({page, isCollab}) => { + await focusEditor(page); + await page.keyboard.type(testCase.text); await assertHTML(page, testCase.html, undefined, {ignoreClasses: true}); - } - }); + + if (!isCollab) { + const escapedText = testCase.text.replace('>', '>'); + await undo(page); + await assertHTML( + page, + `${escapedText}
`, + undefined, + {ignoreClasses: true}, + ); + await redo(page); + await assertHTML(page, testCase.html, undefined, { + ignoreClasses: true, + }); + } + }, + ); }); SIMPLE_TEXT_FORMAT_SHORTCUTS.forEach((testCase) => { - test.fixme(`can convert "${testCase.text}" shortcut`, async ({ - page, - isCollab, - }) => { - await focusEditor(page); - await page.keyboard.type(testCase.text, { - delay: LEGACY_EVENTS ? 50 : 0, - }); - await assertHTML(page, testCase.html, undefined, {ignoreClasses: false}); - await assertMarkdownImportExport(page, testCase.text, testCase.html); - }); + test.fixme( + `can convert "${testCase.text}" shortcut`, + async ({page, isCollab}) => { + await focusEditor(page); + await page.keyboard.type(testCase.text, { + delay: LEGACY_EVENTS ? 50 : 0, + }); + await assertHTML(page, testCase.html, undefined, { + ignoreClasses: false, + }); + await assertMarkdownImportExport(page, testCase.text, testCase.html); + }, + ); }); NESTED_TEXT_FORMAT_SHORTCUTS.forEach((testCase) => { @@ -705,156 +709,163 @@ test.describe('Markdown', () => { }); }); - test.fixme('can undo/redo nested transformations', async ({page, isCollab}) => { - await focusEditor(page); - await page.keyboard.type('~~_**hello world**_~~'); - - const BOLD_ITALIC_STRIKETHROUGH = html` -- - hello world - -
- `; - const BOLD_ITALIC = html` -- ~~ - - hello world - - ~~ -
- `; - const BOLD = html` -- ~~_ - - hello world - - _ -
- `; - const PLAIN = html` -- ~~_**hello world** -
- `; - - await assertHTML(page, BOLD_ITALIC_STRIKETHROUGH); - - if (isCollab) { - return; - } - - await undo(page); // Undo last transformation - await assertHTML(page, BOLD_ITALIC); - await undo(page); // Undo transformation & its text typing - await undo(page); - await assertHTML(page, BOLD); - await undo(page); // Undo transformation & its text typing - await undo(page); - await assertHTML(page, PLAIN); - await redo(page); // Redo transformation & its text typing - await redo(page); - await assertHTML(page, BOLD); - await redo(page); // Redo transformation & its text typing - await redo(page); - await assertHTML(page, BOLD_ITALIC); - await redo(page); // Redo transformation - await assertHTML(page, BOLD_ITALIC_STRIKETHROUGH); - }); + test.fixme( + 'can undo/redo nested transformations', + async ({page, isCollab}) => { + await focusEditor(page); + await page.keyboard.type('~~_**hello world**_~~'); - test.fixme('can convert already styled text (overlapping ranges)', async ({ - page, - }) => { - // type partially bold/underlined text, add opening markdown tag within bold/underline part - // and add closing within plain text - await focusEditor(page); - await pressToggleBold(page); - await pressToggleUnderline(page); - await page.keyboard.type('h*e~~llo'); - await pressToggleBold(page); - await pressToggleUnderline(page); - await page.keyboard.type(' wo~~r*ld'); - await assertHTML( - page, - html` + const BOLD_ITALIC_STRIKETHROUGH = html`- h + hello world +
+ `; + const BOLD_ITALIC = html` ++ ~~ - e + hello world + ~~ +
+ `; + const BOLD = html` ++ ~~_ - llo + hello world - - wo - - - r - - ld + _
- `, - ); - }); - - test.fixme('can convert markdown text into rich text', async ({page, isCollab}) => { - await focusEditor(page); - await page.keyboard.type('```markdown '); - await pasteFromClipboard(page, { - 'text/plain': IMPORTED_MARKDOWN, - }); + `; + const PLAIN = html` ++ ~~_**hello world** +
+ `; - const originalHTML = await getHTML(page); + await assertHTML(page, BOLD_ITALIC_STRIKETHROUGH); - // Import from current markdown codeblock content - await click(page, '.action-button .markdown'); - await assertHTML(page, IMPORTED_MARKDOWN_HTML); + if (isCollab) { + return; + } - if (!isCollab) { + await undo(page); // Undo last transformation + await assertHTML(page, BOLD_ITALIC); + await undo(page); // Undo transformation & its text typing await undo(page); - await assertHTML(page, originalHTML); + await assertHTML(page, BOLD); + await undo(page); // Undo transformation & its text typing + await undo(page); + await assertHTML(page, PLAIN); + await redo(page); // Redo transformation & its text typing await redo(page); - await assertHTML(page, IMPORTED_MARKDOWN_HTML); + await assertHTML(page, BOLD); + await redo(page); // Redo transformation & its text typing + await redo(page); + await assertHTML(page, BOLD_ITALIC); + await redo(page); // Redo transformation + await assertHTML(page, BOLD_ITALIC_STRIKETHROUGH); + }, + ); - // Click again to run export/import cycle twice to make sure - // no extra nodes (e.g. newlines) are created - await click(page, '.action-button .markdown'); - await click(page, '.action-button .markdown'); - await click(page, '.action-button .markdown'); + test.fixme( + 'can convert already styled text (overlapping ranges)', + async ({page}) => { + // type partially bold/underlined text, add opening markdown tag within bold/underline part + // and add closing within plain text + await focusEditor(page); + await pressToggleBold(page); + await pressToggleUnderline(page); + await page.keyboard.type('h*e~~llo'); + await pressToggleBold(page); + await pressToggleUnderline(page); + await page.keyboard.type(' wo~~r*ld'); + await assertHTML( + page, + html` ++ + h + + + e + + + llo + + + wo + + + r + + ld +
+ `, + ); + }, + ); + + test.fixme( + 'can convert markdown text into rich text', + async ({page, isCollab}) => { + await focusEditor(page); + await page.keyboard.type('```markdown '); + await pasteFromClipboard(page, { + 'text/plain': IMPORTED_MARKDOWN, + }); + + const originalHTML = await getHTML(page); + + // Import from current markdown codeblock content await click(page, '.action-button .markdown'); await assertHTML(page, IMPORTED_MARKDOWN_HTML); - } - }); + + if (!isCollab) { + await undo(page); + await assertHTML(page, originalHTML); + await redo(page); + await assertHTML(page, IMPORTED_MARKDOWN_HTML); + + // Click again to run export/import cycle twice to make sure + // no extra nodes (e.g. newlines) are created + await click(page, '.action-button .markdown'); + await click(page, '.action-button .markdown'); + await click(page, '.action-button .markdown'); + await click(page, '.action-button .markdown'); + await assertHTML(page, IMPORTED_MARKDOWN_HTML); + } + }, + ); test.fixme('can type text with markdown', async ({page}) => { await focusEditor(page); @@ -958,50 +969,53 @@ test.describe('Markdown', () => { ); }); - test.fixme('can adjust selection after text match transformer', async ({page}) => { - await focusEditor(page); - await page.keyboard.type('Hello world'); - await moveLeft(page, 6); - await page.keyboard.type('[link](https://lexical.dev)'); - await assertHTML( - page, - html` - - `, - ); - // Selection starts after newly created link element - - if (E2E_BROWSER === 'webkit') { - // TODO: safari keeps dom selection on newly inserted link although Lexical's selection - // is correctly adjusted to start on [ world] text node. #updateDomSelection calls - // selection.setBaseAndExtent correctly, but safari does not seem to sync dom selection - // to newly passed values of anchor/focus/offset - await assertSelection(page, { - anchorOffset: 4, - anchorPath: [0, 1, 0, 0], - focusOffset: 4, - focusPath: [0, 1, 0, 0], - }); - } else { - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 2, 0], - focusOffset: 0, - focusPath: [0, 2, 0], - }); - } - }); + Hello + + link + + world + + `, + ); + // Selection starts after newly created link element + + if (E2E_BROWSER === 'webkit') { + // TODO: safari keeps dom selection on newly inserted link although Lexical's selection + // is correctly adjusted to start on [ world] text node. #updateDomSelection calls + // selection.setBaseAndExtent correctly, but safari does not seem to sync dom selection + // to newly passed values of anchor/focus/offset + await assertSelection(page, { + anchorOffset: 4, + anchorPath: [0, 1, 0, 0], + focusOffset: 4, + focusPath: [0, 1, 0, 0], + }); + } else { + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 2, 0], + focusOffset: 0, + focusPath: [0, 2, 0], + }); + } + }, + ); }); const TYPED_MARKDOWN = `# Markdown Shortcuts diff --git a/demos/playground/src/__tests__/e2e/Mutations.spec.mjs b/demos/playground/src/__tests__/e2e/Mutations.spec.mjs index 0947113c..caa7dd30 100644 --- a/demos/playground/src/__tests__/e2e/Mutations.spec.mjs +++ b/demos/playground/src/__tests__/e2e/Mutations.spec.mjs @@ -49,199 +49,238 @@ async function validateContent(page) { test.describe('Mutations', () => { test.beforeEach(({isCollab, page}) => initialize({isCollab, page})); - test.fixme(`Can restore the DOM to the editor state state`, async ({page}) => { - await focusEditor(page); - await page.keyboard.type( - 'Hello #world. This content #should remain #intact.', - ); - - await validateContent(page); - - // Remove the paragraph - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const paragraph = rootElement.firstChild; - - paragraph.remove(); - }); - await validateContent(page); - - // Remove the paragraph content - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const paragraph = rootElement.firstChild; - - paragraph.textContent = ''; - }); - await validateContent(page); - - // Remove the first text - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const firstTextNode = rootElement.firstChild.firstChild; - - firstTextNode.remove(); - }); - await validateContent(page); - - // Remove the first text contents - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const firstTextNode = rootElement.firstChild.firstChild; - - firstTextNode.textContent = ''; - }); - await validateContent(page); - - // Remove the second text - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const secondTextNode = rootElement.firstChild.firstChild.nextSibling; - - secondTextNode.remove(); - }); - await validateContent(page); - - // Remove the third text - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const thirdTextNode = - rootElement.firstChild.firstChild.nextSibling.nextSibling; - - thirdTextNode.remove(); - }); - await validateContent(page); - - // Remove the forth text - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const forthTextNode = - rootElement.firstChild.firstChild.nextSibling.nextSibling.nextSibling; - - forthTextNode.remove(); - }); - await validateContent(page); - - // Move last to first - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const paragraph = rootElement.firstChild; - const firstTextNode = paragraph.firstChild; - const forthTextNode = - paragraph.firstChild.nextSibling.nextSibling.nextSibling; - - paragraph.insertBefore(forthTextNode, firstTextNode); - }); - await validateContent(page); - - // Reverse sort all the children - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const paragraph = rootElement.firstChild; - const firstTextNode = paragraph.firstChild; - const secondTextNode = paragraph.firstChild.nextSibling; - const thirdTextNode = paragraph.firstChild.nextSibling.nextSibling; - const forthTextNode = - paragraph.firstChild.nextSibling.nextSibling.nextSibling; - - paragraph.insertBefore(forthTextNode, firstTextNode); - paragraph.insertBefore(thirdTextNode, firstTextNode); - paragraph.insertBefore(secondTextNode, firstTextNode); - }); - await validateContent(page); - - // Adding additional nodes to root - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const span = document.createElement('span'); - const span2 = document.createElement('span'); - const text = document.createTextNode('123'); - rootElement.appendChild(span); - rootElement.appendChild(span2); - rootElement.appendChild(text); - }); - await validateContent(page); - - // Adding additional nodes to paragraph - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const paragraph = rootElement.firstChild; - const firstTextNode = paragraph.firstChild; - const span = document.createElement('span'); - const span2 = document.createElement('span'); - const text = document.createTextNode('123'); - paragraph.appendChild(span); - paragraph.appendChild(text); - paragraph.insertBefore(span2, firstTextNode); - }); - await validateContent(page); - - // Adding additional nodes to text nodes - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const paragraph = rootElement.firstChild; - const firstTextNode = paragraph.firstChild; - const span = document.createElement('span'); - const text = document.createTextNode('123'); - firstTextNode.appendChild(span); - firstTextNode.appendChild(text); - }); - await validateContent(page); - - // Replace text nodes on text nodes #1 - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const paragraph = rootElement.firstChild; - const firstTextNode = paragraph.firstChild; - const text = document.createTextNode('123'); - firstTextNode.firstChild.replaceWith(text); - }); - await validateContent(page); - - // Replace text nodes on line break #2 - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const paragraph = rootElement.firstChild; - const firstTextNode = paragraph.firstChild; - const br = document.createElement('br'); - firstTextNode.firstChild.replaceWith(br); - }); - await validateContent(page); - - // Update text content, this should work :) - await await evaluate(page, () => { - const rootElement = document.querySelector('div[contenteditable="true"]'); - const paragraph = rootElement.firstChild; - const firstTextNode = paragraph.firstChild; - firstTextNode.firstChild.nodeValue = 'Bonjour '; - }); - await assertHTML( - page, - html` -- Bonjour - - #world - - . This content - - #should - - remain - - #intact - - . -
- `, - ); - await assertSelection(page, { - anchorOffset: 1, - anchorPath: [0, 6, 0], - focusOffset: 1, - focusPath: [0, 6, 0], - }); - }); + test.fixme( + `Can restore the DOM to the editor state state`, + async ({page}) => { + await focusEditor(page); + await page.keyboard.type( + 'Hello #world. This content #should remain #intact.', + ); + + await validateContent(page); + + // Remove the paragraph + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const paragraph = rootElement.firstChild; + + paragraph.remove(); + }); + await validateContent(page); + + // Remove the paragraph content + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const paragraph = rootElement.firstChild; + + paragraph.textContent = ''; + }); + await validateContent(page); + + // Remove the first text + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const firstTextNode = rootElement.firstChild.firstChild; + + firstTextNode.remove(); + }); + await validateContent(page); + + // Remove the first text contents + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const firstTextNode = rootElement.firstChild.firstChild; + + firstTextNode.textContent = ''; + }); + await validateContent(page); + + // Remove the second text + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const secondTextNode = rootElement.firstChild.firstChild.nextSibling; + + secondTextNode.remove(); + }); + await validateContent(page); + + // Remove the third text + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const thirdTextNode = + rootElement.firstChild.firstChild.nextSibling.nextSibling; + + thirdTextNode.remove(); + }); + await validateContent(page); + + // Remove the forth text + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const forthTextNode = + rootElement.firstChild.firstChild.nextSibling.nextSibling.nextSibling; + + forthTextNode.remove(); + }); + await validateContent(page); + + // Move last to first + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const paragraph = rootElement.firstChild; + const firstTextNode = paragraph.firstChild; + const forthTextNode = + paragraph.firstChild.nextSibling.nextSibling.nextSibling; + + paragraph.insertBefore(forthTextNode, firstTextNode); + }); + await validateContent(page); + + // Reverse sort all the children + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const paragraph = rootElement.firstChild; + const firstTextNode = paragraph.firstChild; + const secondTextNode = paragraph.firstChild.nextSibling; + const thirdTextNode = paragraph.firstChild.nextSibling.nextSibling; + const forthTextNode = + paragraph.firstChild.nextSibling.nextSibling.nextSibling; + + paragraph.insertBefore(forthTextNode, firstTextNode); + paragraph.insertBefore(thirdTextNode, firstTextNode); + paragraph.insertBefore(secondTextNode, firstTextNode); + }); + await validateContent(page); + + // Adding additional nodes to root + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const span = document.createElement('span'); + const span2 = document.createElement('span'); + const text = document.createTextNode('123'); + rootElement.appendChild(span); + rootElement.appendChild(span2); + rootElement.appendChild(text); + }); + await validateContent(page); + + // Adding additional nodes to paragraph + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const paragraph = rootElement.firstChild; + const firstTextNode = paragraph.firstChild; + const span = document.createElement('span'); + const span2 = document.createElement('span'); + const text = document.createTextNode('123'); + paragraph.appendChild(span); + paragraph.appendChild(text); + paragraph.insertBefore(span2, firstTextNode); + }); + await validateContent(page); + + // Adding additional nodes to text nodes + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const paragraph = rootElement.firstChild; + const firstTextNode = paragraph.firstChild; + const span = document.createElement('span'); + const text = document.createTextNode('123'); + firstTextNode.appendChild(span); + firstTextNode.appendChild(text); + }); + await validateContent(page); + + // Replace text nodes on text nodes #1 + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const paragraph = rootElement.firstChild; + const firstTextNode = paragraph.firstChild; + const text = document.createTextNode('123'); + firstTextNode.firstChild.replaceWith(text); + }); + await validateContent(page); + + // Replace text nodes on line break #2 + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const paragraph = rootElement.firstChild; + const firstTextNode = paragraph.firstChild; + const br = document.createElement('br'); + firstTextNode.firstChild.replaceWith(br); + }); + await validateContent(page); + + // Update text content, this should work :) + await await evaluate(page, () => { + const rootElement = document.querySelector( + 'div[contenteditable="true"]', + ); + const paragraph = rootElement.firstChild; + const firstTextNode = paragraph.firstChild; + firstTextNode.firstChild.nodeValue = 'Bonjour '; + }); + await assertHTML( + page, + html` ++ Bonjour + + #world + + . This content + + #should + + remain + + #intact + + . +
+ `, + ); + await assertSelection(page, { + anchorOffset: 1, + anchorPath: [0, 6, 0], + focusOffset: 1, + focusPath: [0, 6, 0], + }); + }, + ); }); diff --git a/demos/playground/src/__tests__/e2e/Navigation.spec.mjs b/demos/playground/src/__tests__/e2e/Navigation.spec.mjs index f1624154..e0268d6a 100644 --- a/demos/playground/src/__tests__/e2e/Navigation.spec.mjs +++ b/demos/playground/src/__tests__/e2e/Navigation.spec.mjs @@ -792,122 +792,61 @@ test.describe('Keyboard Navigation', () => { } }); - test.fixme('can navigate through the text with emoji word by word', async ({ - page, - browserName, - }) => { - await focusEditor(page); - // type sample text - await page.keyboard.type('123:)456 abc:):)de fg'); - await assertSelection(page, { - anchorOffset: 5, - anchorPath: [0, 5, 0], - focusOffset: 5, - focusPath: [0, 5, 0], - }); - // navigate through the text - // 1 left - await moveToPrevWord(page); - await assertSelection(page, { - anchorOffset: 3, - anchorPath: [0, 5, 0], - focusOffset: 3, - focusPath: [0, 5, 0], - }); - // 2 left - await moveToPrevWord(page); - if (browserName === 'firefox') { - await assertSelection(page, { - anchorOffset: 4, - anchorPath: [0, 2, 0], - focusOffset: 4, - focusPath: [0, 2, 0], - }); - } else if (browserName === 'webkit') { - await assertSelection(page, { - anchorOffset: 2, - anchorPath: [0, 4, 0, 0], - focusOffset: 2, - focusPath: [0, 4, 0, 0], - }); - } else { - await assertSelection(page, { - anchorOffset: 2, - anchorPath: [0, 4, 0, 0], - focusOffset: 2, - focusPath: [0, 4, 0, 0], - }); - } - // 3 left - await moveToPrevWord(page); - if (browserName === 'webkit') { + test.fixme( + 'can navigate through the text with emoji word by word', + async ({page, browserName}) => { + await focusEditor(page); + // type sample text + await page.keyboard.type('123:)456 abc:):)de fg'); await assertSelection(page, { - anchorOffset: 4, - anchorPath: [0, 2, 0], - focusOffset: 4, - focusPath: [0, 2, 0], - }); - } else if (browserName === 'firefox') { - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 0, 0], - focusOffset: 0, - focusPath: [0, 0, 0], + anchorOffset: 5, + anchorPath: [0, 5, 0], + focusOffset: 5, + focusPath: [0, 5, 0], }); - } else { + // navigate through the text + // 1 left + await moveToPrevWord(page); await assertSelection(page, { - anchorOffset: 7, - anchorPath: [0, 2, 0], - focusOffset: 7, - focusPath: [0, 2, 0], + anchorOffset: 3, + anchorPath: [0, 5, 0], + focusOffset: 3, + focusPath: [0, 5, 0], }); - } - // Non-Firefox requires more arrow presses - if (browserName !== 'firefox') { - // 4 left + // 2 left await moveToPrevWord(page); - if (browserName === 'webkit') { - await assertSelection(page, { - anchorOffset: 2, - anchorPath: [0, 1, 0, 0], - focusOffset: 2, - focusPath: [0, 1, 0, 0], - }); - } else { + if (browserName === 'firefox') { await assertSelection(page, { anchorOffset: 4, anchorPath: [0, 2, 0], focusOffset: 4, focusPath: [0, 2, 0], }); - } - // 5 left - await moveToPrevWord(page); - if (browserName === 'webkit') { + } else if (browserName === 'webkit') { await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 0, 0], - focusOffset: 0, - focusPath: [0, 0, 0], + anchorOffset: 2, + anchorPath: [0, 4, 0, 0], + focusOffset: 2, + focusPath: [0, 4, 0, 0], }); } else { await assertSelection(page, { anchorOffset: 2, - anchorPath: [0, 1, 0, 0], + anchorPath: [0, 4, 0, 0], focusOffset: 2, - focusPath: [0, 1, 0, 0], + focusPath: [0, 4, 0, 0], }); } - // 6 left + // 3 left await moveToPrevWord(page); - if (browserName === 'chromium') { + if (browserName === 'webkit') { await assertSelection(page, { - anchorOffset: 3, - anchorPath: [0, 0, 0], - focusOffset: 3, - focusPath: [0, 0, 0], + anchorOffset: 4, + anchorPath: [0, 2, 0], + focusOffset: 4, + focusPath: [0, 2, 0], }); - } else if (browserName === 'webkit') { + } else if (browserName === 'firefox') { await assertSelection(page, { anchorOffset: 0, anchorPath: [0, 0, 0], @@ -916,159 +855,185 @@ test.describe('Keyboard Navigation', () => { }); } else { await assertSelection(page, { - anchorOffset: 0, + anchorOffset: 7, anchorPath: [0, 2, 0], - focusOffset: 0, + focusOffset: 7, focusPath: [0, 2, 0], }); } + // Non-Firefox requires more arrow presses + if (browserName !== 'firefox') { + // 4 left + await moveToPrevWord(page); + if (browserName === 'webkit') { + await assertSelection(page, { + anchorOffset: 2, + anchorPath: [0, 1, 0, 0], + focusOffset: 2, + focusPath: [0, 1, 0, 0], + }); + } else { + await assertSelection(page, { + anchorOffset: 4, + anchorPath: [0, 2, 0], + focusOffset: 4, + focusPath: [0, 2, 0], + }); + } + // 5 left + await moveToPrevWord(page); + if (browserName === 'webkit') { + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 0, 0], + focusOffset: 0, + focusPath: [0, 0, 0], + }); + } else { + await assertSelection(page, { + anchorOffset: 2, + anchorPath: [0, 1, 0, 0], + focusOffset: 2, + focusPath: [0, 1, 0, 0], + }); + } + // 6 left + await moveToPrevWord(page); + if (browserName === 'chromium') { + await assertSelection(page, { + anchorOffset: 3, + anchorPath: [0, 0, 0], + focusOffset: 3, + focusPath: [0, 0, 0], + }); + } else if (browserName === 'webkit') { + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 0, 0], + focusOffset: 0, + focusPath: [0, 0, 0], + }); + } else { + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 2, 0], + focusOffset: 0, + focusPath: [0, 2, 0], + }); + } - // 7 left - await moveToPrevWord(page); - if (browserName === 'chromium') { + // 7 left + await moveToPrevWord(page); + if (browserName === 'chromium') { + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 0, 0], + focusOffset: 0, + focusPath: [0, 0, 0], + }); + } else { + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 0, 0], + focusOffset: 0, + focusPath: [0, 0, 0], + }); + } + + // 8 left + await moveToPrevWord(page); await assertSelection(page, { anchorOffset: 0, anchorPath: [0, 0, 0], focusOffset: 0, focusPath: [0, 0, 0], }); - } else { + } + // 1 right + await moveToNextWord(page); + if (browserName === 'webkit') { await assertSelection(page, { - anchorOffset: 0, + anchorOffset: 3, anchorPath: [0, 0, 0], - focusOffset: 0, + focusOffset: 3, focusPath: [0, 0, 0], }); - } - - // 8 left - await moveToPrevWord(page); - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 0, 0], - focusOffset: 0, - focusPath: [0, 0, 0], - }); - } - // 1 right - await moveToNextWord(page); - if (browserName === 'webkit') { - await assertSelection(page, { - anchorOffset: 3, - anchorPath: [0, 0, 0], - focusOffset: 3, - focusPath: [0, 0, 0], - }); - } else if (browserName === 'firefox') { - if (IS_WINDOWS) { - await assertSelection(page, { - anchorOffset: 4, - anchorPath: [0, 2, 0], - focusOffset: 4, - focusPath: [0, 2, 0], - }); + } else if (browserName === 'firefox') { + if (IS_WINDOWS) { + await assertSelection(page, { + anchorOffset: 4, + anchorPath: [0, 2, 0], + focusOffset: 4, + focusPath: [0, 2, 0], + }); + } else { + await assertSelection(page, { + anchorOffset: 3, + anchorPath: [0, 2, 0], + focusOffset: 3, + focusPath: [0, 2, 0], + }); + } } else { await assertSelection(page, { anchorOffset: 3, - anchorPath: [0, 2, 0], + anchorPath: [0, 0, 0], focusOffset: 3, - focusPath: [0, 2, 0], + focusPath: [0, 0, 0], }); } - } else { - await assertSelection(page, { - anchorOffset: 3, - anchorPath: [0, 0, 0], - focusOffset: 3, - focusPath: [0, 0, 0], - }); - } - // 2 right - await moveToNextWord(page); - if (browserName === 'webkit') { - await assertSelection(page, { - anchorOffset: 3, - anchorPath: [0, 2, 0], - focusOffset: 3, - focusPath: [0, 2, 0], - }); - } else if (browserName === 'firefox') { - if (IS_WINDOWS) { + // 2 right + await moveToNextWord(page); + if (browserName === 'webkit') { await assertSelection(page, { anchorOffset: 3, - anchorPath: [0, 5, 0], + anchorPath: [0, 2, 0], focusOffset: 3, - focusPath: [0, 5, 0], - }); - } else { - await assertSelection(page, { - anchorOffset: 2, - anchorPath: [0, 5, 0], - focusOffset: 2, - focusPath: [0, 5, 0], - }); - } - } else { - if (IS_WINDOWS) { - await assertSelection(page, { - anchorOffset: 2, - anchorPath: [0, 1, 0, 0], - focusOffset: 2, - focusPath: [0, 1, 0, 0], + focusPath: [0, 2, 0], }); + } else if (browserName === 'firefox') { + if (IS_WINDOWS) { + await assertSelection(page, { + anchorOffset: 3, + anchorPath: [0, 5, 0], + focusOffset: 3, + focusPath: [0, 5, 0], + }); + } else { + await assertSelection(page, { + anchorOffset: 2, + anchorPath: [0, 5, 0], + focusOffset: 2, + focusPath: [0, 5, 0], + }); + } } else { - await assertSelection(page, { - anchorOffset: 2, - anchorPath: [0, 1, 0, 0], - focusOffset: 2, - focusPath: [0, 1, 0, 0], - }); + if (IS_WINDOWS) { + await assertSelection(page, { + anchorOffset: 2, + anchorPath: [0, 1, 0, 0], + focusOffset: 2, + focusPath: [0, 1, 0, 0], + }); + } else { + await assertSelection(page, { + anchorOffset: 2, + anchorPath: [0, 1, 0, 0], + focusOffset: 2, + focusPath: [0, 1, 0, 0], + }); + } } - } - // 3 right - await moveToNextWord(page); - if (browserName === 'webkit') { - await assertSelection(page, { - anchorOffset: 7, - anchorPath: [0, 2, 0], - focusOffset: 7, - focusPath: [0, 2, 0], - }); - } else if (browserName === 'firefox') { - await assertSelection(page, { - anchorOffset: 5, - anchorPath: [0, 5, 0], - focusOffset: 5, - focusPath: [0, 5, 0], - }); - } else if (IS_WINDOWS) { - await assertSelection(page, { - anchorOffset: 4, - anchorPath: [0, 2, 0], - focusOffset: 4, - focusPath: [0, 2, 0], - }); - } else { - await assertSelection(page, { - anchorOffset: 3, - anchorPath: [0, 2, 0], - focusOffset: 3, - focusPath: [0, 2, 0], - }); - } - // 4 right - await moveToNextWord(page); - if (browserName === 'firefox') { - await assertSelection(page, { - anchorOffset: 5, - anchorPath: [0, 5, 0], - focusOffset: 5, - focusPath: [0, 5, 0], - }); - } else { - // 5 right + // 3 right await moveToNextWord(page); if (browserName === 'webkit') { + await assertSelection(page, { + anchorOffset: 7, + anchorPath: [0, 2, 0], + focusOffset: 7, + focusPath: [0, 2, 0], + }); + } else if (browserName === 'firefox') { await assertSelection(page, { anchorOffset: 5, anchorPath: [0, 5, 0], @@ -1077,23 +1042,22 @@ test.describe('Keyboard Navigation', () => { }); } else if (IS_WINDOWS) { await assertSelection(page, { - anchorOffset: 2, - anchorPath: [0, 4, 0, 0], - focusOffset: 2, - focusPath: [0, 4, 0, 0], + anchorOffset: 4, + anchorPath: [0, 2, 0], + focusOffset: 4, + focusPath: [0, 2, 0], }); - - // 6 right - await moveToNextWord(page); + } else { await assertSelection(page, { anchorOffset: 3, - anchorPath: [0, 5, 0], + anchorPath: [0, 2, 0], focusOffset: 3, - focusPath: [0, 5, 0], + focusPath: [0, 2, 0], }); - - // 7 right - await moveToNextWord(page); + } + // 4 right + await moveToNextWord(page); + if (browserName === 'firefox') { await assertSelection(page, { anchorOffset: 5, anchorPath: [0, 5, 0], @@ -1101,42 +1065,78 @@ test.describe('Keyboard Navigation', () => { focusPath: [0, 5, 0], }); } else { - await assertSelection(page, { - anchorOffset: 2, - anchorPath: [0, 4, 0, 0], - focusOffset: 2, - focusPath: [0, 4, 0, 0], - }); - - // 6 right + // 5 right await moveToNextWord(page); - await assertSelection(page, { - anchorOffset: 2, - anchorPath: [0, 5, 0], - focusOffset: 2, - focusPath: [0, 5, 0], - }); + if (browserName === 'webkit') { + await assertSelection(page, { + anchorOffset: 5, + anchorPath: [0, 5, 0], + focusOffset: 5, + focusPath: [0, 5, 0], + }); + } else if (IS_WINDOWS) { + await assertSelection(page, { + anchorOffset: 2, + anchorPath: [0, 4, 0, 0], + focusOffset: 2, + focusPath: [0, 4, 0, 0], + }); - // 7 right - await moveToNextWord(page); - await assertSelection(page, { - anchorOffset: 5, - anchorPath: [0, 5, 0], - focusOffset: 5, - focusPath: [0, 5, 0], - }); - } + // 6 right + await moveToNextWord(page); + await assertSelection(page, { + anchorOffset: 3, + anchorPath: [0, 5, 0], + focusOffset: 3, + focusPath: [0, 5, 0], + }); - if (browserName === 'webkit') { - // 6 right - await moveToNextWord(page); - await assertSelection(page, { - anchorOffset: 5, - anchorPath: [0, 5, 0], - focusOffset: 5, - focusPath: [0, 5, 0], - }); + // 7 right + await moveToNextWord(page); + await assertSelection(page, { + anchorOffset: 5, + anchorPath: [0, 5, 0], + focusOffset: 5, + focusPath: [0, 5, 0], + }); + } else { + await assertSelection(page, { + anchorOffset: 2, + anchorPath: [0, 4, 0, 0], + focusOffset: 2, + focusPath: [0, 4, 0, 0], + }); + + // 6 right + await moveToNextWord(page); + await assertSelection(page, { + anchorOffset: 2, + anchorPath: [0, 5, 0], + focusOffset: 2, + focusPath: [0, 5, 0], + }); + + // 7 right + await moveToNextWord(page); + await assertSelection(page, { + anchorOffset: 5, + anchorPath: [0, 5, 0], + focusOffset: 5, + focusPath: [0, 5, 0], + }); + } + + if (browserName === 'webkit') { + // 6 right + await moveToNextWord(page); + await assertSelection(page, { + anchorOffset: 5, + anchorPath: [0, 5, 0], + focusOffset: 5, + focusPath: [0, 5, 0], + }); + } } - } - }); + }, + ); }); diff --git a/demos/playground/src/__tests__/e2e/Selection.spec.mjs b/demos/playground/src/__tests__/e2e/Selection.spec.mjs index ebb99b76..336ca0a0 100644 --- a/demos/playground/src/__tests__/e2e/Selection.spec.mjs +++ b/demos/playground/src/__tests__/e2e/Selection.spec.mjs @@ -40,8 +40,8 @@ import { } from '../utils/index.mjs'; test.describe('Selection', () => { - test.beforeEach(({ isCollab, page }) => initialize({ isCollab, page })); - test('does not focus the editor on load', async ({ page }) => { + test.beforeEach(({isCollab, page}) => initialize({isCollab, page})); + test('does not focus the editor on load', async ({page}) => { const editorHasFocus = async () => await evaluate(page, () => { const editorElement = document.querySelector( @@ -62,92 +62,91 @@ test.describe('Selection', () => { expect(await editorHasFocus()).toEqual(false); }); - test.fixme('keeps single active selection for nested editors', async ({ - page, - isPlainText, - browserName, - }) => { - test.skip(isPlainText); - const hasSelection = async (parentSelector) => - await evaluate( - page, - (_parentSelector) => { - return ( - document - .querySelector(`${_parentSelector} > .tree-view-output pre`) - .__lexicalEditor.getEditorState()._selection !== null - ); - }, - parentSelector, - ); + test.fixme( + 'keeps single active selection for nested editors', + async ({page, isPlainText, browserName}) => { + test.skip(isPlainText); + const hasSelection = async (parentSelector) => + await evaluate( + page, + (_parentSelector) => { + return ( + document + .querySelector(`${_parentSelector} > .tree-view-output pre`) + .__lexicalEditor.getEditorState()._selection !== null + ); + }, + parentSelector, + ); - await focusEditor(page); - await insertSampleImage(page); - await insertImageCaption(page, 'Hello world'); - expect(await hasSelection('.image-caption-container')).toBe(true); - expect(await hasSelection('.editor-shell')).toBe(false); + await focusEditor(page); + await insertSampleImage(page); + await insertImageCaption(page, 'Hello world'); + expect(await hasSelection('.image-caption-container')).toBe(true); + expect(await hasSelection('.editor-shell')).toBe(false); - // Click outside of the editor and check that selection remains the same - await click(page, 'header img'); - expect(await hasSelection('.image-caption-container')).toBe(true); - expect(await hasSelection('.editor-shell')).toBe(false); + // Click outside of the editor and check that selection remains the same + await click(page, 'header img'); + expect(await hasSelection('.image-caption-container')).toBe(true); + expect(await hasSelection('.editor-shell')).toBe(false); - // Back to root editor - if (browserName === 'firefox') { - // TODO: - // In firefox .focus() on editor does not trigger selectionchange, while checking it - // explicitly clicking on an editor (passing position that is on the right side to - // prevent clicking on image and its nested editor) - await click(page, '.editor-shell', { position: { x: 600, y: 150 } }); - } else { - await focusEditor(page); - } - expect(await hasSelection('.image-caption-container')).toBe(false); - expect(await hasSelection('.editor-shell')).toBe(true); + // Back to root editor + if (browserName === 'firefox') { + // TODO: + // In firefox .focus() on editor does not trigger selectionchange, while checking it + // explicitly clicking on an editor (passing position that is on the right side to + // prevent clicking on image and its nested editor) + await click(page, '.editor-shell', {position: {x: 600, y: 150}}); + } else { + await focusEditor(page); + } + expect(await hasSelection('.image-caption-container')).toBe(false); + expect(await hasSelection('.editor-shell')).toBe(true); - // Click outside of the editor and check that selection remains the same - await click(page, 'header img'); - expect(await hasSelection('.image-caption-container')).toBe(false); - expect(await hasSelection('.editor-shell')).toBe(true); + // Click outside of the editor and check that selection remains the same + await click(page, 'header img'); + expect(await hasSelection('.image-caption-container')).toBe(false); + expect(await hasSelection('.editor-shell')).toBe(true); - // Back to nested editor editor - await focusEditor(page, '.image-caption-container'); - expect(await hasSelection('.image-caption-container')).toBe(true); - expect(await hasSelection('.editor-shell')).toBe(false); - }); + // Back to nested editor editor + await focusEditor(page, '.image-caption-container'); + expect(await hasSelection('.image-caption-container')).toBe(true); + expect(await hasSelection('.editor-shell')).toBe(false); + }, + ); - test.fixme('can wrap post-linebreak nodes into new element', async ({ - page, - isPlainText, - }) => { - test.skip(isPlainText); - await focusEditor(page); - await page.keyboard.type('Line1'); - await pressShiftEnter(page); - await page.keyboard.type('Line2'); - await page.keyboard.down('Shift'); - await moveToLineBeginning(page); - await page.keyboard.up('Shift'); - await selectFromFormatDropdown(page, '.code'); - await assertHTML( - page, - html` -- Line1 -
-
- Line2
-
- `,
- );
- });
+ test.fixme(
+ 'can wrap post-linebreak nodes into new element',
+ async ({page, isPlainText}) => {
+ test.skip(isPlainText);
+ await focusEditor(page);
+ await page.keyboard.type('Line1');
+ await pressShiftEnter(page);
+ await page.keyboard.type('Line2');
+ await page.keyboard.down('Shift');
+ await moveToLineBeginning(page);
+ await page.keyboard.up('Shift');
+ await selectFromFormatDropdown(page, '.code');
+ await assertHTML(
+ page,
+ html`
+ + Line1 +
+
+ Line2
+
+ `,
+ );
+ },
+ );
test('can delete text by line with CMD+delete', async ({
page,
@@ -210,27 +209,27 @@ test.describe('Selection', () => {
);
});
- test.fixme('Can insert inline element within text and put selection after it', async ({
- page,
- isPlainText,
- }) => {
- test.skip(isPlainText);
- await focusEditor(page);
- await page.keyboard.type('Hello world');
- await moveToPrevWord(page);
- await pasteFromClipboard(page, {
- 'text/html': `link`,
- });
- await sleep(3000);
- await assertSelection(page, {
- anchorOffset: 4,
- anchorPath: [0, 1, 0, 0],
- focusOffset: 4,
- focusPath: [0, 1, 0, 0],
- });
- });
+ test.fixme(
+ 'Can insert inline element within text and put selection after it',
+ async ({page, isPlainText}) => {
+ test.skip(isPlainText);
+ await focusEditor(page);
+ await page.keyboard.type('Hello world');
+ await moveToPrevWord(page);
+ await pasteFromClipboard(page, {
+ 'text/html': `link`,
+ });
+ await sleep(3000);
+ await assertSelection(page, {
+ anchorOffset: 4,
+ anchorPath: [0, 1, 0, 0],
+ focusOffset: 4,
+ focusPath: [0, 1, 0, 0],
+ });
+ },
+ );
- test('Can delete at boundary #4221', async ({ page, isPlainText }) => {
+ test('Can delete at boundary #4221', async ({page, isPlainText}) => {
test.skip(!isPlainText);
await focusEditor(page);
await page.keyboard.type('aaa');
@@ -272,7 +271,7 @@ test.describe('Selection', () => {
);
});
- test('Can select all with node selection', async ({ page, isPlainText }) => {
+ test('Can select all with node selection', async ({page, isPlainText}) => {
test.skip(isPlainText);
await focusEditor(page);
await page.keyboard.type('# Text before');
@@ -288,36 +287,39 @@ test.describe('Selection', () => {
);
});
- test.fixme('Can delete forward a Collapsible', async ({ page, isPlainText }) => {
- test.skip(isPlainText);
- if (!IS_MAC) {
- // Do Windows/Linux have equivalent shortcuts?
- return;
- }
- await focusEditor(page);
- await page.keyboard.type('abc');
- await insertCollapsible(page);
- await moveToEditorBeginning(page);
- await moveRight(page, 3);
- await deleteForward(page);
+ test.fixme(
+ 'Can delete forward a Collapsible',
+ async ({page, isPlainText}) => {
+ test.skip(isPlainText);
+ if (!IS_MAC) {
+ // Do Windows/Linux have equivalent shortcuts?
+ return;
+ }
+ await focusEditor(page);
+ await page.keyboard.type('abc');
+ await insertCollapsible(page);
+ await moveToEditorBeginning(page);
+ await moveRight(page, 3);
+ await deleteForward(page);
- await assertHTML(
- page,
- html`
- - abc -
-+ abc +
+- Hello - world - ! -
- `, - ); + await assertHTML( + page, + html` ++ Hello + world + ! +
+ `, + ); - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 1, 0], - focusOffset: 5, - focusPath: [0, 1, 0], - }); - }); + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 1, 0], + focusOffset: 5, + focusPath: [0, 1, 0], + }); + }, + ); - test.fixme(`Can select text and change the font-size and font-family`, async ({ - page, - isPlainText, - }) => { - test.skip(isPlainText); + test.fixme( + `Can select text and change the font-size and font-family`, + async ({page, isPlainText}) => { + test.skip(isPlainText); - await focusEditor(page); - await page.keyboard.type('Hello world!'); + await focusEditor(page); + await page.keyboard.type('Hello world!'); - await moveLeft(page); - await selectCharacters(page, 'left', 5); + await moveLeft(page); + await selectCharacters(page, 'left', 5); - await assertSelection(page, { - anchorOffset: 11, - anchorPath: [0, 0, 0], - focusOffset: 6, - focusPath: [0, 0, 0], - }); + await assertSelection(page, { + anchorOffset: 11, + anchorPath: [0, 0, 0], + focusOffset: 6, + focusPath: [0, 0, 0], + }); - await click(page, '.font-size'); - await click(page, 'button:has-text("10px")'); + await click(page, '.font-size'); + await click(page, 'button:has-text("10px")'); - await assertHTML( - page, - html` -- Hello - world - ! -
- `, - ); + await assertHTML( + page, + html` ++ Hello + world + ! +
+ `, + ); - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 1, 0], - focusOffset: 5, - focusPath: [0, 1, 0], - }); + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 1, 0], + focusOffset: 5, + focusPath: [0, 1, 0], + }); - await click(page, '.font-family'); - await click(page, 'button:has-text("Georgia")'); + await click(page, '.font-family'); + await click(page, 'button:has-text("Georgia")'); - await assertHTML( - page, - html` -- Hello - - world - - ! -
- `, - ); + await assertHTML( + page, + html` ++ Hello + + world + + ! +
+ `, + ); - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 1, 0], - focusOffset: 5, - focusPath: [0, 1, 0], - }); + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 1, 0], + focusOffset: 5, + focusPath: [0, 1, 0], + }); - await click(page, '.font-size'); - await click(page, 'button:has-text("20px")'); + await click(page, '.font-size'); + await click(page, 'button:has-text("20px")'); - await assertHTML( - page, - html` -- Hello - - world - - ! -
- `, - ); + await assertHTML( + page, + html` ++ Hello + + world + + ! +
+ `, + ); - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 1, 0], - focusOffset: 5, - focusPath: [0, 1, 0], - }); - }); + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 1, 0], + focusOffset: 5, + focusPath: [0, 1, 0], + }); + }, + ); test(`Can select multiple text parts and format them with shortcuts`, async ({ page, @@ -916,61 +916,117 @@ test.describe('TextFormatting', () => { ); }); - test.fixme(`The active state of the button in the toolbar should to be displayed correctly`, async ({ - page, - isPlainText, - }) => { - test.skip(isPlainText); - await focusEditor(page); - await page.keyboard.type('A'); - await page.keyboard.press('Enter'); - await page.keyboard.type('B'); - await selectCharacters(page, 'left', 3); - await toggleBold(page); - await toggleItalic(page); - - const isButtonActiveStatusDisplayedCorrectly = await evaluate(page, () => { - const isFloatingToolbarBoldButtonActive = !!document.querySelector( - '.floating-text-format-popup .popup-item.active i.format.bold', - ); - const isFloatingToolbarItalicButtonActive = !!document.querySelector( - '.floating-text-format-popup .popup-item.active i.format.italic', - ); - const isToolbarBoldButtonActive = !!document.querySelector( - '.toolbar .toolbar-item.active i.format.bold', - ); - const isToolbarItalicButtonActive = !!document.querySelector( - '.toolbar .toolbar-item.active i.format.italic', + test.fixme( + `The active state of the button in the toolbar should to be displayed correctly`, + async ({page, isPlainText}) => { + test.skip(isPlainText); + await focusEditor(page); + await page.keyboard.type('A'); + await page.keyboard.press('Enter'); + await page.keyboard.type('B'); + await selectCharacters(page, 'left', 3); + await toggleBold(page); + await toggleItalic(page); + + const isButtonActiveStatusDisplayedCorrectly = await evaluate( + page, + () => { + const isFloatingToolbarBoldButtonActive = !!document.querySelector( + '.floating-text-format-popup .popup-item.active i.format.bold', + ); + const isFloatingToolbarItalicButtonActive = !!document.querySelector( + '.floating-text-format-popup .popup-item.active i.format.italic', + ); + const isToolbarBoldButtonActive = !!document.querySelector( + '.toolbar .toolbar-item.active i.format.bold', + ); + const isToolbarItalicButtonActive = !!document.querySelector( + '.toolbar .toolbar-item.active i.format.italic', + ); + + return ( + isFloatingToolbarBoldButtonActive && + isFloatingToolbarItalicButtonActive && + isToolbarBoldButtonActive && + isToolbarItalicButtonActive + ); + }, ); - return ( - isFloatingToolbarBoldButtonActive && - isFloatingToolbarItalicButtonActive && - isToolbarBoldButtonActive && - isToolbarItalicButtonActive + expect(isButtonActiveStatusDisplayedCorrectly).toBe(true); + }, + ); + + test.fixme( + 'Regression #2523: can toggle format when selecting a TextNode edge followed by a non TextNode; ', + async ({page, isCollab, isPlainText}) => { + test.skip(isPlainText); + await focusEditor(page); + + await page.keyboard.type('A'); + await insertSampleImage(page); + await page.keyboard.type('BC'); + + await moveLeft(page, 1); + await selectCharacters(page, 'left', 2); + + if (!isCollab) { + await waitForSelector(page, '.editor-image img'); + await assertHTML( + page, + html` +
+ A
+
+
+ A
+
+
- A
-
-
- A
-
-
alert(1)alert(1);
alert(2);
alert(3);
`,
- );
- });
+ test.fixme(
+ `Properly pastes in code blocks`,
+ async ({page, isPlainText, isCollab}) => {
+ test.skip(isPlainText || isCollab);
+ await focusEditor(page);
+ await page.keyboard.type('``` alert(1);');
+ await page.keyboard.press('Enter');
+ await page.keyboard.type('alert(2);');
+ await page.keyboard.press('Enter');
+ await page.keyboard.type('alert(3);');
+ await page.keyboard.press('ArrowUp');
+ await page.keyboard.press('ArrowUp');
+ await page.keyboard.press('ArrowLeft');
+ await selectCharacters(page, 'left', 8);
+ const clipboard = await copyToClipboard(page);
+ await page.keyboard.press('ArrowLeft');
+ await pasteFromClipboard(page, clipboard);
+ await assertHTML(
+ page,
+ `alert(1)alert(1);
alert(2);
alert(3);
`,
+ );
+ },
+ );
});
diff --git a/demos/playground/src/__tests__/regression/230-navigation-around-hashtags.spec.mjs b/demos/playground/src/__tests__/regression/230-navigation-around-hashtags.spec.mjs
index dde412d6..b8764350 100644
--- a/demos/playground/src/__tests__/regression/230-navigation-around-hashtags.spec.mjs
+++ b/demos/playground/src/__tests__/regression/230-navigation-around-hashtags.spec.mjs
@@ -19,33 +19,36 @@ import {
test.describe('Regression test #230', () => {
test.beforeEach(({isCollab, page}) => initialize({isCollab, page}));
- test.fixme(`Is able to right arrow before hashtag after inserting text node`, async ({
- page,
- }) => {
- await focusEditor(page);
- await page.keyboard.type('#foo');
- await waitForSelector(page, '.PlaygroundEditorTheme__hashtag');
- await moveLeft(page, 4);
- await page.keyboard.type('a');
- await page.keyboard.press('Backspace');
- await page.keyboard.press('ArrowRight');
- await assertHTML(
- page,
- html`
- - - #foo - -
- `, - ); - await assertSelection(page, { - anchorOffset: 1, - anchorPath: [0, 0, 0], - focusOffset: 1, - focusPath: [0, 0, 0], - }); - }); + test.fixme( + `Is able to right arrow before hashtag after inserting text node`, + async ({page}) => { + await focusEditor(page); + await page.keyboard.type('#foo'); + await waitForSelector(page, '.PlaygroundEditorTheme__hashtag'); + await moveLeft(page, 4); + await page.keyboard.type('a'); + await page.keyboard.press('Backspace'); + await page.keyboard.press('ArrowRight'); + await assertHTML( + page, + html` ++ + #foo + +
+ `, + ); + await assertSelection(page, { + anchorOffset: 1, + anchorPath: [0, 0, 0], + focusOffset: 1, + focusPath: [0, 0, 0], + }); + }, + ); }); diff --git a/demos/playground/src/__tests__/regression/231-empty-text-nodes.spec.mjs b/demos/playground/src/__tests__/regression/231-empty-text-nodes.spec.mjs index 7a2395cc..d15a1672 100644 --- a/demos/playground/src/__tests__/regression/231-empty-text-nodes.spec.mjs +++ b/demos/playground/src/__tests__/regression/231-empty-text-nodes.spec.mjs @@ -23,28 +23,29 @@ import { test.describe('Regression test #231', () => { test.beforeEach(({isCollab, page}) => initialize({isCollab, page})); - test.fixme(`Does not generate segment error when editing empty text nodes`, async ({ - page, - }) => { - await focusEditor(page); - await page.keyboard.type('#foo'); - await waitForSelector(page, '.PlaygroundEditorTheme__hashtag'); - await moveLeft(page, 4); - await page.keyboard.type('a'); - await page.keyboard.press('Backspace'); - await moveRight(page, 5); - await pressBackspace(page, 5); - await assertHTML( - page, - html` -- - Luke Skywalker - -
- `, - ); - await assertSelection(page, { - anchorOffset: 14, - anchorPath: [0, 0, 0], - focusOffset: 14, - focusPath: [0, 0, 0], - }); - await moveToEditorBeginning(page); - await page.keyboard.press('Enter'); - await page.keyboard.press('Backspace'); - await assertHTML( - page, - html` -- - Luke Skywalker - -
- `, - ); - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 0, 0], - focusOffset: 0, - focusPath: [0, 0, 0], - }); - }); + test.fixme( + `Is able to correctly handle backspace press at the line boundary`, + async ({page}) => { + await focusEditor(page); + await page.keyboard.type('Luke'); + await waitForSelector(page, '#typeahead-menu ul li'); + await page.keyboard.press('Enter'); + await assertHTML( + page, + html` ++ + Luke Skywalker + +
+ `, + ); + await assertSelection(page, { + anchorOffset: 14, + anchorPath: [0, 0, 0], + focusOffset: 14, + focusPath: [0, 0, 0], + }); + await moveToEditorBeginning(page); + await page.keyboard.press('Enter'); + await page.keyboard.press('Backspace'); + await assertHTML( + page, + html` ++ + Luke Skywalker + +
+ `, + ); + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 0, 0], + focusOffset: 0, + focusPath: [0, 0, 0], + }); + }, + ); }); diff --git a/demos/playground/src/__tests__/regression/429-swapping-emoji.spec.mjs b/demos/playground/src/__tests__/regression/429-swapping-emoji.spec.mjs index 9278de12..e1c4df2c 100644 --- a/demos/playground/src/__tests__/regression/429-swapping-emoji.spec.mjs +++ b/demos/playground/src/__tests__/regression/429-swapping-emoji.spec.mjs @@ -18,42 +18,14 @@ import { test.describe('Regression test #429', () => { test.beforeEach(({isCollab, page}) => initialize({isCollab, page})); - test.fixme(`Can add new lines before the line with emoji`, async ({ - isRichText, - page, - }) => { - await focusEditor(page); - await page.keyboard.type(':) or :('); - await assertHTML( - page, - html` -- - 🙂 - - or - - 🙁 - -
- `, - ); - await assertSelection(page, { - anchorOffset: 2, - anchorPath: [0, 2, 0, 0], - focusOffset: 2, - focusPath: [0, 2, 0, 0], - }); - - await moveLeft(page, 6); - await page.keyboard.press('Enter'); - if (isRichText) { + test.fixme( + `Can add new lines before the line with emoji`, + async ({isRichText, page}) => { + await focusEditor(page); + await page.keyboard.type(':) or :('); await assertHTML( page, html` -@@ -68,19 +40,71 @@ test.describe('Regression test #429', () => { `, ); await assertSelection(page, { - anchorOffset: 0, - anchorPath: [1, 0, 0, 0], - focusOffset: 0, - focusPath: [1, 0, 0, 0], + anchorOffset: 2, + anchorPath: [0, 2, 0, 0], + focusOffset: 2, + focusPath: [0, 2, 0, 0], }); - } else { + + await moveLeft(page, 6); + await page.keyboard.press('Enter'); + if (isRichText) { + await assertHTML( + page, + html` +
+ + 🙂 + + or + + 🙁 + +
+ `, + ); + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [1, 0, 0, 0], + focusOffset: 0, + focusPath: [1, 0, 0, 0], + }); + } else { + await assertHTML( + page, + html` +
+
+
+ 🙂
+
+ or
+
+ 🙁
+
+
-
🙂
@@ -93,34 +117,10 @@ test.describe('Regression test #429', () => {
);
await assertSelection(page, {
anchorOffset: 0,
- anchorPath: [0, 1, 0, 0],
+ anchorPath: [0, 0, 0, 0],
focusOffset: 0,
- focusPath: [0, 1, 0, 0],
+ focusPath: [0, 0, 0, 0],
});
- }
-
- await page.keyboard.press('Backspace');
- await assertHTML(
- page,
- html`
-
- - 🙂 - - or - - 🙁 - -
- `, - ); - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [0, 0, 0, 0], - focusOffset: 0, - focusPath: [0, 0, 0, 0], - }); - }); + }, + ); }); diff --git a/demos/playground/src/__tests__/utils/index.mjs b/demos/playground/src/__tests__/utils/index.mjs index f9f1c180..140861f1 100644 --- a/demos/playground/src/__tests__/utils/index.mjs +++ b/demos/playground/src/__tests__/utils/index.mjs @@ -6,12 +6,12 @@ * */ -import { expect, test as base } from '@playwright/test'; -import { randomUUID } from 'node:crypto'; +import {expect, test as base} from '@playwright/test'; +import {randomUUID} from 'node:crypto'; import prettier from 'prettier'; -import { URLSearchParams } from 'url'; +import {URLSearchParams} from 'url'; -import { selectAll } from '../keyboardShortcuts/index.mjs'; +import {selectAll} from '../keyboardShortcuts/index.mjs'; export const E2E_PORT = process.env.E2E_PORT || 5173; export const E2E_BROWSER = process.env.E2E_BROWSER; @@ -68,12 +68,13 @@ export async function initialize({ } const urlParams = appSettingsToURLParams(appSettings); - const url = `http://localhost:${E2E_PORT}/${isCollab ? 'split/' : '' - }?${urlParams.toString()}`; + const url = `http://localhost:${E2E_PORT}/${ + isCollab ? 'split/' : '' + }?${urlParams.toString()}`; // Having more horizontal space prevents redundant text wraps for tests // which affects CMD+ArrowRight/Left navigation - page.setViewportSize({ height: 1000, width: isCollab ? 2500 : 1250 }); + page.setViewportSize({height: 1000, width: isCollab ? 2500 : 1250}); await page.goto(url); await exposeLexicalEditor(page); @@ -102,7 +103,7 @@ export const test = base.extend({ legacyEvents: LEGACY_EVENTS, }); -export { expect } from '@playwright/test'; +export {expect} from '@playwright/test'; function appSettingsToURLParams(appSettings) { const params = new URLSearchParams(); @@ -149,7 +150,7 @@ export async function assertHTML( page, expectedHtml, expectedHtmlFrameRight = expectedHtml, - { ignoreClasses = false, ignoreInlineStyles = false } = {}, + {ignoreClasses = false, ignoreInlineStyles = false} = {}, ) { if (IS_COLLAB) { const withRetry = async (fn) => await retryAsync(page, fn, 5); @@ -223,7 +224,7 @@ async function assertSelectionOnPageOrFrame(page, expected) { return path.reverse(); }; - const { anchorNode, anchorOffset, focusNode, focusOffset } = + const {anchorNode, anchorOffset, focusNode, focusOffset} = window.getSelection(); return { @@ -351,7 +352,7 @@ async function pasteFromClipboardPageOrFrame(pageOrFrame, clipboardData) { const [base64, type] = clipboardValue; const res = await fetch(base64); const blob = await res.blob(); - files.push(new File([blob], 'file', { type })); + files.push(new File([blob], 'file', {type})); } } let eventClipboardData; @@ -398,7 +399,7 @@ async function pasteFromClipboardPageOrFrame(pageOrFrame, clipboardData) { } } }, - { canUseBeforeInput, clipboardData }, + {canUseBeforeInput, clipboardData}, ); } @@ -594,7 +595,7 @@ export async function insertImageCaption(page, caption) { } export async function mouseMoveToSelector(page, selector) { - const { x, width, y, height } = await selectorBoundingBox(page, selector); + const {x, width, y, height} = await selectorBoundingBox(page, selector); await page.mouse.move(x + width / 2, y + height / 2); } @@ -650,7 +651,7 @@ export async function dragImage( ); } -export function prettifyHTML(string, { ignoreClasses, ignoreInlineStyles } = {}) { +export function prettifyHTML(string, {ignoreClasses, ignoreInlineStyles} = {}) { let output = string; if (ignoreClasses) { @@ -661,16 +662,15 @@ export function prettifyHTML(string, { ignoreClasses, ignoreInlineStyles } = {}) output = output.replace(/\sstyle="([^"]*)"/g, ''); } - return prettier - .format(output, { - plugins: ['prettier-plugin-organize-attributes'], - pluginSearchDirs: ['../../../../'], - attributeGroups: ['$DEFAULT', '^data-'], - attributeSort: 'ASC', - bracketSameLine: true, - htmlWhitespaceSensitivity: 'ignore', - parser: 'html', - }) + return prettier.format(output, { + plugins: ['prettier-plugin-organize-attributes'], + pluginSearchDirs: ['../../../../'], + attributeGroups: ['$DEFAULT', '^data-'], + attributeSort: 'ASC', + bracketSameLine: true, + htmlWhitespaceSensitivity: 'ignore', + parser: 'html', + }); } // This function does not suppose to do anything, it's only used as a trigger @@ -772,11 +772,13 @@ export async function selectCellsFromTableCords( } const firstRowFirstColumnCell = await leftFrame.locator( - `table:first-of-type > tr:nth-child(${firstCords.y + 1}) > ${isFirstHeader ? 'th' : 'td' + `table:first-of-type > tr:nth-child(${firstCords.y + 1}) > ${ + isFirstHeader ? 'th' : 'td' }:nth-child(${firstCords.x + 1})`, ); const secondRowSecondCell = await leftFrame.locator( - `table:first-of-type > tr:nth-child(${secondCords.y + 1}) > ${isSecondHeader ? 'th' : 'td' + `table:first-of-type > tr:nth-child(${secondCords.y + 1}) > ${ + isSecondHeader ? 'th' : 'td' }:nth-child(${secondCords.x + 1})`, ); @@ -784,7 +786,7 @@ export async function selectCellsFromTableCords( await firstRowFirstColumnCell.click( // This is a test runner quirk. Chrome seems to need two clicks to focus on the // content editable cell before dragging, but Firefox treats it as a double click event. - E2E_BROWSER === 'chromium' ? { clickCount: 2 } : {}, + E2E_BROWSER === 'chromium' ? {clickCount: 2} : {}, ); await dragMouse( diff --git a/demos/playground/src/index.css b/demos/playground/src/index.css index 64e886e5..9ae9a40b 100644 --- a/demos/playground/src/index.css +++ b/demos/playground/src/index.css @@ -10,7 +10,11 @@ body { margin: 0; - font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular', + font-family: + system-ui, + -apple-system, + BlinkMacSystemFont, + '.SFNSText-Regular', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; @@ -714,7 +718,9 @@ i.prettier-error { z-index: 10; display: block; position: fixed; - box-shadow: 0 12px 28px 0 rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1), + box-shadow: + 0 12px 28px 0 rgba(0, 0, 0, 0.2), + 0 2px 4px 0 rgba(0, 0, 0, 0.1), inset 0 0 0 1px rgba(255, 255, 255, 0.5); border-radius: 8px; min-height: 40px; diff --git a/demos/playground/svelte.config.js b/demos/playground/svelte.config.js index 3630bb39..2cd95b6b 100644 --- a/demos/playground/svelte.config.js +++ b/demos/playground/svelte.config.js @@ -1,7 +1,7 @@ -import sveltePreprocess from 'svelte-preprocess' +import sveltePreprocess from 'svelte-preprocess'; export default { // Consult https://github.com/sveltejs/svelte-preprocess // for more information about preprocessors - preprocess: sveltePreprocess() -} + preprocess: sveltePreprocess(), +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86392005..4d6fedaf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -106,6 +106,9 @@ importers: prettier-plugin-organize-attributes: specifier: ^1.0.0 version: 1.0.0(prettier@3.2.5) + prettier-plugin-svelte: + specifier: ^3.2.2 + version: 3.2.2(prettier@3.2.5)(svelte@4.2.12) serve: specifier: ^14.2.0 version: 14.2.0