feat(recipes): display form error from \$page.form in RecipeForm

- Import page store and render role="alert" error banner
- Add mock for \$app/stores and \$app/forms in RecipeForm tests
- Add tests: error banner shown when form.error set, hidden when null

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-03 10:31:18 +02:00
parent 6505cb4251
commit e4d3008139
2 changed files with 30 additions and 1 deletions

View File

@@ -1,4 +1,6 @@
<script lang="ts">
import { page } from '$app/stores';
type Category = { id: string; name: string; tagType?: string };
type EditRecipe = {
@@ -45,6 +47,11 @@
</script>
<form method="POST" {action}>
<!-- Error banner -->
{#if $page.form?.error}
<div role="alert">{$page.form.error}</div>
{/if}
<!-- Basic info -->
<label for="name">Name</label>
<input id="name" name="name" type="text" bind:value={name} required />

View File

@@ -1,8 +1,17 @@
import { describe, it, expect } from 'vitest';
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/svelte';
import { userEvent } from '@testing-library/user-event';
import { writable } from 'svelte/store';
import RecipeForm from './RecipeForm.svelte';
vi.mock('$app/stores', () => ({
page: writable({ form: null, url: new URL('http://localhost/recipes/new') })
}));
vi.mock('$app/forms', () => ({
enhance: () => ({ destroy: () => {} })
}));
const mockCategories = [
{ id: 'c1', name: 'Pasta', tagType: 'category' },
{ id: 'c2', name: 'Fleisch', tagType: 'category' }
@@ -140,4 +149,17 @@ describe('RecipeForm', () => {
const cancelLink = screen.getByRole('link', { name: /abbrechen/i });
expect(cancelLink).toHaveAttribute('href', '/recipes');
});
it('displays form error message when $page.form.error is set', async () => {
const { page } = await import('$app/stores');
(page as ReturnType<typeof writable>).set({ form: { error: 'Name ist erforderlich' }, url: new URL('http://localhost/recipes/new') });
render(RecipeForm, { props: emptyProps });
expect(screen.getByRole('alert')).toHaveTextContent('Name ist erforderlich');
(page as ReturnType<typeof writable>).set({ form: null, url: new URL('http://localhost/recipes/new') });
});
it('does not display error banner when form has no error', () => {
render(RecipeForm, { props: emptyProps });
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
});
});