feat(recipes): validate image MIME type on file select
Rejects non-allowlisted types (only JPEG, PNG, GIF, WebP accepted) with an inline error message. Uses image/bmp as test vector since it passes accept="image/*" but is not in the allowed set. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -64,6 +64,7 @@
|
|||||||
let imageError = $state<string | null>(null);
|
let imageError = $state<string | null>(null);
|
||||||
|
|
||||||
const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
||||||
|
const ALLOWED_MIME_TYPES = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];
|
||||||
|
|
||||||
function handleImageChange(e: Event) {
|
function handleImageChange(e: Event) {
|
||||||
const file = (e.currentTarget as HTMLInputElement).files?.[0];
|
const file = (e.currentTarget as HTMLInputElement).files?.[0];
|
||||||
@@ -73,6 +74,11 @@
|
|||||||
(e.currentTarget as HTMLInputElement).value = '';
|
(e.currentTarget as HTMLInputElement).value = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!ALLOWED_MIME_TYPES.includes(file.type)) {
|
||||||
|
imageError = 'Dateityp nicht unterstützt. Erlaubt: JPEG, PNG, GIF, WebP.';
|
||||||
|
(e.currentTarget as HTMLInputElement).value = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
imageError = null;
|
imageError = null;
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
|
|||||||
@@ -189,4 +189,26 @@ describe('RecipeForm', () => {
|
|||||||
|
|
||||||
expect(screen.queryByText(/datei zu groß/i)).not.toBeInTheDocument();
|
expect(screen.queryByText(/datei zu groß/i)).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('shows error when selected file has unsupported type', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(RecipeForm, { props: emptyProps });
|
||||||
|
|
||||||
|
const bmpFile = new File(['content'], 'image.bmp', { type: 'image/bmp' });
|
||||||
|
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
|
||||||
|
await user.upload(fileInput, bmpFile);
|
||||||
|
|
||||||
|
expect(screen.getByText(/dateityp/i)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not show type error for supported image types', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(RecipeForm, { props: emptyProps });
|
||||||
|
|
||||||
|
const jpgFile = new File(['content'], 'photo.jpg', { type: 'image/jpeg' });
|
||||||
|
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
|
||||||
|
await user.upload(fileInput, jpgFile);
|
||||||
|
|
||||||
|
expect(screen.queryByText(/dateityp/i)).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user