diff --git a/expenses_manager/expenses/tests/test_fuel.py b/expenses_manager/expenses/tests/test_fuel.py
index 72be9a4..c00a4e6 100644
--- a/expenses_manager/expenses/tests/test_fuel.py
+++ b/expenses_manager/expenses/tests/test_fuel.py
@@ -67,3 +67,165 @@ def test_fuel_delete_post_cascades_to_fuelentry(auth_client, user, account, cate
assert not Expense.objects.filter(pk=expense.pk).exists()
assert not FuelEntry.objects.filter(pk=entry.pk).exists()
+
+
+def _edit_payload(account, edit_date, amount, odometer, liters, next_url=None):
+ payload = {
+ "date": edit_date.strftime("%Y-%m-%d"),
+ "amount": str(amount),
+ "account": account.pk,
+ "odometer": str(odometer),
+ "liters": str(liters),
+ }
+ if next_url is not None:
+ payload["next"] = next_url
+ return payload
+
+
+def test_fuel_edit_post_updates_expense_and_fuelentry(auth_client, user, account, category):
+ entry = _make_fuel_entry(user, account, category, odometer=1000, liters=Decimal("20"), amount=Decimal("50"))
+ expense = entry.expense
+ new_date = date(2024, 3, 1)
+
+ response = auth_client.post(
+ reverse('fuel_edit', args=[expense.pk]),
+ _edit_payload(account, new_date, Decimal("45.50"), 1200, Decimal("22.5")),
+ )
+
+ assert response.status_code == 302
+
+ expense.refresh_from_db()
+ entry.refresh_from_db()
+
+ assert expense.amount == Decimal("45.50")
+ assert expense.date == new_date
+ assert expense.account_id == account.pk
+ assert entry.odometer == 1200
+ assert entry.liters == Decimal("22.5")
+
+
+def test_fuel_edit_invalid_post_returns_200_and_does_not_modify(auth_client, user, account, category):
+ entry = _make_fuel_entry(user, account, category, odometer=1000, liters=Decimal("20"), amount=Decimal("50"))
+ expense = entry.expense
+ original_date = expense.date
+
+ payload = _edit_payload(account, date(2024, 3, 1), Decimal("45.50"), 1200, Decimal("22.5"))
+ payload["liters"] = ""
+
+ response = auth_client.post(reverse('fuel_edit', args=[expense.pk]), payload)
+
+ assert response.status_code == 200
+
+ expense.refresh_from_db()
+ entry.refresh_from_db()
+
+ assert expense.amount == Decimal("50")
+ assert expense.date == original_date
+ assert entry.odometer == 1000
+ assert entry.liters == Decimal("20")
+
+
+def test_fuel_edit_redirects_to_next_when_relative(auth_client, user, account, category):
+ entry = _make_fuel_entry(user, account, category, odometer=1000, liters=Decimal("20"))
+ expense = entry.expense
+ next_url = reverse('expense_list')
+
+ response = auth_client.post(
+ reverse('fuel_edit', args=[expense.pk]),
+ _edit_payload(account, date(2024, 3, 1), Decimal("45.50"), 1200, Decimal("22.5"), next_url=next_url),
+ )
+
+ assert response.status_code == 302
+ assert response.url == next_url
+
+
+def test_fuel_edit_ignores_external_next(auth_client, user, account, category):
+ entry = _make_fuel_entry(user, account, category, odometer=1000, liters=Decimal("20"))
+ expense = entry.expense
+
+ response = auth_client.post(
+ reverse('fuel_edit', args=[expense.pk]),
+ _edit_payload(
+ account, date(2024, 3, 1), Decimal("45.50"), 1200, Decimal("22.5"),
+ next_url="https://evil.com",
+ ),
+ )
+
+ assert response.status_code == 302
+ assert response.url == reverse('expense_list')
+
+
+def test_fuel_delete_get_does_not_delete(auth_client, user, account, category):
+ entry = _make_fuel_entry(user, account, category, odometer=1000, liters=Decimal("20"))
+ expense = entry.expense
+
+ response = auth_client.get(reverse('fuel_delete', args=[expense.pk]))
+
+ assert response.status_code == 200
+ assert Expense.objects.filter(pk=expense.pk).exists()
+ assert FuelEntry.objects.filter(pk=entry.pk).exists()
+
+
+def test_fuel_delete_get_cancel_link_uses_next_when_provided(auth_client, user, account, category):
+ entry = _make_fuel_entry(user, account, category, odometer=1000, liters=Decimal("20"))
+ expense = entry.expense
+ next_url = reverse('expense_list')
+
+ response = auth_client.get(reverse('fuel_delete', args=[expense.pk]), {"next": next_url})
+
+ assert response.status_code == 200
+ assert f'Cancelar'.encode() in response.content
+
+
+def test_fuel_delete_get_cancel_link_falls_back_to_fuel_list_without_next(auth_client, user, account, category):
+ entry = _make_fuel_entry(user, account, category, odometer=1000, liters=Decimal("20"))
+ expense = entry.expense
+ fuel_list_url = reverse('fuel_list')
+
+ response = auth_client.get(reverse('fuel_delete', args=[expense.pk]))
+
+ assert response.status_code == 200
+ assert f'Cancelar'.encode() in response.content
+
+
+def test_fuel_delete_post_redirects_to_next_when_relative(auth_client, user, account, category):
+ entry = _make_fuel_entry(user, account, category, odometer=1000, liters=Decimal("20"))
+ expense = entry.expense
+ next_url = reverse('expense_list')
+
+ response = auth_client.post(reverse('fuel_delete', args=[expense.pk]), {"next": next_url})
+
+ assert response.status_code == 302
+ assert response.url == next_url
+
+
+def test_fuel_delete_post_ignores_external_next(auth_client, user, account, category):
+ entry = _make_fuel_entry(user, account, category, odometer=1000, liters=Decimal("20"))
+ expense = entry.expense
+
+ response = auth_client.post(reverse('fuel_delete', args=[expense.pk]), {"next": "https://evil.com"})
+
+ assert response.status_code == 302
+ assert response.url == reverse('fuel_list')
+
+
+def test_fuel_delete_get_ignores_unsafe_next_in_cancel_link(auth_client, user, account, category):
+ entry = _make_fuel_entry(user, account, category, odometer=1000, liters=Decimal("20"))
+ expense = entry.expense
+ fuel_list_url = reverse('fuel_list')
+
+ response = auth_client.get(reverse('fuel_delete', args=[expense.pk]), {"next": "javascript:alert(1)"})
+
+ assert response.status_code == 200
+ assert b"javascript:" not in response.content
+ assert f'Cancelar'.encode() in response.content
+
+
+def test_fuel_edit_get_ignores_unsafe_next_in_cancel_link(auth_client, user, account, category):
+ entry = _make_fuel_entry(user, account, category, odometer=1000, liters=Decimal("20"))
+ expense = entry.expense
+
+ response = auth_client.get(reverse('fuel_edit', args=[expense.pk]), {"next": "javascript:alert(1)"})
+
+ assert response.status_code == 200
+ assert b"javascript:" not in response.content