terminal-tabs.spec.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import type { Page } from "@playwright/test"
  2. import { runTerminal, waitTerminalReady } from "../actions"
  3. import { test, expect } from "../fixtures"
  4. import { terminalSelector } from "../selectors"
  5. import { terminalToggleKey, workspacePersistKey } from "../utils"
  6. type State = {
  7. active?: string
  8. all: Array<{
  9. id: string
  10. title: string
  11. titleNumber: number
  12. buffer?: string
  13. }>
  14. }
  15. async function open(page: Page) {
  16. const terminal = page.locator(terminalSelector)
  17. const visible = await terminal.isVisible().catch(() => false)
  18. if (!visible) await page.keyboard.press(terminalToggleKey)
  19. await waitTerminalReady(page, { term: terminal })
  20. }
  21. async function store(page: Page, key: string) {
  22. return page.evaluate((key) => {
  23. const raw = localStorage.getItem(key)
  24. if (raw) return JSON.parse(raw) as State
  25. for (let i = 0; i < localStorage.length; i++) {
  26. const next = localStorage.key(i)
  27. if (!next?.endsWith(":workspace:terminal")) continue
  28. const value = localStorage.getItem(next)
  29. if (!value) continue
  30. return JSON.parse(value) as State
  31. }
  32. }, key)
  33. }
  34. test("inactive terminal tab buffers persist across tab switches", async ({ page, withProject }) => {
  35. await withProject(async ({ directory, gotoSession }) => {
  36. const key = workspacePersistKey(directory, "terminal")
  37. const one = `E2E_TERM_ONE_${Date.now()}`
  38. const two = `E2E_TERM_TWO_${Date.now()}`
  39. const tabs = page.locator('#terminal-panel [data-slot="tabs-trigger"]')
  40. const first = tabs.filter({ hasText: /Terminal 1/ }).first()
  41. const second = tabs.filter({ hasText: /Terminal 2/ }).first()
  42. await gotoSession()
  43. await open(page)
  44. await runTerminal(page, { cmd: `echo ${one}`, token: one })
  45. await page.getByRole("button", { name: /new terminal/i }).click()
  46. await expect(tabs).toHaveCount(2)
  47. await runTerminal(page, { cmd: `echo ${two}`, token: two })
  48. await first.click()
  49. await expect(first).toHaveAttribute("aria-selected", "true")
  50. await expect
  51. .poll(
  52. async () => {
  53. const state = await store(page, key)
  54. const first = state?.all.find((item) => item.titleNumber === 1)?.buffer ?? ""
  55. const second = state?.all.find((item) => item.titleNumber === 2)?.buffer ?? ""
  56. return {
  57. first: first.includes(one),
  58. second: second.includes(two),
  59. }
  60. },
  61. { timeout: 5_000 },
  62. )
  63. .toEqual({ first: false, second: true })
  64. await second.click()
  65. await expect(second).toHaveAttribute("aria-selected", "true")
  66. await expect
  67. .poll(
  68. async () => {
  69. const state = await store(page, key)
  70. const first = state?.all.find((item) => item.titleNumber === 1)?.buffer ?? ""
  71. const second = state?.all.find((item) => item.titleNumber === 2)?.buffer ?? ""
  72. return {
  73. first: first.includes(one),
  74. second: second.includes(two),
  75. }
  76. },
  77. { timeout: 5_000 },
  78. )
  79. .toEqual({ first: true, second: false })
  80. })
  81. })
  82. test("closing the active terminal tab falls back to the previous tab", async ({ page, withProject }) => {
  83. await withProject(async ({ directory, gotoSession }) => {
  84. const key = workspacePersistKey(directory, "terminal")
  85. const tabs = page.locator('#terminal-panel [data-slot="tabs-trigger"]')
  86. await gotoSession()
  87. await open(page)
  88. await page.getByRole("button", { name: /new terminal/i }).click()
  89. await expect(tabs).toHaveCount(2)
  90. const second = tabs.filter({ hasText: /Terminal 2/ }).first()
  91. await second.click()
  92. await expect(second).toHaveAttribute("aria-selected", "true")
  93. await second.hover()
  94. await page
  95. .getByRole("button", { name: /close terminal/i })
  96. .nth(1)
  97. .click({ force: true })
  98. const first = tabs.filter({ hasText: /Terminal 1/ }).first()
  99. await expect(tabs).toHaveCount(1)
  100. await expect(first).toHaveAttribute("aria-selected", "true")
  101. await expect
  102. .poll(
  103. async () => {
  104. const state = await store(page, key)
  105. return {
  106. count: state?.all.length ?? 0,
  107. first: state?.all.some((item) => item.titleNumber === 1) ?? false,
  108. }
  109. },
  110. { timeout: 15_000 },
  111. )
  112. .toEqual({ count: 1, first: true })
  113. })
  114. })