summaryrefslogtreecommitdiff
path: root/internal/api/stories_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/api/stories_test.go')
-rw-r--r--internal/api/stories_test.go84
1 files changed, 84 insertions, 0 deletions
diff --git a/internal/api/stories_test.go b/internal/api/stories_test.go
index 8516ade..cf522e1 100644
--- a/internal/api/stories_test.go
+++ b/internal/api/stories_test.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
+ "strings"
"testing"
"github.com/thepeterstone/claudomator/internal/task"
@@ -118,3 +119,86 @@ func TestAddTaskToStory_AutoWiresDependsOn(t *testing.T) {
t.Errorf("task3.DependsOn: want [%s], got %v", task2.ID, task3.DependsOn)
}
}
+
+func TestBuildStoryElaboratePrompt(t *testing.T) {
+ prompt := buildStoryElaboratePrompt()
+ checks := []struct {
+ label string
+ want string
+ }{
+ {"schema: name field", `"name"`},
+ {"schema: branch_name field", `"branch_name"`},
+ {"schema: tasks field", `"tasks"`},
+ {"schema: validation field", `"validation"`},
+ {"rule: git push", "git push origin"},
+ {"rule: sequential subtasks", "sequentially"},
+ {"rule: specific file paths", "file paths"},
+ }
+ for _, c := range checks {
+ if !strings.Contains(prompt, c.want) {
+ t.Errorf("%s: prompt should contain %q", c.label, c.want)
+ }
+ }
+}
+
+func TestHandleStoryApprove_WiresDepends(t *testing.T) {
+ srv, _ := testServer(t)
+
+ body := `{
+ "name": "My Story",
+ "branch_name": "story/my-story",
+ "tasks": [
+ {"name": "Task 1", "instructions": "do task 1", "subtasks": []},
+ {"name": "Task 2", "instructions": "do task 2", "subtasks": []},
+ {"name": "Task 3", "instructions": "do task 3", "subtasks": []}
+ ],
+ "validation": {"type": "build", "steps": ["go build ./..."], "success_criteria": "compiles"}
+ }`
+ req := httptest.NewRequest("POST", "/api/stories/approve", bytes.NewBufferString(body))
+ req.Header.Set("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ srv.mux.ServeHTTP(w, req)
+
+ if w.Code != http.StatusCreated {
+ t.Fatalf("expected 201, got %d: %s", w.Code, w.Body.String())
+ }
+
+ var resp struct {
+ Story task.Story `json:"story"`
+ TaskIDs []string `json:"task_ids"`
+ }
+ if err := json.NewDecoder(w.Body).Decode(&resp); err != nil {
+ t.Fatalf("decode response: %v", err)
+ }
+ if len(resp.TaskIDs) != 3 {
+ t.Fatalf("expected 3 task IDs, got %d", len(resp.TaskIDs))
+ }
+ if resp.Story.Name != "My Story" {
+ t.Errorf("story name: want 'My Story', got %q", resp.Story.Name)
+ }
+
+ // Verify depends_on chain via the store.
+ store := srv.store
+ task1, err := store.GetTask(resp.TaskIDs[0])
+ if err != nil {
+ t.Fatalf("GetTask[0]: %v", err)
+ }
+ task2, err := store.GetTask(resp.TaskIDs[1])
+ if err != nil {
+ t.Fatalf("GetTask[1]: %v", err)
+ }
+ task3, err := store.GetTask(resp.TaskIDs[2])
+ if err != nil {
+ t.Fatalf("GetTask[2]: %v", err)
+ }
+
+ if len(task1.DependsOn) != 0 {
+ t.Errorf("task1.DependsOn: want [], got %v", task1.DependsOn)
+ }
+ if len(task2.DependsOn) != 1 || task2.DependsOn[0] != task1.ID {
+ t.Errorf("task2.DependsOn: want [%s], got %v", task1.ID, task2.DependsOn)
+ }
+ if len(task3.DependsOn) != 1 || task3.DependsOn[0] != task2.ID {
+ t.Errorf("task3.DependsOn: want [%s], got %v", task2.ID, task3.DependsOn)
+ }
+}