diff --git a/frontend/src/routes/household/staples/+page.svelte b/frontend/src/routes/household/staples/+page.svelte index 6a67101..3aec917 100644 --- a/frontend/src/routes/household/staples/+page.svelte +++ b/frontend/src/routes/household/staples/+page.svelte @@ -2,6 +2,44 @@ Vorräte einrichten — Mealplan -
-

A3 — Vorräte einrichten (coming soon)

-
+ + +{#if isOnboarding} +
+ + + + +
+ +

Schritt 2 von 3

+ + +
+ +
+ + + +
+
+{:else} +
+

Vorräte

+ +
+{/if} diff --git a/frontend/src/routes/household/staples/page.test.ts b/frontend/src/routes/household/staples/page.test.ts new file mode 100644 index 0000000..3f016b5 --- /dev/null +++ b/frontend/src/routes/household/staples/page.test.ts @@ -0,0 +1,86 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { render, screen } from '@testing-library/svelte'; +import Page from './+page.svelte'; + +vi.mock('$app/state', () => ({ + page: { url: { searchParams: { get: vi.fn() } } } +})); + +const mockCategories = [ + { + id: 'cat-1', + name: 'Öle & Fette', + ingredients: [ + { id: 'ing-1', name: 'Olivenöl', isStaple: true }, + { id: 'ing-2', name: 'Butter', isStaple: false } + ] + } +]; + +describe('staples page — onboarding context (?ctx=onboarding)', () => { + beforeEach(() => { + vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true })); + }); + + afterEach(() => { + vi.unstubAllGlobals(); + }); + + it('renders ProgressSidebar with step 2 active', () => { + render(Page, { props: { data: { categories: mockCategories }, ctx: 'onboarding' } }); + expect(screen.getByTestId('step-2')).toHaveAttribute('aria-current', 'step'); + }); + + it('renders Continue button linking to /household/invite', () => { + render(Page, { props: { data: { categories: mockCategories }, ctx: 'onboarding' } }); + const continueLink = screen.getByRole('link', { name: /weiter/i }); + expect(continueLink).toHaveAttribute('href', '/household/invite'); + }); + + it('renders Skip button linking to /planner', () => { + render(Page, { props: { data: { categories: mockCategories }, ctx: 'onboarding' } }); + const skipLink = screen.getByRole('link', { name: /überspringen/i }); + expect(skipLink).toHaveAttribute('href', '/planner'); + }); + + it('renders the StaplesManager with categories', () => { + render(Page, { props: { data: { categories: mockCategories }, ctx: 'onboarding' } }); + expect(screen.getByText('Öle & Fette')).toBeInTheDocument(); + }); + + it('sets the page title', () => { + render(Page, { props: { data: { categories: mockCategories }, ctx: 'onboarding' } }); + expect(document.title).toBe('Vorräte einrichten — Mealplan'); + }); + + it('renders mobile step indicator Schritt 2 von 3', () => { + render(Page, { props: { data: { categories: mockCategories }, ctx: 'onboarding' } }); + expect(screen.getByText(/schritt 2 von 3/i)).toBeInTheDocument(); + }); +}); + +describe('staples page — settings context (no ctx)', () => { + beforeEach(() => { + vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true })); + }); + + afterEach(() => { + vi.unstubAllGlobals(); + }); + + it('does not render ProgressSidebar', () => { + render(Page, { props: { data: { categories: mockCategories } } }); + expect(screen.queryByTestId('step-1')).not.toBeInTheDocument(); + }); + + it('does not render Continue or Skip buttons', () => { + render(Page, { props: { data: { categories: mockCategories } } }); + expect(screen.queryByRole('link', { name: /weiter/i })).not.toBeInTheDocument(); + expect(screen.queryByRole('link', { name: /überspringen/i })).not.toBeInTheDocument(); + }); + + it('renders a settings heading', () => { + render(Page, { props: { data: { categories: mockCategories } } }); + expect(screen.getByRole('heading', { name: /vorräte/i })).toBeInTheDocument(); + }); +});