session-tab-switch-metrics.test.ts 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import { expect, test } from "bun:test"
  2. import { classifySessionSwitch } from "../timeline/session-tab-switch-metrics"
  3. test("counts source and blank samples before the destination is observed", () => {
  4. const result = classifySessionSwitch([
  5. { observedAtMs: 16, destination: [], source: ["source"], hasVisibleRows: true, last: false },
  6. { observedAtMs: 32, destination: [], source: [], hasVisibleRows: false, last: false },
  7. { observedAtMs: 48, destination: ["destination"], source: [], hasVisibleRows: true, last: true, bottomErrorPx: 0 },
  8. { observedAtMs: 64, destination: ["destination"], source: [], hasVisibleRows: true, last: true, bottomErrorPx: 0 },
  9. { observedAtMs: 80, destination: ["destination"], source: [], hasVisibleRows: true, last: true, bottomErrorPx: 0 },
  10. ])
  11. expect(result.blankSamples).toBe(1)
  12. expect(result.sourceSamples).toBe(1)
  13. expect(result.unknownSamples).toBe(0)
  14. expect(result.firstDestinationObservedMs).toBe(48)
  15. expect(result.stableObservedMs).toBe(80)
  16. })
  17. test("does not classify mixed source and destination content as correct", () => {
  18. const result = classifySessionSwitch([
  19. {
  20. observedAtMs: 16,
  21. destination: ["destination"],
  22. source: ["source"],
  23. hasVisibleRows: true,
  24. last: true,
  25. bottomErrorPx: 0,
  26. },
  27. { observedAtMs: 32, destination: ["destination"], source: [], hasVisibleRows: true, last: true, bottomErrorPx: 0 },
  28. { observedAtMs: 48, destination: ["destination"], source: [], hasVisibleRows: true, last: true, bottomErrorPx: 0 },
  29. { observedAtMs: 64, destination: ["destination"], source: [], hasVisibleRows: true, last: true, bottomErrorPx: 0 },
  30. ])
  31. expect(result.firstCorrectObservedMs).toBe(32)
  32. expect(result.stableObservedMs).toBe(64)
  33. })
  34. test("reports missing correctness without throwing", () => {
  35. const result = classifySessionSwitch([
  36. {
  37. observedAtMs: 16,
  38. destination: ["destination"],
  39. source: ["source"],
  40. hasVisibleRows: true,
  41. last: true,
  42. bottomErrorPx: 0,
  43. },
  44. ])
  45. expect(result.firstDestinationObservedMs).toBe(16)
  46. expect(result.firstCorrectObservedMs).toBeNull()
  47. expect(result.stableObservedMs).toBeNull()
  48. })
  49. test("requires an explicitly tracked part to be visible", () => {
  50. const result = classifySessionSwitch([
  51. {
  52. observedAtMs: 16,
  53. destination: ["destination"],
  54. source: [],
  55. hasVisibleRows: true,
  56. last: true,
  57. requiredPartVisible: false,
  58. bottomErrorPx: 0,
  59. },
  60. ])
  61. expect(result.firstCorrectObservedMs).toBeNull()
  62. })
  63. test("can measure content correctness without requiring a bottom anchor", () => {
  64. const result = classifySessionSwitch([
  65. {
  66. observedAtMs: 16,
  67. destination: ["destination"],
  68. source: [],
  69. hasVisibleRows: true,
  70. last: true,
  71. requiredPartVisible: true,
  72. bottomAnchorRequired: false,
  73. },
  74. ])
  75. expect(result.firstCorrectObservedMs).toBe(16)
  76. })