package domain import ( "errors" "testing" ) func TestVerifySpec_Validate(t *testing.T) { tests := []struct { name string spec VerifySpec wantErr error }{ { name: "valid spec with URL only", spec: VerifySpec{URL: "https://example.com"}, wantErr: nil, }, { name: "valid spec with all fields", spec: VerifySpec{ URL: "https://example.com/page", Viewports: []string{"1920x1080", "375x667"}, WaitFor: "#main", WaitTimeout: 5000, FullPage: true, Video: true, CallbackURL: "https://webhook.example.com/notify", }, wantErr: nil, }, { name: "empty URL", spec: VerifySpec{}, wantErr: ErrVerifyURLRequired, }, { name: "invalid URL scheme", spec: VerifySpec{URL: "ftp://example.com"}, wantErr: nil, // Validate will fail but not return ErrVerifyURLRequired }, { name: "invalid callback URL scheme", spec: VerifySpec{URL: "https://example.com", CallbackURL: "ftp://webhook.com"}, wantErr: nil, // Validate will fail but not return ErrVerifyURLRequired }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.spec.Validate() if tt.wantErr != nil { if !errors.Is(err, tt.wantErr) { t.Errorf("Validate() error = %v, want %v", err, tt.wantErr) } } else if tt.name == "invalid URL scheme" || tt.name == "invalid callback URL scheme" { // These should fail with a different error if err == nil { t.Errorf("Validate() expected error for %s", tt.name) } } else if err != nil { t.Errorf("Validate() unexpected error = %v", err) } }) } } func TestVerifySpec_WithDefaults(t *testing.T) { t.Run("applies defaults to empty spec", func(t *testing.T) { spec := &VerifySpec{URL: "https://example.com"} result := spec.WithDefaults() if len(result.Viewports) != 3 { t.Errorf("expected 3 default viewports, got %d", len(result.Viewports)) } if result.Viewports[0] != "1920x1080" { t.Errorf("expected first viewport '1920x1080', got %q", result.Viewports[0]) } if result.WaitFor != "body" { t.Errorf("expected WaitFor 'body', got %q", result.WaitFor) } if result.WaitTimeout != 10000 { t.Errorf("expected WaitTimeout 10000, got %d", result.WaitTimeout) } }) t.Run("preserves existing values", func(t *testing.T) { spec := &VerifySpec{ URL: "https://example.com", Viewports: []string{"800x600"}, WaitFor: "#app", WaitTimeout: 5000, } result := spec.WithDefaults() if len(result.Viewports) != 1 || result.Viewports[0] != "800x600" { t.Errorf("expected preserved viewports, got %v", result.Viewports) } if result.WaitFor != "#app" { t.Errorf("expected preserved WaitFor, got %q", result.WaitFor) } if result.WaitTimeout != 5000 { t.Errorf("expected preserved WaitTimeout, got %d", result.WaitTimeout) } }) t.Run("does not modify original", func(t *testing.T) { spec := &VerifySpec{URL: "https://example.com"} _ = spec.WithDefaults() if len(spec.Viewports) != 0 { t.Error("original spec should not be modified") } }) } func TestVerifyResult_ToWorkResult(t *testing.T) { t.Run("success with screenshots", func(t *testing.T) { result := &VerifyResult{ Success: true, Screenshots: map[string]string{ "1920x1080": "/captures/task-1/1920_1080.png", "375x667": "/captures/task-1/375_667.png", }, DurationMs: 1500, } wr := result.ToWorkResult() if wr.Output != "" { t.Errorf("expected empty output on success, got %q", wr.Output) } if wr.Artifacts["screenshot_1920x1080"] != "/captures/task-1/1920_1080.png" { t.Errorf("screenshot_1920x1080 = %q", wr.Artifacts["screenshot_1920x1080"]) } if wr.Artifacts["screenshot_375x667"] != "/captures/task-1/375_667.png" { t.Errorf("screenshot_375x667 = %q", wr.Artifacts["screenshot_375x667"]) } if wr.Artifacts["duration_ms"] != "1500" { t.Errorf("duration_ms = %q", wr.Artifacts["duration_ms"]) } }) t.Run("success with video", func(t *testing.T) { result := &VerifyResult{ Success: true, Screenshots: map[string]string{"1920x1080": "/captures/task-1/1920_1080.png"}, Video: "/captures/task-1/recording.webm", DurationMs: 2000, } wr := result.ToWorkResult() if wr.Artifacts["video"] != "/captures/task-1/recording.webm" { t.Errorf("video = %q", wr.Artifacts["video"]) } }) t.Run("failure uses error as output", func(t *testing.T) { result := &VerifyResult{ Success: false, Error: "capture failed: timeout", } wr := result.ToWorkResult() if wr.Output != "capture failed: timeout" { t.Errorf("Output = %q, want error message", wr.Output) } }) t.Run("nil receiver returns empty result", func(t *testing.T) { var result *VerifyResult wr := result.ToWorkResult() if wr.Output != "" { t.Errorf("Output = %q, want empty", wr.Output) } if wr.Artifacts != nil { t.Errorf("Artifacts = %v, want nil", wr.Artifacts) } }) t.Run("evaluation results included", func(t *testing.T) { result := &VerifyResult{ Success: true, Evaluation: "Page renders correctly with all elements visible", Score: 85, Passed: true, DurationMs: 1000, } wr := result.ToWorkResult() if wr.Artifacts["evaluation"] != "Page renders correctly with all elements visible" { t.Errorf("evaluation = %q", wr.Artifacts["evaluation"]) } if wr.Artifacts["score"] != "85" { t.Errorf("score = %q", wr.Artifacts["score"]) } if wr.Artifacts["passed"] != "true" { t.Errorf("passed = %q", wr.Artifacts["passed"]) } }) } func TestVerifyResult_ToBuildResult(t *testing.T) { t.Run("success conversion", func(t *testing.T) { result := &VerifyResult{ Success: true, Screenshots: map[string]string{ "1920x1080": "/captures/task-1/1920_1080.png", }, Video: "/captures/task-1/recording.webm", DurationMs: 1500, } br := result.ToBuildResult() if !br.Success { t.Error("expected success = true") } if br.DurationMs != 1500 { t.Errorf("DurationMs = %d, want 1500", br.DurationMs) } if br.Artifacts["screenshot_1920x1080"] != "/captures/task-1/1920_1080.png" { t.Errorf("screenshot artifact missing") } if br.Artifacts["video"] != "/captures/task-1/recording.webm" { t.Errorf("video artifact missing") } }) t.Run("failure conversion", func(t *testing.T) { result := &VerifyResult{ Success: false, Error: "capture failed", DurationMs: 500, } br := result.ToBuildResult() if br.Success { t.Error("expected success = false") } if br.Error != "capture failed" { t.Errorf("Error = %q", br.Error) } }) t.Run("nil receiver returns empty", func(t *testing.T) { var result *VerifyResult br := result.ToBuildResult() if br.Success { t.Error("expected success = false for nil") } }) } func TestDefaultViewports(t *testing.T) { viewports := DefaultViewports() if len(viewports) != 3 { t.Fatalf("expected 3 viewports, got %d", len(viewports)) } expected := []string{"1920x1080", "768x1024", "375x667"} for i, vp := range expected { if viewports[i] != vp { t.Errorf("viewport[%d] = %q, want %q", i, viewports[i], vp) } } }