Просмотр исходного кода

fix(app): preserve file tree tab on reopen + fix e2e test regressions (#16482)

Filip 1 месяц назад
Родитель
Сommit
66fcab7b08

+ 3 - 3
packages/app/e2e/app/home.spec.ts

@@ -1,17 +1,17 @@
 import { test, expect } from "../fixtures"
-import { serverName } from "../utils"
+import { serverNamePattern } from "../utils"
 
 test("home renders and shows core entrypoints", async ({ page }) => {
   await page.goto("/")
 
   await expect(page.getByRole("button", { name: "Open project" }).first()).toBeVisible()
-  await expect(page.getByRole("button", { name: serverName })).toBeVisible()
+  await expect(page.getByRole("button", { name: serverNamePattern })).toBeVisible()
 })
 
 test("server picker dialog opens from home", async ({ page }) => {
   await page.goto("/")
 
-  const trigger = page.getByRole("button", { name: serverName })
+  const trigger = page.getByRole("button", { name: serverNamePattern })
   await expect(trigger).toBeVisible()
   await trigger.click()
 

+ 11 - 8
packages/app/e2e/app/server-default.spec.ts

@@ -1,6 +1,6 @@
 import { test, expect } from "../fixtures"
-import { serverName, serverUrl } from "../utils"
-import { clickListItem, closeDialog, clickMenuItem } from "../actions"
+import { serverNamePattern, serverUrls } from "../utils"
+import { closeDialog, clickMenuItem } from "../actions"
 
 const DEFAULT_SERVER_URL_KEY = "opencode.settings.dat:defaultServerUrl"
 
@@ -31,10 +31,9 @@ test("can set a default server on web", async ({ page, gotoSession }) => {
   const dialog = page.getByRole("dialog")
   await expect(dialog).toBeVisible()
 
-  const row = dialog.locator('[data-slot="list-item"]').filter({ hasText: serverName }).first()
-  await expect(row).toBeVisible()
+  await expect(dialog.getByText(serverNamePattern).first()).toBeVisible()
 
-  const menuTrigger = row.locator('[data-slot="dropdown-menu-trigger"]').first()
+  const menuTrigger = dialog.locator('[data-slot="dropdown-menu-trigger"]').first()
   await expect(menuTrigger).toBeVisible()
   await menuTrigger.click({ force: true })
 
@@ -42,14 +41,18 @@ test("can set a default server on web", async ({ page, gotoSession }) => {
   await expect(menu).toBeVisible()
   await clickMenuItem(menu, /set as default/i)
 
-  await expect.poll(() => page.evaluate((key) => localStorage.getItem(key), DEFAULT_SERVER_URL_KEY)).toBe(serverUrl)
-  await expect(row.getByText("Default", { exact: true })).toBeVisible()
+  await expect
+    .poll(async () =>
+      serverUrls.includes((await page.evaluate((key) => localStorage.getItem(key), DEFAULT_SERVER_URL_KEY)) ?? ""),
+    )
+    .toBe(true)
+  await expect(dialog.getByText("Default", { exact: true })).toBeVisible()
 
   await closeDialog(page, dialog)
 
   await ensurePopoverOpen()
 
-  const serverRow = popover.locator("button").filter({ hasText: serverName }).first()
+  const serverRow = popover.locator("button").filter({ hasText: serverNamePattern }).first()
   await expect(serverRow).toBeVisible()
   await expect(serverRow.getByText("Default", { exact: true })).toBeVisible()
 })

+ 5 - 3
packages/app/e2e/commands/panels.spec.ts

@@ -10,6 +10,8 @@ const expanded = async (el: { getAttribute: (name: string) => Promise<string | n
 test("review panel can be toggled via keybind", async ({ page, gotoSession }) => {
   await gotoSession()
 
+  const reviewPanel = page.locator("#review-panel")
+
   const treeToggle = page.getByRole("button", { name: "Toggle file tree" }).first()
   await expect(treeToggle).toBeVisible()
   if (await expanded(treeToggle)) await treeToggle.click()
@@ -19,13 +21,13 @@ test("review panel can be toggled via keybind", async ({ page, gotoSession }) =>
   await expect(reviewToggle).toBeVisible()
   if (await expanded(reviewToggle)) await reviewToggle.click()
   await expect(reviewToggle).toHaveAttribute("aria-expanded", "false")
-  await expect(page.locator("#review-panel")).toHaveCount(0)
+  await expect(reviewPanel).toHaveAttribute("aria-hidden", "true")
 
   await page.keyboard.press(`${modKey}+Shift+R`)
   await expect(reviewToggle).toHaveAttribute("aria-expanded", "true")
-  await expect(page.locator("#review-panel")).toBeVisible()
+  await expect(reviewPanel).toHaveAttribute("aria-hidden", "false")
 
   await page.keyboard.press(`${modKey}+Shift+R`)
   await expect(reviewToggle).toHaveAttribute("aria-expanded", "false")
-  await expect(page.locator("#review-panel")).toHaveCount(0)
+  await expect(reviewPanel).toHaveAttribute("aria-hidden", "true")
 })

+ 7 - 0
packages/app/e2e/files/file-tree.spec.ts

@@ -43,6 +43,13 @@ test("file tree can expand folders and open a file", async ({ page, gotoSession
   await tab.click()
   await expect(tab).toHaveAttribute("aria-selected", "true")
 
+  await toggle.click()
+  await expect(toggle).toHaveAttribute("aria-expanded", "false")
+
+  await toggle.click()
+  await expect(toggle).toHaveAttribute("aria-expanded", "true")
+  await expect(allTab).toHaveAttribute("aria-selected", "true")
+
   const viewer = page.locator('[data-component="file"][data-mode="text"]').first()
   await expect(viewer).toBeVisible()
   await expect(viewer).toContainText("export default function FileTree")

+ 8 - 8
packages/app/e2e/session/session-undo-redo.spec.ts

@@ -45,7 +45,7 @@ async function seedConversation(input: {
     .toBe(true)
 
   if (!userMessageID) throw new Error("Expected a user message id")
-  await expect(input.page.locator(`[data-message-id="${userMessageID}"]`).first()).toBeVisible({ timeout: 30_000 })
+  await expect(input.page.locator(`[data-message-id="${userMessageID}"]`)).toHaveCount(1, { timeout: 30_000 })
   return { prompt, userMessageID }
 }
 
@@ -123,7 +123,7 @@ test("slash redo clears revert and restores latest state", async ({ page, withPr
         .toBeUndefined()
 
       await expect(seeded.prompt).not.toContainText(token)
-      await expect(page.locator(`[data-message-id="${seeded.userMessageID}"]`).first()).toBeVisible()
+      await expect(page.locator(`[data-message-id="${seeded.userMessageID}"]`)).toHaveCount(1)
     })
   })
 })
@@ -158,8 +158,8 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro
       const firstMessage = page.locator(`[data-message-id="${first.userMessageID}"]`)
       const secondMessage = page.locator(`[data-message-id="${second.userMessageID}"]`)
 
-      await expect(firstMessage.first()).toBeVisible()
-      await expect(secondMessage.first()).toBeVisible()
+      await expect(firstMessage).toHaveCount(1)
+      await expect(secondMessage).toHaveCount(1)
 
       await second.prompt.click()
       await page.keyboard.press(`${modKey}+A`)
@@ -176,7 +176,7 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro
         })
         .toBe(second.userMessageID)
 
-      await expect(firstMessage.first()).toBeVisible()
+      await expect(firstMessage).toHaveCount(1)
       await expect(secondMessage).toHaveCount(0)
 
       await second.prompt.click()
@@ -210,7 +210,7 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro
         })
         .toBe(second.userMessageID)
 
-      await expect(firstMessage.first()).toBeVisible()
+      await expect(firstMessage).toHaveCount(1)
       await expect(secondMessage).toHaveCount(0)
 
       await second.prompt.click()
@@ -226,8 +226,8 @@ test("slash undo/redo traverses multi-step revert stack", async ({ page, withPro
         })
         .toBeUndefined()
 
-      await expect(firstMessage.first()).toBeVisible()
-      await expect(secondMessage.first()).toBeVisible()
+      await expect(firstMessage).toHaveCount(1)
+      await expect(secondMessage).toHaveCount(1)
     })
   })
 })

