session.spec.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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, sdk, gotoSession }) => {
  30. const stamp = Date.now()
  31. const originalTitle = `e2e rename test ${stamp}`
  32. const newTitle = `e2e renamed ${stamp}`
  33. await withSession(sdk, originalTitle, async (session) => {
  34. await seedMessage(sdk, session.id)
  35. await gotoSession(session.id)
  36. const menu = await openSessionMoreMenu(page, session.id)
  37. await clickMenuItem(menu, /rename/i)
  38. const input = page.locator(".session-scroller").locator(inlineInputSelector).first()
  39. await expect(input).toBeVisible()
  40. await input.fill(newTitle)
  41. await input.press("Enter")
  42. await expect(page.getByRole("heading", { level: 1 }).first()).toContainText(newTitle)
  43. })
  44. })
  45. test("session can be archived via header menu", async ({ page, sdk, gotoSession }) => {
  46. const stamp = Date.now()
  47. const title = `e2e archive test ${stamp}`
  48. await withSession(sdk, title, async (session) => {
  49. await seedMessage(sdk, session.id)
  50. await gotoSession(session.id)
  51. const menu = await openSessionMoreMenu(page, session.id)
  52. await clickMenuItem(menu, /archive/i)
  53. await expect
  54. .poll(
  55. async () => {
  56. const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  57. return data?.time?.archived
  58. },
  59. { timeout: 30_000 },
  60. )
  61. .not.toBeUndefined()
  62. await openSidebar(page)
  63. await expect(page.locator(sessionItemSelector(session.id))).toHaveCount(0)
  64. })
  65. })
  66. test("session can be deleted via header menu", async ({ page, sdk, gotoSession }) => {
  67. const stamp = Date.now()
  68. const title = `e2e delete test ${stamp}`
  69. await withSession(sdk, title, async (session) => {
  70. await seedMessage(sdk, session.id)
  71. await gotoSession(session.id)
  72. const menu = await openSessionMoreMenu(page, session.id)
  73. await clickMenuItem(menu, /delete/i)
  74. await confirmDialog(page, /delete/i)
  75. await expect
  76. .poll(
  77. async () => {
  78. const data = await sdk.session
  79. .get({ sessionID: session.id })
  80. .then((r) => r.data)
  81. .catch(() => undefined)
  82. return data?.id
  83. },
  84. { timeout: 30_000 },
  85. )
  86. .toBeUndefined()
  87. await openSidebar(page)
  88. await expect(page.locator(sessionItemSelector(session.id))).toHaveCount(0)
  89. })
  90. })
  91. test("session can be shared and unshared via header button", async ({ page, sdk, gotoSession }) => {
  92. test.skip(shareDisabled, "Share is disabled in this environment (OPENCODE_DISABLE_SHARE).")
  93. const stamp = Date.now()
  94. const title = `e2e share test ${stamp}`
  95. await withSession(sdk, title, async (session) => {
  96. await seedMessage(sdk, session.id)
  97. await gotoSession(session.id)
  98. const { rightSection, popoverBody } = await openSharePopover(page)
  99. await popoverBody.getByRole("button", { name: "Publish" }).first().click()
  100. await expect
  101. .poll(
  102. async () => {
  103. const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  104. return data?.share?.url || undefined
  105. },
  106. { timeout: 30_000 },
  107. )
  108. .not.toBeUndefined()
  109. const copyButton = rightSection.locator('button[aria-label="Copy link"]').first()
  110. await expect(copyButton).toBeVisible({ timeout: 30_000 })
  111. const sharedPopover = await openSharePopover(page)
  112. const unpublish = sharedPopover.popoverBody.getByRole("button", { name: "Unpublish" }).first()
  113. await expect(unpublish).toBeVisible({ timeout: 30_000 })
  114. await unpublish.click()
  115. await expect
  116. .poll(
  117. async () => {
  118. const data = await sdk.session.get({ sessionID: session.id }).then((r) => r.data)
  119. return data?.share?.url || undefined
  120. },
  121. { timeout: 30_000 },
  122. )
  123. .toBeUndefined()
  124. await expect(copyButton).not.toBeVisible({ timeout: 30_000 })
  125. const unsharedPopover = await openSharePopover(page)
  126. await expect(unsharedPopover.popoverBody.getByRole("button", { name: "Publish" }).first()).toBeVisible({
  127. timeout: 30_000,
  128. })
  129. })
  130. })