f7b5df4db8
calculator-widget.tsx Speicherzeile und favorites-widget.tsx
Ansichtsumschalter waren schlichte <div> mit aria-label, das die Rolle
generic stillschweigend verwarf. role="toolbar" ergaenzt (geprueft
sauber; role="group"/"region" loesen useSemanticElements neu aus).
Taschenrechner: fest verdrahteter Text wandert in
calculator.memoryLabel; bei dieser Gelegenheit auch Anzeigefeld
(displayLabel) und Rueckschritt-Taste (backspaceLabel) in den Katalog
gezogen (D-05), da diese Datei ohnehin geaendert wird.
Favoriten: die bisherige Beschriftung ("Favoriten") war sachlich
falsch fuer einen Listen/Kachel-Umschalter — neuer, zutreffender
Schluessel favorites.viewModeLabel statt des wiederverwendeten
favorites.name.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
106 lines
4.0 KiB
TypeScript
106 lines
4.0 KiB
TypeScript
import { render, screen, fireEvent } from '@testing-library/react';
|
||
import { describe, expect, it, vi } from 'vitest';
|
||
|
||
// Mock next-intl — returns the real de.json strings for the few keys this
|
||
// widget actually renders as accessible names/labels, the raw key otherwise
|
||
// (locale-agnostic fallback for anything not explicitly mapped here).
|
||
vi.mock('next-intl', () => ({
|
||
useTranslations: () => (key: string) => {
|
||
const map: Record<string, string> = {
|
||
'calculator.name': 'Taschenrechner',
|
||
'calculator.displayLabel': 'Anzeige',
|
||
'calculator.memoryLabel': 'Speicherfunktionen',
|
||
'calculator.backspaceLabel': 'Rückschritt',
|
||
};
|
||
return map[key] ?? key;
|
||
},
|
||
}));
|
||
|
||
// Must import after mocks
|
||
import { CalculatorWidget } from './calculator-widget';
|
||
|
||
const defaultProps = {
|
||
instanceId: 'calc-1',
|
||
config: {},
|
||
isEditMode: false,
|
||
};
|
||
|
||
describe('CalculatorWidget', () => {
|
||
it('renders with initial display "0"', () => {
|
||
render(<CalculatorWidget {...defaultProps} />);
|
||
const display = screen.getByLabelText('Anzeige');
|
||
expect(display).toHaveTextContent('0');
|
||
});
|
||
|
||
it('calculates 7 + 3 = 10', () => {
|
||
render(<CalculatorWidget {...defaultProps} />);
|
||
|
||
fireEvent.click(screen.getByRole('button', { name: '7' }));
|
||
fireEvent.click(screen.getByRole('button', { name: '+' }));
|
||
fireEvent.click(screen.getByRole('button', { name: '3' }));
|
||
fireEvent.click(screen.getByRole('button', { name: /gleich/i }));
|
||
|
||
expect(screen.getByLabelText('Anzeige')).toHaveTextContent('10');
|
||
});
|
||
|
||
it('calculates 8 × 2 = 16', () => {
|
||
render(<CalculatorWidget {...defaultProps} />);
|
||
|
||
fireEvent.click(screen.getByRole('button', { name: '8' }));
|
||
fireEvent.click(screen.getByRole('button', { name: '×' }));
|
||
fireEvent.click(screen.getByRole('button', { name: '2' }));
|
||
fireEvent.click(screen.getByRole('button', { name: /gleich/i }));
|
||
|
||
expect(screen.getByLabelText('Anzeige')).toHaveTextContent('16');
|
||
});
|
||
|
||
it('shows "Fehler" on division by zero', () => {
|
||
render(<CalculatorWidget {...defaultProps} />);
|
||
|
||
fireEvent.click(screen.getByRole('button', { name: '5' }));
|
||
fireEvent.click(screen.getByRole('button', { name: '÷' }));
|
||
fireEvent.click(screen.getByRole('button', { name: '0' }));
|
||
fireEvent.click(screen.getByRole('button', { name: /gleich/i }));
|
||
|
||
expect(screen.getByLabelText('Anzeige')).toHaveTextContent('Fehler');
|
||
});
|
||
|
||
it('handles keyboard input: 5 * 6 Enter = 30', () => {
|
||
render(<CalculatorWidget {...defaultProps} />);
|
||
|
||
const container = screen.getByRole('application');
|
||
|
||
fireEvent.keyDown(container, { key: '5' });
|
||
fireEvent.keyDown(container, { key: '*' });
|
||
fireEvent.keyDown(container, { key: '6' });
|
||
fireEvent.keyDown(container, { key: 'Enter' });
|
||
|
||
expect(screen.getByLabelText('Anzeige')).toHaveTextContent('30');
|
||
});
|
||
|
||
it('handles decimal comma: 1,5 + 1,5 = 3', () => {
|
||
render(<CalculatorWidget {...defaultProps} />);
|
||
|
||
fireEvent.click(screen.getByRole('button', { name: '1' }));
|
||
fireEvent.click(screen.getByRole('button', { name: ',' }));
|
||
fireEvent.click(screen.getByRole('button', { name: '5' }));
|
||
fireEvent.click(screen.getByRole('button', { name: '+' }));
|
||
fireEvent.click(screen.getByRole('button', { name: '1' }));
|
||
fireEvent.click(screen.getByRole('button', { name: ',' }));
|
||
fireEvent.click(screen.getByRole('button', { name: '5' }));
|
||
fireEvent.click(screen.getByRole('button', { name: /gleich/i }));
|
||
|
||
expect(screen.getByLabelText('Anzeige')).toHaveTextContent('3');
|
||
});
|
||
|
||
it('quick-260916-bwo: Anzeige und Tasten tragen Container-Query-Klassen, Tasten fuellen ihre Zelle', () => {
|
||
render(<CalculatorWidget {...defaultProps} />);
|
||
|
||
expect(screen.getByLabelText('Anzeige').className).toMatch(/cqw/);
|
||
const seven = screen.getByRole('button', { name: '7' });
|
||
expect(seven.className).toMatch(/cqw/);
|
||
expect(seven.className).toContain('h-full');
|
||
expect(screen.getByRole('button', { name: 'CE' }).className).toMatch(/cqw/);
|
||
});
|
||
});
|