package tide_test import ( "context" "errors" "fmt" "net/http" "net/http/httptest" "os" "git.golem15.com/golem15/summercms/modules/tide" ) // backend stands in for one implementation of GET /api/blog/posts. func backend(body string) *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") fmt.Fprint(w, body) })) } func ExampleReplayFlow() { ctx := context.Background() // The reference (PHP) backend and two Go ports. IDs and *_at timestamps // legitimately differ; the second port changed a title. reference := backend(`{"data":[{"id":12,"title":"Hello","created_at":"2026-09-30T10:00:00+00:00"}]}`) defer reference.Close() port := backend(`{"data":[{"id":3,"title":"Hello","created_at":"2026-10-01T08:30:00+00:00"}]}`) defer port.Close() broken := backend(`{"data":[{"id":3,"title":"hello","created_at":"2026-10-01T08:30:00+00:00"}]}`) defer broken.Close() raw, err := os.ReadFile("testdata/docs/posts-spec.yaml") if err != nil { fmt.Println(err) return } spec, err := tide.ParseFlow(raw) if err != nil { fmt.Println(err) return } // Record the reference once; the flow is what testdata/parity keeps. flow, err := tide.RecordFlow(ctx, spec, tide.RecordConfig{Target: reference.URL}) if err != nil { fmt.Println(err) return } for _, target := range []string{port.URL, broken.URL} { res, err := tide.ReplayFlow(ctx, flow, tide.ReplayConfig{Target: target}) var mismatch *tide.MismatchError if errors.As(err, &mismatch) { res = mismatch.Result // a difference is an error carrying the result } else if err != nil { fmt.Println(err) return } fmt.Println("ok:", res.OK) for _, step := range res.Steps { for _, d := range step.Diffs { fmt.Printf(" %s %s: want %s, got %s\n", step.ID, d.Path, d.Expected, d.Actual) } } } // Output: // ok: true // ok: false // list-posts $.data[0].title: want "Hello", got "hello" }