terminal-composer-focus.spec.ts 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import { base64Encode } from "@opencode-ai/core/util/encode"
  2. import { expect, test } from "@playwright/test"
  3. import { mockOpenCodeServer } from "../utils/mock-server"
  4. import { expectSessionTitle } from "../utils/waits"
  5. const directory = "C:/OpenCode/TerminalComposerFocus"
  6. const projectID = "proj_terminal_composer_focus"
  7. const sessionID = "ses_terminal_composer_focus"
  8. const ptyID = "pty_terminal_composer_focus"
  9. test.use({ viewport: { width: 1440, height: 900 } })
  10. test("routes typing to the composer unless the open terminal is focused", async ({ page }) => {
  11. await mockOpenCodeServer(page, {
  12. directory,
  13. project: {
  14. id: projectID,
  15. worktree: directory,
  16. vcs: "git",
  17. name: "terminal-composer-focus",
  18. time: { created: 1700000000000, updated: 1700000000000 },
  19. sandboxes: [],
  20. },
  21. provider: {
  22. all: [
  23. {
  24. id: "opencode",
  25. name: "OpenCode",
  26. models: { test: { id: "test", name: "Test", limit: { context: 200_000 } } },
  27. },
  28. ],
  29. connected: ["opencode"],
  30. default: { providerID: "opencode", modelID: "test" },
  31. },
  32. sessions: [
  33. {
  34. id: sessionID,
  35. slug: "terminal-composer-focus",
  36. projectID,
  37. directory,
  38. title: "Terminal composer focus",
  39. version: "dev",
  40. time: { created: 1700000000000, updated: 1700000000000 },
  41. },
  42. ],
  43. pageMessages: () => ({ items: [] }),
  44. })
  45. await page.route("**/pty", (route) =>
  46. route.fulfill({
  47. status: 200,
  48. contentType: "application/json",
  49. body: JSON.stringify({ id: ptyID, title: "Terminal 1" }),
  50. }),
  51. )
  52. await page.route(`**/pty/${ptyID}`, (route) =>
  53. route.fulfill({ status: 200, contentType: "application/json", body: "{}" }),
  54. )
  55. await page.route(`**/pty/${ptyID}/connect-token*`, (route) =>
  56. route.fulfill({
  57. status: 200,
  58. contentType: "application/json",
  59. headers: { "access-control-allow-origin": "*" },
  60. body: JSON.stringify({ ticket: "e2e-ticket" }),
  61. }),
  62. )
  63. await page.routeWebSocket(new RegExp(`/pty/${ptyID}/connect`), () => undefined)
  64. await page.addInitScript(() => {
  65. localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } }))
  66. })
  67. await page.goto(`/${base64Encode(directory)}/session/${sessionID}`)
  68. await expectSessionTitle(page, "Terminal composer focus")
  69. const composer = page.locator('[data-component="prompt-input"]')
  70. const terminal = page.locator('[data-component="terminal"]')
  71. await page.keyboard.press("Control+Backquote")
  72. await expect(terminal).toBeVisible()
  73. await expect.poll(() => terminal.evaluate((element) => element.contains(document.activeElement))).toBe(true)
  74. await page.keyboard.type("x")
  75. await expect(composer).toHaveText("")
  76. await page.waitForTimeout(300)
  77. await page.evaluate(() => (document.activeElement as HTMLElement | null)?.blur())
  78. await page.keyboard.type("a")
  79. await expect(composer).toBeFocused()
  80. await expect(composer).toHaveText("a")
  81. })