diff --git a/internal/cooked/client.go b/internal/cooked/client.go index 2cbb5af4eaa37bba440912d6990e16ce201d8efc..d8fd1f0f6a7d39496a339ac3a7388da7dd05a019 100644 --- a/internal/cooked/client.go +++ b/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 { diff --git a/internal/cooked/client_test.go b/internal/cooked/client_test.go index d5e65754b171db5abbdbf55fbfb4c155bcc8c688..3aa655ba16963a3151088a18f4332141161e49b9 100644 --- a/internal/cooked/client_test.go +++ b/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()