fixtures.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { test as base, expect, type Page } from "@playwright/test"
  2. import type { E2EWindow } from "../src/testing/terminal"
  3. import { cleanupSession, cleanupTestProject, createTestProject, seedProjects, sessionIDFromUrl } from "./actions"
  4. import { promptSelector } from "./selectors"
  5. import { createSdk, dirSlug, getWorktree, sessionPath } from "./utils"
  6. export const settingsKey = "settings.v3"
  7. type TestFixtures = {
  8. sdk: ReturnType<typeof createSdk>
  9. gotoSession: (sessionID?: string) => Promise<void>
  10. withProject: <T>(
  11. callback: (project: {
  12. directory: string
  13. slug: string
  14. gotoSession: (sessionID?: string) => Promise<void>
  15. trackSession: (sessionID: string, directory?: string) => void
  16. trackDirectory: (directory: string) => void
  17. }) => Promise<T>,
  18. options?: { extra?: string[] },
  19. ) => Promise<T>
  20. }
  21. type WorkerFixtures = {
  22. directory: string
  23. slug: string
  24. }
  25. export const test = base.extend<TestFixtures, WorkerFixtures>({
  26. directory: [
  27. async ({}, use) => {
  28. const directory = await getWorktree()
  29. await use(directory)
  30. },
  31. { scope: "worker" },
  32. ],
  33. slug: [
  34. async ({ directory }, use) => {
  35. await use(dirSlug(directory))
  36. },
  37. { scope: "worker" },
  38. ],
  39. sdk: async ({ directory }, use) => {
  40. await use(createSdk(directory))
  41. },
  42. gotoSession: async ({ page, directory }, use) => {
  43. await seedStorage(page, { directory })
  44. const gotoSession = async (sessionID?: string) => {
  45. await page.goto(sessionPath(directory, sessionID))
  46. await expect(page.locator(promptSelector)).toBeVisible()
  47. }
  48. await use(gotoSession)
  49. },
  50. withProject: async ({ page }, use) => {
  51. await use(async (callback, options) => {
  52. const root = await createTestProject()
  53. const slug = dirSlug(root)
  54. const sessions = new Map<string, string>()
  55. const dirs = new Set<string>()
  56. await seedStorage(page, { directory: root, extra: options?.extra })
  57. const gotoSession = async (sessionID?: string) => {
  58. await page.goto(sessionPath(root, sessionID))
  59. await expect(page.locator(promptSelector)).toBeVisible()
  60. const current = sessionIDFromUrl(page.url())
  61. if (current) trackSession(current)
  62. }
  63. const trackSession = (sessionID: string, directory?: string) => {
  64. sessions.set(sessionID, directory ?? root)
  65. }
  66. const trackDirectory = (directory: string) => {
  67. if (directory !== root) dirs.add(directory)
  68. }
  69. try {
  70. await gotoSession()
  71. return await callback({ directory: root, slug, gotoSession, trackSession, trackDirectory })
  72. } finally {
  73. await Promise.allSettled(
  74. Array.from(sessions, ([sessionID, directory]) => cleanupSession({ sessionID, directory })),
  75. )
  76. await Promise.allSettled(Array.from(dirs, (directory) => cleanupTestProject(directory)))
  77. await cleanupTestProject(root)
  78. }
  79. })
  80. },
  81. })
  82. async function seedStorage(page: Page, input: { directory: string; extra?: string[] }) {
  83. await seedProjects(page, input)
  84. await page.addInitScript(() => {
  85. const win = window as E2EWindow
  86. win.__opencode_e2e = {
  87. ...win.__opencode_e2e,
  88. model: {
  89. enabled: true,
  90. },
  91. prompt: {
  92. enabled: true,
  93. },
  94. terminal: {
  95. enabled: true,
  96. terminals: {},
  97. },
  98. }
  99. localStorage.setItem(
  100. "opencode.global.dat:model",
  101. JSON.stringify({
  102. recent: [{ providerID: "opencode", modelID: "big-pickle" }],
  103. user: [],
  104. variant: {},
  105. }),
  106. )
  107. })
  108. }
  109. export { expect }