mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-23 18:55:37 -04:00
9e0d3976e1
Co-authored-by: Frank <frank@anoma.ly> Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com> Co-authored-by: Brendan Allan <git@brendonovich.dev> Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: Jack <jack@anoma.ly> Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com> Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com> Co-authored-by: James Long <longster@gmail.com> Co-authored-by: Dustin Deus <deusdustin@gmail.com> Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box> Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com> Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local> Co-authored-by: Dax <mail@thdxr.com> Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com> Co-authored-by: Jay <53023+jayair@users.noreply.github.com> Co-authored-by: runvip <164729189+runvip@users.noreply.github.com> Co-authored-by: opencode <opencode@sst.dev> Co-authored-by: Julian Coy <julian@ex-machina.co> Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com> Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com> Co-authored-by: Kit Langton <kit.langton@gmail.com> Co-authored-by: Simon Klee <hello@simonklee.dk> Co-authored-by: Jay <air@live.ca> Co-authored-by: David Hill <1879069+iamdavidhill@users.noreply.github.com>
64 lines
2.5 KiB
TypeScript
64 lines
2.5 KiB
TypeScript
import { expect, type TestInfo } from "@playwright/test"
|
|
import { writeFile } from "node:fs/promises"
|
|
import { analyzeVisualObservations, analyzeVisualTraceByMarker } from "./analyzer"
|
|
import type { VisualPlan } from "./invariant"
|
|
import type { VisualProbeResult } from "./model"
|
|
|
|
export async function reportVisualStability<RegionName extends string>(
|
|
testInfo: TestInfo,
|
|
name: string,
|
|
result: VisualProbeResult<RegionName>,
|
|
plan: VisualPlan<RegionName>,
|
|
) {
|
|
const trace = { markers: result.markers, samples: result.samples }
|
|
const issues = plan.perMarker
|
|
? analyzeVisualTraceByMarker(trace, plan)
|
|
: analyzeVisualObservations(result.samples, plan)
|
|
const tracePath = testInfo.outputPath(`${name}-visual-trace.json`)
|
|
const issuesPath = testInfo.outputPath(`${name}-visual-issues.json`)
|
|
await writeFile(tracePath, JSON.stringify(trace, null, 2))
|
|
await writeFile(
|
|
issuesPath,
|
|
JSON.stringify({ issues, markers: result.markers, capturedFrameCount: result.frames.length }, null, 2),
|
|
)
|
|
await testInfo.attach(`${name}-visual-trace`, { path: tracePath, contentType: "application/json" })
|
|
await testInfo.attach(`${name}-visual-issues`, { path: issuesPath, contentType: "application/json" })
|
|
if (issues.length) await attachViolationFrames(testInfo, name, result, issues)
|
|
expect(issues, `${name}: ${issues.join("\n")}`).toEqual([])
|
|
}
|
|
|
|
async function attachViolationFrames<RegionName extends string>(
|
|
testInfo: TestInfo,
|
|
name: string,
|
|
result: VisualProbeResult<RegionName>,
|
|
issues: string[],
|
|
) {
|
|
if (result.frames.length === 0) return
|
|
const targets = [
|
|
...new Set(
|
|
issues.flatMap((issue) => {
|
|
const match = issue.match(/ at (\d+)ms/)
|
|
if (match) return [Number(match[1])]
|
|
const marker = result.markers.find((item) => issue.startsWith(`${item.label}:`))
|
|
return marker ? [marker.at] : []
|
|
}),
|
|
),
|
|
].slice(0, 6)
|
|
for (const [violation, target] of targets.entries()) {
|
|
const nearest = result.frames.reduce(
|
|
(best, frame, index) => (Math.abs(frame.at - target) < Math.abs(result.frames[best]!.at - target) ? index : best),
|
|
0,
|
|
)
|
|
for (const [label, index] of [
|
|
["before", Math.max(0, nearest - 1)],
|
|
["violation", nearest],
|
|
["after", Math.min(result.frames.length - 1, nearest + 1)],
|
|
] as const) {
|
|
await testInfo.attach(`${name}-${violation + 1}-${label}-${Math.round(result.frames[index]!.at)}ms`, {
|
|
body: Buffer.from(result.frames[index]!.data, "base64"),
|
|
contentType: "image/jpeg",
|
|
})
|
|
}
|
|
}
|
|
}
|