|
| 1 | +import { expect, type Page } from '@playwright/test'; |
| 2 | + |
| 3 | +import { loadFixture } from '../../playwright/paths'; |
| 4 | +import { test } from '../../playwright/test'; |
| 5 | + |
| 6 | +// Regression guard for undo history surviving a tab change. Switching the active |
| 7 | +// request unmounts the previous request's pane (its editors) and mounts the next; |
| 8 | +// the undo history must survive that remount via the shared editor-state cache, so |
| 9 | +// Cmd/Ctrl+Z still undoes after returning to the request. See docs/undo-redo-baseline.md. |
| 10 | + |
| 11 | +const URL_SEL = 'div.editor__container:has(textarea#request-url-bar) .CodeMirror'; |
| 12 | +const isMac = process.platform === 'darwin'; |
| 13 | + |
| 14 | +const readUrlState = (page: Page) => |
| 15 | + page.evaluate((sel: string) => { |
| 16 | + const node = document.querySelector(sel) as any; |
| 17 | + const cm = node?.CodeMirror; |
| 18 | + return { |
| 19 | + value: cm?.getValue() as string, |
| 20 | + undo: cm?.historySize().undo as number, |
| 21 | + }; |
| 22 | + }, URL_SEL); |
| 23 | + |
| 24 | +test('undo history survives switching request tabs', async ({ page, app, insomnia }) => { |
| 25 | + const text = await loadFixture('simple.yaml'); |
| 26 | + await app.evaluate(async ({ clipboard }, t) => clipboard.writeText(t), text); |
| 27 | + await page.getByLabel('Import').click(); |
| 28 | + await page.locator('[data-test-id="import-from-clipboard"]').click(); |
| 29 | + await page.getByRole('button', { name: 'Scan' }).click(); |
| 30 | + await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click(); |
| 31 | + await page.getByRole('dialog').waitFor({ state: 'hidden' }); |
| 32 | + |
| 33 | + // Open the first request and edit its URL, building undo history. |
| 34 | + await insomnia.navigationSidebar.clickRequestOrFolder('example http'); |
| 35 | + const urlInput = page.locator(`${URL_SEL} textarea`); |
| 36 | + await urlInput.focus(); |
| 37 | + await page.keyboard.type('/undo-marker'); |
| 38 | + // Web-first assertion settles the debounced persist + loader revalidation. |
| 39 | + await expect.soft(page.locator(URL_SEL)).toContainText('/undo-marker'); |
| 40 | + expect.soft((await readUrlState(page)).undo).toBeGreaterThan(0); |
| 41 | + |
| 42 | + // Change tabs: to another request and back. This unmounts the first request's |
| 43 | + // URL editor and remounts it — the round-trip that used to drop undo history. |
| 44 | + await insomnia.navigationSidebar.clickRequestOrFolder('proxyEnabled'); |
| 45 | + await insomnia.navigationSidebar.clickRequestOrFolder('example http'); |
| 46 | + await expect.soft(page.locator(URL_SEL)).toContainText('/undo-marker'); |
| 47 | + |
| 48 | + const afterSwitch = await readUrlState(page); |
| 49 | + // Value preserved AND undo history restored across the remount. |
| 50 | + expect.soft(afterSwitch.value).toContain('/undo-marker'); |
| 51 | + expect.soft(afterSwitch.undo).toBeGreaterThan(0); |
| 52 | + |
| 53 | + // Undo works on the remounted editor: it reverts the edit made before the switch. |
| 54 | + await page.locator(`${URL_SEL} textarea`).focus(); |
| 55 | + await page.keyboard.press(isMac ? 'Meta+z' : 'Control+z'); |
| 56 | + await expect.soft(page.locator(URL_SEL)).not.toContainText('/undo-marker'); |
| 57 | +}); |
0 commit comments