summaryrefslogtreecommitdiff
path: root/tests/admin_inlines
diff options
context:
space:
mode:
authorCarlton Gibson <carlton.gibson@noumenal.es>2019-10-24 16:37:55 +0200
committerCarlton Gibson <carlton@noumenal.es>2019-10-25 13:28:08 +0200
commit24e540fbd71bd2b0843e751bde61ad0052a811b3 (patch)
tree0ad75be6f7adb7cc0eedb83af2dacd8a252455c1 /tests/admin_inlines
parent6ea3aadd17f937e69d121e3ae1a415a435e3267d (diff)
downloaddjango-24e540fbd71bd2b0843e751bde61ad0052a811b3.tar.gz
Fixed #29087 -- Added delete buttons for unsaved admin inlines on validation error.
Diffstat (limited to 'tests/admin_inlines')
-rw-r--r--tests/admin_inlines/models.py10
-rw-r--r--tests/admin_inlines/tests.py94
2 files changed, 103 insertions, 1 deletions
diff --git a/tests/admin_inlines/models.py b/tests/admin_inlines/models.py
index a42e2588e9..1a705c55c7 100644
--- a/tests/admin_inlines/models.py
+++ b/tests/admin_inlines/models.py
@@ -110,11 +110,21 @@ class Inner4Stacked(models.Model):
dummy = models.IntegerField(help_text="Awesome stacked help text is awesome.")
holder = models.ForeignKey(Holder4, models.CASCADE)
+ class Meta:
+ constraints = [
+ models.UniqueConstraint(fields=['dummy', 'holder'], name='unique_stacked_dummy_per_holder')
+ ]
+
class Inner4Tabular(models.Model):
dummy = models.IntegerField(help_text="Awesome tabular help text is awesome.")
holder = models.ForeignKey(Holder4, models.CASCADE)
+ class Meta:
+ constraints = [
+ models.UniqueConstraint(fields=['dummy', 'holder'], name='unique_tabular_dummy_per_holder')
+ ]
+
# Models for #12749
diff --git a/tests/admin_inlines/tests.py b/tests/admin_inlines/tests.py
index fe0d913b0d..a43c43560f 100644
--- a/tests/admin_inlines/tests.py
+++ b/tests/admin_inlines/tests.py
@@ -145,7 +145,7 @@ class TestInline(TestDataMixin, TestCase):
# Here colspan is "4": two fields (title1 and title2), one hidden field and the delete checkbox.
self.assertContains(
response,
- '<tr><td colspan="4"><ul class="errorlist nonfield">'
+ '<tr class="row-form-errors"><td colspan="4"><ul class="errorlist nonfield">'
'<li>The two titles must be the same</li></ul></td></tr>'
)
@@ -907,8 +907,100 @@ class SeleniumTests(AdminSeleniumTestCase):
self.assertEqual(rows_length(), 5, msg="sanity check")
for delete_link in self.selenium.find_elements_by_css_selector('%s .inline-deletelink' % inline_id):
delete_link.click()
+ with self.disable_implicit_wait():
+ self.assertEqual(rows_length(), 0)
+
+ def test_delete_invalid_stacked_inlines(self):
+ from selenium.common.exceptions import NoSuchElementException
+ self.admin_login(username='super', password='secret')
+ self.selenium.get(self.live_server_url + reverse('admin:admin_inlines_holder4_add'))
+
+ inline_id = '#inner4stacked_set-group'
+
+ def rows_length():
+ return len(self.selenium.find_elements_by_css_selector('%s .dynamic-inner4stacked_set' % inline_id))
self.assertEqual(rows_length(), 3)
+ add_button = self.selenium.find_element_by_link_text(
+ 'Add another Inner4 stacked')
+ add_button.click()
+ add_button.click()
+ self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_inner4stacked_set-4-dummy')), 1)
+
+ # Enter some data and click 'Save'.
+ self.selenium.find_element_by_name('dummy').send_keys('1')
+ self.selenium.find_element_by_name('inner4stacked_set-0-dummy').send_keys('100')
+ self.selenium.find_element_by_name('inner4stacked_set-1-dummy').send_keys('101')
+ self.selenium.find_element_by_name('inner4stacked_set-2-dummy').send_keys('222')
+ self.selenium.find_element_by_name('inner4stacked_set-3-dummy').send_keys('103')
+ self.selenium.find_element_by_name('inner4stacked_set-4-dummy').send_keys('222')
+ self.selenium.find_element_by_xpath('//input[@value="Save"]').click()
+ self.wait_page_loaded()
+
+ self.assertEqual(rows_length(), 5, msg="sanity check")
+ errorlist = self.selenium.find_element_by_css_selector(
+ '%s .dynamic-inner4stacked_set .errorlist li' % inline_id
+ )
+ self.assertEqual('Please correct the duplicate values below.', errorlist.text)
+ delete_link = self.selenium.find_element_by_css_selector('#inner4stacked_set-4 .inline-deletelink')
+ delete_link.click()
+ self.assertEqual(rows_length(), 4)
+ with self.disable_implicit_wait(), self.assertRaises(NoSuchElementException):
+ self.selenium.find_element_by_css_selector('%s .dynamic-inner4stacked_set .errorlist li' % inline_id)
+
+ self.selenium.find_element_by_xpath('//input[@value="Save"]').click()
+ self.wait_page_loaded()
+
+ # The objects have been created in the database.
+ self.assertEqual(Inner4Stacked.objects.all().count(), 4)
+
+ def test_delete_invalid_tabular_inlines(self):
+ from selenium.common.exceptions import NoSuchElementException
+ self.admin_login(username='super', password='secret')
+ self.selenium.get(self.live_server_url + reverse('admin:admin_inlines_holder4_add'))
+
+ inline_id = '#inner4tabular_set-group'
+
+ def rows_length():
+ return len(self.selenium.find_elements_by_css_selector('%s .dynamic-inner4tabular_set' % inline_id))
+ self.assertEqual(rows_length(), 3)
+
+ add_button = self.selenium.find_element_by_link_text(
+ 'Add another Inner4 tabular')
+ add_button.click()
+ add_button.click()
+ self.assertEqual(len(self.selenium.find_elements_by_css_selector('#id_inner4tabular_set-4-dummy')), 1)
+
+ # Enter some data and click 'Save'.
+ self.selenium.find_element_by_name('dummy').send_keys('1')
+ self.selenium.find_element_by_name('inner4tabular_set-0-dummy').send_keys('100')
+ self.selenium.find_element_by_name('inner4tabular_set-1-dummy').send_keys('101')
+ self.selenium.find_element_by_name('inner4tabular_set-2-dummy').send_keys('222')
+ self.selenium.find_element_by_name('inner4tabular_set-3-dummy').send_keys('103')
+ self.selenium.find_element_by_name('inner4tabular_set-4-dummy').send_keys('222')
+ self.selenium.find_element_by_xpath('//input[@value="Save"]').click()
+ self.wait_page_loaded()
+
+ self.assertEqual(rows_length(), 5, msg="sanity check")
+
+ # Non-field errorlist is in its own <tr> just before
+ # tr#inner4tabular_set-3:
+ errorlist = self.selenium.find_element_by_css_selector(
+ '%s #inner4tabular_set-3 + .row-form-errors .errorlist li' % inline_id
+ )
+ self.assertEqual('Please correct the duplicate values below.', errorlist.text)
+ delete_link = self.selenium.find_element_by_css_selector('#inner4tabular_set-4 .inline-deletelink')
+ delete_link.click()
+ self.assertEqual(rows_length(), 4)
+ with self.disable_implicit_wait(), self.assertRaises(NoSuchElementException):
+ self.selenium.find_element_by_css_selector('%s .dynamic-inner4tabular_set .errorlist li' % inline_id)
+
+ self.selenium.find_element_by_xpath('//input[@value="Save"]').click()
+ self.wait_page_loaded()
+
+ # The objects have been created in the database.
+ self.assertEqual(Inner4Tabular.objects.all().count(), 4)
+
def test_add_inlines(self):
"""
The "Add another XXX" link correctly adds items to the inline form.