import type { Page } from "@playwright/test" import { runTerminal, waitTerminalReady } from "../actions" import { test, expect } from "../fixtures" import { dropdownMenuContentSelector, terminalSelector } from "../selectors" import { terminalToggleKey, workspacePersistKey } from "../utils" type State = { active?: string all: Array<{ id: string title: string titleNumber: number buffer?: string }> } async function open(page: Page) { const terminal = page.locator(terminalSelector) const visible = await terminal.isVisible().catch(() => false) if (!visible) await page.keyboard.press(terminalToggleKey) await waitTerminalReady(page, { term: terminal }) } async function store(page: Page, key: string) { return page.evaluate((key) => { const raw = localStorage.getItem(key) if (raw) return JSON.parse(raw) as State for (let i = 0; i < localStorage.length; i++) { const next = localStorage.key(i) if (!next?.endsWith(":workspace:terminal")) continue const value = localStorage.getItem(next) if (!value) continue return JSON.parse(value) as State } }, key) } test("inactive terminal tab buffers persist across tab switches", async ({ page, project }) => { await project.open() const key = workspacePersistKey(project.directory, "terminal") const one = `E2E_TERM_ONE_${Date.now()}` const two = `E2E_TERM_TWO_${Date.now()}` const tabs = page.locator('#terminal-panel [data-slot="tabs-trigger"]') const first = tabs.filter({ hasText: /Terminal 1/ }).first() const second = tabs.filter({ hasText: /Terminal 2/ }).first() await project.gotoSession() await open(page) await runTerminal(page, { cmd: `echo ${one}`, token: one }) await page.getByRole("button", { name: /new terminal/i }).click() await expect(tabs).toHaveCount(2) await runTerminal(page, { cmd: `echo ${two}`, token: two }) await first.click() await expect(first).toHaveAttribute("aria-selected", "true") await expect .poll( async () => { const state = await store(page, key) const first = state?.all.find((item) => item.titleNumber === 1)?.buffer ?? "" const second = state?.all.find((item) => item.titleNumber === 2)?.buffer ?? "" return { first: first.includes(one), second: second.includes(two), } }, { timeout: 5_000 }, ) .toEqual({ first: false, second: true }) await second.click() await expect(second).toHaveAttribute("aria-selected", "true") await expect .poll( async () => { const state = await store(page, key) const first = state?.all.find((item) => item.titleNumber === 1)?.buffer ?? "" const second = state?.all.find((item) => item.titleNumber === 2)?.buffer ?? "" return { first: first.includes(one), second: second.includes(two), } }, { timeout: 5_000 }, ) .toEqual({ first: true, second: false }) }) test("closing the active terminal tab falls back to the previous tab", async ({ page, project }) => { await project.open() const key = workspacePersistKey(project.directory, "terminal") const tabs = page.locator('#terminal-panel [data-slot="tabs-trigger"]') await project.gotoSession() await open(page) await page.getByRole("button", { name: /new terminal/i }).click() await expect(tabs).toHaveCount(2) const second = tabs.filter({ hasText: /Terminal 2/ }).first() await second.click() await expect(second).toHaveAttribute("aria-selected", "true") await second.hover() await page .getByRole("button", { name: /close terminal/i }) .nth(1) .click({ force: true }) const first = tabs.filter({ hasText: /Terminal 1/ }).first() await expect(tabs).toHaveCount(1) await expect(first).toHaveAttribute("aria-selected", "true") await expect .poll( async () => { const state = await store(page, key) return { count: state?.all.length ?? 0, first: state?.all.some((item) => item.titleNumber === 1) ?? false, } }, { timeout: 15_000 }, ) .toEqual({ count: 1, first: true }) }) test("terminal tab can be renamed from the context menu", async ({ page, project }) => { await project.open() const key = workspacePersistKey(project.directory, "terminal") const rename = `E2E term ${Date.now()}` const tab = page.locator('#terminal-panel [data-slot="tabs-trigger"]').first() await project.gotoSession() await open(page) await expect(tab).toContainText(/Terminal 1/) await tab.click({ button: "right" }) const menu = page.locator(dropdownMenuContentSelector).first() await expect(menu).toBeVisible() await menu.getByRole("menuitem", { name: /^Rename$/i }).click() await expect(menu).toHaveCount(0) const input = page.locator('#terminal-panel input[type="text"]').first() await expect(input).toBeVisible() await input.fill(rename) await input.press("Enter") await expect(input).toHaveCount(0) await expect(tab).toContainText(rename) await expect .poll( async () => { const state = await store(page, key) return state?.all[0]?.title }, { timeout: 5_000 }, ) .toBe(rename) })