diff options
Diffstat (limited to 'tests/e2e/markdown-editor.test.e2e.js')
-rw-r--r-- | tests/e2e/markdown-editor.test.e2e.js | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/tests/e2e/markdown-editor.test.e2e.js b/tests/e2e/markdown-editor.test.e2e.js new file mode 100644 index 0000000..4a3b414 --- /dev/null +++ b/tests/e2e/markdown-editor.test.e2e.js @@ -0,0 +1,177 @@ +// @ts-check +import {expect} from '@playwright/test'; +import {test, load_logged_in_context, login_user} from './utils_e2e.js'; + +test.beforeAll(async ({browser}, workerInfo) => { + await login_user(browser, workerInfo, 'user2'); +}); + +test('markdown indentation', async ({browser}, workerInfo) => { + const context = await load_logged_in_context(browser, workerInfo, 'user2'); + + const initText = `* first\n* second\n* third\n* last`; + + const page = await context.newPage(); + const response = await page.goto('/user2/repo1/issues/new'); + await expect(response?.status()).toBe(200); + + const textarea = page.locator('textarea[name=content]'); + const tab = ' '; + const indent = page.locator('button[data-md-action="indent"]'); + const unindent = page.locator('button[data-md-action="unindent"]'); + await textarea.fill(initText); + await textarea.click(); // Tab handling is disabled until pointer event or input. + + // Indent, then unindent first line + await textarea.focus(); + await textarea.evaluate((it) => it.setSelectionRange(0, 0)); + await indent.click(); + await expect(textarea).toHaveValue(`${tab}* first\n* second\n* third\n* last`); + await unindent.click(); + await expect(textarea).toHaveValue(initText); + + // Indent second line while somewhere inside of it + await textarea.focus(); + await textarea.press('ArrowDown'); + await textarea.press('ArrowRight'); + await textarea.press('ArrowRight'); + await indent.click(); + await expect(textarea).toHaveValue(`* first\n${tab}* second\n* third\n* last`); + + // Subsequently, select a chunk of 2nd and 3rd line and indent both, preserving the cursor position in relation to text + await textarea.focus(); + await textarea.evaluate((it) => it.setSelectionRange(it.value.indexOf('cond'), it.value.indexOf('hird'))); + await indent.click(); + const lines23 = `* first\n${tab}${tab}* second\n${tab}* third\n* last`; + await expect(textarea).toHaveValue(lines23); + await expect(textarea).toHaveJSProperty('selectionStart', lines23.indexOf('cond')); + await expect(textarea).toHaveJSProperty('selectionEnd', lines23.indexOf('hird')); + + // Then unindent twice, erasing all indents. + await unindent.click(); + await expect(textarea).toHaveValue(`* first\n${tab}* second\n* third\n* last`); + await unindent.click(); + await expect(textarea).toHaveValue(initText); + + // Indent and unindent with cursor at the end of the line + await textarea.focus(); + await textarea.evaluate((it) => it.setSelectionRange(it.value.indexOf('cond'), it.value.indexOf('cond'))); + await textarea.press('End'); + await indent.click(); + await expect(textarea).toHaveValue(`* first\n${tab}* second\n* third\n* last`); + await unindent.click(); + await expect(textarea).toHaveValue(initText); + + // Check that Tab does work after input + await textarea.focus(); + await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.press('Shift+Enter'); // Avoid triggering the prefix continuation feature + await textarea.pressSequentially('* least'); + await indent.click(); + await expect(textarea).toHaveValue(`* first\n* second\n* third\n* last\n${tab}* least`); + + // Check that partial indents are cleared + await textarea.focus(); + await textarea.fill(initText); + await textarea.evaluate((it) => it.setSelectionRange(it.value.indexOf('* second'), it.value.indexOf('* second'))); + await textarea.pressSequentially(' '); + await unindent.click(); + await expect(textarea).toHaveValue(initText); +}); + +test('markdown list continuation', async ({browser}, workerInfo) => { + const context = await load_logged_in_context(browser, workerInfo, 'user2'); + + const initText = `* first\n* second\n* third\n* last`; + + const page = await context.newPage(); + const response = await page.goto('/user2/repo1/issues/new'); + await expect(response?.status()).toBe(200); + + const textarea = page.locator('textarea[name=content]'); + const tab = ' '; + const indent = page.locator('button[data-md-action="indent"]'); + await textarea.fill(initText); + + // Test continuation of '* ' prefix + await textarea.evaluate((it) => it.setSelectionRange(it.value.indexOf('cond'), it.value.indexOf('cond'))); + await textarea.press('End'); + await textarea.press('Enter'); + await textarea.pressSequentially('middle'); + await expect(textarea).toHaveValue(`* first\n* second\n* middle\n* third\n* last`); + + // Test continuation of ' * ' prefix + await indent.click(); + await textarea.press('Enter'); + await textarea.pressSequentially('muddle'); + await expect(textarea).toHaveValue(`* first\n* second\n${tab}* middle\n${tab}* muddle\n* third\n* last`); + + // Test breaking in the middle of a line + await textarea.evaluate((it) => it.setSelectionRange(it.value.lastIndexOf('ddle'), it.value.lastIndexOf('ddle'))); + await textarea.pressSequentially('tate'); + await textarea.press('Enter'); + await textarea.pressSequentially('me'); + await expect(textarea).toHaveValue(`* first\n* second\n${tab}* middle\n${tab}* mutate\n${tab}* meddle\n* third\n* last`); + + // Test not triggering when Shift held + await textarea.fill(initText); + await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.press('Shift+Enter'); + await textarea.press('Enter'); + await textarea.pressSequentially('...but not least'); + await expect(textarea).toHaveValue(`* first\n* second\n* third\n* last\n\n...but not least`); + + // Test continuation of ordered list + await textarea.fill(`1. one\n2. two`); + await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.press('Enter'); + await textarea.pressSequentially('three'); + await expect(textarea).toHaveValue(`1. one\n2. two\n3. three`); + + // Test continuation of alternative ordered list syntax + await textarea.fill(`1) one\n2) two`); + await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.press('Enter'); + await textarea.pressSequentially('three'); + await expect(textarea).toHaveValue(`1) one\n2) two\n3) three`); + + // Test continuation of blockquote + await textarea.fill(`> knowledge is power`); + await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.press('Enter'); + await textarea.pressSequentially('france is bacon'); + await expect(textarea).toHaveValue(`> knowledge is power\n> france is bacon`); + + // Test continuation of checklists + await textarea.fill(`- [ ] have a problem\n- [x] create a solution`); + await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.press('Enter'); + await textarea.pressSequentially('write a test'); + await expect(textarea).toHaveValue(`- [ ] have a problem\n- [x] create a solution\n- [ ] write a test`); + + // Test all conceivable syntax (except ordered lists) + const prefixes = [ + '- ', // A space between the bullet and the content is required. + ' - ', // I have seen single space in front of -/* being used and even recommended, I think. + '* ', + '+ ', + ' ', + ' ', + ' - ', + '\t', + '\t\t* ', + '> ', + '> > ', + '- [ ] ', + '- [ ]', // This does seem to render, so allow. + '* [ ] ', + '+ [ ] ', + ]; + for (const prefix of prefixes) { + await textarea.fill(`${prefix}one`); + await textarea.evaluate((it) => it.setSelectionRange(it.value.length, it.value.length)); + await textarea.press('Enter'); + await textarea.pressSequentially('two'); + await expect(textarea).toHaveValue(`${prefix}one\n${prefix}two`); + } +}); |