|
|
@@ -1,6 +1,15 @@
|
|
|
import { expect } from '@playwright/test'
|
|
|
import { test } from './fixtures'
|
|
|
-import { createRandomPage, enterNextBlock, modKey } from './utils'
|
|
|
+import {
|
|
|
+ createRandomPage,
|
|
|
+ enterNextBlock,
|
|
|
+ modKey,
|
|
|
+ repeatKeyPress,
|
|
|
+ moveCursor,
|
|
|
+ selectCharacters,
|
|
|
+ getSelection,
|
|
|
+ getCursorPos,
|
|
|
+} from './utils'
|
|
|
import { dispatch_kb_events } from './util/keyboard-events'
|
|
|
import * as kb_events from './util/keyboard-events'
|
|
|
|
|
|
@@ -619,3 +628,192 @@ test('should keep correct undo and redo seq after indenting or outdenting the bl
|
|
|
await page.keyboard.press(modKey + '+Shift+z')
|
|
|
await expect(page.locator('textarea >> nth=0')).toHaveText("aaa bbb")
|
|
|
})
|
|
|
+
|
|
|
+test.describe('Text Formatting', () => {
|
|
|
+ const formats = [
|
|
|
+ { name: 'bold', prefix: '**', postfix: '**', shortcut: modKey + '+b' },
|
|
|
+ { name: 'italic', prefix: '*', postfix: '*', shortcut: modKey + '+i' },
|
|
|
+ {
|
|
|
+ name: 'strikethrough',
|
|
|
+ prefix: '~~',
|
|
|
+ postfix: '~~',
|
|
|
+ shortcut: modKey + '+Shift+s',
|
|
|
+ },
|
|
|
+ // {
|
|
|
+ // name: 'underline',
|
|
|
+ // prefix: '<u>',
|
|
|
+ // postfix: '</u>',
|
|
|
+ // shortcut: modKey + '+u',
|
|
|
+ // },
|
|
|
+ ]
|
|
|
+
|
|
|
+ for (const format of formats) {
|
|
|
+ test.describe(`${format.name} formatting`, () => {
|
|
|
+ test('Applying to an empty selection inserts placeholder formatting and places cursor correctly', async ({
|
|
|
+ page,
|
|
|
+ block,
|
|
|
+ }) => {
|
|
|
+ await createRandomPage(page)
|
|
|
+
|
|
|
+ const text = 'Lorem ipsum'
|
|
|
+ await block.mustFill(text)
|
|
|
+
|
|
|
+ // move the cursor to the end of Lorem
|
|
|
+ await repeatKeyPress(page, 'ArrowLeft', text.length - 'ipsum'.length)
|
|
|
+ await page.keyboard.press('Space')
|
|
|
+
|
|
|
+ // Apply formatting
|
|
|
+ await page.keyboard.press(format.shortcut)
|
|
|
+
|
|
|
+ await expect(page.locator('textarea >> nth=0')).toHaveText(
|
|
|
+ `Lorem ${format.prefix}${format.postfix} ipsum`
|
|
|
+ )
|
|
|
+
|
|
|
+ // Verify cursor position
|
|
|
+ const cursorPos = await getCursorPos(page)
|
|
|
+ expect(cursorPos).toBe(' ipsum'.length + format.prefix.length)
|
|
|
+ })
|
|
|
+
|
|
|
+ test('Applying to an entire block encloses the block in formatting and places cursor correctly', async ({
|
|
|
+ page,
|
|
|
+ block,
|
|
|
+ }) => {
|
|
|
+ await createRandomPage(page)
|
|
|
+
|
|
|
+ const text = 'Lorem ipsum-dolor sit.'
|
|
|
+ await block.mustFill(text)
|
|
|
+
|
|
|
+ // Select the entire block
|
|
|
+ await page.keyboard.press(modKey + '+a')
|
|
|
+
|
|
|
+ // Apply formatting
|
|
|
+ await page.keyboard.press(format.shortcut)
|
|
|
+
|
|
|
+ await expect(page.locator('textarea >> nth=0')).toHaveText(
|
|
|
+ `${format.prefix}${text}${format.postfix}`
|
|
|
+ )
|
|
|
+
|
|
|
+ // Verify cursor position
|
|
|
+ const cursorPosition = await getCursorPos(page)
|
|
|
+ expect(cursorPosition).toBe(format.prefix.length + text.length)
|
|
|
+ })
|
|
|
+
|
|
|
+ test('Applying and then removing from a word connected with a special character correctly formats and then reverts', async ({
|
|
|
+ page,
|
|
|
+ block,
|
|
|
+ }) => {
|
|
|
+ await createRandomPage(page)
|
|
|
+
|
|
|
+ await block.mustFill('Lorem ipsum-dolor sit.')
|
|
|
+
|
|
|
+ // Select 'ipsum'
|
|
|
+ // Move the cursor to the desired position
|
|
|
+ await moveCursor(page, -16)
|
|
|
+
|
|
|
+ // Select the desired length of text
|
|
|
+ await selectCharacters(page, 5)
|
|
|
+
|
|
|
+ // Apply formatting
|
|
|
+ await page.keyboard.press(format.shortcut)
|
|
|
+
|
|
|
+ // Verify that 'ipsum' is formatted
|
|
|
+ await expect(page.locator('textarea >> nth=0')).toHaveText(
|
|
|
+ `Lorem ${format.prefix}ipsum${format.postfix}-dolor sit.`
|
|
|
+ )
|
|
|
+
|
|
|
+ // Re-select 'ipsum'
|
|
|
+ // Move the cursor to the desired position
|
|
|
+ await moveCursor(page, -5)
|
|
|
+
|
|
|
+ // Select the desired length of text
|
|
|
+ await selectCharacters(page, 5)
|
|
|
+
|
|
|
+ // Remove formatting
|
|
|
+ await page.keyboard.press(format.shortcut)
|
|
|
+ await expect(page.locator('textarea >> nth=0')).toHaveText(
|
|
|
+ 'Lorem ipsum-dolor sit.'
|
|
|
+ )
|
|
|
+
|
|
|
+ // Verify the word 'ipsum' is still selected
|
|
|
+ const selection = await getSelection(page)
|
|
|
+ expect(selection).toBe('ipsum')
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+test.describe('Always auto-pair symbols', () => {
|
|
|
+ // Define the symbols that should be auto-paired
|
|
|
+ const autoPairSymbols = [
|
|
|
+ { name: 'square brackets', prefix: '[', postfix: ']' },
|
|
|
+ { name: 'curly brackets', prefix: '{', postfix: '}' },
|
|
|
+ { name: 'parentheses', prefix: '(', postfix: ')' },
|
|
|
+ // { name: 'angle brackets', prefix: '<', postfix: '>' },
|
|
|
+ { name: 'backtick', prefix: '`', postfix: '`' },
|
|
|
+ // { name: 'single quote', prefix: "'", postfix: "'" },
|
|
|
+ // { name: 'double quote', prefix: '"', postfix: '"' },
|
|
|
+ ]
|
|
|
+
|
|
|
+ for (const symbol of autoPairSymbols) {
|
|
|
+ test(`${symbol.name} auto-pairing`, async ({ page }) => {
|
|
|
+ await createRandomPage(page)
|
|
|
+
|
|
|
+ // Type prefix and check that the postfix is automatically added
|
|
|
+ page.type('textarea >> nth=0', symbol.prefix, { delay: 100 })
|
|
|
+ await expect(page.locator('textarea >> nth=0')).toHaveText(
|
|
|
+ `${symbol.prefix}${symbol.postfix}`
|
|
|
+ )
|
|
|
+
|
|
|
+ // Check that the cursor is positioned correctly between the prefix and postfix
|
|
|
+ const CursorPos = await getCursorPos(page)
|
|
|
+ expect(CursorPos).toBe(symbol.prefix.length)
|
|
|
+ })
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+test.describe('Auto-pair symbols only with text selection', () => {
|
|
|
+ const autoPairSymbols = [
|
|
|
+ // { name: 'tilde', prefix: '~', postfix: '~' },
|
|
|
+ { name: 'asterisk', prefix: '*', postfix: '*' },
|
|
|
+ { name: 'underscore', prefix: '_', postfix: '_' },
|
|
|
+ { name: 'caret', prefix: '^', postfix: '^' },
|
|
|
+ { name: 'equal', prefix: '=', postfix: '=' },
|
|
|
+ { name: 'slash', prefix: '/', postfix: '/' },
|
|
|
+ { name: 'plus', prefix: '+', postfix: '+' },
|
|
|
+ ]
|
|
|
+
|
|
|
+ for (const symbol of autoPairSymbols) {
|
|
|
+ test(`Only auto-pair ${symbol.name} with text selection`, async ({
|
|
|
+ page,
|
|
|
+ block,
|
|
|
+ }) => {
|
|
|
+ await createRandomPage(page)
|
|
|
+
|
|
|
+ // type the symbol
|
|
|
+ page.type('textarea >> nth=0', symbol.prefix, { delay: 100 })
|
|
|
+
|
|
|
+ // Verify that there is no auto-pairing
|
|
|
+ await expect(page.locator('textarea >> nth=0')).toHaveText(symbol.prefix)
|
|
|
+
|
|
|
+ // remove prefix
|
|
|
+ await page.keyboard.press('Backspace')
|
|
|
+
|
|
|
+ // add text
|
|
|
+ await block.mustType('Lorem')
|
|
|
+ // select text
|
|
|
+ await page.keyboard.press(modKey + '+a')
|
|
|
+
|
|
|
+ // Type the prefix
|
|
|
+ await page.type('textarea >> nth=0', symbol.prefix, { delay: 100 })
|
|
|
+
|
|
|
+ // Verify that an additional postfix was automatically added around 'Lorem'
|
|
|
+ await expect(page.locator('textarea >> nth=0')).toHaveText(
|
|
|
+ `${symbol.prefix}Lorem${symbol.postfix}`
|
|
|
+ )
|
|
|
+
|
|
|
+ // Verify 'Lorem' is selected
|
|
|
+ const selection = await getSelection(page)
|
|
|
+ expect(selection).toBe('Lorem')
|
|
|
+ })
|
|
|
+ }
|
|
|
+})
|