Compare commits
7 Commits
6de7f5a9b5
...
7c66dcad3a
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c66dcad3a | |||
| 01a321caa9 | |||
| 2d1604492d | |||
| 3742364956 | |||
| 36dfea34cc | |||
| 66525484a6 | |||
| e5614ccf30 |
@@ -53,4 +53,11 @@ describe('ProgressSidebar', () => {
|
||||
expect(screen.getByTestId('step-2')).not.toHaveAttribute('aria-current');
|
||||
expect(screen.getByTestId('step-3')).not.toHaveAttribute('aria-current');
|
||||
});
|
||||
|
||||
it('step 3 active: steps 1 and 2 are both completed', () => {
|
||||
render(ProgressSidebar, { props: { currentStep: 3 } });
|
||||
expect(screen.getByTestId('step-1')).toHaveAttribute('data-state', 'completed');
|
||||
expect(screen.getByTestId('step-2')).toHaveAttribute('data-state', 'completed');
|
||||
expect(screen.getByTestId('step-3')).toHaveAttribute('aria-current', 'step');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
</script>
|
||||
|
||||
<form method="POST" novalidate use:enhance onsubmit={handleSubmit}>
|
||||
<h1 class="mb-[8px] font-['var(--font-display)'] text-[24px] font-semibold">Haushalt benennen</h1>
|
||||
<p class="mb-[24px] text-[14px] text-[var(--color-text-muted)]">
|
||||
<h1 class="mb-[8px] font-[var(--font-display)] text-[18px] font-medium md:text-[28px]">Haushalt benennen</h1>
|
||||
<p class="mb-[24px] text-[12px] text-[var(--color-text-muted)] md:text-[14px]">
|
||||
Gib deinem Haushalt einen Namen, damit du ihn leicht wiederfindest.
|
||||
</p>
|
||||
|
||||
|
||||
@@ -41,7 +41,9 @@ describe('HouseholdSetupForm', () => {
|
||||
const user = userEvent.setup();
|
||||
render(HouseholdSetupForm);
|
||||
|
||||
// override disabled to allow submit attempt by typing then clearing
|
||||
// Type then clear: sets touched=true, which makes the $derived error visible
|
||||
// as soon as the field is empty. The button is disabled so the click is a no-op,
|
||||
// but the error is already shown from the touched+empty state.
|
||||
const input = screen.getByLabelText('Haushaltsname');
|
||||
await user.type(input, 'a');
|
||||
await user.clear(input);
|
||||
|
||||
@@ -18,6 +18,10 @@ export const actions = {
|
||||
return fail(400, { errors: { name: 'Haushaltsname ist erforderlich' }, name: '' });
|
||||
}
|
||||
|
||||
if (name.length > 100) {
|
||||
return fail(400, { errors: { name: 'Haushaltsname darf maximal 100 Zeichen lang sein' }, name });
|
||||
}
|
||||
|
||||
const api = apiClient(fetch);
|
||||
const { data, error } = await api.POST('/v1/households', {
|
||||
body: { name }
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
<!-- Desktop progress sidebar — hidden on mobile -->
|
||||
<aside
|
||||
class="hidden md:flex w-[300px] flex-shrink-0 flex-col bg-[var(--color-surface)] border-r border-[var(--color-border)] p-[40px_28px]"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<ProgressSidebar currentStep={1} />
|
||||
</aside>
|
||||
|
||||
@@ -71,8 +71,7 @@ describe('household setup — form action', () => {
|
||||
function mockSuccess() {
|
||||
return {
|
||||
data: { data: { id: 'hh-123', name: 'Smith family', members: [] } },
|
||||
error: undefined,
|
||||
response: { headers: { get: vi.fn().mockReturnValue(null) } }
|
||||
error: undefined
|
||||
};
|
||||
}
|
||||
|
||||
@@ -123,6 +122,28 @@ describe('household setup — form action', () => {
|
||||
expect(result.data.name).toBe('');
|
||||
});
|
||||
|
||||
it('returns fail(400) when name exceeds 100 characters', async () => {
|
||||
const longName = 'a'.repeat(101);
|
||||
const result = await actions.default(createRequest({ name: longName }));
|
||||
|
||||
expect(result.status).toBe(400);
|
||||
expect(result.data.errors.name).toBeTruthy();
|
||||
expect(mockPost).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('accepts name at exactly 100 characters', async () => {
|
||||
mockPost.mockResolvedValue(mockSuccess());
|
||||
const maxName = 'a'.repeat(100);
|
||||
|
||||
try {
|
||||
await actions.default(createRequest({ name: maxName }));
|
||||
} catch {
|
||||
// redirect throws
|
||||
}
|
||||
|
||||
expect(mockPost).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns fail with form error on API failure', async () => {
|
||||
mockPost.mockResolvedValue({
|
||||
data: undefined,
|
||||
|
||||
@@ -9,7 +9,7 @@ vi.mock('$app/forms', () => ({
|
||||
describe('household setup page', () => {
|
||||
it('renders the form heading', () => {
|
||||
render(Page);
|
||||
expect(screen.getByText('Haushalt benennen')).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: 'Haushalt benennen' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the household name input', () => {
|
||||
|
||||
@@ -1,7 +1 @@
|
||||
import '@testing-library/jest-dom/vitest';
|
||||
import { configure } from '@testing-library/dom';
|
||||
|
||||
// Exclude elements inside aria-hidden containers from text queries,
|
||||
// so that visually-hidden sidebars (e.g. ProgressSidebar in onboarding pages)
|
||||
// don't create duplicate text matches when the same text appears in the main content.
|
||||
configure({ defaultIgnore: 'script, style, [aria-hidden="true"] *' });
|
||||
|
||||
Reference in New Issue
Block a user