feat(suggestions): C2 — Meal suggestions (variety-aware) (#40)
feat(suggestions): implement C2 meal suggestion screen (Issue #27) Co-authored-by: Marcel Raddatz <marcel@raddatz.cloud> Co-committed-by: Marcel Raddatz <marcel@raddatz.cloud>
This commit was merged in pull request #40.
This commit is contained in:
60
frontend/src/lib/planner/SuggestionCard.test.ts
Normal file
60
frontend/src/lib/planner/SuggestionCard.test.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { render, screen } from '@testing-library/svelte';
|
||||
import SuggestionCard from './SuggestionCard.svelte';
|
||||
|
||||
const goodSuggestion = {
|
||||
recipe: { id: 'r1', name: 'Pasta al Limone', effort: 'Easy', cookTimeMin: 25 },
|
||||
simulatedScore: 9.2,
|
||||
reasoningType: 'good' as const,
|
||||
reasoningLabel: 'Frisches Protein · Aufwandsbalance'
|
||||
};
|
||||
|
||||
const warningSuggestion = {
|
||||
recipe: { id: 'r2', name: 'Hühnchen Curry', effort: 'Medium', cookTimeMin: 45 },
|
||||
simulatedScore: 6.1,
|
||||
reasoningType: 'warning' as const,
|
||||
reasoningLabel: 'Hähnchen schon 2 Tage dabei'
|
||||
};
|
||||
|
||||
describe('SuggestionCard', () => {
|
||||
it('renders recipe name', () => {
|
||||
render(SuggestionCard, { props: { suggestion: goodSuggestion, rank: 1, planId: 'p1', slotDate: '2026-04-01', weekStart: '2026-03-30' } });
|
||||
expect(screen.getByText('Pasta al Limone')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders rank number', () => {
|
||||
render(SuggestionCard, { props: { suggestion: goodSuggestion, rank: 1, planId: 'p1', slotDate: '2026-04-01', weekStart: '2026-03-30' } });
|
||||
expect(screen.getByText('1')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders cook time and effort metadata', () => {
|
||||
render(SuggestionCard, { props: { suggestion: goodSuggestion, rank: 1, planId: 'p1', slotDate: '2026-04-01', weekStart: '2026-03-30' } });
|
||||
expect(screen.getByText(/25 Min/)).toBeTruthy();
|
||||
expect(screen.getByText(/Easy/)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders green reasoning badge for good suggestions', () => {
|
||||
render(SuggestionCard, { props: { suggestion: goodSuggestion, rank: 1, planId: 'p1', slotDate: '2026-04-01', weekStart: '2026-03-30' } });
|
||||
const badge = screen.getByTestId('reasoning-badge');
|
||||
expect(badge.getAttribute('data-type')).toBe('good');
|
||||
expect(badge.textContent).toContain('Frisches Protein');
|
||||
});
|
||||
|
||||
it('renders yellow reasoning badge for warnings', () => {
|
||||
render(SuggestionCard, { props: { suggestion: warningSuggestion, rank: 2, planId: 'p1', slotDate: '2026-04-01', weekStart: '2026-03-30' } });
|
||||
const badge = screen.getByTestId('reasoning-badge');
|
||||
expect(badge.getAttribute('data-type')).toBe('warning');
|
||||
expect(badge.textContent).toContain('Hähnchen');
|
||||
});
|
||||
|
||||
it('renders a pick button/form', () => {
|
||||
render(SuggestionCard, { props: { suggestion: goodSuggestion, rank: 1, planId: 'p1', slotDate: '2026-04-01', weekStart: '2026-03-30' } });
|
||||
expect(screen.getByRole('button', { name: /Wählen/i })).toBeTruthy();
|
||||
});
|
||||
|
||||
it('card without reasoning renders without crashing', () => {
|
||||
const noReasoning = { ...goodSuggestion, reasoningType: undefined, reasoningLabel: undefined };
|
||||
render(SuggestionCard, { props: { suggestion: noReasoning, rank: 1, planId: 'p1', slotDate: '2026-04-01', weekStart: '2026-03-30' } });
|
||||
expect(screen.getByText('Pasta al Limone')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user