Files
opencode/packages/app/perf/composer.bench.ts

103 lines
3.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// The composer with a lot in it: a 44,000-character saved draft, and a long prompt history with screenshots. At
// 1440×900.
import { bench, web } from "@hona/strobe"
import { fixture, mockStressTimeline } from "../e2e/utils/session-fixture"
import { countDraftEncodes, draftEnd, mockLargeDraft, recalled, seedHistory } from "./fixtures/composer"
import { installProjects } from "./fixtures/home"
import { cached } from "./fixtures/mock"
const composer = '[data-component="composer-editor"]'
const newSession = '[data-component="new-session"] [data-component="composer-editor"][contenteditable="true"]'
const typed = " Keep the existing error handling and add coverage."
export default bench({
targets: {
web: web({
expect: { title: "OpenCode" },
viewport: { width: 1440, height: 900 },
async prepare({ case: name, playwright, mock, url }) {
const server = new URL(url).origin
const page = cached(playwright.page, mock)
if (!name.includes("history")) {
await countDraftEncodes(page)
return mockLargeDraft(page, server)
}
await seedHistory(page, server)
await mockStressTimeline(page, { server })
await installProjects(page, [fixture.directory])
return { path: "/" }
},
url: ({ prepared }) => prepared.path,
}),
},
async setup({ case: name, page }) {
if (name.includes("history")) {
await page.waitFor('[data-action="home-new-session"]', { timeout: 60_000 })
await page.idle()
return
}
// The caret at the end of the large draft.
await page.waitFor(composer, { text: draftEnd, timeout: 60_000 })
await page.click(composer)
await page.press("ControlOrMeta+End")
await page.idle()
},
cases: {
// Each keystroke changes the draft and saves it; `count.draft.encode` is how many times the draft was encoded.
"type in a large draft": {
primary: "main.work",
metrics: ["interaction.p95", "count.draft.encode"],
async run({ page }) {
await page.type(composer, typed, { delay: 50 })
await page.idle()
},
async reset({ page }) {
for (let step = 0; step < typed.length; step++) await page.press("Backspace")
await page.idle()
},
},
// Twenty caret moves: each saves the caret position, not the text.
"move the cursor in a large draft": {
primary: "main.work",
metrics: ["interaction.p95", "count.draft.encode"],
async run({ page }) {
for (let step = 0; step < 20; step++) await page.press("ArrowLeft", { until: "frame" })
await page.idle()
},
async reset({ page }) {
await page.press("ControlOrMeta+End")
await page.idle()
},
},
// A new session's composer loads the history (counted: the run waits until the page settles), then ArrowUp
// recalls the newest prompt and its screenshot.
"recall a prompt from history": {
primary: "main.work",
metrics: ["run.duration"],
async run({ page }) {
await page.click('[data-action="home-new-session"]', { until: newSession })
await page.idle()
await page.press("ArrowUp")
await page.waitFor(newSession, { text: recalled })
await page.idle()
},
async reset({ page }) {
await page.goto("/", { until: '[data-action="home-new-session"]', timeout: 60_000 })
await page.idle()
},
},
},
})