diff options
Diffstat (limited to 'internal/handlers/widget_test.go')
| -rw-r--r-- | internal/handlers/widget_test.go | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/internal/handlers/widget_test.go b/internal/handlers/widget_test.go index 95f5264..a6ff095 100644 --- a/internal/handlers/widget_test.go +++ b/internal/handlers/widget_test.go @@ -1028,3 +1028,164 @@ func TestHandleWidgetTaskNextDate_NonRecurringTask_Returns400(t *testing.T) { } } +func TestHandleWidgetProjectsGet_ReturnsNonArchivedProjects(t *testing.T) { + s, cleanup := setupTestDB(t) + defer cleanup() + h := &Handler{store: s} + if _, err := s.CreateProject("Sailing prep", "#3B82F6"); err != nil { + t.Fatal(err) + } + + req := httptest.NewRequest("GET", "/api/widget/projects", nil) + w := httptest.NewRecorder() + http.HandlerFunc(h.HandleWidgetProjectsGet).ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String()) + } + var projects []projectResponse + if err := json.NewDecoder(w.Body).Decode(&projects); err != nil { + t.Fatalf("failed to decode response: %v", err) + } + if len(projects) != 1 || projects[0].Name != "Sailing prep" { + t.Fatalf("projects = %+v, want 1 entry named 'Sailing prep'", projects) + } +} + +func TestHandleWidgetProjectsCreate_CreatesProject(t *testing.T) { + s, cleanup := setupTestDB(t) + defer cleanup() + h := &Handler{store: s} + + body := `{"name":"Sailing prep","color":"#3B82F6"}` + req := httptest.NewRequest("POST", "/api/widget/projects", strings.NewReader(body)) + w := httptest.NewRecorder() + http.HandlerFunc(h.HandleWidgetProjectsCreate).ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String()) + } + var resp projectResponse + if err := json.NewDecoder(w.Body).Decode(&resp); err != nil { + t.Fatalf("failed to decode response: %v", err) + } + if resp.Name != "Sailing prep" || resp.Color != "#3B82F6" || resp.ID == "" { + t.Errorf("resp = %+v, want a created project with name/color/id set", resp) + } +} + +func TestHandleWidgetTaskProject_SetsProjectID(t *testing.T) { + s, cleanup := setupTestDB(t) + defer cleanup() + h := &Handler{store: s} + project, err := s.CreateProject("Sailing prep", "#3B82F6") + if err != nil { + t.Fatal(err) + } + if _, err := s.DB().Exec(`INSERT INTO native_tasks (id, content) VALUES ('plain-1', 'Buy line')`); err != nil { + t.Fatal(err) + } + + body := `{"id":"plain-1","project_id":"` + project.ID + `"}` + req := httptest.NewRequest("POST", "/api/widget/task/project", strings.NewReader(body)) + w := httptest.NewRecorder() + http.HandlerFunc(h.HandleWidgetTaskProject).ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String()) + } + task, err := s.GetNativeTaskByID("plain-1") + if err != nil { + t.Fatal(err) + } + if task.ProjectID != project.ID { + t.Errorf("ProjectID = %q, want %q", task.ProjectID, project.ID) + } +} + +func TestHandleWidgetTaskLabels_SetsLabels(t *testing.T) { + s, cleanup := setupTestDB(t) + defer cleanup() + h := &Handler{store: s} + if _, err := s.DB().Exec(`INSERT INTO native_tasks (id, content) VALUES ('plain-1', 'Buy line')`); err != nil { + t.Fatal(err) + } + + body := `{"id":"plain-1","labels":["chore","urgent"]}` + req := httptest.NewRequest("POST", "/api/widget/task/labels", strings.NewReader(body)) + w := httptest.NewRecorder() + http.HandlerFunc(h.HandleWidgetTaskLabels).ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String()) + } + task, err := s.GetNativeTaskByID("plain-1") + if err != nil { + t.Fatal(err) + } + if len(task.Labels) != 2 || task.Labels[0] != "chore" || task.Labels[1] != "urgent" { + t.Errorf("Labels = %v, want [chore urgent]", task.Labels) + } +} + +func TestHandleWidgetLabelsColorSet_ThenGet_ReturnsIt(t *testing.T) { + s, cleanup := setupTestDB(t) + defer cleanup() + h := &Handler{store: s} + + body := `{"name":"chore","color":"#F59E0B"}` + setReq := httptest.NewRequest("POST", "/api/widget/labels/color", strings.NewReader(body)) + setW := httptest.NewRecorder() + http.HandlerFunc(h.HandleWidgetLabelsColorSet).ServeHTTP(setW, setReq) + if setW.Code != http.StatusOK { + t.Fatalf("expected 200, got %d: %s", setW.Code, setW.Body.String()) + } + + getReq := httptest.NewRequest("GET", "/api/widget/labels", nil) + getW := httptest.NewRecorder() + http.HandlerFunc(h.HandleWidgetLabelsGet).ServeHTTP(getW, getReq) + if getW.Code != http.StatusOK { + t.Fatalf("expected 200, got %d: %s", getW.Code, getW.Body.String()) + } + var colors []labelColorResponse + if err := json.NewDecoder(getW.Body).Decode(&colors); err != nil { + t.Fatalf("failed to decode response: %v", err) + } + if len(colors) != 1 || colors[0].Name != "chore" || colors[0].Color != "#F59E0B" { + t.Fatalf("colors = %+v, want [{chore #F59E0B}]", colors) + } +} + +func TestHandleWidgetTaskDetail_IncludesProjectAndLabels(t *testing.T) { + s, cleanup := setupTestDB(t) + defer cleanup() + h := &Handler{store: s} + project, err := s.CreateProject("Sailing prep", "#3B82F6") + if err != nil { + t.Fatal(err) + } + if _, err := s.DB().Exec(` + INSERT INTO native_tasks (id, content, project_id, labels) VALUES ('rec-1', 'Water plants', ?, '["chore"]') + `, project.ID); err != nil { + t.Fatal(err) + } + + req := httptest.NewRequest("GET", "/api/widget/task?id=rec-1&source=doot", nil) + w := httptest.NewRecorder() + http.HandlerFunc(h.HandleWidgetTaskDetail).ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String()) + } + var resp taskDetailResponse + if err := json.NewDecoder(w.Body).Decode(&resp); err != nil { + t.Fatalf("failed to decode response: %v", err) + } + if resp.Project == nil || resp.Project.ID != project.ID || resp.Project.Name != "Sailing prep" { + t.Fatalf("Project = %+v, want the created project", resp.Project) + } + if len(resp.Labels) != 1 || resp.Labels[0] != "chore" { + t.Errorf("Labels = %v, want [chore]", resp.Labels) + } +} + |
