Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions apps/bench/src/__tests__/bench-app.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,89 @@ describe("BenchApp", () => {
expect(interactionSpy.mock.calls[0]?.[3]).toMatchObject({
rowGroups: ["col_5"],
});
expect(window[BENCH_RESULT_KEY]).not.toHaveProperty("rowModel");
}, 20_000);

test("publishes diagnostic query attribution only for an opted-in group run", async () => {
const rowModel = {
diagnostics: true as const,
updatePlanChecksum: "plan",
acceptedPatchCount: 0,
checksumAcceptedPatchCount: 0,
finalChecksum: "final",
expectedFinalChecksum: "final",
rebuild: null,
queryTransition: {
status: "completed" as const,
durationMs: 40,
rowsEvaluated: 120,
transitionRows: 60,
sliceCount: 8,
sliceTotalMs: 12,
sliceP95Ms: 2,
sliceMaxMs: 3,
schedulerWaitCount: 7,
schedulerWaitTotalMs: 20,
schedulerWaitP95Ms: 4,
schedulerWaitMaxMs: 5,
residualMs: 8,
preModelHandoffMs: 4,
postModelSurfaceMs: 20,
},
};
const interactionSpy = vi
.spyOn(benchRuntime, "measureBenchInteractionRun")
.mockResolvedValueOnce({
status: "completed",
notes: ["interaction mode: group"],
metrics: {
interaction_latency_ms: 21,
settle_duration_ms: 43,
post_interaction_blank_gap_frames: 0,
post_interaction_anchor_shift_px: 0,
post_interaction_row_height_error_p95_px: 0,
post_interaction_row_height_error_measurable_rows: 11,
result_row_count: 124,
selected_row_preserved: 1,
focused_row_preserved: 1,
dom_nodes_peak: 400,
rendered_rows_peak: 11,
rendered_cells_peak: 440,
},
rowModel,
});

render(
<BenchApp
search="?adapter=pretable&scenario=S2&scale=smoke&script=group&diagnostics=row-model&transitionBudgetMs=1&autorun=1"
browserVersion="123.0"
/>,
);

await waitFor(
() => {
expect(window[BENCH_RESULT_KEY]).toMatchObject({
status: "completed",
scriptName: "group",
rowModel: {
diagnostics: true,
queryTransition: {
status: "completed",
schedulerWaitCount: 7,
},
},
});
},
{ timeout: 15_000 },
);

expect(interactionSpy.mock.calls[0]?.[6]).toBeTruthy();
expect(interactionSpy.mock.calls[0]?.[6]?.transitionBudgetMs).toBe(1);
expect(window[BENCH_RESULT_KEY]?.notes).toContain(
"requested row model transition budget ms: 1",
);
}, 20_000);

