| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- import { expect, test } from '@playwright/test';
- /**
- * Tests for Emacs keymap functionality in the editor.
- * Verifies that the registered EmacsHandler bindings produce the expected
- * markdown output in the editor source — i.e. the observable contract
- * (content changes) rather than internal implementation details.
- *
- * Keymap isolation strategy: page.route intercepts GET /_api/v3/personal-setting/editor-settings
- * and returns keymapMode:'emacs' without touching the database. PUT requests are swallowed for
- * the same reason. Because the route is scoped to the test's page instance, no other test file
- * is affected and no afterEach cleanup is required.
- *
- * @see packages/editor/src/client/services-internal/keymaps/emacs/
- * Requirements: 4.1, 5.2, 9.3
- */
- const EDITOR_SETTINGS_ROUTE = '**/_api/v3/personal-setting/editor-settings';
- test.describe
- .serial('Emacs keymap mode', () => {
- test.beforeEach(async ({ page }) => {
- // Return keymapMode:'emacs' for every settings fetch without writing to DB.
- // PUT requests (e.g. from UI interactions) are also swallowed so the DB stays clean.
- await page.route(EDITOR_SETTINGS_ROUTE, async (route) => {
- if (route.request().method() === 'GET') {
- await route.fulfill({
- contentType: 'application/json',
- body: JSON.stringify({ keymapMode: 'emacs' }),
- });
- } else {
- await route.fulfill({
- status: 200,
- contentType: 'application/json',
- body: '{}',
- });
- }
- });
- await page.goto('/Sandbox/emacs-keymap-test-page');
- // Open Editor
- await expect(page.getByTestId('editor-button')).toBeVisible();
- await page.getByTestId('editor-button').click();
- await expect(page.locator('.cm-content')).toBeVisible();
- await expect(page.getByTestId('grw-editor-navbar-bottom')).toBeVisible();
- });
- test('C-c C-s b should wrap text in bold markdown markers (Req 4.1)', async ({
- page,
- }) => {
- // Focus the editor
- await page.locator('.cm-content').click();
- // With no selection, C-c C-s b inserts ** markers and positions cursor between them
- await page.keyboard.press('Control+c');
- await page.keyboard.press('Control+s');
- await page.keyboard.press('b');
- // Type text inside the inserted markers
- await page.keyboard.type('bold text');
- // Verify: bold markdown markers surround the typed text in the editor source
- await expect(page.locator('.cm-content')).toContainText('**bold text**');
- });
- test('C-c C-l should insert a markdown link template (Req 5.2)', async ({
- page,
- }) => {
- // Focus the editor
- await page.locator('.cm-content').click();
- // With no selection, C-c C-l inserts []() and positions cursor after [
- await page.keyboard.press('Control+c');
- await page.keyboard.press('Control+l');
- // Type the link display text inside the brackets
- await page.keyboard.type('link text');
- // Verify: link template with typed display text appears in the editor source
- await expect(page.locator('.cm-content')).toContainText('[link text]()');
- });
- test('C-c C-n should navigate cursor to the next heading (Req 9.3)', async ({
- page,
- }) => {
- // Set up document with two headings.
- // Fill directly and wait for the rendered heading text (without # markers) to appear in the
- // preview, because appendTextToEditorUntilContains checks raw text which markdown headings
- // strip on render.
- await page
- .locator('.cm-content')
- .fill('# First Heading\n\n## Second Heading');
- await expect(page.getByTestId('page-editor-preview-body')).toContainText(
- 'Second Heading',
- );
- // Click on the first line to position cursor before "## Second Heading"
- await page.locator('.cm-line').first().click();
- // Navigate to the next heading with C-c C-n
- await page.keyboard.press('Control+c');
- await page.keyboard.press('Control+n');
- // Cursor is now at the beginning of "## Second Heading".
- // Move to end of that line and append a unique marker to verify cursor position.
- await page.keyboard.press('End');
- await page.keyboard.type(' NAVIGATED');
- // Verify: the marker was appended at the second heading, not the first
- await expect(page.locator('.cm-content')).toContainText(
- '## Second Heading NAVIGATED',
- );
- });
- test('C-x C-s should save the page (Req 6.1)', async ({ page }) => {
- // Type content to ensure there is something to save
- await page.locator('.cm-content').click();
- await page.keyboard.type('Emacs save test');
- // Save with the Emacs two-stroke save binding
- await page.keyboard.press('Control+x');
- await page.keyboard.press('Control+s');
- // Expect a success toast notification confirming the page was saved
- await expect(page.locator('.Toastify__toast--success')).toBeVisible();
- });
- });
|