chore: generate
This commit is contained in:
@@ -111,7 +111,13 @@ function reasoningPart(index: number, partIndex: number, length: number): Messag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toolPart(index: number, partIndex: number, tool: string, input: Record<string, unknown>, outputLength = 160): MessagePart {
|
function toolPart(
|
||||||
|
index: number,
|
||||||
|
partIndex: number,
|
||||||
|
tool: string,
|
||||||
|
input: Record<string, unknown>,
|
||||||
|
outputLength = 160,
|
||||||
|
): MessagePart {
|
||||||
const metadata =
|
const metadata =
|
||||||
tool === "apply_patch"
|
tool === "apply_patch"
|
||||||
? { files: [patchFile(index, "update"), patchFile(index + 1, index % 2 === 0 ? "add" : "delete")] }
|
? { files: [patchFile(index, "update"), patchFile(index + 1, index % 2 === 0 ? "add" : "delete")] }
|
||||||
@@ -168,7 +174,9 @@ function patch(seed: number, length: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function code(seed: number, lines: number) {
|
function code(seed: number, lines: number) {
|
||||||
return Array.from({ length: lines }, (_, index) => `export const value${index} = "${lorem(seed + index, 32)}"`).join("\n")
|
return Array.from({ length: lines }, (_, index) => `export const value${index} = "${lorem(seed + index, 32)}"`).join(
|
||||||
|
"\n",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function turn(index: number): Message[] {
|
function turn(index: number): Message[] {
|
||||||
@@ -189,12 +197,14 @@ function turn(index: number): Message[] {
|
|||||||
...(index % 6 === 0
|
...(index % 6 === 0
|
||||||
? [toolPart(index, 7, "write", { filePath: `src/generated/write-${index}.ts`, content: code(index, 28) }, 560)]
|
? [toolPart(index, 7, "write", { filePath: `src/generated/write-${index}.ts`, content: code(index, 28) }, 560)]
|
||||||
: []),
|
: []),
|
||||||
...(index % 8 === 0 ? [toolPart(index, 8, "apply_patch", { files: [`src/generated/patch-${index}.ts`] }, 620)] : []),
|
...(index % 8 === 0
|
||||||
...(index % 7 === 0 ? [toolPart(index, 4, "bash", { command: "bun typecheck", description: "Verify generated output" }, 620)] : []),
|
? [toolPart(index, 8, "apply_patch", { files: [`src/generated/patch-${index}.ts`] }, 620)]
|
||||||
...(index % 10 === 0 ? [toolPart(index, 9, "webfetch", { url: "https://example.com/docs/sample" }, 120)] : []),
|
|
||||||
...(index % 11 === 0
|
|
||||||
? [toolPart(index, 10, "websearch", { query: "sample movement notes" }, 240)]
|
|
||||||
: []),
|
: []),
|
||||||
|
...(index % 7 === 0
|
||||||
|
? [toolPart(index, 4, "bash", { command: "bun typecheck", description: "Verify generated output" }, 620)]
|
||||||
|
: []),
|
||||||
|
...(index % 10 === 0 ? [toolPart(index, 9, "webfetch", { url: "https://example.com/docs/sample" }, 120)] : []),
|
||||||
|
...(index % 11 === 0 ? [toolPart(index, 10, "websearch", { query: "sample movement notes" }, 240)] : []),
|
||||||
...(index % 13 === 0
|
...(index % 13 === 0
|
||||||
? [
|
? [
|
||||||
toolPart(
|
toolPart(
|
||||||
@@ -232,7 +242,14 @@ function orderedParts(message: Message) {
|
|||||||
|
|
||||||
export const fixture = {
|
export const fixture = {
|
||||||
directory,
|
directory,
|
||||||
project: { id: projectID, worktree: directory, vcs: "git", name: "smoke-project", time: { created: 1700000000000, updated: 1700000000000 }, sandboxes: [] },
|
project: {
|
||||||
|
id: projectID,
|
||||||
|
worktree: directory,
|
||||||
|
vcs: "git",
|
||||||
|
name: "smoke-project",
|
||||||
|
time: { created: 1700000000000, updated: 1700000000000 },
|
||||||
|
sandboxes: [],
|
||||||
|
},
|
||||||
provider: {
|
provider: {
|
||||||
all: [
|
all: [
|
||||||
{
|
{
|
||||||
@@ -245,8 +262,24 @@ export const fixture = {
|
|||||||
default: { providerID: "opencode", modelID: "claude-opus-4-6" },
|
default: { providerID: "opencode", modelID: "claude-opus-4-6" },
|
||||||
},
|
},
|
||||||
sessions: [
|
sessions: [
|
||||||
{ id: sourceID, slug: "source", projectID, directory, title: "Uncommitted changes inquiry", version: "dev", time: { created: 1700000000000, updated: 1700000000000 } },
|
{
|
||||||
{ id: targetID, slug: "target", projectID, directory, title: "Example Game: sample jump movement & sample physics analysis", version: "dev", time: { created: 1700000001000, updated: 1700000001000 } },
|
id: sourceID,
|
||||||
|
slug: "source",
|
||||||
|
projectID,
|
||||||
|
directory,
|
||||||
|
title: "Uncommitted changes inquiry",
|
||||||
|
version: "dev",
|
||||||
|
time: { created: 1700000000000, updated: 1700000000000 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: targetID,
|
||||||
|
slug: "target",
|
||||||
|
projectID,
|
||||||
|
directory,
|
||||||
|
title: "Example Game: sample jump movement & sample physics analysis",
|
||||||
|
version: "dev",
|
||||||
|
time: { created: 1700000001000, updated: 1700000001000 },
|
||||||
|
},
|
||||||
],
|
],
|
||||||
sourceID,
|
sourceID,
|
||||||
targetID,
|
targetID,
|
||||||
@@ -254,14 +287,25 @@ export const fixture = {
|
|||||||
expected: {
|
expected: {
|
||||||
sourceTitle: "Uncommitted changes inquiry",
|
sourceTitle: "Uncommitted changes inquiry",
|
||||||
targetTitle: "Example Game: sample jump movement & sample physics analysis",
|
targetTitle: "Example Game: sample jump movement & sample physics analysis",
|
||||||
targetMessageIDs: targetMessages.filter((message) => message.info.role === "user").map((message) => message.info.id),
|
targetMessageIDs: targetMessages
|
||||||
targetPartIDs: targetMessages.flatMap((message) => orderedParts(message).filter(renderable).map((part) => part.id)),
|
.filter((message) => message.info.role === "user")
|
||||||
|
.map((message) => message.info.id),
|
||||||
|
targetPartIDs: targetMessages.flatMap((message) =>
|
||||||
|
orderedParts(message)
|
||||||
|
.filter(renderable)
|
||||||
|
.map((part) => part.id),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pageMessages(sessionID: string, limit: number, before?: string) {
|
export function pageMessages(sessionID: string, limit: number, before?: string) {
|
||||||
const messages = fixture.messages[sessionID as keyof typeof fixture.messages] ?? []
|
const messages = fixture.messages[sessionID as keyof typeof fixture.messages] ?? []
|
||||||
const end = before ? Math.max(0, messages.findIndex((message) => message.info.id === before)) : messages.length
|
const end = before
|
||||||
|
? Math.max(
|
||||||
|
0,
|
||||||
|
messages.findIndex((message) => message.info.id === before),
|
||||||
|
)
|
||||||
|
: messages.length
|
||||||
const start = Math.max(0, end - limit)
|
const start = Math.max(0, end - limit)
|
||||||
return {
|
return {
|
||||||
items: messages.slice(start, end),
|
items: messages.slice(start, end),
|
||||||
|
|||||||
@@ -172,7 +172,12 @@ async function configureSmokePage(page: Page) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function expectCanScrollToStart(page: Page, expectedPartIDs: string[], expectedMessageIDs: string[], errors: string[]) {
|
async function expectCanScrollToStart(
|
||||||
|
page: Page,
|
||||||
|
expectedPartIDs: string[],
|
||||||
|
expectedMessageIDs: string[],
|
||||||
|
errors: string[],
|
||||||
|
) {
|
||||||
await pointAtTimeline(page)
|
await pointAtTimeline(page)
|
||||||
const seenParts = new Set<string>()
|
const seenParts = new Set<string>()
|
||||||
const seenMessages = new Set<string>()
|
const seenMessages = new Set<string>()
|
||||||
@@ -189,7 +194,11 @@ async function expectCanScrollToStart(page: Page, expectedPartIDs: string[], exp
|
|||||||
expectOrderedIDs(expectedMessageIDs, unique(current.messageIds), "mounted message")
|
expectOrderedIDs(expectedMessageIDs, unique(current.messageIds), "mounted message")
|
||||||
expectOrderedIDs(expectedMessageIDs, unique(current.visibleMessageIds), "visible message")
|
expectOrderedIDs(expectedMessageIDs, unique(current.visibleMessageIds), "visible message")
|
||||||
|
|
||||||
if (current.scrollTop <= 1 && seenParts.size === expectedPartIDs.length && seenMessages.size === expectedMessageIDs.length) {
|
if (
|
||||||
|
current.scrollTop <= 1 &&
|
||||||
|
seenParts.size === expectedPartIDs.length &&
|
||||||
|
seenMessages.size === expectedMessageIDs.length
|
||||||
|
) {
|
||||||
expectCompleteScroll(current, expectedPartIDs, expectedMessageIDs, seenParts, seenMessages, samples)
|
expectCompleteScroll(current, expectedPartIDs, expectedMessageIDs, seenParts, seenMessages, samples)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -345,7 +354,12 @@ async function waitForTimelineStable(page: Page) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function expectSessionTimelineReady(page: Page, expectedPartIDs: string[], expectedMessageIDs: string[], errors: string[]) {
|
async function expectSessionTimelineReady(
|
||||||
|
page: Page,
|
||||||
|
expectedPartIDs: string[],
|
||||||
|
expectedMessageIDs: string[],
|
||||||
|
errors: string[],
|
||||||
|
) {
|
||||||
await waitForTimelineStable(page)
|
await waitForTimelineStable(page)
|
||||||
for (const text of forbiddenText) await expect(page.getByText(text)).toHaveCount(0)
|
for (const text of forbiddenText) await expect(page.getByText(text)).toHaveCount(0)
|
||||||
const currentState = await timelineState(page)
|
const currentState = await timelineState(page)
|
||||||
@@ -365,8 +379,14 @@ function expectCompleteScroll(
|
|||||||
samples: TraversalSample[],
|
samples: TraversalSample[],
|
||||||
) {
|
) {
|
||||||
expect(state.scrollTop, `timeline should reach the start\n${sampleSummary(samples)}`).toBeLessThanOrEqual(1)
|
expect(state.scrollTop, `timeline should reach the start\n${sampleSummary(samples)}`).toBeLessThanOrEqual(1)
|
||||||
expect(expectedPartIDs.filter((id) => !seenParts.has(id)), `missing visible timeline parts\n${sampleSummary(samples)}`).toEqual([])
|
expect(
|
||||||
expect(expectedMessageIDs.filter((id) => !seenMessages.has(id)), `missing visible messages\n${sampleSummary(samples)}`).toEqual([])
|
expectedPartIDs.filter((id) => !seenParts.has(id)),
|
||||||
|
`missing visible timeline parts\n${sampleSummary(samples)}`,
|
||||||
|
).toEqual([])
|
||||||
|
expect(
|
||||||
|
expectedMessageIDs.filter((id) => !seenMessages.has(id)),
|
||||||
|
`missing visible messages\n${sampleSummary(samples)}`,
|
||||||
|
).toEqual([])
|
||||||
expect(new Set(expectedPartIDs).size).toBe(expectedPartIDs.length)
|
expect(new Set(expectedPartIDs).size).toBe(expectedPartIDs.length)
|
||||||
expect(new Set(expectedMessageIDs).size).toBe(expectedMessageIDs.length)
|
expect(new Set(expectedMessageIDs).size).toBe(expectedMessageIDs.length)
|
||||||
expect(expectedPartIDs.length).toBe(331)
|
expect(expectedPartIDs.length).toBe(331)
|
||||||
@@ -379,7 +399,10 @@ async function openProject(page: Page, projectName: string) {
|
|||||||
|
|
||||||
async function navigateToSession(page: Page, sessionId: string, expectedTitle: string) {
|
async function navigateToSession(page: Page, sessionId: string, expectedTitle: string) {
|
||||||
// Use evaluate to click to avoid strict visibility/animation issues during rapid e2e navigation
|
// Use evaluate to click to avoid strict visibility/animation issues during rapid e2e navigation
|
||||||
await page.locator(`a[href*="${sessionId}"]`).first().evaluate((el) => (el as HTMLElement).click())
|
await page
|
||||||
|
.locator(`a[href*="${sessionId}"]`)
|
||||||
|
.first()
|
||||||
|
.evaluate((el) => (el as HTMLElement).click())
|
||||||
await expect(page.getByRole("heading", { name: expectedTitle })).toBeVisible()
|
await expect(page.getByRole("heading", { name: expectedTitle })).toBeVisible()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
import type { Page, Route } from "@playwright/test"
|
import type { Page, Route } from "@playwright/test"
|
||||||
|
|
||||||
const emptyList = new Set(["/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/status", "/vcs/diff"])
|
const emptyList = new Set([
|
||||||
|
"/skill",
|
||||||
|
"/command",
|
||||||
|
"/lsp",
|
||||||
|
"/formatter",
|
||||||
|
"/permission",
|
||||||
|
"/question",
|
||||||
|
"/vcs/status",
|
||||||
|
"/vcs/diff",
|
||||||
|
])
|
||||||
const emptyObject = new Set(["/global/config", "/config", "/provider/auth", "/mcp", "/session/status"])
|
const emptyObject = new Set(["/global/config", "/config", "/provider/auth", "/mcp", "/session/status"])
|
||||||
|
|
||||||
export interface MockServerConfig {
|
export interface MockServerConfig {
|
||||||
|
|||||||
Reference in New Issue
Block a user