session.spec.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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, project }) => {
  30. const stamp = Date.now()
  31. const originalTitle = `e2e rename test ${stamp}`
  32. const renamedTitle = `e2e renamed ${stamp}`
  33. await project.open()
  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. test("session can be archived via header menu", async ({ page, project }) => {
  60. const stamp = Date.now()
  61. const title = `e2e archive test ${stamp}`
  62. await project.open()
  63. await withSession(project.sdk, title, async (session) => {
  64. project.trackSession(session.id)
  65. await seedMessage(project.sdk, session.id)
  66. await project.gotoSession(session.id)
  67. const menu = await openSessionMoreMenu(page, session.id)
  68. await clickMenuItem(menu, /archive/i)
  69. await expect
  70. .poll(
  71. async () => {
  72. const data = await project.sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  73. return data?.time?.archived
  74. },
  75. { timeout: 30_000 },
  76. )
  77. .not.toBeUndefined()
  78. await openSidebar(page)
  79. await expect(page.locator(sessionItemSelector(session.id))).toHaveCount(0)
  80. })
  81. })
  82. test("session can be deleted via header menu", async ({ page, project }) => {
  83. const stamp = Date.now()
  84. const title = `e2e delete test ${stamp}`
  85. await project.open()
  86. await withSession(project.sdk, title, async (session) => {
  87. project.trackSession(session.id)
  88. await seedMessage(project.sdk, session.id)
  89. await project.gotoSession(session.id)
  90. const menu = await openSessionMoreMenu(page, session.id)
  91. await clickMenuItem(menu, /delete/i)
  92. await confirmDialog(page, /delete/i)
  93. await expect
  94. .poll(
  95. async () => {
  96. const data = await project.sdk.session
  97. .get({ sessionID: session.id })
  98. .then((r) => r.data)
  99. .catch(() => undefined)
  100. return data?.id
  101. },
  102. { timeout: 30_000 },
  103. )
  104. .toBeUndefined()
  105. await openSidebar(page)
  106. await expect(page.locator(sessionItemSelector(session.id))).toHaveCount(0)
  107. })
  108. })
  109. test("session can be shared and unshared via header button", async ({ page, project }) => {
  110. test.skip(shareDisabled, "Share is disabled in this environment (OPENCODE_DISABLE_SHARE).")
  111. const stamp = Date.now()
  112. const title = `e2e share test ${stamp}`
  113. await project.open()
  114. await withSession(project.sdk, title, async (session) => {
  115. project.trackSession(session.id)
  116. await project.gotoSession(session.id)
  117. await project.prompt(`share seed ${stamp}`)
  118. const shared = await openSharePopover(page)
  119. const publish = shared.popoverBody.getByRole("button", { name: "Publish" }).first()
  120. await expect(publish).toBeVisible({ timeout: 30_000 })
  121. await publish.click()
  122. await expect(shared.popoverBody.getByRole("button", { name: "Unpublish" }).first()).toBeVisible({
  123. timeout: 30_000,
  124. })
  125. await expect
  126. .poll(
  127. async () => {
  128. const data = await project.sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  129. return data?.share?.url || undefined
  130. },
  131. { timeout: 30_000 },
  132. )
  133. .not.toBeUndefined()
  134. const unpublish = shared.popoverBody.getByRole("button", { name: "Unpublish" }).first()
  135. await expect(unpublish).toBeVisible({ timeout: 30_000 })
  136. await unpublish.click()
  137. await expect(shared.popoverBody.getByRole("button", { name: "Publish" }).first()).toBeVisible({
  138. timeout: 30_000,
  139. })
  140. await expect
  141. .poll(
  142. async () => {
  143. const data = await project.sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  144. return data?.share?.url || undefined
  145. },
  146. { timeout: 30_000 },
  147. )
  148. .toBeUndefined()
  149. const unshared = await openSharePopover(page)
  150. await expect(unshared.popoverBody.getByRole("button", { name: "Publish" }).first()).toBeVisible({
  151. timeout: 30_000,
  152. })
  153. })
  154. })