session-tab-switch-benchmark.spec.ts 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import type { Page } from "@playwright/test"
  2. import { expectSessionTitle } from "../../utils/waits"
  3. import { benchmark, expect, withBenchmarkPage } from "../benchmark"
  4. import { fixture } from "./session-timeline-stress.fixture"
  5. import { installStressSessionTabs, mockStressTimeline, stressSessionHref } from "./timeline-test-helpers"
  6. import { measureSessionSwitch, waitForStableTimeline } from "./session-tab-switch-probe"
  7. type Result = Awaited<ReturnType<typeof measureSessionSwitch>>
  8. benchmark("benchmarks cold and hot session tab switching", async ({ browser, report }, testInfo) => {
  9. benchmark.setTimeout(180_000)
  10. const results = { cold: [] as Result[], hot: [] as Result[] }
  11. for (const mode of ["cold", "hot"] as const) {
  12. for (let run = 0; run < 5; run++) {
  13. results[mode].push(
  14. await withBenchmarkPage(browser, `session-tab-switch-${mode}-${run}`, (page) => trial(page, mode), testInfo),
  15. )
  16. }
  17. }
  18. report({ results, summary: summarize(results) })
  19. })
  20. async function trial(page: Page, mode: "cold" | "hot") {
  21. await mockStressTimeline(page)
  22. await installStressSessionTabs(page)
  23. if (mode === "hot") {
  24. await page.goto(stressSessionHref(fixture.targetID))
  25. await expectSessionTitle(page, fixture.expected.targetTitle)
  26. await waitForStableTimeline(page, fixture.expected.targetMessageIDs.at(-1)!)
  27. await switchSession(page, fixture.sourceID, fixture.expected.sourceTitle)
  28. } else {
  29. await page.goto(stressSessionHref(fixture.sourceID))
  30. await expectSessionTitle(page, fixture.expected.sourceTitle)
  31. }
  32. await waitForStableTimeline(page, fixture.expected.sourceMessageIDs.at(-1)!)
  33. const destinationIDs = fixture.messages[fixture.targetID].map((message) => message.info.id)
  34. const sourceIDs = fixture.messages[fixture.sourceID].map((message) => message.info.id)
  35. const lastID = fixture.expected.targetMessageIDs.at(-1)!
  36. const href = stressSessionHref(fixture.targetID)
  37. const result = await measureSessionSwitch(page, {
  38. destinationIDs,
  39. sourceIDs,
  40. lastID,
  41. href,
  42. switch: () => switchSession(page, fixture.targetID, fixture.expected.targetTitle),
  43. })
  44. return result
  45. }
  46. function summarize(results: Record<"cold" | "hot", Result[]>) {
  47. const stats = (values: (number | null)[]) => {
  48. const sorted = values.filter((value): value is number => value !== null).sort((a, b) => a - b)
  49. return {
  50. min: sorted[0] ?? null,
  51. median: sorted[Math.floor(sorted.length / 2)] ?? null,
  52. max: sorted.at(-1) ?? null,
  53. missing: values.length - sorted.length,
  54. }
  55. }
  56. return Object.fromEntries(
  57. Object.entries(results).map(([mode, values]) => [
  58. mode,
  59. {
  60. firstDestinationObservedMs: stats(values.map((value) => value.firstDestinationObservedMs)),
  61. firstCorrectObservedMs: stats(values.map((value) => value.firstCorrectObservedMs)),
  62. stableObservedMs: stats(values.map((value) => value.stableObservedMs)),
  63. },
  64. ]),
  65. )
  66. }
  67. async function switchSession(page: Page, sessionID: string, title: string) {
  68. const href = stressSessionHref(sessionID)
  69. const tab = page.locator(`[data-slot="titlebar-tabs"] a[href="${href}"]`).first()
  70. await expect(tab).toBeVisible()
  71. await tab.click()
  72. await expectSessionTitle(page, title)
  73. }