test("paints and selects the resident window BEFORE the replace window opens", async () => {
// Everything the app owes the measurement is owed by the time it is invoked, so
// all of it is read at call time: the adapter must be holding the 200-row resident
Expand Down
232 changes: 232 additions & 0 deletions apps/bench/src/__tests__/bench-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,74 @@ import {
} from "../bench-runtime";
import { benchUpdatesExcludedColumnIds } from "../interaction-plan";
import type { BenchQueryState } from "../bench-types";
import type {
RowModelDiagnosticsController,
RowModelQueryTransitionRead,
} from "../row-model-diagnostics";

function createInteractionDiagnosticsStub(
read: RowModelQueryTransitionRead | null,
) {
const events: string[] = [];
let armed = false;
let disarmCount = 0;
const controller = {
armNextQueryTransition() {
events.push("arm");
armed = true;
},
disarmQueryTransition() {
events.push("disarm");
armed = false;
disarmCount += 1;
},
readQueryTransition() {
events.push("read");
return read;
},
createRunSummary() {
events.push("summary");
return {
diagnostics: true as const,
updatePlanChecksum: "plan",
acceptedPatchCount: 0,
checksumAcceptedPatchCount: 0,
finalChecksum: "final",
expectedFinalChecksum: "final",
rebuild: null,
queryTransition:
read === null
? null
: {
status: read.status,
durationMs: read.durationMs,
rowsEvaluated: read.rowsEvaluated,
transitionRows: read.transitionRows,
sliceCount: read.sliceCount,
sliceTotalMs: read.sliceTotalMs,
sliceP95Ms: read.sliceP95Ms,
sliceMaxMs: read.sliceMaxMs,
schedulerWaitCount: read.schedulerWaitCount,
schedulerWaitTotalMs: read.schedulerWaitTotalMs,
schedulerWaitP95Ms: read.schedulerWaitP95Ms,
schedulerWaitMaxMs: read.schedulerWaitMaxMs,
residualMs: read.residualMs,
},
};
},
} as unknown as RowModelDiagnosticsController;

return {
controller,
events,
get armed() {
return armed;
},
get disarmCount() {
return disarmCount;
},
};
}

describe("bench runtime", () => {
test("waits for a stable rendered-row baseline instead of sampling zero", async () => {
Expand Down Expand Up @@ -566,6 +634,170 @@ describe("bench runtime", () => {
}
});

test("partitions a captured query transition inside the discrete interaction", async () => {
const { layoutRow, root, viewport } = createDataUpdateHarness();
const rows = [
...viewport.querySelectorAll<HTMLElement>("[data-pretable-row]"),
];
const pending = {
frames: 0,
apply: () => {
for (const [index, row] of rows.entries()) {
layoutRow(row, index - 1);
}
},
};
const restore = installFrameStub(pending);
const diagnostics = createInteractionDiagnosticsStub(
Object.freeze({
status: "completed",
startedAt: 20,
completedAt: 60,
durationMs: 40,
rowsEvaluated: 120,
transitionRows: 60,
sliceCount: 8,
sliceTotalMs: 12,
sliceP95Ms: 2,
sliceMaxMs: 3,
schedulerWaitCount: 7,
schedulerWaitTotalMs: 20,
schedulerWaitP95Ms: 4,
schedulerWaitMaxMs: 5,
residualMs: 8,
}),
);

try {
const result = await measureBenchInteractionRun(
root,
"pretable",
"group",
{
focusedRowId: null,
resultRowCount: 3,
selectedRowId: null,
},
() => ({
focusedRowId: null,
resultRowCount: 3,
selectedRowId: null,
}),
() => {
expect(diagnostics.armed).toBe(true);
diagnostics.events.push("trigger");
pending.frames = 2;
},
diagnostics.controller,
);

expect(result.status).toBe("completed");
expect(result.rowModel?.queryTransition).toMatchObject({
status: "completed",
durationMs: 40,
preModelHandoffMs: 4,
postModelSurfaceMs: 20,
});
expect(
result.rowModel!.queryTransition!.preModelHandoffMs! +
result.rowModel!.queryTransition!.durationMs +
result.rowModel!.queryTransition!.postModelSurfaceMs!,
).toBeCloseTo(
result.metrics.interaction_latency_ms! +
result.metrics.settle_duration_ms!,
5,
);
expect(diagnostics.events.indexOf("arm")).toBeLessThan(
diagnostics.events.indexOf("trigger"),
);
expect(diagnostics.disarmCount).toBe(1);
expect(diagnostics.events.at(-1)).toBe("disarm");
} finally {
restore();
}
});

test("makes a diagnostic interaction partial when no query transition is captured", async () => {
const { layoutRow, root, viewport } = createDataUpdateHarness();
const rows = [
...viewport.querySelectorAll<HTMLElement>("[data-pretable-row]"),
];
const pending = {
frames: 0,
apply: () => {
for (const [index, row] of rows.entries()) {
layoutRow(row, index - 1);
}
},
};
const restore = installFrameStub(pending);
const diagnostics = createInteractionDiagnosticsStub(null);

try {
const result = await measureBenchInteractionRun(
root,
"pretable",
"group",
{
focusedRowId: null,
resultRowCount: 3,
selectedRowId: null,
},
() => ({
focusedRowId: null,
resultRowCount: 3,
selectedRowId: null,
}),
() => {
pending.frames = 2;
},
diagnostics.controller,
);

expect(result.status).toBe("partial");
expect(result.notes).toContain(
"row-model diagnostics captured no query transition for the interaction",
);
expect(result.rowModel).toBeUndefined();
expect(diagnostics.disarmCount).toBe(1);
} finally {
restore();
}
});

test("disarms query diagnostics when the interaction trigger throws", async () => {
const { root } = createDataUpdateHarness();
const restore = installFrameStub({ frames: 0, apply: () => undefined });
const diagnostics = createInteractionDiagnosticsStub(null);

try {
await expect(
measureBenchInteractionRun(
root,
"pretable",
"group",
{
focusedRowId: null,
resultRowCount: 3,
selectedRowId: null,
},
() => ({
focusedRowId: null,
resultRowCount: 3,
selectedRowId: null,
}),
() => {
throw new Error("trigger failed");
},
diagnostics.controller,
),
).rejects.toThrow("trigger failed");
expect(diagnostics.disarmCount).toBe(1);
} finally {
restore();
}
});

test("refuses to complete an interaction whose row count never reached the plan", async () => {
const { layoutRow, root, viewport } = createDataUpdateHarness();
const rows = [
Expand Down
3 changes: 3 additions & 0 deletions apps/bench/src/__tests__/pretable-adapter.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ describe("PretableAdapter", () => {
<PretableAdapter
dataset={dataset}
diagnostics
transitionBudgetMs={1}
runKey={1}
scriptName="updates-grouped"
seed={91_337}
Expand All @@ -202,6 +203,7 @@ describe("PretableAdapter", () => {
expect(window.__PRETABLE_ROW_MODEL_BENCH__?.read().diagnosticsEnabled).toBe(
true,
);
expect(window.__PRETABLE_ROW_MODEL_BENCH__?.transitionBudgetMs).toBe(1);

unmount();
expect(window.__PRETABLE_ROW_MODEL_BENCH__).toBeUndefined();
Expand All @@ -210,6 +212,7 @@ describe("PretableAdapter", () => {
<PretableAdapter
dataset={dataset}
diagnostics={false}
transitionBudgetMs={-1}
runKey={2}
seed={91_337}
/>,
Expand Down
14 changes: 14 additions & 0 deletions apps/bench/src/__tests__/query-state.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@ import { describe, expect, test } from "vitest";
import { parseBenchQuery } from "../query-state";

describe("parseBenchQuery", () => {
test("accepts only positive finite transition budgets", () => {
expect(
parseBenchQuery(
"?adapter=pretable&diagnostics=row-model&transitionBudgetMs=1",
).transitionBudgetMs,
).toBe(1);
for (const raw of ["0", "-1", "Infinity", "NaN"]) {
expect(
parseBenchQuery(`?transitionBudgetMs=${raw}`).transitionBudgetMs,
).toBeUndefined();
}
expect(parseBenchQuery("").transitionBudgetMs).toBeUndefined();
});

test("uses deterministic P0a defaults", () => {
expect(parseBenchQuery("")).toEqual({
adapterId: "pretable",
Expand Down
Loading