+ 16 - 0
packages/app/e2e/utils.ts

@@ -7,6 +7,22 @@ export const serverPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"
 export const serverUrl = `http://${serverHost}:${serverPort}`
 export const serverName = `${serverHost}:${serverPort}`
 
+const localHosts = ["127.0.0.1", "localhost"]
+
+const serverLabels = (() => {
+  const url = new URL(serverUrl)
+  if (!localHosts.includes(url.hostname)) return [serverName]
+  return localHosts.map((host) => `${host}:${url.port}`)
+})()
+
+export const serverNames = [...new Set(serverLabels)]
+
+export const serverUrls = serverNames.map((name) => `http://${name}`)
+
+const escape = (value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
+
+export const serverNamePattern = new RegExp(`(?:${serverNames.map(escape).join("|")})`)
+
 export const modKey = process.platform === "darwin" ? "Meta" : "Control"
 export const terminalToggleKey = "Control+Backquote"
 

+ 0 - 17
packages/app/src/pages/session.tsx

@@ -1038,23 +1038,6 @@ export default function Page() {
     tabs().setActive(next)
   })
 
-  createEffect(
-    on(
-      () => layout.fileTree.opened(),
-      (opened, prev) => {
-        if (prev === undefined) return
-        if (!isDesktop()) return
-
-        if (opened) {
-          const active = tabs().active()
-          const tab = active === "review" || (!active && hasReview()) ? "changes" : "all"
-          layout.fileTree.setTab(tab)
-        }
-      },
-      { defer: true },
-    ),
-  )
-
   createEffect(() => {
     const id = params.id
     if (!id) return