Stop the print preview measuring itself into a freeze
Opening the org chart PDF preview locked up the browser tab. The measurement that fits each sheet to the page fed itself: the effect listed onFaktor in its dependencies, and onFaktor was an arrow function created fresh on every render, so the effect re-ran after every render. It measured, reported the scale, and the report called setState with a newly built object every time — new object, so React saw a change, re-rendered, and the effect ran again. Measure, render, measure, until React gave up with "Maximum update depth exceeded". Two changes, and the mutation test says either one closes the loop on its own: the callback now lives in a ref so the effect depends only on the sheet identity, and the reducer returns the previous state unchanged when the scale has not moved. Both are worth keeping — the ref stops the effect from re-running, the guard stops pointless renders. This shipped broken, and the reason it shipped is in the test file now. Every element in jsdom is zero pixels, so the measurement bailed out on its first line and the feedback never started; nine tests covering the selection, the page count and the hierarchy all passed against a component that froze on contact with a real browser. The new test gives the elements a size, and fails with the exact error a user hits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { render, screen, within } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
||||
import { PrintChart } from "@/components/orgchart/PrintChart";
|
||||
import type { OrgEmployee, OrgUnitNode, OrgVacancy } from "@/components/orgchart/types";
|
||||
import { buildPrintModel } from "@/lib/orgchart-print";
|
||||
@@ -67,6 +67,42 @@ async function zurVorschau(user: ReturnType<typeof userEvent.setup>) {
|
||||
await user.click(screen.getByRole("button", { name: /Vorschau/ }));
|
||||
}
|
||||
|
||||
// Die Vorschau misst sich selbst, um den Massstab zu bestimmen. Das ist eine
|
||||
// Rückkopplung: messen → Zustand ändern → neu rendern → messen. Bricht sie
|
||||
// nicht ab, friert der Browser-Tab ein, sobald jemand die Vorschau öffnet.
|
||||
//
|
||||
// In jsdom hat jedes Element die Grösse 0, deshalb steigt die Messung dort
|
||||
// sonst sofort aus und die Schleife entsteht gar nicht erst — genau deshalb
|
||||
// ist der Fehler durch alle bisherigen Tests gekommen. Hier bekommen die
|
||||
// Elemente Masse, damit die Rückkopplung wirklich läuft.
|
||||
describe("PrintChart — Messung", () => {
|
||||
const masse = { clientWidth: 900, clientHeight: 600 };
|
||||
const gesichert: Record<string, PropertyDescriptor | undefined> = {};
|
||||
|
||||
beforeAll(() => {
|
||||
for (const [name, wert] of Object.entries(masse)) {
|
||||
gesichert[name] = Object.getOwnPropertyDescriptor(HTMLElement.prototype, name);
|
||||
Object.defineProperty(HTMLElement.prototype, name, { configurable: true, value: wert });
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
for (const name of Object.keys(masse)) {
|
||||
if (gesichert[name]) Object.defineProperty(HTMLElement.prototype, name, gesichert[name]!);
|
||||
else delete (HTMLElement.prototype as unknown as Record<string, unknown>)[name];
|
||||
}
|
||||
});
|
||||
|
||||
it("kommt zur Ruhe, statt sich selbst immer weiter neu zu vermessen", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderChart();
|
||||
// Ein Durchlauf, der nicht abbricht, endet in React mit „Maximum update
|
||||
// depth exceeded" — der Klick wirft dann.
|
||||
await user.click(screen.getByRole("button", { name: /Vorschau/ }));
|
||||
expect(blaetter()).toHaveLength(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe("PrintChart", () => {
|
||||
it("fragt zuerst, was gedruckt wird, und zeigt vorher kein Blatt", () => {
|
||||
renderChart();
|
||||
|
||||
Reference in New Issue
Block a user