session.spec.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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, sessionTimelineHeaderSelector } 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, sdk, gotoSession }) => {
  30. const stamp = Date.now()
  31. const originalTitle = `e2e rename test ${stamp}`
  32. const renamedTitle = `e2e renamed ${stamp}`
  33. await withSession(sdk, originalTitle, async (session) => {
  34. await seedMessage(sdk, session.id)
  35. await gotoSession(session.id)
  36. await expect(page.locator(sessionTimelineHeaderSelector).getByRole("heading", { level: 1 }).first()).toHaveText(
  37. originalTitle,
  38. )
  39. const menu = await openSessionMoreMenu(page, session.id)
  40. await clickMenuItem(menu, /rename/i)
  41. const input = page.locator(sessionTimelineHeaderSelector).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 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.locator(sessionTimelineHeaderSelector).getByRole("heading", { level: 1 }).first()).toHaveText(
  57. renamedTitle,
  58. )
  59. })
  60. })
  61. test("session can be archived via header menu", async ({ page, sdk, gotoSession }) => {
  62. const stamp = Date.now()
  63. const title = `e2e archive test ${stamp}`
  64. await withSession(sdk, title, async (session) => {
  65. await seedMessage(sdk, session.id)
  66. await 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 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, sdk, gotoSession }) => {
  83. const stamp = Date.now()
  84. const title = `e2e delete test ${stamp}`
  85. await withSession(sdk, title, async (session) => {
  86. await seedMessage(sdk, session.id)
  87. await gotoSession(session.id)
  88. const menu = await openSessionMoreMenu(page, session.id)
  89. await clickMenuItem(menu, /delete/i)
  90. await confirmDialog(page, /delete/i)
  91. await expect
  92. .poll(
  93. async () => {
  94. const data = await sdk.session
  95. .get({ sessionID: session.id })
  96. .then((r) => r.data)
  97. .catch(() => undefined)
  98. return data?.id
  99. },
  100. { timeout: 30_000 },
  101. )
  102. .toBeUndefined()
  103. await openSidebar(page)
  104. await expect(page.locator(sessionItemSelector(session.id))).toHaveCount(0)
  105. })
  106. })
  107. test("session can be shared and unshared via header button", async ({ page, sdk, gotoSession }) => {
  108. test.skip(shareDisabled, "Share is disabled in this environment (OPENCODE_DISABLE_SHARE).")
  109. const stamp = Date.now()
  110. const title = `e2e share test ${stamp}`
  111. await withSession(sdk, title, async (session) => {
  112. await seedMessage(sdk, session.id)
  113. await gotoSession(session.id)
  114. const shared = await openSharePopover(page)
  115. const publish = shared.popoverBody.getByRole("button", { name: "Publish" }).first()
  116. await expect(publish).toBeVisible({ timeout: 30_000 })
  117. await publish.click()
  118. await expect(shared.popoverBody.getByRole("button", { name: "Unpublish" }).first()).toBeVisible({
  119. timeout: 30_000,
  120. })
  121. await expect
  122. .poll(
  123. async () => {
  124. const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  125. return data?.share?.url || undefined
  126. },
  127. { timeout: 30_000 },
  128. )
  129. .not.toBeUndefined()
  130. const unpublish = shared.popoverBody.getByRole("button", { name: "Unpublish" }).first()
  131. await expect(unpublish).toBeVisible({ timeout: 30_000 })
  132. await unpublish.click()
  133. await expect(shared.popoverBody.getByRole("button", { name: "Publish" }).first()).toBeVisible({
  134. timeout: 30_000,
  135. })
  136. await expect
  137. .poll(
  138. async () => {
  139. const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  140. return data?.share?.url || undefined
  141. },
  142. { timeout: 30_000 },
  143. )
  144. .toBeUndefined()
  145. const unshared = await openSharePopover(page)
  146. await expect(unshared.popoverBody.getByRole("button", { name: "Publish" }).first()).toBeVisible({
  147. timeout: 30_000,
  148. })
  149. })
  150. })