session.spec.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import { test, expect } from "../fixtures"
  2. import {
  3. openSidebar,
  4. openSessionMoreMenu,
  5. clickMenuItem,
  6. confirmDialog,
  7. openSharePopover,
  8. withSession,
  9. } from "../actions"
  10. import { sessionItemSelector, inlineInputSelector } from "../selectors"
  11. const shareDisabled = process.env.OPENCODE_DISABLE_SHARE === "true" || process.env.OPENCODE_DISABLE_SHARE === "1"
  12. type Sdk = Parameters<typeof withSession>[0]
  13. async function seedMessage(sdk: Sdk, sessionID: string) {
  14. await sdk.session.promptAsync({
  15. sessionID,
  16. noReply: true,
  17. parts: [{ type: "text", text: "e2e seed" }],
  18. })
  19. await expect
  20. .poll(
  21. async () => {
  22. const messages = await sdk.session.messages({ sessionID, limit: 1 }).then((r) => r.data ?? [])
  23. return messages.length
  24. },
  25. { timeout: 30_000 },
  26. )
  27. .toBeGreaterThan(0)
  28. }
  29. test("session can be renamed via header menu", async ({ page, withBackendProject }) => {
  30. const stamp = Date.now()
  31. const originalTitle = `e2e rename test ${stamp}`
  32. const renamedTitle = `e2e renamed ${stamp}`
  33. await withBackendProject(async (project) => {
  34. await withSession(project.sdk, originalTitle, async (session) => {
  35. project.trackSession(session.id)
  36. await seedMessage(project.sdk, session.id)
  37. await project.gotoSession(session.id)
  38. await expect(page.getByRole("heading", { level: 1 }).first()).toHaveText(originalTitle)
  39. const menu = await openSessionMoreMenu(page, session.id)
  40. await clickMenuItem(menu, /rename/i)
  41. const input = page.locator(".scroll-view__viewport").locator(inlineInputSelector).first()
  42. await expect(input).toBeVisible()
  43. await expect(input).toBeFocused()
  44. await input.fill(renamedTitle)
  45. await expect(input).toHaveValue(renamedTitle)
  46. await input.press("Enter")
  47. await expect
  48. .poll(
  49. async () => {
  50. const data = await project.sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  51. return data?.title
  52. },
  53. { timeout: 30_000 },
  54. )
  55. .toBe(renamedTitle)
  56. await expect(page.getByRole("heading", { level: 1 }).first()).toHaveText(renamedTitle)
  57. })
  58. })
  59. })
  60. test("session can be archived via header menu", async ({ page, withBackendProject }) => {
  61. const stamp = Date.now()
  62. const title = `e2e archive test ${stamp}`
  63. await withBackendProject(async (project) => {
  64. await withSession(project.sdk, title, async (session) => {
  65. project.trackSession(session.id)
  66. await seedMessage(project.sdk, session.id)
  67. await project.gotoSession(session.id)
  68. const menu = await openSessionMoreMenu(page, session.id)
  69. await clickMenuItem(menu, /archive/i)
  70. await expect
  71. .poll(
  72. async () => {
  73. const data = await project.sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  74. return data?.time?.archived
  75. },
  76. { timeout: 30_000 },
  77. )
  78. .not.toBeUndefined()
  79. await openSidebar(page)
  80. await expect(page.locator(sessionItemSelector(session.id))).toHaveCount(0)
  81. })
  82. })
  83. })
  84. test("session can be deleted via header menu", async ({ page, withBackendProject }) => {
  85. const stamp = Date.now()
  86. const title = `e2e delete test ${stamp}`
  87. await withBackendProject(async (project) => {
  88. await withSession(project.sdk, title, async (session) => {
  89. project.trackSession(session.id)
  90. await seedMessage(project.sdk, session.id)
  91. await project.gotoSession(session.id)
  92. const menu = await openSessionMoreMenu(page, session.id)
  93. await clickMenuItem(menu, /delete/i)
  94. await confirmDialog(page, /delete/i)
  95. await expect
  96. .poll(
  97. async () => {
  98. const data = await project.sdk.session
  99. .get({ sessionID: session.id })
  100. .then((r) => r.data)
  101. .catch(() => undefined)
  102. return data?.id
  103. },
  104. { timeout: 30_000 },
  105. )
  106. .toBeUndefined()
  107. await openSidebar(page)
  108. await expect(page.locator(sessionItemSelector(session.id))).toHaveCount(0)
  109. })
  110. })
  111. })
  112. test("session can be shared and unshared via header button", async ({ page, withBackendProject }) => {
  113. test.skip(shareDisabled, "Share is disabled in this environment (OPENCODE_DISABLE_SHARE).")
  114. const stamp = Date.now()
  115. const title = `e2e share test ${stamp}`
  116. await withBackendProject(async (project) => {
  117. await withSession(project.sdk, title, async (session) => {
  118. project.trackSession(session.id)
  119. await seedMessage(project.sdk, session.id)
  120. await project.gotoSession(session.id)
  121. const shared = await openSharePopover(page)
  122. const publish = shared.popoverBody.getByRole("button", { name: "Publish" }).first()
  123. await expect(publish).toBeVisible({ timeout: 30_000 })
  124. await publish.click()
  125. await expect(shared.popoverBody.getByRole("button", { name: "Unpublish" }).first()).toBeVisible({
  126. timeout: 30_000,
  127. })
  128. await expect
  129. .poll(
  130. async () => {
  131. const data = await project.sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  132. return data?.share?.url || undefined
  133. },
  134. { timeout: 30_000 },
  135. )
  136. .not.toBeUndefined()
  137. const unpublish = shared.popoverBody.getByRole("button", { name: "Unpublish" }).first()
  138. await expect(unpublish).toBeVisible({ timeout: 30_000 })
  139. await unpublish.click()
  140. await expect(shared.popoverBody.getByRole("button", { name: "Publish" }).first()).toBeVisible({
  141. timeout: 30_000,
  142. })
  143. await expect
  144. .poll(
  145. async () => {
  146. const data = await project.sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  147. return data?.share?.url || undefined
  148. },
  149. { timeout: 30_000 },
  150. )
  151. .toBeUndefined()
  152. const unshared = await openSharePopover(page)
  153. await expect(unshared.popoverBody.getByRole("button", { name: "Publish" }).first()).toBeVisible({
  154. timeout: 30_000,
  155. })
  156. })
  157. })
  158. })