feat(variety): implement C3 variety review screen (Issue #28)
- Add /planner/variety route with mobile stacked + desktop 2-column layout - Implement VarietyScoreHero: Fraunces score display + progress bar + color-coded description - Implement ScoreBreakdownList: 3 sub-score rows (protein diversity, ingredient overlap, effort balance) - Implement VarietyWarningCards: yellow-tint warning cards derived from API tagRepeats/ingredientOverlaps - Implement EffortBar: proportional colored segments (Easy/Medium/Hard) with ×N labels - Desktop: protein grid (7 columns, repeat highlight with yellow ring) + effort bar in right panel - Client-side sub-score derivation from VarietyScoreResponse (tagged for TODO to move to API) - 26 new tests across 5 components + server load function; 455 tests total, 0 type errors Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
43
frontend/src/lib/planner/VarietyScoreHero.test.ts
Normal file
43
frontend/src/lib/planner/VarietyScoreHero.test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { render, screen } from '@testing-library/svelte';
|
||||
import VarietyScoreHero from './VarietyScoreHero.svelte';
|
||||
|
||||
describe('VarietyScoreHero', () => {
|
||||
it('renders the score number', () => {
|
||||
render(VarietyScoreHero, { props: { score: 8.2 } });
|
||||
expect(screen.getByTestId('score-value').textContent).toContain('8.2');
|
||||
});
|
||||
|
||||
it('renders "out of 10" label', () => {
|
||||
render(VarietyScoreHero, { props: { score: 8.2 } });
|
||||
expect(screen.getByTestId('score-label').textContent).toContain('10');
|
||||
});
|
||||
|
||||
it('renders a progressbar with correct aria attributes', () => {
|
||||
render(VarietyScoreHero, { props: { score: 8.2 } });
|
||||
const bar = screen.getByRole('progressbar');
|
||||
expect(bar.getAttribute('aria-valuenow')).toBe('8.2');
|
||||
expect(bar.getAttribute('aria-valuemin')).toBe('0');
|
||||
expect(bar.getAttribute('aria-valuemax')).toBe('10');
|
||||
});
|
||||
|
||||
it('shows "Excellent variety" description for score >= 9', () => {
|
||||
render(VarietyScoreHero, { props: { score: 9.5 } });
|
||||
expect(screen.getByTestId('score-description').textContent).toContain('Ausgezeichnet');
|
||||
});
|
||||
|
||||
it('shows "Good variety" description for score 7-8.9', () => {
|
||||
render(VarietyScoreHero, { props: { score: 7.5 } });
|
||||
expect(screen.getByTestId('score-description').textContent).toContain('Gut');
|
||||
});
|
||||
|
||||
it('shows "Getting there" description for score 4-6.9', () => {
|
||||
render(VarietyScoreHero, { props: { score: 5.0 } });
|
||||
expect(screen.getByTestId('score-description').textContent).toContain('Verbesserbar');
|
||||
});
|
||||
|
||||
it('shows "Needs improvement" description for score < 4', () => {
|
||||
render(VarietyScoreHero, { props: { score: 2.1 } });
|
||||
expect(screen.getByTestId('score-description').textContent).toContain('Unzureichend');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user