( label: string, frames: readonly T[], output: string, budget: InteractionBudget, readMetrics: (frame: T) => InteractionFrameMetrics, )
| 79 | } |
| 80 | |
| 81 | export function assertInteractionContract<T>( |
| 82 | label: string, |
| 83 | frames: readonly T[], |
| 84 | output: string, |
| 85 | budget: InteractionBudget, |
| 86 | readMetrics: (frame: T) => InteractionFrameMetrics, |
| 87 | ): void { |
| 88 | expect(frames.length, `${label} emitted no frames`).toBeGreaterThan(0) |
| 89 | |
| 90 | const metrics = frames.map(readMetrics) |
| 91 | |
| 92 | expect( |
| 93 | metrics.every(frame => frame.flickers === 0), |
| 94 | `${label} emitted flicker frames`, |
| 95 | ).toBe(true) |
| 96 | expect(output.includes('\u001b[2J'), `${label} emitted ED2 clear-screen`).toBe( |
| 97 | false, |
| 98 | ) |
| 99 | expect(output.includes('\u001b[3J'), `${label} emitted ED3 scrollback wipe`).toBe( |
| 100 | false, |
| 101 | ) |
| 102 | |
| 103 | if (budget.maxFrames !== undefined && frames.length > budget.maxFrames) { |
| 104 | throw new Error( |
| 105 | `${label} exceeded the frame budget: ${frames.length} > ${budget.maxFrames}`, |
| 106 | ) |
| 107 | } |
| 108 | |
| 109 | const maxBytes = Math.max(...metrics.map(frame => frame.bytes), 0) |
| 110 | if (maxBytes > budget.maxBytes) { |
| 111 | throw new Error( |
| 112 | `${label} exceeded the repaint byte budget: ${maxBytes} > ${budget.maxBytes}`, |
| 113 | ) |
| 114 | } |
| 115 | |
| 116 | if (budget.maxMeasured !== undefined) { |
| 117 | const maxMeasured = Math.max(...metrics.map(frame => frame.yogaMeasured), 0) |
| 118 | if (maxMeasured > budget.maxMeasured) { |
| 119 | throw new Error( |
| 120 | `${label} exceeded the Yoga measure budget: ${maxMeasured} > ${budget.maxMeasured}`, |
| 121 | ) |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | if (budget.maxVisited !== undefined) { |
| 126 | const maxVisited = Math.max(...metrics.map(frame => frame.yogaVisited), 0) |
| 127 | if (maxVisited > budget.maxVisited) { |
| 128 | throw new Error( |
| 129 | `${label} exceeded the Yoga visit budget: ${maxVisited} > ${budget.maxVisited}`, |
| 130 | ) |
| 131 | } |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | export function readJsonLines<T>(path: string): T[] { |
| 136 | if (!existsSync(path)) { |
no test coverage detected