session-request-docks.spec.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import { base64Encode } from "@opencode-ai/core/util/encode"
  2. import { expect, test, type Page } from "@playwright/test"
  3. import { mockOpenCodeServer } from "../utils/mock-server"
  4. import { expectSessionTitle } from "../utils/waits"
  5. const directory = "C:/OpenCode/RequestDocks"
  6. const projectID = "proj_request_docks"
  7. const sessionID = "ses_request_docks"
  8. const title = "Request dock regression"
  9. test("shows a pending question dock", async ({ page }) => {
  10. await mockServer(page, {
  11. questions: [
  12. {
  13. id: "question-request",
  14. sessionID,
  15. questions: [
  16. {
  17. header: "Implementation",
  18. question: "Which implementation should be used?",
  19. options: [
  20. { label: "Minimal", description: "Use the smallest correct change" },
  21. { label: "Extended", description: "Include additional behavior" },
  22. ],
  23. },
  24. ],
  25. },
  26. ],
  27. })
  28. await page.goto(`/${base64Encode(directory)}/session/${sessionID}`)
  29. await expectSessionTitle(page, title)
  30. const question = page.locator('[data-component="dock-prompt"][data-kind="question"]')
  31. await expect(question).toBeVisible()
  32. await expect(question.getByText("Which implementation should be used?")).toBeVisible()
  33. await expect(question.getByRole("radio", { name: /Minimal/ })).toBeVisible()
  34. await expect(question.getByRole("radio", { name: /Extended/ })).toBeVisible()
  35. await expect(page.locator('[data-component="session-composer"]')).toHaveCount(0)
  36. await question.getByRole("radio", { name: /Minimal/ }).click()
  37. const reply = page.waitForRequest(
  38. (request) => request.method() === "POST" && new URL(request.url()).pathname === "/question/question-request/reply",
  39. )
  40. await question.getByRole("button", { name: "Submit" }).click()
  41. expect((await reply).postDataJSON()).toEqual({ answers: [["Minimal"]] })
  42. })
  43. test("shows a pending permission dock", async ({ page }) => {
  44. await mockServer(page, {
  45. permissions: [
  46. {
  47. id: "permission-request",
  48. sessionID,
  49. permission: "bash",
  50. patterns: ["git status", "git diff"],
  51. metadata: {},
  52. always: [],
  53. },
  54. ],
  55. })
  56. await page.goto(`/${base64Encode(directory)}/session/${sessionID}`)
  57. await expectSessionTitle(page, title)
  58. const permission = page.locator('[data-component="dock-prompt"][data-kind="permission"]')
  59. await expect(permission).toBeVisible()
  60. await expect(permission.getByText("git status")).toBeVisible()
  61. await expect(permission.getByText("git diff")).toBeVisible()
  62. await expect(permission.locator('[data-slot="permission-footer-actions"] button')).toHaveCount(3)
  63. await expect(page.locator('[data-component="session-composer"]')).toHaveCount(0)
  64. const reply = page.waitForRequest((request) => request.method() === "POST")
  65. await permission.getByRole("button", { name: "Allow once" }).click()
  66. const request = await reply
  67. expect(new URL(request.url()).pathname).toBe(`/session/${sessionID}/permissions/permission-request`)
  68. expect(request.postDataJSON()).toEqual({ response: "once" })
  69. })
  70. async function mockServer(
  71. page: Page,
  72. requests: {
  73. permissions?: unknown[] | (() => unknown[])
  74. questions?: unknown[] | (() => unknown[])
  75. },
  76. ) {
  77. await mockOpenCodeServer(page, {
  78. directory,
  79. project: {
  80. id: projectID,
  81. worktree: directory,
  82. vcs: "git",
  83. name: "request-docks",
  84. time: { created: 1700000000000, updated: 1700000000000 },
  85. sandboxes: [],
  86. },
  87. provider: {
  88. all: [
  89. {
  90. id: "opencode",
  91. name: "OpenCode",
  92. models: {
  93. "claude-opus-4-6": {
  94. id: "claude-opus-4-6",
  95. name: "Claude Opus 4.6",
  96. limit: { context: 200_000 },
  97. },
  98. },
  99. },
  100. ],
  101. connected: ["opencode"],
  102. default: { providerID: "opencode", modelID: "claude-opus-4-6" },
  103. },
  104. sessions: [
  105. {
  106. id: sessionID,
  107. slug: "request-docks",
  108. projectID,
  109. directory,
  110. title,
  111. version: "dev",
  112. time: { created: 1700000000000, updated: 1700000000000 },
  113. },
  114. ],
  115. pageMessages: () => ({ items: [] }),
  116. permissions: requests.permissions,
  117. questions: requests.questions,
  118. })
  119. await page.addInitScript(() => {
  120. localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } }))
  121. })
  122. }