Added testing for DateField, DateTimeField, and validators on the Model and ModelForm (#23)

* Added testing for DateField and DateTimeField

* Update makefile

* Adding some of the tests with validators on model

* Added ModelForm clean_field and clean tests

Co-authored-by: Thu Trang Pham <thu@joinmodernhealth.com>
This commit is contained in:
Thu Trang Pham
2021-03-31 12:46:02 -07:00
committed by GitHub
parent c88eb16a9b
commit 4d6b2900d8
16 changed files with 763 additions and 11 deletions
+21 -1
View File
@@ -32,7 +32,8 @@ These are some areas which might/probably have issues that are not currently tes
- [x] ManyToManyField
- [x] OneToOneField
- [x] ForeignKey
- [x] DateField
- [x] DateTimeField
- [x] Custom Readonly fields
### Options
@@ -104,3 +105,22 @@ Note: Currently the code always calls super().\_changeform_view(), which would e
- [x] ModelAdmin.has_add_permission
- [x] ModelAdmin.has_change_permission
### Tests for confirming models/forms with validations
- [x] ModelForm.clean_field
- [x] ModelForm.clean
- [x] Model.clean
- [x] validator on the model field
There are other possible combos of theses
### Tests where save functions are overridden
- [ ] ModelForm.save
- [ ] ModelAdmin.save_model
### Tests for storage backends for ImageField and FileField
- [x] Local storage
- [ ] S3
@@ -1,8 +1,10 @@
"""
Tests with different form input types
"""
from datetime import timedelta
from django.utils import timezone
from importlib import reload
from tests.factories import ShopFactory
from tests.factories import ShopFactory, TransactionFactory
from tests.market.models import GeneralManager, Item, ShoppingMall, Town
from admin_confirm.tests.helpers import AdminConfirmIntegrationTestCase
@@ -98,3 +100,37 @@ class ConfirmWithFormInputTypes(AdminConfirmIntegrationTestCase):
mall.refresh_from_db()
self.assertIn("New Name", mall.name)
self.assertEqual(gm2, mall.general_manager)
def test_datetime_and_field_should_work(self):
original_timestamp = timezone.now() - timedelta(hours=1)
transaction = TransactionFactory(timestamp=original_timestamp)
self.selenium.get(
self.live_server_url + f"/admin/market/transaction/{transaction.id}/change/"
)
self.assertIn(CONFIRM_CHANGE, self.selenium.page_source)
# Set date via text input
date_input = self.selenium.find_element(By.ID, "id_date")
date_input.clear()
date_input.send_keys("2021-01-01")
self.assertEqual(date_input.get_attribute("value"), "2021-01-01")
# Set timestamp via text input
timestamp_date = self.selenium.find_element(By.ID, "id_timestamp_0")
timestamp_date.clear()
timestamp_date.send_keys(str(timezone.now().date()))
timestamp_time = self.selenium.find_element(By.ID, "id_timestamp_1")
timestamp_time.clear()
timestamp_time.send_keys(str(timezone.now().time()))
# Click save and continue
self.selenium.find_element(By.NAME, "_continue").click()
# Click Yes I'm Sure on confirmation page
self.assertIn("Confirm", self.selenium.page_source)
self.selenium.find_element(By.NAME, "_continue").click()
transaction.refresh_from_db()
self.assertEqual(str(transaction.date), "2021-01-01")
self.assertTrue(transaction.timestamp > original_timestamp)
@@ -0,0 +1,109 @@
from django.urls import reverse
from django.utils import timezone
from admin_confirm.tests.helpers import AdminConfirmTestCase
from tests.market.models import Transaction
from tests.factories import ShopFactory, TransactionFactory
class TestModelFieldTypes(AdminConfirmTestCase):
def test_confirm_add_of_datetime_and_field(self):
shop = ShopFactory()
expected_date = timezone.now().date()
expected_timestamp = timezone.now()
data = {
"date": str(expected_date),
"timestamp_0": str(expected_timestamp.date()),
"timestamp_1": str(expected_timestamp.time()),
"currency": "USD",
"shop": shop.id,
"total": 0,
"_confirm_add": True,
"_save": True,
}
response = self.client.post(reverse("admin:market_transaction_add"), data)
# Should not have been added yet
self.assertEqual(Transaction.objects.count(), 0)
# Ensure not redirected (confirmation page does not redirect)
self.assertEqual(response.status_code, 200)
expected_templates = [
"admin/market/transaction/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_transaction_add"), data)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/admin/market/transaction/")
self.assertEqual(Transaction.objects.count(), 1)
# Ensure that the date and timestamp saved correctly
transaction = Transaction.objects.first()
self.assertEqual(transaction.date, expected_date)
self.assertEqual(transaction.timestamp, expected_timestamp)
def test_confirm_change_of_datetime_and_date_field(self):
transaction = TransactionFactory()
original_date = transaction.date
original_timestamp = transaction.timestamp
data = {
"id": transaction.id,
"date": "2021-01-01",
"timestamp_0": "2021-01-01",
"timestamp_1": "12:30:00",
"currency": "USD",
"shop": transaction.shop.id,
"total": 0,
"_confirm_change": True,
"csrfmiddlewaretoken": "fake token",
"_continue": True,
}
response = self.client.post(
f"/admin/market/transaction/{transaction.id}/change/", data
)
# Ensure not redirected (confirmation page does not redirect)
self.assertEqual(response.status_code, 200)
expected_templates = [
"admin/market/transaction/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, save_action="_continue"
)
# Hasn't changed item yet
transaction.refresh_from_db()
self.assertEqual(transaction.date, original_date)
self.assertEqual(transaction.timestamp, original_timestamp)
# Selecting to "Yes, I'm sure" on the confirmation page
# Would post to the same endpoint
del data["_confirm_change"]
response = self.client.post(
f"/admin/market/transaction/{transaction.id}/change/", data
)
# will show the change page for this transaction
self.assertEqual(response.status_code, 302)
self.assertEqual(
response.url, f"/admin/market/transaction/{transaction.id}/change/"
)
# Should not be the confirmation page, we already confirmed change
self.assertNotEqual(response.templates, expected_templates)
self.assertEqual(Transaction.objects.count(), 1)
transaction.refresh_from_db()
self.assertEqual(str(transaction.date), "2021-01-01")
self.assertEqual(str(transaction.timestamp.date()), "2021-01-01")
self.assertEqual(str(transaction.timestamp.time()), "12:30:00")
@@ -0,0 +1,334 @@
"""
Ensures that confirmations work with validators on the Model and on the Modelform.
"""
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 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)
# Should not have redirected, since there was an error
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.assertTrue("error" in str(response.content))
self.assertTrue("Invalid Currency" in str(response.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)
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)
# Should not have redirected, since there was an error
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.assertTrue("error" in str(response.content))
self.assertTrue(
"Shop does not have enough of the item stocked" in str(response.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)
# 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, 200)
self.assertEqual(Checkout.objects.count(), 0)
self.assertIn("error", str(response.content))
self.assertIn("Invalid Total 111", str(response.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)
# 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, 200)
self.assertEqual(Checkout.objects.count(), 0)
self.assertIn("error", str(response.content))
self.assertIn("Invalid Total 222", str(response.content))