ep_headings2
Version:
Adds heading support to Etherpad Lite. Includes improved suppot for export, i18n etc.
81 lines (69 loc) • 3.38 kB
text/typescript
import {expect, test} from '@playwright/test';
import {clearPadContent, getPadBody, goToNewPad, writeToPad}
from 'ep_etherpad-lite/tests/frontend-new/helper/padHelper';
test.beforeEach(async ({page}) => {
await goToNewPad(page);
});
test.describe('ep_headings2 - Set Heading and ensure its removed properly', () => {
test('Heading select has aria-label for accessibility', async ({page}) => {
const select = page.locator('#heading-selection');
await expect(select).toHaveAttribute('aria-label', /.+/);
});
test('Focus returns to editor after selecting a heading', async ({page}) => {
const padBody = await getPadBody(page);
await padBody.click();
await clearPadContent(page);
await writeToPad(page, 'Test focus');
// Pick H1 in the heading-selection <select>; the niceSelect wrapper
// intercepts native change events so we set the value on the
// underlying element and dispatch change manually, matching what
// the legacy spec did with chrome$('#heading-selection').change().
await page.evaluate(() => {
const sel = document.querySelector<HTMLSelectElement>('#heading-selection')!;
sel.value = '0';
sel.dispatchEvent(new Event('change', {bubbles: true}));
});
// The line gains an <h1> wrapper.
await expect(padBody.locator('div').first().locator('h1')).toHaveCount(1);
// Focus should return to the inner ace iframe (not the toolbar
// <select> the user just clicked). Verify by checking activeElement
// in the outer document is the ace_inner iframe.
const focusedFrameName = await page.evaluate(() => {
const ae = document.activeElement as HTMLElement | null;
return (ae?.tagName === 'IFRAME' && (ae as HTMLIFrameElement).name) || null;
});
expect(focusedFrameName).toBe('ace_outer');
});
test('Option select is changed when heading is changed', async ({page}) => {
const padBody = await getPadBody(page);
await padBody.click();
await clearPadContent(page);
await writeToPad(page, 'First Line!');
// Apply H1 to the first line.
await page.evaluate(() => {
const sel = document.querySelector<HTMLSelectElement>('#heading-selection')!;
sel.value = '0';
sel.dispatchEvent(new Event('change', {bubbles: true}));
});
await expect(padBody.locator('div').first().locator('h1')).toHaveCount(1);
// Move to a fresh second line — the selector should reset to
// "no heading" (-1) because the cursor is no longer on an H1.
// Use insertText instead of keyboard.type: Firefox under
// WITH_PLUGINS load racily drops chars from per-key events, which
// is the same fix etherpad core's writeToPad helper applied in
// #7625.
await page.keyboard.press('End');
await page.keyboard.press('Enter');
await page.keyboard.insertText('Second Line');
// Wait for the selector to update to "-1" (Etherpad polls the
// current line's heading attribute on caret moves).
await expect.poll(async () =>
page.evaluate(() =>
(document.querySelector<HTMLSelectElement>('#heading-selection')!).value),
{timeout: 10_000}).toBe('-1');
// Second line is plain text, not wrapped in <h1>.
const second = padBody.locator('div').nth(1);
await expect(second.locator('h1')).toHaveCount(0);
await expect(second).toHaveText('Second Line');
});
});