-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix caret jumping in certain cases with cursor blot
- Loading branch information
Showing
5 changed files
with
220 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import { expect } from '@playwright/test'; | ||
import { test } from './fixtures/index.js'; | ||
import { SHORTKEY } from './utils/index.js'; | ||
|
||
test.describe('cursor', () => { | ||
test.beforeEach(async ({ editorPage }) => { | ||
await editorPage.open(); | ||
}); | ||
|
||
test.describe('type', () => { | ||
test('normal typing with one format', async ({ page, editorPage }) => { | ||
await editorPage.setContents([{ insert: '1234\n' }]); | ||
await editorPage.moveCursorAfterText('12'); | ||
await page.keyboard.press(`${SHORTKEY}+b`); | ||
await page.keyboard.type('abc'); | ||
expect(await editorPage.getContents()).toEqual([ | ||
{ insert: '12' }, | ||
{ insert: 'abc', attributes: { bold: true } }, | ||
{ insert: '34\n' }, | ||
]); | ||
expect(await editorPage.getSelection()).toEqual({ index: 5, length: 0 }); | ||
await expect(editorPage.cursorBlot).not.toBeAttached(); | ||
}); | ||
|
||
test('normal typing with two formats', async ({ page, editorPage }) => { | ||
await editorPage.setContents([{ insert: '1234\n' }]); | ||
await editorPage.moveCursorAfterText('12'); | ||
await page.keyboard.press(`${SHORTKEY}+b`); | ||
await page.keyboard.press(`${SHORTKEY}+i`); | ||
await page.keyboard.type('abc'); | ||
expect(await editorPage.getContents()).toEqual([ | ||
{ insert: '12' }, | ||
{ insert: 'abc', attributes: { bold: true, italic: true } }, | ||
{ insert: '34\n' }, | ||
]); | ||
expect(await editorPage.getSelection()).toEqual({ index: 5, length: 0 }); | ||
await expect(editorPage.cursorBlot).not.toBeAttached(); | ||
}); | ||
|
||
test('normal typing with one format omitting', async ({ | ||
page, | ||
editorPage, | ||
}) => { | ||
await editorPage.setContents([ | ||
{ insert: '1234', attributes: { bold: true, italic: true } }, | ||
{ insert: '\n' }, | ||
]); | ||
await editorPage.moveCursorAfterText('12'); | ||
await page.keyboard.press(`${SHORTKEY}+b`); | ||
await page.keyboard.type('abc'); | ||
expect(await editorPage.getContents()).toEqual([ | ||
{ insert: '12', attributes: { bold: true, italic: true } }, | ||
{ insert: 'abc', attributes: { italic: true } }, | ||
{ insert: '34', attributes: { bold: true, italic: true } }, | ||
{ insert: '\n' }, | ||
]); | ||
expect(await editorPage.getSelection()).toEqual({ index: 5, length: 0 }); | ||
await expect(editorPage.cursorBlot).not.toBeAttached(); | ||
}); | ||
}); | ||
|
||
test('paste', async ({ clipboard, editorPage, page }) => { | ||
await editorPage.setContents([{ insert: '1234\n' }]); | ||
await editorPage.moveCursorAfterText('12'); | ||
await clipboard.writeText('abc'); | ||
await page.keyboard.press(`${SHORTKEY}+b`); | ||
await clipboard.paste(); | ||
expect(await editorPage.getContents()).toEqual([ | ||
{ insert: '12' }, | ||
{ insert: 'abc', attributes: { bold: true } }, | ||
{ insert: '34\n' }, | ||
]); | ||
expect(await editorPage.getSelection()).toEqual({ index: 5, length: 0 }); | ||
await expect(editorPage.cursorBlot).not.toBeAttached(); | ||
}); | ||
|
||
test.describe('IME', () => { | ||
test('confirm composition', async ({ composition, editorPage, page }) => { | ||
await editorPage.setContents([{ insert: '1234\n' }]); | ||
await editorPage.moveCursorAfterText('12'); | ||
await page.keyboard.press(`${SHORTKEY}+b`); | ||
const ime = await composition.start(); | ||
await ime.update('w'); | ||
await ime.update('o'); | ||
await ime.commit('我'); | ||
expect(await editorPage.getContents()).toEqual([ | ||
{ insert: '12' }, | ||
{ insert: '我', attributes: { bold: true } }, | ||
{ insert: '34\n' }, | ||
]); | ||
expect(await editorPage.getSelection()).toEqual({ index: 3, length: 0 }); | ||
await expect(editorPage.cursorBlot).not.toBeAttached(); | ||
}); | ||
|
||
test('cancel composition', async ({ composition, editorPage, page }) => { | ||
await editorPage.setContents([{ insert: '1234\n' }]); | ||
await editorPage.moveCursorAfterText('12'); | ||
await page.keyboard.press(`${SHORTKEY}+b`); | ||
const ime = await composition.start(); | ||
await ime.update('w'); | ||
await ime.update('o'); | ||
await ime.cancel(); | ||
expect(await editorPage.getContents()).toEqual([{ insert: '1234\n' }]); | ||
expect(await editorPage.getSelection()).toEqual({ index: 2, length: 0 }); | ||
await expect(editorPage.cursorBlot).not.toBeAttached(); | ||
}); | ||
}); | ||
|
||
test.describe('caret movements', () => { | ||
test('arrow keys', async ({ editorPage, page }) => { | ||
await editorPage.setContents([{ insert: '1234\n' }]); | ||
await editorPage.moveCursorAfterText('12'); | ||
await page.keyboard.press(`${SHORTKEY}+b`); | ||
await page.keyboard.press('ArrowRight'); | ||
expect(await editorPage.getSelection()).toEqual({ index: 3, length: 0 }); | ||
await expect(editorPage.cursorBlot).not.toBeAttached(); | ||
}); | ||
|
||
test('jumping', async ({ editorPage, page }) => { | ||
await editorPage.setContents([{ insert: '12345\n' }]); | ||
await editorPage.moveCursorAfterText('12'); | ||
await page.keyboard.press(`${SHORTKEY}+b`); | ||
await editorPage.moveCursorAfterText('34'); | ||
expect(await editorPage.getSelection()).toEqual({ index: 4, length: 0 }); | ||
await expect(editorPage.cursorBlot).not.toBeAttached(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { unlink, writeFile } from 'fs/promises'; | ||
import { unlinkSync } from 'fs'; | ||
import { tmpdir } from 'os'; | ||
import { join } from 'path'; | ||
import { globSync } from 'glob'; | ||
|
||
const sleep = (ms: number) => | ||
new Promise((resolve) => { | ||
setTimeout(resolve, ms); | ||
}); | ||
|
||
const PREFIX = 'playwright_locker_'; | ||
|
||
class Locker { | ||
public static clearAll() { | ||
globSync(join(tmpdir(), `${PREFIX}*.txt`)).forEach(unlinkSync); | ||
} | ||
|
||
constructor(private key: string) {} | ||
|
||
private get filePath() { | ||
return join(tmpdir(), `${PREFIX}${this.key}.txt`); | ||
} | ||
|
||
async lock() { | ||
try { | ||
await writeFile(this.filePath, '', { flag: 'wx' }); | ||
} catch { | ||
await sleep(50); | ||
await this.lock(); | ||
} | ||
} | ||
|
||
async release() { | ||
await unlink(this.filePath); | ||
} | ||
} | ||
|
||
export default Locker; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters