django-admin-confirm-briq/admin_confirm/tests/unit/test_with_validators.py

312 lines
12 KiB
Python

"""
Ensures that confirmations work with validators on the Model and on the Modelform.
NOTE: These unit tests are not enough to ensure that confirmations work with validators.
Please ensure to add integration tests too!
"""
from admin_confirm.constants import CONFIRM_ADD
from unittest import mock
from django.urls import reverse
from django.utils import timezone
from admin_confirm.tests.helpers import AdminConfirmTestCase
from tests.market.models import Checkout, ItemSale
from tests.factories import (
InventoryFactory,
ItemFactory,
ShopFactory,
TransactionFactory,
)
class TestWithValidators(AdminConfirmTestCase):
@mock.patch("tests.market.models.ItemSale.clean")
def test_can_confirm_for_models_with_validator_on_model_field(self, _mock_clean):
# ItemSale.currency has a validator on it
item = ItemFactory()
transaction = TransactionFactory()
data = {
"transaction": transaction.id,
"item": item.id,
"quantity": 1,
"currency": "USD",
"total": 10.00,
"_confirm_add": True,
"_save": True,
}
response = self.client.post(reverse("admin:market_itemsale_add"), data)
# Should not have been added yet
self.assertEqual(ItemSale.objects.count(), 0)
# Ensure not redirected (confirmation page does not redirect)
self.assertEqual(response.status_code, 200)
expected_templates = [
"admin/market/itemsale/change_confirmation.html",
"admin/market/change_confirmation.html",
"admin/change_confirmation.html",
]
self.assertEqual(response.template_name, expected_templates)
self._assertSubmitHtml(rendered_content=response.rendered_content)
# Confirmation page would not have the _confirm_add sent on submit
del data["_confirm_add"]
# Selecting to "Yes, I'm sure" on the confirmation page
# Would post to the same endpoint
response = self.client.post(reverse("admin:market_itemsale_add"), data)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/admin/market/itemsale/")
self.assertEqual(ItemSale.objects.count(), 1)
# Ensure that the date and timestamp saved correctly
item_sale = ItemSale.objects.first()
self.assertEqual(item_sale.transaction, transaction)
self.assertEqual(item_sale.item, item)
self.assertEqual(item_sale.currency, "USD")
def test_cannot_confirm_for_models_with_validator_on_model_field_if_validator_fails(
self,
):
# ItemSale.currency has a validator on it
shop = ShopFactory()
item = ItemFactory()
InventoryFactory(shop=shop, item=item, quantity=10)
transaction = TransactionFactory(shop=shop)
data = {
"transaction": transaction.id,
"item": item.id,
"quantity": 1,
"currency": "FAKE",
"total": 10.00,
"_confirm_add": True,
"_save": True,
}
response = self.client.post(reverse("admin:market_itemsale_add"), data)
# Should show form with error and not confirmation page
self.assertEqual(response.status_code, 200)
expected_templates = [
"admin/market/itemsale/change_form.html",
"admin/market/change_form.html",
"admin/change_form.html",
]
self.assertEqual(response.template_name, expected_templates)
self.assertEqual(ItemSale.objects.count(), 0)
self.assertIn("error", str(response.rendered_content))
self.assertIn("Invalid Currency", str(response.rendered_content))
# Should still ask for confirmation
self.assertIn(CONFIRM_ADD, response.rendered_content)
def test_can_confirm_for_models_with_clean_overridden(self):
shop = ShopFactory()
item = ItemFactory()
InventoryFactory(shop=shop, item=item, quantity=10)
transaction = TransactionFactory(shop=shop)
data = {
"transaction": transaction.id,
"item": item.id,
"quantity": 9,
"currency": "USD",
"total": 10.00,
"_confirm_add": True,
"_save": True,
}
response = self.client.post(reverse("admin:market_itemsale_add"), data)
# Should not have been added yet
self.assertEqual(ItemSale.objects.count(), 0)
# Ensure not redirected (confirmation page does not redirect)
self.assertEqual(response.status_code, 200)
expected_templates = [
"admin/market/itemsale/change_confirmation.html",
"admin/market/change_confirmation.html",
"admin/change_confirmation.html",
]
self.assertEqual(response.template_name, expected_templates)
self._assertSubmitHtml(rendered_content=response.rendered_content)
# Confirmation page would not have the _confirm_add sent on submit
del data["_confirm_add"]
# Selecting to "Yes, I'm sure" on the confirmation page
# Would post to the same endpoint
response = self.client.post(reverse("admin:market_itemsale_add"), data)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/admin/market/itemsale/")
self.assertEqual(ItemSale.objects.count(), 1)
# Ensure that the date and timestamp saved correctly
item_sale = ItemSale.objects.first()
self.assertEqual(item_sale.transaction, transaction)
self.assertEqual(item_sale.item, item)
self.assertEqual(item_sale.currency, "USD")
def test_cannot_confirm_for_models_with_clean_overridden_if_clean_fails(self):
shop = ShopFactory()
item = ItemFactory()
InventoryFactory(shop=shop, item=item, quantity=1)
transaction = TransactionFactory(shop=shop)
# Asking to buy more than the shop has in stock
data = {
"transaction": transaction.id,
"item": item.id,
"quantity": 9,
"currency": "USD",
"total": 10.00,
"_confirm_add": True,
"_save": True,
}
response = self.client.post(reverse("admin:market_itemsale_add"), data)
# Should not have been added yet
self.assertEqual(ItemSale.objects.count(), 0)
# Ensure it shows the form and not the confirmation page
self.assertEqual(response.status_code, 200)
expected_templates = [
"admin/market/itemsale/change_form.html",
"admin/market/change_form.html",
"admin/change_form.html",
]
self.assertEqual(response.template_name, expected_templates)
self.assertTrue("error" in str(response.content))
self.assertTrue(
"Shop does not have enough of the item stocked" in str(response.content)
)
# Should still be asking for confirmation
self.assertIn(CONFIRM_ADD, response.rendered_content)
# Fix the issue by buying only what shop has in stock
data["quantity"] = 1
# _confirm_add would still be in the POST data
response = self.client.post(reverse("admin:market_itemsale_add"), data)
# Should show confirmation page
# Ensure not redirected (confirmation page does not redirect)
self.assertEqual(response.status_code, 200)
expected_templates = [
"admin/market/itemsale/change_confirmation.html",
"admin/market/change_confirmation.html",
"admin/change_confirmation.html",
]
self.assertEqual(response.template_name, expected_templates)
self._assertSubmitHtml(rendered_content=response.rendered_content)
def test_can_confirm_for_modelform_with_clean_field_and_clean_overridden(self):
shop = ShopFactory()
data = {
"shop": shop.id,
"currency": "USD",
"total": 10.00,
"date": str(timezone.now().date()),
"timestamp_0": str(timezone.now().date()),
"timestamp_1": str(timezone.now().time()),
"_confirm_add": True,
"_save": True,
}
response = self.client.post(reverse("admin:market_checkout_add"), data)
# Should not have been added yet
self.assertEqual(Checkout.objects.count(), 0)
# Ensure not redirected (confirmation page does not redirect)
self.assertEqual(response.status_code, 200)
expected_templates = [
"admin/market/checkout/change_confirmation.html",
"admin/market/change_confirmation.html",
"admin/change_confirmation.html",
]
self.assertEqual(response.template_name, expected_templates)
self._assertSubmitHtml(rendered_content=response.rendered_content)
# Confirmation page would not have the _confirm_add sent on submit
del data["_confirm_add"]
# Selecting to "Yes, I'm sure" on the confirmation page
# Would post to the same endpoint
response = self.client.post(reverse("admin:market_checkout_add"), data)
print(response.content)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/admin/market/checkout/")
self.assertEqual(Checkout.objects.count(), 1)
# Ensure that the date and timestamp saved correctly
checkout = Checkout.objects.first()
self.assertEqual(checkout.shop, shop)
self.assertEqual(checkout.total, 10.00)
self.assertEqual(checkout.currency, "USD")
def test_cannot_confirm_for_modelform_with_clean_field_overridden_if_validation_fails(
self,
):
shop = ShopFactory()
data = {
"shop": shop.id,
"currency": "USD",
"total": "111",
"date": str(timezone.now().date()),
"timestamp_0": str(timezone.now().date()),
"timestamp_1": str(timezone.now().time()),
"_confirm_add": True,
"_save": True,
}
response = self.client.post(reverse("admin:market_checkout_add"), data)
# Should not have been added yet
self.assertEqual(Checkout.objects.count(), 0)
# Should show form with error and not confirmation page
self.assertEqual(response.status_code, 200)
expected_templates = [
"admin/market/checkout/change_form.html",
"admin/market/change_form.html",
"admin/change_form.html",
]
self.assertEqual(response.template_name, expected_templates)
self.assertEqual(Checkout.objects.count(), 0)
self.assertIn("error", str(response.rendered_content))
self.assertIn("Invalid Total 111", str(response.rendered_content))
# Should still ask for confirmation
self.assertIn(CONFIRM_ADD, response.rendered_content)
def test_cannot_confirm_for_modelform_with_clean_overridden_if_validation_fails(
self,
):
shop = ShopFactory()
data = {
"shop": shop.id,
"currency": "USD",
"total": "222",
"date": str(timezone.now().date()),
"timestamp_0": str(timezone.now().date()),
"timestamp_1": str(timezone.now().time()),
"_confirm_add": True,
"_save": True,
}
response = self.client.post(reverse("admin:market_checkout_add"), data)
# Should not have been added yet
self.assertEqual(Checkout.objects.count(), 0)
# Should not have been added yet
self.assertEqual(Checkout.objects.count(), 0)
# Should show form with error and not confirmation page
self.assertEqual(response.status_code, 200)
expected_templates = [
"admin/market/checkout/change_form.html",
"admin/market/change_form.html",
"admin/change_form.html",
]
self.assertEqual(response.template_name, expected_templates)
self.assertEqual(Checkout.objects.count(), 0)
self.assertIn("error", str(response.rendered_content))
self.assertIn("Invalid Total 222", str(response.rendered_content))
# Should still ask for confirmation
self.assertIn(CONFIRM_ADD, response.rendered_content)