recipes: delete recipe client

Amolith created

Change summary

internal/cooked/client.go      |  7 +++++++
internal/cooked/client_test.go | 33 +++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+)

Detailed changes

internal/cooked/client.go 🔗

@@ -216,6 +216,13 @@ func (c *Client) UpdateRecipeContent(ctx context.Context, recipeID, markdown str
 	return c.doAuthenticated(ctx, http.MethodPost, path, body, nil)
 }
 
+// DeleteRecipe logs in when needed and deletes an existing recipe.
+func (c *Client) DeleteRecipe(ctx context.Context, recipeID string) error {
+	path := "/api/recipe/" + url.PathEscape(recipeID)
+
+	return c.doAuthenticated(ctx, http.MethodDelete, path, nil, nil)
+}
+
 func (c *Client) getRecipes(ctx context.Context, path string) ([]RecipeCard, error) {
 	var response recipeListResponse
 	decodeRecipes := func(decoder *json.Decoder) error {

internal/cooked/client_test.go 🔗

@@ -159,6 +159,21 @@ func TestUpdateRecipeContentACIDRecipesSave8And9And13UpdatesExistingRecipe(t *te
 	}
 }
 
+func TestDeleteRecipeDeletesSavedRecipe(t *testing.T) {
+	var deleteCalls int
+	client, closeServer := newTestClient(t, deleteRecipeTestHandler(t, &deleteCalls))
+	defer closeServer()
+
+	err := client.DeleteRecipe(context.Background(), "recipe/with space")
+	if err != nil {
+		t.Fatalf("DeleteRecipe() error = %v", err)
+	}
+
+	if deleteCalls != 1 {
+		t.Fatalf("delete calls = %d, want 1", deleteCalls)
+	}
+}
+
 func TestUserPathEscapesAuthenticatedUsername(t *testing.T) {
 	client := &Client{authenticatedUsername: "user/name"}
 
@@ -356,6 +371,24 @@ func updateRecipeContentTestHandler(t *testing.T, updateCalls *int) http.Handler
 	}
 }
 
+func deleteRecipeTestHandler(t *testing.T, deleteCalls *int) http.HandlerFunc {
+	t.Helper()
+
+	return func(w http.ResponseWriter, r *http.Request) {
+		switch r.URL.EscapedPath() {
+		case "/api/public/login":
+			writeLoginResponse(t, w)
+		case "/api/recipe/recipe%2Fwith%20space":
+			requireMethod(t, r, http.MethodDelete, "delete recipe")
+			requireSessionCookie(t, r)
+			(*deleteCalls)++
+			w.WriteHeader(http.StatusNoContent)
+		default:
+			t.Fatalf("unexpected path %s", r.URL.EscapedPath())
+		}
+	}
+}
+
 func requirePreviewRecipeTextRequest(t *testing.T, r *http.Request) {
 	t.Helper()