diff --git a/tide/manifest.go b/tide/manifest.go index bcfc75c..db10b80 100644 --- a/tide/manifest.go +++ b/tide/manifest.go @@ -65,6 +65,7 @@ type RouteCase struct { Headers map[string]string `yaml:"headers,omitempty"` Fixture string `yaml:"fixture,omitempty"` Request *Request `yaml:"request,omitempty"` + Capture []CaptureRule `yaml:"capture,omitempty"` } // ManifestConfig drives recording or replay of a manifest. @@ -296,7 +297,7 @@ func RecordManifest(ctx context.Context, m Manifest, cfg ManifestConfig) (Covera break } } - if allRecorded { + if allRecorded && !cfg.Update { cov.markRecorded(route) continue } @@ -396,6 +397,7 @@ func recordRoute(ctx context.Context, route Route, cfg ManifestConfig) error { ID: c.ID, RouteID: route.ID, Request: caseRequest(route, c), + Capture: c.Capture, Normalize: route.Normalize, Headers: mergeHeaders(route.Headers, c.Headers), }}, diff --git a/tide/manifest_test.go b/tide/manifest_test.go index 7202f1e..6441328 100644 --- a/tide/manifest_test.go +++ b/tide/manifest_test.go @@ -9,6 +9,7 @@ import ( "net/http/httptest" "os" "path/filepath" + "strconv" "strings" "testing" ) @@ -406,3 +407,69 @@ func TestRecordSeedResolvesRelativeSpec(t *testing.T) { t.Fatalf("existing seed must not re-hit PHP: %d", hits) } } + +func TestRecordManifestUpdateRerecords(t *testing.T) { + fixtures := t.TempDir() + hits := 0 + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hits++ + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"n":` + strconv.Itoa(hits) + `}`)) + })) + t.Cleanup(srv.Close) + m := Manifest{ + Version: 1, + AuthGroups: []string{"public"}, + Routes: []Route{{ + ID: "GET /x public", Method: http.MethodGet, Path: "/x", + AuthGroup: "public", Status: StatusPending, + Cases: []RouteCase{{ + ID: "ok", Status: 200, Fixture: "routes/x.yaml", + Request: &Request{Method: http.MethodGet, Path: "/x"}, + }}, + }}, + } + if _, err := RecordManifest(context.Background(), m, ManifestConfig{Target: srv.URL, Fixtures: fixtures, Resume: true}); err != nil { + t.Fatal(err) + } + if _, err := RecordManifest(context.Background(), m, ManifestConfig{Target: srv.URL, Fixtures: fixtures, Resume: true, Update: true}); err != nil { + t.Fatal(err) + } + if hits != 2 { + t.Fatalf("update must recapture, hits=%d", hits) + } +} + +func TestRouteCaseCaptureUpdatesStore(t *testing.T) { + fixtures := t.TempDir() + vars := filepath.Join(t.TempDir(), "vars.yaml") + store, err := OpenStore(vars) + if err != nil { + t.Fatal(err) + } + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"data":{"token":"shareTokValue99"}}`)) + })) + t.Cleanup(srv.Close) + m := Manifest{ + Version: 1, + AuthGroups: []string{"public"}, + Routes: []Route{{ + ID: "POST /share public", Method: http.MethodPost, Path: "/share", + AuthGroup: "public", Status: StatusPending, + Cases: []RouteCase{{ + ID: "ok", Status: 200, Fixture: "routes/share.yaml", + Request: &Request{Method: http.MethodPost, Path: "/share"}, + Capture: []CaptureRule{{From: "response.json", Path: "$.data.token", As: "share:collection"}}, + }}, + }}, + } + if _, err := RecordManifest(context.Background(), m, ManifestConfig{Target: srv.URL, Fixtures: fixtures, Store: store}); err != nil { + t.Fatal(err) + } + got, ok := store.Get("share:collection") + if !ok || got != "shareTokValue99" { + t.Fatalf("capture: ok=%v val=%q", ok, got) + } +}