| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- import { test } from "@playwright/test"
- import {
- defineVisualRegions,
- reportVisualStability,
- startVisualProbe,
- stopVisualProbe,
- visualPlan,
- } from "../../utils/visual-stability"
- import {
- assistantMessage,
- partUpdated,
- setupTimeline,
- textPart,
- toolPart,
- userMessage,
- waitForVisualSettle,
- } from "./fixture"
- const profiles = [
- { name: "edit", tool: "edit", input: { filePath: "src/edit.ts" } },
- {
- name: "multi patch",
- tool: "apply_patch",
- input: { files: ["src/a.ts", "src/b.ts", "src/old.ts", "src/moved.ts"] },
- },
- ] as const
- for (const profile of profiles) {
- test(`stabilizes ${profile.name} pending to completed`, async ({ page }, testInfo) => {
- const partID = `prt_file_matrix_${profiles.indexOf(profile)}`
- const followingID = `prt_file_matrix_following_${profiles.indexOf(profile)}`
- const timeline = await setupTimeline(page, {
- messages: [
- userMessage(),
- assistantMessage(
- [
- toolPart(partID, profile.tool, "pending", profile.input),
- textPart(followingID, `Following ${profile.name}`),
- ],
- { completed: false },
- ),
- ],
- settings: { editToolPartsExpanded: true },
- cpuRate: 4,
- })
- await waitForVisualSettle(page, [`[data-timeline-part-id="${partID}"]`, `[data-timeline-part-id="${followingID}"]`])
- const regions = defineVisualRegions({
- tool: { selector: `[data-timeline-part-id="${partID}"]`, closest: '[data-timeline-row="AssistantPart"]' },
- following: {
- selector: `[data-timeline-part-id="${followingID}"]`,
- closest: '[data-timeline-row="AssistantPart"]',
- },
- })
- await startVisualProbe(page, regions)
- await timeline.send(partUpdated(toolPart(partID, profile.tool, "running", profile.input)), 180)
- await timeline.send(partUpdated(completedPart(partID, profile)), 900)
- const trace = await stopVisualProbe<keyof typeof regions>(page)
- await reportVisualStability(
- testInfo,
- `file-${profile.name}`,
- trace,
- visualPlan(
- regions,
- [
- { type: "required", regions: ["tool", "following"] },
- { type: "unique", regions: ["tool", "following"] },
- { type: "stable", regions: ["tool", "following"] },
- { type: "opacity", regions: "all" },
- { type: "continuity", regions: "all" },
- { type: "motion", regions: "all", maxPositionReversals: 0, maxReversals: 1 },
- { type: "label-stability", regions: "all" },
- { type: "preserve-bottom-anchor" },
- { type: "flow", regions: ["tool", "following"] },
- ],
- { perMarker: true },
- ),
- )
- })
- }
- function completedPart(partID: string, profile: (typeof profiles)[number]) {
- if (profile.tool === "edit") {
- return toolPart(partID, profile.tool, "completed", profile.input, {
- metadata: {
- filediff: {
- file: "src/edit.ts",
- additions: 50,
- deletions: 50,
- before: source(50, false),
- after: source(50, true),
- },
- },
- })
- }
- const files = [
- patchFile("src/a.ts", "update"),
- patchFile("src/b.ts", "add"),
- patchFile("src/old.ts", "delete"),
- { ...patchFile("src/moved.ts", "move"), move: "src/new-place.ts" },
- ]
- return toolPart(partID, profile.tool, "completed", profile.input, { metadata: { files } })
- }
- function patchFile(filePath: string, type: "add" | "update" | "delete" | "move") {
- return {
- filePath,
- relativePath: filePath,
- type,
- additions: type === "delete" ? 0 : 20,
- deletions: type === "add" ? 0 : 20,
- before: type === "add" ? undefined : source(20, false),
- after: type === "delete" ? undefined : source(20, true),
- }
- }
- function source(count: number, changed: boolean) {
- return Array.from(
- { length: count },
- (_, index) => `export const value${index} = ${changed ? index + 1 : index}\n`,
- ).join("")
- }
|