chore: fix flaky test

This commit is contained in:
adamelmore
2026-02-26 08:53:36 -06:00
parent 05ac0a73e1
commit b4d0090e00
4 changed files with 131 additions and 14 deletions

View File

@@ -9,7 +9,7 @@ import {
sessionIDFromUrl, sessionIDFromUrl,
} from "../actions" } from "../actions"
import { projectSwitchSelector, promptSelector, workspaceItemSelector, workspaceNewSessionSelector } from "../selectors" import { projectSwitchSelector, promptSelector, workspaceItemSelector, workspaceNewSessionSelector } from "../selectors"
import { createSdk, dirSlug } from "../utils" import { createSdk, dirSlug, sessionPath } from "../utils"
function slugFromUrl(url: string) { function slugFromUrl(url: string) {
return /\/([^/]+)\/session(?:\/|$)/.exec(url)?.[1] ?? "" return /\/([^/]+)\/session(?:\/|$)/.exec(url)?.[1] ?? ""
@@ -51,7 +51,6 @@ test("switching back to a project opens the latest workspace session", async ({
const other = await createTestProject() const other = await createTestProject()
const otherSlug = dirSlug(other) const otherSlug = dirSlug(other)
const stamp = Date.now()
let rootDir: string | undefined let rootDir: string | undefined
let workspaceDir: string | undefined let workspaceDir: string | undefined
let sessionID: string | undefined let sessionID: string | undefined
@@ -80,6 +79,7 @@ test("switching back to a project opens the latest workspace session", async ({
const workspaceSlug = slugFromUrl(page.url()) const workspaceSlug = slugFromUrl(page.url())
workspaceDir = base64Decode(workspaceSlug) workspaceDir = base64Decode(workspaceSlug)
if (!workspaceDir) throw new Error(`Failed to decode workspace slug: ${workspaceSlug}`)
await openSidebar(page) await openSidebar(page)
const workspace = page.locator(workspaceItemSelector(workspaceSlug)).first() const workspace = page.locator(workspaceItemSelector(workspaceSlug)).first()
@@ -92,15 +92,14 @@ test("switching back to a project opens the latest workspace session", async ({
await expect(page).toHaveURL(new RegExp(`/${workspaceSlug}/session(?:[/?#]|$)`)) await expect(page).toHaveURL(new RegExp(`/${workspaceSlug}/session(?:[/?#]|$)`))
const prompt = page.locator(promptSelector) const created = await createSdk(workspaceDir)
await expect(prompt).toBeVisible() .session.create()
await prompt.fill(`project switch remembers workspace ${stamp}`) .then((x) => x.data?.id)
await prompt.press("Enter") if (!created) throw new Error(`Failed to create session for workspace: ${workspaceDir}`)
await expect.poll(() => sessionIDFromUrl(page.url()) ?? "", { timeout: 30_000 }).not.toBe("")
const created = sessionIDFromUrl(page.url())
if (!created) throw new Error(`Failed to parse session id from URL: ${page.url()}`)
sessionID = created sessionID = created
await page.goto(sessionPath(workspaceDir, created))
await expect(page.locator(promptSelector)).toBeVisible()
await expect(page).toHaveURL(new RegExp(`/${workspaceSlug}/session/${created}(?:[/?#]|$)`)) await expect(page).toHaveURL(new RegExp(`/${workspaceSlug}/session/${created}(?:[/?#]|$)`))
await openSidebar(page) await openSidebar(page)
@@ -114,7 +113,8 @@ test("switching back to a project opens the latest workspace session", async ({
await expect(rootButton).toBeVisible() await expect(rootButton).toBeVisible()
await rootButton.click() await rootButton.click()
await expect(page).toHaveURL(new RegExp(`/${workspaceSlug}/session/${created}(?:[/?#]|$)`)) await expect.poll(() => sessionIDFromUrl(page.url()) ?? "").toBe(created)
await expect(page).toHaveURL(new RegExp(`/session/${created}(?:[/?#]|$)`))
}, },
{ extra: [other] }, { extra: [other] },
) )

View File

@@ -61,6 +61,7 @@ import {
displayName, displayName,
errorMessage, errorMessage,
getDraggableId, getDraggableId,
latestRootSession,
sortedRootSessions, sortedRootSessions,
syncWorkspaceOrder, syncWorkspaceOrder,
workspaceKey, workspaceKey,
@@ -1093,14 +1094,51 @@ export default function Layout(props: ParentProps) {
return meta?.worktree ?? directory return meta?.worktree ?? directory
} }
function navigateToProject(directory: string | undefined) { async function navigateToProject(directory: string | undefined) {
if (!directory) return if (!directory) return
const root = projectRoot(directory) const root = projectRoot(directory)
server.projects.touch(root) server.projects.touch(root)
const project = layout.projects.list().find((item) => item.worktree === root)
const dirs = Array.from(new Set([root, ...(store.workspaceOrder[root] ?? []), ...(project?.sandboxes ?? [])]))
const openSession = async (target: { directory: string; id: string }) => {
const resolved = await globalSDK.client.session
.get({ sessionID: target.id })
.then((x) => x.data)
.catch(() => undefined)
const next = resolved?.directory ? resolved : target
setStore("lastProjectSession", root, { directory: next.directory, id: next.id, at: Date.now() })
navigateWithSidebarReset(`/${base64Encode(next.directory)}/session/${next.id}`)
}
const projectSession = store.lastProjectSession[root] const projectSession = store.lastProjectSession[root]
if (projectSession?.id) { if (projectSession?.id) {
navigateWithSidebarReset(`/${base64Encode(projectSession.directory)}/session/${projectSession.id}`) await openSession(projectSession)
return
}
const latest = latestRootSession(
dirs.map((item) => globalSync.child(item, { bootstrap: false })[0]),
Date.now(),
)
if (latest) {
await openSession(latest)
return
}
const fetched = latestRootSession(
await Promise.all(
dirs.map(async (item) => ({
path: { directory: item },
session: await globalSDK.client.session
.list({ directory: item })
.then((x) => x.data ?? [])
.catch(() => []),
})),
),
Date.now(),
)
if (fetched) {
await openSession(fetched)
return return
} }

View File

@@ -1,6 +1,25 @@
import { describe, expect, test } from "bun:test" import { describe, expect, test } from "bun:test"
import { type Session } from "@opencode-ai/sdk/v2/client"
import { collectOpenProjectDeepLinks, drainPendingDeepLinks, parseDeepLink } from "./deep-links" import { collectOpenProjectDeepLinks, drainPendingDeepLinks, parseDeepLink } from "./deep-links"
import { displayName, errorMessage, getDraggableId, syncWorkspaceOrder, workspaceKey } from "./helpers" import {
displayName,
errorMessage,
getDraggableId,
latestRootSession,
syncWorkspaceOrder,
workspaceKey,
} from "./helpers"
const session = (input: Partial<Session> & Pick<Session, "id" | "directory">) =>
({
title: "",
version: "v2",
parentID: undefined,
messageCount: 0,
permissions: { session: {}, share: {} },
time: { created: 0, updated: 0, archived: undefined },
...input,
}) as Session
describe("layout deep links", () => { describe("layout deep links", () => {
test("parses open-project deep links", () => { test("parses open-project deep links", () => {
@@ -73,6 +92,61 @@ describe("layout workspace helpers", () => {
expect(result).toEqual(["/root", "/c", "/b"]) expect(result).toEqual(["/root", "/c", "/b"])
}) })
test("finds the latest root session across workspaces", () => {
const result = latestRootSession(
[
{
path: { directory: "/root" },
session: [session({ id: "root", directory: "/root", time: { created: 1, updated: 1, archived: undefined } })],
},
{
path: { directory: "/workspace" },
session: [
session({
id: "workspace",
directory: "/workspace",
time: { created: 2, updated: 2, archived: undefined },
}),
],
},
],
120_000,
)
expect(result?.id).toBe("workspace")
})
test("ignores archived and child sessions when finding latest root session", () => {
const result = latestRootSession(
[
{
path: { directory: "/workspace" },
session: [
session({
id: "archived",
directory: "/workspace",
time: { created: 10, updated: 10, archived: 10 },
}),
session({
id: "child",
directory: "/workspace",
parentID: "parent",
time: { created: 20, updated: 20, archived: undefined },
}),
session({
id: "root",
directory: "/workspace",
time: { created: 30, updated: 30, archived: undefined },
}),
],
},
],
120_000,
)
expect(result?.id).toBe("root")
})
test("extracts draggable id safely", () => { test("extracts draggable id safely", () => {
expect(getDraggableId({ draggable: { id: "x" } })).toBe("x") expect(getDraggableId({ draggable: { id: "x" } })).toBe("x")
expect(getDraggableId({ draggable: { id: 42 } })).toBeUndefined() expect(getDraggableId({ draggable: { id: 42 } })).toBeUndefined()

View File

@@ -28,6 +28,11 @@ export const isRootVisibleSession = (session: Session, directory: string) =>
export const sortedRootSessions = (store: { session: Session[]; path: { directory: string } }, now: number) => export const sortedRootSessions = (store: { session: Session[]; path: { directory: string } }, now: number) =>
store.session.filter((session) => isRootVisibleSession(session, store.path.directory)).sort(sortSessions(now)) store.session.filter((session) => isRootVisibleSession(session, store.path.directory)).sort(sortSessions(now))
export const latestRootSession = (stores: { session: Session[]; path: { directory: string } }[], now: number) =>
stores
.flatMap((store) => store.session.filter((session) => isRootVisibleSession(session, store.path.directory)))
.sort(sortSessions(now))[0]
export const childMapByParent = (sessions: Session[]) => { export const childMapByParent = (sessions: Session[]) => {
const map = new Map<string, string[]>() const map = new Map<string, string[]>()
for (const session of sessions) { for (const session of sessions) {