client_recipe_validation_test.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: LicenseRef-MutuaL-1.2
  4
  5package cooked
  6
  7import (
  8	"context"
  9	"net/http"
 10	"strings"
 11	"testing"
 12)
 13
 14func TestListRecipesACIDAPIClientResponses1AcceptsEmptyRecipesList(t *testing.T) {
 15	client, closeServer := newTestClient(t, rawRecipeListTestHandler(
 16		t,
 17		"/api/user/returned-user/recipes",
 18		`[]`,
 19	))
 20	defer closeServer()
 21
 22	recipes, err := client.ListRecipes(context.Background(), 1, 10)
 23	if err != nil {
 24		t.Fatalf("ListRecipes() error = %v", err)
 25	}
 26	if len(recipes) != 0 {
 27		t.Fatalf("recipes length = %d, want 0", len(recipes))
 28	}
 29}
 30
 31func TestListRecipesACIDAPIClientResponses1RejectsNullRecipesList(t *testing.T) {
 32	client, closeServer := newTestClient(t, rawRecipeListTestHandler(
 33		t,
 34		"/api/user/returned-user/recipes",
 35		`null`,
 36	))
 37	defer closeServer()
 38
 39	_, err := client.ListRecipes(context.Background(), 1, 10)
 40	if err == nil {
 41		t.Fatal("ListRecipes() error = nil, want missing recipes error")
 42	}
 43}
 44
 45func TestSearchRecipesACIDAPIClientResponses1RejectsRecipeCardsWithoutIDOrTitle(t *testing.T) {
 46	tests := []struct {
 47		name string
 48		body string
 49	}{
 50		{name: "missing id", body: `[{"title":"Pasta"}]`},
 51		{name: "blank title", body: `[{"id":"recipe-1","title":"   "}]`},
 52	}
 53
 54	for _, tt := range tests {
 55		t.Run(tt.name, func(t *testing.T) {
 56			client, closeServer := newTestClient(t, rawRecipeListTestHandler(
 57				t,
 58				"/api/user/returned-user/recipes/search",
 59				tt.body,
 60			))
 61			defer closeServer()
 62
 63			_, err := client.SearchRecipes(context.Background(), "pasta", 1)
 64			if err == nil {
 65				t.Fatal("SearchRecipes() error = nil, want invalid recipe card error")
 66			}
 67		})
 68	}
 69}
 70
 71// api-client.RESPONSES.1 recipes.SAVE.7 recipes.SAVE.9
 72func TestSaveRecipeDraftACIDAPIClientResponses1RejectsMissingRecipeID(t *testing.T) {
 73	var saveCalls int
 74	client, closeServer := newTestClient(t, rawSaveRecipeDraftTestHandler(t, &saveCalls, `{}`))
 75	defer closeServer()
 76
 77	_, err := client.SaveRecipeDraft(
 78		context.Background(),
 79		"draft/with space",
 80		"# Pasta\n\n1. Boil pasta.",
 81		4,
 82	)
 83	if err == nil {
 84		t.Fatal("SaveRecipeDraft() error = nil, want missing recipe ID error")
 85	}
 86	if !strings.Contains(err.Error(), "missing recipe ID") {
 87		t.Fatalf("SaveRecipeDraft() error = %v, want missing recipe ID error", err)
 88	}
 89	if saveCalls != 1 {
 90		t.Fatalf("save calls = %d, want 1", saveCalls)
 91	}
 92}
 93
 94func rawRecipeListTestHandler(t *testing.T, path, body string) http.HandlerFunc {
 95	t.Helper()
 96
 97	return func(w http.ResponseWriter, r *http.Request) {
 98		switch r.URL.Path {
 99		case "/api/public/login":
100			writeLoginResponse(t, w)
101		case path:
102			w.Header().Set("Content-Type", "application/json")
103			if _, err := w.Write([]byte(body)); err != nil {
104				t.Fatalf("write raw recipe list response: %v", err)
105			}
106		default:
107			t.Fatalf("unexpected path %s", r.URL.Path)
108		}
109	}
110}
111
112func rawSaveRecipeDraftTestHandler(t *testing.T, saveCalls *int, body string) http.HandlerFunc {
113	t.Helper()
114
115	return func(w http.ResponseWriter, r *http.Request) {
116		switch r.URL.EscapedPath() {
117		case "/api/public/login":
118			writeLoginResponse(t, w)
119		case "/api/extract/draft%2Fwith%20space/save":
120			requireMethod(t, r, http.MethodPost, "save recipe draft")
121			requireSessionCookie(t, r)
122			requireRecipeContentRequest(t, r, "draft save")
123			(*saveCalls)++
124			w.Header().Set("Content-Type", "application/json")
125			if _, err := w.Write([]byte(body)); err != nil {
126				t.Fatalf("write raw save draft response: %v", err)
127			}
128		default:
129			t.Fatalf("unexpected path %s", r.URL.EscapedPath())
130		}
131	}
132}