From 235f4f47acb95260c87ba8cc365251f7309a4bb1 Mon Sep 17 00:00:00 2001 From: Ozoniuss Date: Wed, 7 Feb 2024 22:19:30 +0200 Subject: [PATCH] Delete an expense via the casheer client This change adds a method to the casheer client to allow deleting an expense, given an entry id. It also tests the functionality end to end. --- client/httpclient/calls/delete.go | 2 +- client/httpclient/expenses.go | 5 ++ e2e/expenses_test.go | 103 +++++++++++++++++++++--------- 3 files changed, 80 insertions(+), 30 deletions(-) diff --git a/client/httpclient/calls/delete.go b/client/httpclient/calls/delete.go index 3434ef1..016fd3f 100644 --- a/client/httpclient/calls/delete.go +++ b/client/httpclient/calls/delete.go @@ -8,6 +8,6 @@ import ( // MakeDELETE makes a simple DELETE request to the target url, and returns // either a typed response or an error response. -func MakeDELETE[T casheerapi.DeleteDebtResponse](client *http.Client, url string) (T, error) { +func MakeDELETE[T casheerapi.DeleteDebtResponse | casheerapi.DeleteExpenseResponse](client *http.Client, url string) (T, error) { return makeRequest[T]("DELETE", client, url, nil, nil) } diff --git a/client/httpclient/expenses.go b/client/httpclient/expenses.go index 9608913..fc42fbe 100644 --- a/client/httpclient/expenses.go +++ b/client/httpclient/expenses.go @@ -68,3 +68,8 @@ func (c *CasheerHTTPClient) CreateBasicExpenseWithoutId(category string, subcate } return c.CreateBasicExpense(entryId, name, description, paymentMethod, amount, currency) } + +func (c *CasheerHTTPClient) DeleteExpenseForEntry(entryId, expenseId int) (public.DeleteExpenseResponse, error) { + requestURL := c.entriesURL.JoinPath(strconv.Itoa(entryId), "expenses/", strconv.Itoa(expenseId)).String() + return calls.MakeDELETE[public.DeleteExpenseResponse](c.httpClient, requestURL) +} diff --git a/e2e/expenses_test.go b/e2e/expenses_test.go index 0fff503..88f5541 100644 --- a/e2e/expenses_test.go +++ b/e2e/expenses_test.go @@ -20,56 +20,101 @@ func setupEntry(t *testing.T) int { return id } -func Test_CreateBasicExpense_ExpenseIsCreated_and_ReturnedValuesAreCorrect(t *testing.T) { - - t.Cleanup(func() { - store.DeleteAllData(conn) - }) - entid := setupEntry(t) +type basicExpenseInfo struct { + name string + description string + paymentMethod string + amount int + currency string +} - var name = "expense 1" - var description = "description" - var paymentMethod = "card" - var amount = 1500 - var ccurrency = "RON" - expenseResponse, err := casheerClient.CreateBasicExpense(entid, name, description, paymentMethod, amount, ccurrency) - if err != nil { - t.Fatalf("Did not expect error when creating expense, but got error: %s\n", err.Error()) +func getDummyExpenseInfo() basicExpenseInfo { + return basicExpenseInfo{ + name: "name", + description: "description", + paymentMethod: "card", + amount: 1500, + currency: "RON", } +} - if expenseResponse.Data.Type != "expense" { - t.Errorf("Invalid return type, expected \"expense\" but got \"%s\"\n", expenseResponse.Data.Type) +func compareExpenseWithResponse(t *testing.T, expenseInfo basicExpenseInfo, responseData casheerapi.ExpenseData) { + if responseData.Type != "expense" { + t.Errorf("Invalid return type, expected \"expense\" but got \"%s\"\n", responseData.Type) } // Check attributes - if expenseResponse.Data.Attributes.Name != name { - t.Errorf("Expense name doesn't match; expected %s but got %s\n", name, expenseResponse.Data.Attributes.Name) + if responseData.Attributes.Name != expenseInfo.name { + t.Errorf("Expense name doesn't match; expected %s but got %s\n", expenseInfo.name, responseData.Attributes.Name) } - if expenseResponse.Data.Attributes.Description != description { - t.Errorf("Expense description doesn't match; expected %s but got %s\n", description, expenseResponse.Data.Attributes.Description) + if responseData.Attributes.Description != expenseInfo.description { + t.Errorf("Expense description doesn't match; expected %s but got %s\n", expenseInfo.description, responseData.Attributes.Description) } - if expenseResponse.Data.Attributes.PaymentMethod != paymentMethod { - t.Errorf("Expense payment method doesn't match; expected %s but got %s\n", paymentMethod, expenseResponse.Data.Attributes.PaymentMethod) + if responseData.Attributes.PaymentMethod != expenseInfo.paymentMethod { + t.Errorf("Expense payment method doesn't match; expected %s but got %s\n", expenseInfo.paymentMethod, responseData.Attributes.PaymentMethod) } - val := currency.NewRONValue(1500) - if expenseResponse.Data.Attributes.Value != (casheerapi.MonetaryValueAttributes{ + + val := currency.NewRONValue(expenseInfo.amount) + if responseData.Attributes.Value != (casheerapi.MonetaryValueAttributes{ Amount: val.Amount, Exponent: val.Exponent, Currency: val.Currency, }) { - t.Errorf("Expense value doesn't match; expected %v but got %v\n", expenseResponse.Data.Attributes.Value, casheerapi.MonetaryValueAttributes{ + t.Errorf("Expense value doesn't match; expected %v but got %v\n", responseData.Attributes.Value, casheerapi.MonetaryValueAttributes{ Amount: val.Amount, Exponent: val.Exponent, Currency: val.Currency, }) } +} - if !strings.Contains(expenseResponse.Data.Links.Self, fmt.Sprintf("%d/expenses/%s", entid, expenseResponse.Data.Id)) { - t.Errorf("Invalid related link format; got %s\n", expenseResponse.Data.Links.Self) +func checkExpenseLinks(t *testing.T, entid int, responseData casheerapi.ExpenseData) { + if !strings.Contains(responseData.Links.Self, fmt.Sprintf("%d/expenses/%s", entid, responseData.Id)) { + t.Errorf("Invalid related link format; got %s\n", responseData.Links.Self) } // Check related resources - if !strings.Contains(expenseResponse.Data.Relationships.Entries.Links.Related, strconv.Itoa(entid)) { - t.Errorf("Expected related link (%s) to include expense id (%d)\n", expenseResponse.Data.Relationships.Entries.Links.Related, entid) + if !strings.Contains(responseData.Relationships.Entries.Links.Related, strconv.Itoa(entid)) { + t.Errorf("Expected related link (%s) to include expense id (%d)\n", responseData.Relationships.Entries.Links.Related, entid) + } +} + +func Test_CreateBasicExpense_ExpenseIsCreated_and_ReturnedValuesAreCorrect(t *testing.T) { + + t.Cleanup(func() { + store.DeleteAllData(conn) + }) + entid := setupEntry(t) + + expenseInfo := getDummyExpenseInfo() + expenseResponse, err := casheerClient.CreateBasicExpense(entid, expenseInfo.name, expenseInfo.description, expenseInfo.paymentMethod, expenseInfo.amount, expenseInfo.currency) + if err != nil { + t.Fatalf("Did not expect error when creating expense, but got error: %s\n", err.Error()) + } + + compareExpenseWithResponse(t, expenseInfo, expenseResponse.Data) + checkExpenseLinks(t, entid, expenseResponse.Data) +} + +func Test_DeleteExpense_ExistingExpenseIsDeleted(t *testing.T) { + + t.Cleanup(func() { + store.DeleteAllData(conn) + }) + entid := setupEntry(t) + + expenseInfo := getDummyExpenseInfo() + expenseResponseCreate, err := casheerClient.CreateBasicExpense(entid, expenseInfo.name, expenseInfo.description, expenseInfo.paymentMethod, expenseInfo.amount, expenseInfo.currency) + if err != nil { + t.Fatalf("Did not expect error when creating expense, but got error: %s\n", err.Error()) } + + expid, _ := strconv.Atoi(expenseResponseCreate.Data.Id) + expenseResponseDelete, err := casheerClient.DeleteExpenseForEntry(entid, expid) + if err != nil { + t.Fatalf("Did not expect error when deleting existing expense, but got error: %s\n", err.Error()) + } + // Do not check links because a deleted expense should not have links. + compareExpenseWithResponse(t, expenseInfo, expenseResponseDelete.Data) + }