You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tests.py 7.1KB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. from django.contrib.staticfiles.testing import StaticLiveServerTestCase
  2. from django.test import modify_settings
  3. from django.test.selenium import SeleniumTestCase
  4. from django.utils.deprecation import MiddlewareMixin
  5. from django.utils.translation import gettext as _
  6. class CSPMiddleware(MiddlewareMixin):
  7. """The admin's JavaScript should be compatible with CSP."""
  8. def process_response(self, request, response):
  9. response['Content-Security-Policy'] = "default-src 'self'"
  10. return response
  11. @modify_settings(MIDDLEWARE={'append': 'django.contrib.admin.tests.CSPMiddleware'})
  12. class AdminSeleniumTestCase(SeleniumTestCase, StaticLiveServerTestCase):
  13. available_apps = [
  14. 'django.contrib.admin',
  15. 'django.contrib.auth',
  16. 'django.contrib.contenttypes',
  17. 'django.contrib.sessions',
  18. 'django.contrib.sites',
  19. ]
  20. def wait_until(self, callback, timeout=10):
  21. """
  22. Block the execution of the tests until the specified callback returns a
  23. value that is not falsy. This method can be called, for example, after
  24. clicking a link or submitting a form. See the other public methods that
  25. call this function for more details.
  26. """
  27. from selenium.webdriver.support.wait import WebDriverWait
  28. WebDriverWait(self.selenium, timeout).until(callback)
  29. def wait_for_popup(self, num_windows=2, timeout=10):
  30. """
  31. Block until `num_windows` are present (usually 2, but can be
  32. overridden in the case of pop-ups opening other pop-ups).
  33. """
  34. self.wait_until(lambda d: len(d.window_handles) == num_windows, timeout)
  35. def wait_for(self, css_selector, timeout=10):
  36. """
  37. Block until a CSS selector is found on the page.
  38. """
  39. from selenium.webdriver.common.by import By
  40. from selenium.webdriver.support import expected_conditions as ec
  41. self.wait_until(
  42. ec.presence_of_element_located((By.CSS_SELECTOR, css_selector)),
  43. timeout
  44. )
  45. def wait_for_text(self, css_selector, text, timeout=10):
  46. """
  47. Block until the text is found in the CSS selector.
  48. """
  49. from selenium.webdriver.common.by import By
  50. from selenium.webdriver.support import expected_conditions as ec
  51. self.wait_until(
  52. ec.text_to_be_present_in_element(
  53. (By.CSS_SELECTOR, css_selector), text),
  54. timeout
  55. )
  56. def wait_for_value(self, css_selector, text, timeout=10):
  57. """
  58. Block until the value is found in the CSS selector.
  59. """
  60. from selenium.webdriver.common.by import By
  61. from selenium.webdriver.support import expected_conditions as ec
  62. self.wait_until(
  63. ec.text_to_be_present_in_element_value(
  64. (By.CSS_SELECTOR, css_selector), text),
  65. timeout
  66. )
  67. def wait_until_visible(self, css_selector, timeout=10):
  68. """
  69. Block until the element described by the CSS selector is visible.
  70. """
  71. from selenium.webdriver.common.by import By
  72. from selenium.webdriver.support import expected_conditions as ec
  73. self.wait_until(
  74. ec.visibility_of_element_located((By.CSS_SELECTOR, css_selector)),
  75. timeout
  76. )
  77. def wait_until_invisible(self, css_selector, timeout=10):
  78. """
  79. Block until the element described by the CSS selector is invisible.
  80. """
  81. from selenium.webdriver.common.by import By
  82. from selenium.webdriver.support import expected_conditions as ec
  83. self.wait_until(
  84. ec.invisibility_of_element_located((By.CSS_SELECTOR, css_selector)),
  85. timeout
  86. )
  87. def wait_page_loaded(self):
  88. """
  89. Block until page has started to load.
  90. """
  91. from selenium.common.exceptions import TimeoutException
  92. try:
  93. # Wait for the next page to be loaded
  94. self.wait_for('body')
  95. except TimeoutException:
  96. # IE7 occasionally returns an error "Internet Explorer cannot
  97. # display the webpage" and doesn't load the next page. We just
  98. # ignore it.
  99. pass
  100. def admin_login(self, username, password, login_url='/admin/'):
  101. """
  102. Log in to the admin.
  103. """
  104. self.selenium.get('%s%s' % (self.live_server_url, login_url))
  105. username_input = self.selenium.find_element_by_name('username')
  106. username_input.send_keys(username)
  107. password_input = self.selenium.find_element_by_name('password')
  108. password_input.send_keys(password)
  109. login_text = _('Log in')
  110. self.selenium.find_element_by_xpath(
  111. '//input[@value="%s"]' % login_text).click()
  112. self.wait_page_loaded()
  113. def get_css_value(self, selector, attribute):
  114. """
  115. Return the value for the CSS attribute of a DOM element specified by
  116. the given selector. Uses the jQuery that ships with Django.
  117. """
  118. return self.selenium.execute_script(
  119. 'return django.jQuery("%s").css("%s")' % (selector, attribute))
  120. def get_select_option(self, selector, value):
  121. """
  122. Return the <OPTION> with the value `value` inside the <SELECT> widget
  123. identified by the CSS selector `selector`.
  124. """
  125. from selenium.common.exceptions import NoSuchElementException
  126. options = self.selenium.find_elements_by_css_selector('%s > option' % selector)
  127. for option in options:
  128. if option.get_attribute('value') == value:
  129. return option
  130. raise NoSuchElementException('Option "%s" not found in "%s"' % (value, selector))
  131. def _assertOptionsValues(self, options_selector, values):
  132. if values:
  133. options = self.selenium.find_elements_by_css_selector(options_selector)
  134. actual_values = []
  135. for option in options:
  136. actual_values.append(option.get_attribute('value'))
  137. self.assertEqual(values, actual_values)
  138. else:
  139. # Prevent the `find_elements_by_css_selector` call from blocking
  140. # if the selector doesn't match any options as we expect it
  141. # to be the case.
  142. with self.disable_implicit_wait():
  143. self.wait_until(
  144. lambda driver: not driver.find_elements_by_css_selector(options_selector)
  145. )
  146. def assertSelectOptions(self, selector, values):
  147. """
  148. Assert that the <SELECT> widget identified by `selector` has the
  149. options with the given `values`.
  150. """
  151. self._assertOptionsValues("%s > option" % selector, values)
  152. def assertSelectedOptions(self, selector, values):
  153. """
  154. Assert that the <SELECT> widget identified by `selector` has the
  155. selected options with the given `values`.
  156. """
  157. self._assertOptionsValues("%s > option:checked" % selector, values)
  158. def has_css_class(self, selector, klass):
  159. """
  160. Return True if the element identified by `selector` has the CSS class
  161. `klass`.
  162. """
  163. return (self.selenium.find_element_by_css_selector(selector)
  164. .get_attribute('class').find(klass) != -1)