fix(editor): Strg/Cmd/Alt-Tasten frei, 40-Megapixel-Grenze, Umbenennen-Test

- Vorschau: Tastenkürzel mit Strg/Cmd/Alt gehören dem Browser (Seitenzoom).
- decodeImage lehnt Bilder über 40 Megapixel nach dem Laden, vor dem
  Dekodieren ab (Meldung "Das Bild ist zu groß (max. 40 Megapixel).").
- Test, dass das Umbenennen-Feld den Namen markiert (tat der Code schon).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-04 11:11:06 +00:00
1 parent 144181f2c9
commit 9c4e80ec9a
8 files changed
+144 -8

No files matched your search

+25 -1
View File
@@ -31,7 +31,11 @@ vi.mock('../account/auth', () => ({
}));
vi.mock('../account/login-dialog', () => ({ requireLogin: mocks.requireLogin }));
vi.mock('./router', () => ({ navigate: mocks.navigate }));
vi.mock('../editor/upload', () => ({ READ_MESSAGE: 'Das Bild konnte nicht gelesen werden.', decodeImage: mocks.decodeImage }));
vi.mock('../editor/upload', () => ({
READ_MESSAGE: 'Das Bild konnte nicht gelesen werden.',
PIXELS_MESSAGE: 'Das Bild ist zu groß (max. 40 Megapixel).',
decodeImage: mocks.decodeImage,
}));
vi.mock('../card/render', () => ({ loadCardAssets: mocks.loadCardAssets, exportCard: mocks.exportCard }));
vi.mock('../editor/download', async (importOriginal) => ({
...(await importOriginal<typeof import('../editor/download')>()),
@@ -267,6 +271,19 @@ describe('Meine Karten: Öffnen und Herunterladen', () => {
expect(tileFor('a').querySelector('.card-msg')!.textContent).toBe('');
});
it('Herunterladen eines über 40 Megapixel großen Bildes zeigt die Größen-Meldung an der Kachel', async () => {
mocks.list.mockResolvedValue([card('a', 'Alpha')]);
mocks.loadImage.mockResolvedValue(new Blob(['i'], { type: 'image/png' }));
mocks.decodeImage.mockRejectedValue(new Error('Das Bild ist zu groß (max. 40 Megapixel).'));
mount();
await vi.waitFor(() => expect(tiles()).toHaveLength(1));
button(tileFor('a'), 'Herunterladen').click();
await vi.waitFor(() =>
expect(tileFor('a').querySelector('.card-msg')!.textContent).toBe('Das Bild ist zu groß (max. 40 Megapixel).'),
);
expect(mocks.saveBlobAs).not.toHaveBeenCalled();
});
it('Herunterladen ohne Bilddatei zeigt die Meldung an der Kachel', async () => {
mocks.list.mockResolvedValue([card('a', 'Alpha')]);
mocks.loadImage.mockRejectedValue(Object.assign(new Error('weg'), { code: 404, type: 'storage_file_not_found' }));
@@ -370,6 +387,13 @@ describe('Meine Karten: Umbenennen', () => {
expect(tileFor('b').querySelector('input')).toBeNull();
});
it('der vorhandene Name ist beim Öffnen komplett markiert (Tippen ersetzt ihn, statt davor einzufügen)', async () => {
const input = await startRename();
expect(document.activeElement).toBe(input);
expect(input.selectionStart).toBe(0);
expect(input.selectionEnd).toBe('Beta'.length);
});
it('Esc bricht ab, ohne etwas zu speichern', async () => {
const input = await startRename();
input.value = 'Anders';
+2 -2
View File
@@ -13,7 +13,7 @@ import { confirmDialog } from '../editor/confirm-dialog';
import { el } from '../editor/dom';
import { downloadFileName, pngSizeWarning, saveBlobAs } from '../editor/download';
import type { EditorStore } from '../editor/state';
import { READ_MESSAGE, decodeImage } from '../editor/upload';
import { PIXELS_MESSAGE, READ_MESSAGE, decodeImage } from '../editor/upload';
import { navigate } from './router';
const LOADING = 'Karten werden geladen …';
@@ -328,7 +328,7 @@ export function mountCardsPage(root: HTMLElement, store: EditorStore): () => voi
function failureText(err: unknown): string {
if (err instanceof LoginCancelled) return LOGIN_NEEDED;
if (err instanceof Error && err.message === READ_MESSAGE) return READ_MESSAGE;
if (err instanceof Error && (err.message === READ_MESSAGE || err.message === PIXELS_MESSAGE)) return err.message;
return errorMessage(err, 'load');
}