test(quick-260921-ldf): Test 14/15 halten jeden Commit fest statt nur den Endzustand

Der alte Test 1 fand den Fehler nur durch Zufall: er las den DOM einmal,
nachdem findByRole den Dialog gemeldet hatte, und traf damit mal den
falschen ersten, meist den richtigen zweiten Commit. Ein Fehlschlag auf
rund siebzehn volle Laeufe.

Die beiden neuen Tests beobachten stattdessen per MutationObserver JEDEN
Commit waehrend des Oeffnens und dulden keinen einzigen, in dem das
Vorschaubild sichtbar ist und das Haekchen aus. Test 14 deckt das erste
Oeffnen ab, Test 15 das erneute Oeffnen nach einem Versand mit
abgewaehltem Haekchen und getipptem Text - dort darf weder der alte
Dankestext noch der alte Text noch ein ausgeschaltetes Haekchen in
irgendeinem Commit auftauchen.

Beide sind gegen den Stand vor dem Fix in fuenf von fuenf Laeufen rot,
danach gruen. Kein retry, kein hoeheres Zeitlimit: die Ursache war nie
blosse Zeit, sondern ein falscher Zustand, den es jetzt nicht mehr gibt.
Test 1 bleibt unveraendert in der Sache und prueft weiterhin dieselbe
Zusicherung.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
2026-09-21 15:38:54 +02:00
parent de7fdb7377
commit 9f02fcc190
@@ -349,6 +349,82 @@ describe('BugReportButton (quick-260914-m97)', () => {
expect(body.get('clientVersion')).toBe('');
expect(body.get('clientCommit')).toBe('');
});
/**
* Test 14/15 (quick-260921-ldf) sind der Nachweis fuer die Ursache des
* Wackeltests aus CI-Lauf 395. Der Dialog zog seinen Anfangszustand frueher
* per `useEffect` nach; React schrieb deshalb bei JEDEM Oeffnen zuerst einen
* falschen DOM-Zustand fest und korrigierte ihn erst einen Commit spaeter.
* Gemessen hielt der falsche Zustand zwei volle Makrotask-Runden — lange
* genug, dass der Browser ihn zeichnen konnte und der Test ihn gelegentlich
* sah. Die beiden Tests beobachten jeden Commit und dulden keinen einzigen
* falschen.
*/
function protokolliereCommits(): { commits: string[]; stop: () => void } {
const commits: string[] = [];
const obs = new MutationObserver(() => {
const dialog = document.querySelector('[role="dialog"]');
if (!dialog) return;
const bild = dialog.querySelector('img');
const box = document.getElementById('bug-report-attach') as HTMLInputElement | null;
const feld = document.getElementById('bug-report-description') as HTMLTextAreaElement | null;
const danke = dialog.textContent?.includes(T.sent) ?? false;
commits.push(
`bild=${bild ? 'ja' : 'nein'} haekchen=${box ? (box.checked ? 'an' : 'aus') : '-'} ` +
`gesperrt=${box ? box.disabled : '-'} text="${feld?.value ?? ''}" danke=${danke}`,
);
});
obs.observe(document.body, { childList: true, subtree: true, attributes: true });
return { commits, stop: () => obs.disconnect() };
}
it('Test 14 (quick-260921-ldf): kein falscher Zwischenzustand — in KEINEM Commit steht das Vorschaubild mit ausgeschaltetem Haekchen', async () => {
const { commits, stop } = protokolliereCommits();
try {
const user = userEvent.setup();
await renderButton();
await openDialog(user);
} finally {
stop();
}
expect(commits.length).toBeGreaterThan(0);
const falsche = commits.filter((c) => c.includes('bild=ja') && c.includes('haekchen=aus') && c.includes('gesperrt=false'));
expect(falsche).toEqual([]);
// Und der allererste Commit mit Dialog ist schon der richtige.
expect(commits[0]).toContain('bild=ja');
expect(commits[0]).toContain('haekchen=an');
});
it('Test 15 (quick-260921-ldf): erneutes Oeffnen startet frisch — kein alter Dankestext, kein alter Text, Haekchen wieder an', async () => {
mockFetch.mockResolvedValue(jsonResponse(200, { sent: true }));
const user = userEvent.setup();
await renderButton();
// Erstes Oeffnen: Haekchen abwaehlen, Text tippen, senden, schliessen.
await openDialog(user);
await user.click(screen.getByRole('checkbox', { name: T.attachScreenshot }));
await user.type(screen.getByLabelText(T.descriptionLabel), 'alter Text');
await user.click(screen.getByRole('button', { name: T.send }));
await screen.findByText(T.sent);
await user.click(screen.getByRole('button', { name: T.close }));
await waitFor(() => expect(screen.queryByRole('dialog')).toBeNull());
// Zweites Oeffnen: jeder Commit muss frisch sein.
const { commits, stop } = protokolliereCommits();
try {
await openDialog(user);
} finally {
stop();
}
expect(commits.length).toBeGreaterThan(0);
expect(commits.filter((c) => c.includes('danke=true'))).toEqual([]);
expect(commits.filter((c) => c.includes('text="alter Text"'))).toEqual([]);
expect(commits.filter((c) => c.includes('bild=ja') && c.includes('haekchen=aus') && c.includes('gesperrt=false'))).toEqual([]);
expect(screen.getByRole('checkbox', { name: T.attachScreenshot })).toBeChecked();
expect(screen.getByLabelText(T.descriptionLabel)).toHaveValue('');
});
});
describe('computeCaptureSize (quick-260914-m97, reine Funktion)', () => {