diff options
author | Carlton Gibson <carlton.gibson@noumenal.es> | 2019-10-24 16:37:55 +0200 |
---|---|---|
committer | Carlton Gibson <carlton@noumenal.es> | 2019-10-25 13:28:08 +0200 |
commit | 24e540fbd71bd2b0843e751bde61ad0052a811b3 (patch) | |
tree | 0ad75be6f7adb7cc0eedb83af2dacd8a252455c1 /tests/admin_inlines | |
parent | 6ea3aadd17f937e69d121e3ae1a415a435e3267d (diff) | |
download | django-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.py | 10 | ||||
-rw-r--r-- | tests/admin_inlines/tests.py | 94 |
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. |