From 9f02fcc1909edb62b31d3ba606639d58f49c3135 Mon Sep 17 00:00:00 2001 From: Schalli Date: Mon, 21 Sep 2026 15:38:54 +0200 Subject: [PATCH] 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) Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J --- .../bug-report/bug-report-button.test.tsx | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/apps/web/src/components/bug-report/bug-report-button.test.tsx b/apps/web/src/components/bug-report/bug-report-button.test.tsx index f7282e6..09c6294 100644 --- a/apps/web/src/components/bug-report/bug-report-button.test.tsx +++ b/apps/web/src/components/bug-report/bug-report-button.test.tsx @@ -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)', () => {