feat(quick-260921-iwr): Rundenliste der Stoppuhr per Test belegt, MergeTab-Entfernen abgesichert

- Wirkungslose eslint-disable-Zeile in stopwatch-widget.tsx ersetzt durch
  Sachhinweis: Zeilen halten keinen Zustand, Rundennummer wird aus Laenge
  und Position berechnet. Keine neue Unterdrueckung, ARRAYKEY bleibt bei 19.
- Neuer Testfall in stopwatch-widget.test.tsx: zwei Runden nacheinander,
  neuere Runde steht oben, Rundennummern 2/1 stimmen zu ihrer eigenen Zeit.
- Neue MergeTab.test.tsx: Entfernen der mittleren Datei laesst genau erste
  und dritte Datei mit eigenem Namen und eigenem Entfernen-Knopf uebrig.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
2026-09-21 13:55:42 +02:00
parent cfba3c9532
commit 8716fa5234
4 changed files with 527 additions and 1 deletions
@@ -0,0 +1,74 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { afterEach, describe, expect, it, vi } from 'vitest';
// Mock next-intl — passthrough t(key) => key (same pattern as stopwatch-widget.test.tsx)
vi.mock('next-intl', () => ({
useTranslations: () => (key: string) => key,
}));
// Mock ../actions — MergeTab only needs mergeCertsAction and downloadBase64 to exist;
// this test never triggers the merge action itself, only file-list management.
vi.mock('../actions', () => ({
mergeCertsAction: vi.fn(),
downloadBase64: vi.fn(),
}));
import { MergeTab } from './MergeTab';
afterEach(() => {
vi.restoreAllMocks();
});
describe('MergeTab — Dateiliste', () => {
it('quick-260921-iwr: Entfernen der mittleren Datei laesst genau die erste und dritte Datei uebrig, in dieser Reihenfolge, mit ihren eigenen Namen (belegt den Positionsschluessel bei einer schrumpfenden Liste)', async () => {
render(<MergeTab password="" />);
const fileInput = screen.getByTestId('merge-file-input');
const file1 = new File(['cert1'], 'erste.pem', { type: 'application/x-pem-file' });
const file2 = new File(['cert2'], 'mittlere.pem', { type: 'application/x-pem-file' });
const file3 = new File(['cert3'], 'dritte.pem', { type: 'application/x-pem-file' });
fireEvent.change(fileInput, { target: { files: [file1, file2, file3] } });
// Alle drei Dateien sind zunaechst gelistet
expect(screen.getByText('erste.pem')).toBeInTheDocument();
expect(screen.getByText('mittlere.pem')).toBeInTheDocument();
expect(screen.getByText('dritte.pem')).toBeInTheDocument();
// Die mittlere Datei ueber ihren Entfernen-Knopf loeschen (aria-label enthaelt den Dateinamen)
const removeMiddleBtn = screen.getByLabelText('Remove mittlere.pem');
fireEvent.click(removeMiddleBtn);
// "mittlere.pem" ist verschwunden
expect(screen.queryByText('mittlere.pem')).not.toBeInTheDocument();
// Die erste und dritte Datei stehen weiterhin mit ihren eigenen Namen in der Liste,
// in dieser Reihenfolge — kein Verwechseln durch den Positionsschluessel.
const remainingNames = screen
.getAllByText(/\.pem$/)
.map((el) => el.textContent);
expect(remainingNames).toEqual(['erste.pem', 'dritte.pem']);
// Die dritte Datei behaelt ihren eigenen Entfernen-Knopf (eigener Name im aria-label,
// nicht der der geloeschten mittleren Datei).
expect(screen.getByLabelText('Remove erste.pem')).toBeInTheDocument();
expect(screen.getByLabelText('Remove dritte.pem')).toBeInTheDocument();
expect(screen.queryByLabelText('Remove mittlere.pem')).not.toBeInTheDocument();
});
it('quick-260921-iwr: Entfernen der ersten Datei laesst die zweite an ihrer eigenen Stelle mit eigenem Namen zurueck', async () => {
render(<MergeTab password="" />);
const fileInput = screen.getByTestId('merge-file-input');
const file1 = new File(['cert1'], 'a.pem', { type: 'application/x-pem-file' });
const file2 = new File(['cert2'], 'b.pem', { type: 'application/x-pem-file' });
fireEvent.change(fileInput, { target: { files: [file1, file2] } });
fireEvent.click(screen.getByLabelText('Remove a.pem'));
expect(screen.queryByText('a.pem')).not.toBeInTheDocument();
expect(screen.getByText('b.pem')).toBeInTheDocument();
expect(screen.getByLabelText('Remove b.pem')).toBeInTheDocument();
});
});