diff --git a/frontend/src/components/MealList.jsx b/frontend/src/components/MealList.jsx index 7a6390f..f1f293d 100644 --- a/frontend/src/components/MealList.jsx +++ b/frontend/src/components/MealList.jsx @@ -869,7 +869,7 @@ export default function MealList({ refreshTrigger, onMealDeleted, onMealUpdated, min="0" value={component.base_calories} onChange={(e) => updateComponentNutrition(idx, 'base_calories', e.target.value)} - className="w-full px-1 sm:px-2 py-1 border text-xs sm:text-sm text-white" + className={`w-full px-1 sm:px-2 py-1 border ${colors.inputBorder} ${colors.inputBg} text-xs sm:text-sm text-white`} />
@@ -880,7 +880,7 @@ export default function MealList({ refreshTrigger, onMealDeleted, onMealUpdated, min="0" value={component.base_protein_g} onChange={(e) => updateComponentNutrition(idx, 'base_protein_g', e.target.value)} - className="w-full px-1 sm:px-2 py-1 border text-xs sm:text-sm text-white" + className={`w-full px-1 sm:px-2 py-1 border ${colors.inputBorder} ${colors.inputBg} text-xs sm:text-sm text-white`} />
@@ -891,7 +891,7 @@ export default function MealList({ refreshTrigger, onMealDeleted, onMealUpdated, min="0" value={component.base_carbs_g} onChange={(e) => updateComponentNutrition(idx, 'base_carbs_g', e.target.value)} - className="w-full px-1 sm:px-2 py-1 border text-xs sm:text-sm text-white" + className={`w-full px-1 sm:px-2 py-1 border ${colors.inputBorder} ${colors.inputBg} text-xs sm:text-sm text-white`} />
@@ -902,7 +902,7 @@ export default function MealList({ refreshTrigger, onMealDeleted, onMealUpdated, min="0" value={component.base_fat_g} onChange={(e) => updateComponentNutrition(idx, 'base_fat_g', e.target.value)} - className="w-full px-1 sm:px-2 py-1 border text-xs sm:text-sm text-white" + className={`w-full px-1 sm:px-2 py-1 border ${colors.inputBorder} ${colors.inputBg} text-xs sm:text-sm text-white`} />
@@ -913,7 +913,7 @@ export default function MealList({ refreshTrigger, onMealDeleted, onMealUpdated, min="0" value={component.base_fiber_g} onChange={(e) => updateComponentNutrition(idx, 'base_fiber_g', e.target.value)} - className="w-full px-1 sm:px-2 py-1 border text-xs sm:text-sm text-white" + className={`w-full px-1 sm:px-2 py-1 border ${colors.inputBorder} ${colors.inputBg} text-xs sm:text-sm text-white`} />
@@ -1027,7 +1027,7 @@ export default function MealList({ refreshTrigger, onMealDeleted, onMealUpdated, min="0" value={simpleMacros.base_calories} onChange={(e) => updateSimpleMacro('base_calories', e.target.value)} - className="w-full px-1 sm:px-2 py-1 border text-xs sm:text-sm text-white" + className={`w-full px-1 sm:px-2 py-1 border ${colors.inputBorder} ${colors.inputBg} text-xs sm:text-sm text-white`} />
@@ -1038,7 +1038,7 @@ export default function MealList({ refreshTrigger, onMealDeleted, onMealUpdated, min="0" value={simpleMacros.base_protein_g} onChange={(e) => updateSimpleMacro('base_protein_g', e.target.value)} - className="w-full px-1 sm:px-2 py-1 border text-xs sm:text-sm text-white" + className={`w-full px-1 sm:px-2 py-1 border ${colors.inputBorder} ${colors.inputBg} text-xs sm:text-sm text-white`} />
@@ -1049,7 +1049,7 @@ export default function MealList({ refreshTrigger, onMealDeleted, onMealUpdated, min="0" value={simpleMacros.base_carbs_g} onChange={(e) => updateSimpleMacro('base_carbs_g', e.target.value)} - className="w-full px-1 sm:px-2 py-1 border text-xs sm:text-sm text-white" + className={`w-full px-1 sm:px-2 py-1 border ${colors.inputBorder} ${colors.inputBg} text-xs sm:text-sm text-white`} />
@@ -1060,7 +1060,7 @@ export default function MealList({ refreshTrigger, onMealDeleted, onMealUpdated, min="0" value={simpleMacros.base_fat_g} onChange={(e) => updateSimpleMacro('base_fat_g', e.target.value)} - className="w-full px-1 sm:px-2 py-1 border text-xs sm:text-sm text-white" + className={`w-full px-1 sm:px-2 py-1 border ${colors.inputBorder} ${colors.inputBg} text-xs sm:text-sm text-white`} />
@@ -1071,7 +1071,7 @@ export default function MealList({ refreshTrigger, onMealDeleted, onMealUpdated, min="0" value={simpleMacros.base_fiber_g} onChange={(e) => updateSimpleMacro('base_fiber_g', e.target.value)} - className="w-full px-1 sm:px-2 py-1 border text-xs sm:text-sm text-white" + className={`w-full px-1 sm:px-2 py-1 border ${colors.inputBorder} ${colors.inputBg} text-xs sm:text-sm text-white`} />
diff --git a/frontend/src/components/__tests__/MealList.test.jsx b/frontend/src/components/__tests__/MealList.test.jsx new file mode 100644 index 0000000..c11561d --- /dev/null +++ b/frontend/src/components/__tests__/MealList.test.jsx @@ -0,0 +1,84 @@ +/** + * Tests for MealList component - edit mode input contrast (issue #3) + */ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { render, screen, fireEvent } from '@testing-library/react'; +import MealList from '../MealList'; + +// All vi.mock calls MUST use inline factory functions (no external const references), +// so shared fixtures go through vi.hoisted. +const { mockMeal, createBuilder } = vi.hoisted(() => { + const mockMeal = { + id: 'meal-1', + user_id: 'test-user-id', + meal_name: 'Grilled Chicken', + meal_type: 'lunch', + consumed_at: '2024-01-15T12:00:00.000Z', + total_calories: 200, + total_protein_g: 30, + total_carbs_g: 5, + total_fat_g: 8, + total_fiber_g: 2, + portion_size: null, + portion_unit: null, + is_compound: false, + notes: '', + }; + + const createBuilder = (result) => { + const builder = {}; + ['select', 'eq', 'gte', 'lte', 'order', 'limit', 'delete', 'insert', 'update'].forEach((fn) => { + builder[fn] = () => builder; + }); + builder.single = () => Promise.resolve(result); + builder.then = (resolve, reject) => Promise.resolve(result).then(resolve, reject); + return builder; + }; + + return { mockMeal, createBuilder }; +}); + +vi.mock('../../supabaseClient', () => ({ + supabase: { + auth: { + getUser: vi.fn().mockResolvedValue({ data: { user: { id: 'test-user-id' } } }), + }, + from: vi.fn((table) => { + if (table === 'meals') { + return createBuilder({ data: [mockMeal], error: null }); + } + if (table === 'meal_components') { + return createBuilder({ data: [], error: null }); + } + return createBuilder({ data: [], error: null }); + }), + storage: { + from: vi.fn(() => ({ + remove: vi.fn().mockResolvedValue({ data: null, error: null }), + })), + }, + }, +})); + +describe('MealList - edit mode input contrast', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('gives every macro number input a dark background in manual edit mode', async () => { + render(); + + const editButton = await screen.findByRole('button', { name: 'Edit' }); + fireEvent.click(editButton); + + const editManuallyButton = await screen.findByText('Edit Manually'); + fireEvent.click(editManuallyButton); + + const numberInputs = screen.getAllByRole('spinbutton'); + expect(numberInputs).toHaveLength(5); + numberInputs.forEach((input) => { + expect(input).toHaveClass('bg-black'); + expect(input).toHaveClass('border-[#1a1a1a]'); + }); + }); +}); diff --git a/frontend/src/index.css b/frontend/src/index.css index 41c44d6..2248c32 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -16,6 +16,7 @@ body { @apply bg-black text-white antialiased; font-family: 'Plus Jakarta Sans', system-ui, sans-serif; + color-scheme: dark; } h1, h2, h3, h4, h5, h6 {