diff --git a/django/contrib/admin/tests.py b/django/contrib/admin/tests.py index f623e6605c..86745202a9 100644 --- a/django/contrib/admin/tests.py +++ b/django/contrib/admin/tests.py @@ -1,3 +1,5 @@ +from contextlib import contextmanager + from django.contrib.staticfiles.testing import StaticLiveServerTestCase from django.test import modify_settings from django.test.selenium import SeleniumTestCase @@ -97,19 +99,26 @@ class AdminSeleniumTestCase(SeleniumTestCase, StaticLiveServerTestCase): timeout ) - def wait_page_loaded(self): + def wait_page_ready(self, timeout=10): """ - Block until page has started to load. + Block until the page is ready. """ - from selenium.common.exceptions import TimeoutException - try: - # Wait for the next page to be loaded - self.wait_for('body') - except TimeoutException: - # IE7 occasionally returns an error "Internet Explorer cannot - # display the webpage" and doesn't load the next page. We just - # ignore it. - pass + self.wait_until( + lambda driver: driver.execute_script('return document.readyState;') == 'complete', + timeout, + ) + + @contextmanager + def wait_page_loaded(self, timeout=10): + """ + Block until a new page has loaded and is ready. + """ + from selenium.webdriver.support import expected_conditions as ec + old_page = self.selenium.find_element_by_tag_name('html') + yield + # Wait for the next page to be loaded + self.wait_until(ec.staleness_of(old_page), timeout=timeout) + self.wait_page_ready(timeout=timeout) def admin_login(self, username, password, login_url='/admin/'): """ @@ -121,9 +130,8 @@ class AdminSeleniumTestCase(SeleniumTestCase, StaticLiveServerTestCase): password_input = self.selenium.find_element_by_name('password') password_input.send_keys(password) login_text = _('Log in') - self.selenium.find_element_by_xpath( - '//input[@value="%s"]' % login_text).click() - self.wait_page_loaded() + with self.wait_page_loaded(): + self.selenium.find_element_by_xpath('//input[@value="%s"]' % login_text).click() def get_css_value(self, selector, attribute): """ diff --git a/tests/admin_inlines/tests.py b/tests/admin_inlines/tests.py index a43c43560f..fa005ad17b 100644 --- a/tests/admin_inlines/tests.py +++ b/tests/admin_inlines/tests.py @@ -934,8 +934,8 @@ class SeleniumTests(AdminSeleniumTestCase): 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() + with self.wait_page_loaded(): + self.selenium.find_element_by_xpath('//input[@value="Save"]').click() self.assertEqual(rows_length(), 5, msg="sanity check") errorlist = self.selenium.find_element_by_css_selector( @@ -948,8 +948,8 @@ class SeleniumTests(AdminSeleniumTestCase): 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() + with self.wait_page_loaded(): + self.selenium.find_element_by_xpath('//input[@value="Save"]').click() # The objects have been created in the database. self.assertEqual(Inner4Stacked.objects.all().count(), 4) @@ -978,8 +978,8 @@ class SeleniumTests(AdminSeleniumTestCase): 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() + with self.wait_page_loaded(): + self.selenium.find_element_by_xpath('//input[@value="Save"]').click() self.assertEqual(rows_length(), 5, msg="sanity check") @@ -995,8 +995,8 @@ class SeleniumTests(AdminSeleniumTestCase): 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() + with self.wait_page_loaded(): + self.selenium.find_element_by_xpath('//input[@value="Save"]').click() # The objects have been created in the database. self.assertEqual(Inner4Tabular.objects.all().count(), 4) @@ -1050,8 +1050,8 @@ class SeleniumTests(AdminSeleniumTestCase): self.selenium.find_element_by_name('profile_set-2-first_name').send_keys('2 first name 1') self.selenium.find_element_by_name('profile_set-2-last_name').send_keys('2 last name 2') - self.selenium.find_element_by_xpath('//input[@value="Save"]').click() - self.wait_page_loaded() + with self.wait_page_loaded(): + self.selenium.find_element_by_xpath('//input[@value="Save"]').click() # The objects have been created in the database self.assertEqual(ProfileCollection.objects.all().count(), 1) diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index c9ca64097f..393bcab9ce 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -4584,8 +4584,8 @@ class SeleniumTests(AdminSeleniumTestCase): num_initial_select2_inputs + 6 ) # Save and check that everything is properly stored in the database - self.selenium.find_element_by_xpath('//input[@value="Save"]').click() - self.wait_page_loaded() + with self.wait_page_loaded(): + self.selenium.find_element_by_xpath('//input[@value="Save"]').click() self.assertEqual(MainPrepopulated.objects.all().count(), 1) MainPrepopulated.objects.get( name=' this is the mAin nÀMë and it\'s awεšomeııı', @@ -4652,8 +4652,8 @@ class SeleniumTests(AdminSeleniumTestCase): self.assertEqual(slug2, 'option-two-main-name-best') # Save the object - self.selenium.find_element_by_xpath('//input[@value="Save"]').click() - self.wait_page_loaded() + with self.wait_page_loaded(): + self.selenium.find_element_by_xpath('//input[@value="Save"]').click() self.selenium.get(object_url) self.selenium.find_element_by_id('id_name').send_keys(' hello') diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py index 2bbf176ec3..aa81d187d8 100644 --- a/tests/admin_widgets/tests.py +++ b/tests/admin_widgets/tests.py @@ -940,8 +940,8 @@ class DateTimePickerShortcutsSeleniumTests(AdminWidgetSeleniumTestCase): self.selenium.find_elements_by_css_selector('.field-birthdate .timezonewarning') # Submit the form. - self.selenium.find_element_by_tag_name('form').submit() - self.wait_page_loaded() + with self.wait_page_loaded(): + self.selenium.find_element_by_tag_name('form').submit() # Make sure that "now" in javascript is within 10 seconds # from "now" on the server side. @@ -1128,13 +1128,13 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): self.admin_login(username='super', password='secret', login_url='/') self.selenium.get(self.live_server_url + reverse('admin:admin_widgets_school_change', args=(self.school.id,))) - self.wait_page_loaded() + self.wait_page_ready() self.execute_basic_operations('vertical', 'students') self.execute_basic_operations('horizontal', 'alumni') # Save and check that everything is properly stored in the database --- self.selenium.find_element_by_xpath('//input[@value="Save"]').click() - self.wait_page_loaded() + self.wait_page_ready() self.school = School.objects.get(id=self.school.id) # Reload from database self.assertEqual(list(self.school.students.all()), [self.arthur, self.cliff, self.jason, self.john]) self.assertEqual(list(self.school.alumni.all()), [self.arthur, self.cliff, self.jason, self.john]) @@ -1218,8 +1218,8 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): input.send_keys([Keys.BACK_SPACE, Keys.BACK_SPACE]) # Save and check that everything is properly stored in the database --- - self.selenium.find_element_by_xpath('//input[@value="Save"]').click() - self.wait_page_loaded() + with self.wait_page_loaded(): + self.selenium.find_element_by_xpath('//input[@value="Save"]').click() self.school = School.objects.get(id=self.school.id) # Reload from database self.assertEqual(list(self.school.students.all()), [self.jason, self.peter]) self.assertEqual(list(self.school.alumni.all()), [self.jason, self.peter]) @@ -1267,8 +1267,8 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase): # self.selenium.refresh() or send_keys(Keys.F5) does hard reload and # doesn't replicate what happens when a user clicks the browser's # 'Refresh' button. - self.selenium.execute_script("location.reload()") - self.wait_page_loaded() + with self.wait_page_loaded(): + self.selenium.execute_script("location.reload()") options_len = len(self.selenium.find_elements_by_css_selector('#id_students_to > option')) self.assertEqual(options_len, 2)