From 5c659d9046add8c77bd7699961a910505dcb4bc2 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Mon, 24 Aug 2026 06:20:52 +0000 Subject: Remove confirmed-orphaned routes, handlers, and templates From the sitemap audit: /tabs/meals (same dead-tab pattern as the removed /tabs/conditions, only reachable via ?tab=meals with no nav button), /partials/lists (superseded by inline .Lists rendering in trello-board.html), /shopping/toggle and /shopping/mode/{store}/toggle (superseded by the one-way complete/filter model), plus the orphaned trello-boards.html and error-banner.html templates that nothing rendered or included. Rewrote the meals grouping test to exercise groupMeals() directly since that logic is still live via the timeline. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_017GMEkHeqKz6FLkmizowBTK --- internal/handlers/handlers_test.go | 271 ++----------------------------------- 1 file changed, 12 insertions(+), 259 deletions(-) (limited to 'internal/handlers/handlers_test.go') diff --git a/internal/handlers/handlers_test.go b/internal/handlers/handlers_test.go index ca24778..61fb75d 100644 --- a/internal/handlers/handlers_test.go +++ b/internal/handlers/handlers_test.go @@ -819,169 +819,6 @@ func TestShoppingComplete_ExternalItemMarkedChecked(t *testing.T) { } } -// TestShoppingToggle_UpdatesItemState verifies toggle correctly updates state -func TestShoppingToggle_UpdatesItemState(t *testing.T) { - db, cleanup := setupTestDB(t) - defer cleanup() - - h := &Handler{ - store: db, - renderer: newTestRenderer(), - config: &config.Config{}, - } - - // Add user item - _ = db.SaveUserShoppingItem("Toggle Item", "TestStore") - items, _ := db.GetUserShoppingItems() - itemID := items[0].ID - - // Toggle to checked - req := httptest.NewRequest("POST", "/shopping/toggle", nil) - req.Form = map[string][]string{ - "id": {fmt.Sprintf("user-%d", itemID)}, - "source": {"user"}, - "checked": {"true"}, - } - w := httptest.NewRecorder() - h.HandleShoppingToggle(w, req) - - if w.Code != http.StatusOK { - t.Errorf("Expected status 200, got %d", w.Code) - } - - // Verify item is checked - items, _ = db.GetUserShoppingItems() - if !items[0].Checked { - t.Error("Expected item to be checked after toggle") - } - - // Toggle back to unchecked - req = httptest.NewRequest("POST", "/shopping/toggle", nil) - req.Form = map[string][]string{ - "id": {fmt.Sprintf("user-%d", itemID)}, - "source": {"user"}, - "checked": {"false"}, - } - w = httptest.NewRecorder() - h.HandleShoppingToggle(w, req) - - items, _ = db.GetUserShoppingItems() - if items[0].Checked { - t.Error("Expected item to be unchecked after second toggle") - } -} - -// TestShoppingToggle_ExternalSources verifies toggle works for external sources -func TestShoppingToggle_ExternalSources(t *testing.T) { - db, cleanup := setupTestDB(t) - defer cleanup() - - h := &Handler{ - store: db, - renderer: newTestRenderer(), - config: &config.Config{}, - } - - tests := []struct { - source string - itemID string - }{ - {"trello", "trello-toggle-123"}, - {"plantoeat", "pte-toggle-456"}, - } - - for _, tc := range tests { - t.Run(tc.source, func(t *testing.T) { - // Toggle to checked - req := httptest.NewRequest("POST", "/shopping/toggle", nil) - req.Form = map[string][]string{ - "id": {tc.itemID}, - "source": {tc.source}, - "checked": {"true"}, - } - w := httptest.NewRecorder() - h.HandleShoppingToggle(w, req) - - if w.Code != http.StatusOK { - t.Errorf("Expected status 200, got %d", w.Code) - } - - checks, _ := db.GetShoppingItemChecks(tc.source) - if !checks[tc.itemID] { - t.Errorf("Expected %s item to be checked", tc.source) - } - }) - } -} - -// TestShoppingToggle_UnknownSource verifies error for unknown source -func TestShoppingToggle_UnknownSource(t *testing.T) { - db, cleanup := setupTestDB(t) - defer cleanup() - - h := &Handler{ - store: db, - config: &config.Config{}, - } - - req := httptest.NewRequest("POST", "/shopping/toggle", nil) - req.Form = map[string][]string{ - "id": {"unknown-123"}, - "source": {"unknown"}, - "checked": {"true"}, - } - w := httptest.NewRecorder() - h.HandleShoppingToggle(w, req) - - if w.Code != http.StatusBadRequest { - t.Errorf("Expected status 400 for unknown source, got %d", w.Code) - } -} - -// TestShoppingModeToggle_ReturnsUpdatedList verifies shopping mode toggle returns items -func TestShoppingModeToggle_ReturnsUpdatedList(t *testing.T) { - db, cleanup := setupTestDB(t) - defer cleanup() - - h := &Handler{ - store: db, - renderer: newTestRenderer(), - config: &config.Config{}, - } - - // Add items - _ = db.SaveUserShoppingItem("Item 1", "TestStore") - _ = db.SaveUserShoppingItem("Item 2", "TestStore") - - items, _ := db.GetUserShoppingItems() - itemID := items[0].ID - - // Toggle in shopping mode - req := httptest.NewRequest("POST", "/shopping/mode/TestStore/toggle", nil) - req.Form = map[string][]string{ - "id": {fmt.Sprintf("user-%d", itemID)}, - "source": {"user"}, - "checked": {"true"}, - } - - rctx := chi.NewRouteContext() - rctx.URLParams.Add("store", "TestStore") - req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) - - w := httptest.NewRecorder() - h.HandleShoppingModeToggle(w, req) - - if w.Code != http.StatusOK { - t.Errorf("Expected status 200, got %d", w.Code) - } - - // Response should be HTML (items list) - contentType := w.Header().Get("Content-Type") - if !strings.Contains(contentType, "text/html") { - t.Errorf("Expected HTML response, got %s", contentType) - } -} - // TestShoppingTabFiltersCheckedItems verifies checked items excluded from tab func TestShoppingTabFiltersCheckedItems(t *testing.T) { db, cleanup := setupTestDB(t) @@ -1057,26 +894,6 @@ func TestHandleTabTasks(t *testing.T) { } } -func TestHandleTabMeals(t *testing.T) { - db, cleanup := setupTestDB(t) - defer cleanup() - - h := &Handler{ - store: db, - renderer: newTestRenderer(), - config: &config.Config{CacheTTLMinutes: 5}, - } - - req := httptest.NewRequest("GET", "/tabs/meals", nil) - w := httptest.NewRecorder() - - h.HandleTabMeals(w, req) - - if w.Code != http.StatusOK { - t.Errorf("Expected status 200, got %d", w.Code) - } -} - func TestHandleTabPlanning(t *testing.T) { db, cleanup := setupTestDB(t) defer cleanup() @@ -2120,35 +1937,6 @@ func TestHandleSetTaskRecurrence_InvalidFreq_Returns400(t *testing.T) { } } -// ============================================================================= -// HandleGetListsOptions template tests -// ============================================================================= - -// TestHandleGetListsOptions_RendersTemplate verifies that HandleGetListsOptions uses -// the renderer with the "lists-options" template. -func TestHandleGetListsOptions_RendersTemplate(t *testing.T) { - h, cleanup := setupTestHandler(t) - defer cleanup() - - h.trelloClient = &mockTrelloClient{boards: []models.Board{}} - - req := httptest.NewRequest("GET", "/trello/lists?board_id=board1", nil) - w := httptest.NewRecorder() - h.HandleGetListsOptions(w, req) - - mr := h.renderer.(*MockRenderer) - var found bool - for _, call := range mr.Calls { - if call.Name == "lists-options" { - found = true - break - } - } - if !found { - t.Error("Expected renderer to be called with 'lists-options' template") - } -} - // TestHandleSyncSources_AddsLogEntry verifies that syncing sources creates a sync log entry. func TestHandleSyncSources_AddsLogEntry(t *testing.T) { h, cleanup := setupTestHandler(t) @@ -2339,67 +2127,32 @@ func TestHandleTabPlanning_TomorrowBoundary(t *testing.T) { } // ============================================================================= -// HandleTabMeals grouping test +// groupMeals grouping test // ============================================================================= -// TestHandleTabMeals_GroupingMergesRecipes verifies that multiple meals sharing -// the same date+mealType are combined into a single CombinedMeal entry whose -// RecipeNames contains all merged recipe names. -func TestHandleTabMeals_GroupingMergesRecipes(t *testing.T) { - db, cleanup := setupTestDB(t) - defer cleanup() - +// TestGroupMeals_MergesRecipes verifies that multiple meals sharing the same +// date+mealType are combined into a single CombinedMeal entry whose +// RecipeNames contains all merged recipe names. groupMeals is still live +// logic used by the timeline (see timeline_logic.go). +func TestGroupMeals_MergesRecipes(t *testing.T) { today := config.Today() meals := []models.Meal{ {ID: "m1", RecipeName: "Pasta", Date: today, MealType: "dinner", RecipeURL: "http://example.com/pasta"}, {ID: "m2", RecipeName: "Salad", Date: today, MealType: "dinner", RecipeURL: "http://example.com/salad"}, {ID: "m3", RecipeName: "Oatmeal", Date: today, MealType: "breakfast", RecipeURL: "http://example.com/oatmeal"}, } - if err := db.SaveMeals(meals); err != nil { - t.Fatalf("Failed to save meals: %v", err) - } - renderer := NewMockRenderer() - h := &Handler{ - store: db, - renderer: renderer, - config: &config.Config{CacheTTLMinutes: 5}, - } - - req := httptest.NewRequest("GET", "/tabs/meals", nil) - w := httptest.NewRecorder() - h.HandleTabMeals(w, req) - - if w.Code != http.StatusOK { - t.Errorf("Expected 200, got %d", w.Code) - } - - var mealsCall *RenderCall - for i, call := range renderer.Calls { - if call.Name == "meals-tab" { - c := renderer.Calls[i] - mealsCall = &c - break - } - } - if mealsCall == nil { - t.Fatal("Expected meals-tab to be rendered") - } - - data, ok := mealsCall.Data.(struct{ Meals []CombinedMeal }) - if !ok { - t.Fatalf("Expected meals data struct, got %T", mealsCall.Data) - } + combined := groupMeals(meals) // m1 + m2 share date+dinner → 1 CombinedMeal; m3 is breakfast → 1 CombinedMeal - if len(data.Meals) != 2 { - t.Errorf("Expected 2 combined meals, got %d", len(data.Meals)) + if len(combined) != 2 { + t.Errorf("Expected 2 combined meals, got %d", len(combined)) } var dinner *CombinedMeal - for i := range data.Meals { - if data.Meals[i].MealType == "dinner" { - dinner = &data.Meals[i] + for i := range combined { + if combined[i].MealType == "dinner" { + dinner = &combined[i] break } } -- cgit v1.2.3