test: tests that assumed an idle machine wait for what they assert, or carry a budget for their work
Under a busy machine (the gate's lanes side by side, 12 busy cores) these went red at random: a press landed while the button was still busy, an answer was settled before it was asked for, a page grew past one wait's budget, a lazy chunk was transformed inside a 1 s wait, focus was taken a frame after the press. They now wait for the condition they depend on, preload the chunks they open, and the tests that do heavy work (whole-repo scans, the type-aware linter, module resets) carry an explicit budget naming that work. The whole suite four times under 12 busy-loop processes: red 4/4 before, 0/4 after.
This commit is contained in:
@@ -47,6 +47,15 @@ afterEach(() => {
|
||||
|
||||
const bodyRows = () => host!.querySelectorAll("tbody tr").length;
|
||||
|
||||
// Waits for the page to grow to `n` rows, one background step at a time: each step must come, but on
|
||||
// a busy machine all of them together can outlast one wait's budget (seen at 190 of 200).
|
||||
async function grownTo(n: number) {
|
||||
for (let had = bodyRows(); had < n; had = bodyRows()) {
|
||||
await waitFor(() => expect(bodyRows()).toBeGreaterThan(had));
|
||||
}
|
||||
expect(bodyRows()).toBe(n);
|
||||
}
|
||||
|
||||
// Mounts synchronously, so what the DOM holds right after is the first render alone.
|
||||
function mount(rows: Row[], columns: Column<Row>[], narrowedBy = "") {
|
||||
host = document.createElement("div");
|
||||
@@ -68,7 +77,7 @@ describe("DataTable — a long page mounts in steps", () => {
|
||||
it("paints its first rows at once and the rest after", async () => {
|
||||
mount(many(200), plain);
|
||||
expect(bodyRows()).toBe(FIRST_ROWS);
|
||||
await waitFor(() => expect(bodyRows()).toBe(200));
|
||||
await grownTo(200);
|
||||
});
|
||||
|
||||
it("does not re-render the rows it already holds as it grows", async () => {
|
||||
@@ -84,21 +93,21 @@ describe("DataTable — a long page mounts in steps", () => {
|
||||
},
|
||||
];
|
||||
mount(many(200), counted);
|
||||
await waitFor(() => expect(bodyRows()).toBe(200));
|
||||
await grownTo(200);
|
||||
// The first row was drawn by the first render, not again by each step after it.
|
||||
expect(renders.get("r0")).toBe(1);
|
||||
});
|
||||
|
||||
it("starts over from the first rows when the caller narrows them, not on new data", async () => {
|
||||
const draw = mount(many(200), plain, "");
|
||||
await waitFor(() => expect(bodyRows()).toBe(200));
|
||||
await grownTo(200);
|
||||
// New data for the same view (a refetch): the page keeps what it shows.
|
||||
draw(many(200), "");
|
||||
expect(bodyRows()).toBe(200);
|
||||
// A search the caller applied: the urgent render is small again.
|
||||
draw(many(150, "s"), "s");
|
||||
expect(bodyRows()).toBe(FIRST_ROWS);
|
||||
await waitFor(() => expect(bodyRows()).toBe(150));
|
||||
await grownTo(150);
|
||||
});
|
||||
|
||||
// Channels turns the page to the row a priority pick moved and focuses it in the commit
|
||||
|
||||
Reference in New Issue
Block a user