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.
 
 
 
 

164 lines
6.3 KiB

  1. import os
  2. from unittest import SkipTest
  3. from django.contrib.staticfiles.testing import StaticLiveServerTestCase
  4. from django.utils.module_loading import import_string
  5. from django.utils.translation import ugettext as _
  6. class AdminSeleniumWebDriverTestCase(StaticLiveServerTestCase):
  7. available_apps = [
  8. 'django.contrib.admin',
  9. 'django.contrib.auth',
  10. 'django.contrib.contenttypes',
  11. 'django.contrib.sessions',
  12. 'django.contrib.sites',
  13. ]
  14. webdriver_class = 'selenium.webdriver.firefox.webdriver.WebDriver'
  15. @classmethod
  16. def setUpClass(cls):
  17. if not os.environ.get('DJANGO_SELENIUM_TESTS', False):
  18. raise SkipTest('Selenium tests not requested')
  19. try:
  20. cls.selenium = import_string(cls.webdriver_class)()
  21. except Exception as e:
  22. raise SkipTest('Selenium webdriver "%s" not installed or not '
  23. 'operational: %s' % (cls.webdriver_class, str(e)))
  24. # This has to be last to ensure that resources are cleaned up properly!
  25. super(AdminSeleniumWebDriverTestCase, cls).setUpClass()
  26. @classmethod
  27. def _tearDownClassInternal(cls):
  28. if hasattr(cls, 'selenium'):
  29. cls.selenium.quit()
  30. super(AdminSeleniumWebDriverTestCase, cls)._tearDownClassInternal()
  31. def wait_until(self, callback, timeout=10):
  32. """
  33. Helper function that blocks the execution of the tests until the
  34. specified callback returns a value that is not falsy. This function can
  35. be called, for example, after clicking a link or submitting a form.
  36. See the other public methods that call this function for more details.
  37. """
  38. from selenium.webdriver.support.wait import WebDriverWait
  39. WebDriverWait(self.selenium, timeout).until(callback)
  40. def wait_for_popup(self, num_windows=2, timeout=10):
  41. """
  42. Block until `num_windows` are present (usually 2, but can be
  43. overridden in the case of pop-ups opening other pop-ups).
  44. """
  45. self.wait_until(lambda d: len(d.window_handles) == num_windows, timeout)
  46. def wait_loaded_tag(self, tag_name, timeout=10):
  47. """
  48. Helper function that blocks until the element with the given tag name
  49. is found on the page.
  50. """
  51. self.wait_for(tag_name, timeout)
  52. def wait_for(self, css_selector, timeout=10):
  53. """
  54. Helper function that blocks until a CSS selector is found on the page.
  55. """
  56. from selenium.webdriver.common.by import By
  57. from selenium.webdriver.support import expected_conditions as ec
  58. self.wait_until(
  59. ec.presence_of_element_located((By.CSS_SELECTOR, css_selector)),
  60. timeout
  61. )
  62. def wait_for_text(self, css_selector, text, timeout=10):
  63. """
  64. Helper function that blocks until the text is found in the CSS selector.
  65. """
  66. from selenium.webdriver.common.by import By
  67. from selenium.webdriver.support import expected_conditions as ec
  68. self.wait_until(
  69. ec.text_to_be_present_in_element(
  70. (By.CSS_SELECTOR, css_selector), text),
  71. timeout
  72. )
  73. def wait_for_value(self, css_selector, text, timeout=10):
  74. """
  75. Helper function that blocks until the value is found in the CSS selector.
  76. """
  77. from selenium.webdriver.common.by import By
  78. from selenium.webdriver.support import expected_conditions as ec
  79. self.wait_until(
  80. ec.text_to_be_present_in_element_value(
  81. (By.CSS_SELECTOR, css_selector), text),
  82. timeout
  83. )
  84. def wait_page_loaded(self):
  85. """
  86. Block until page has started to load.
  87. """
  88. from selenium.common.exceptions import TimeoutException
  89. try:
  90. # Wait for the next page to be loaded
  91. self.wait_loaded_tag('body')
  92. except TimeoutException:
  93. # IE7 occasionally returns an error "Internet Explorer cannot
  94. # display the webpage" and doesn't load the next page. We just
  95. # ignore it.
  96. pass
  97. def admin_login(self, username, password, login_url='/admin/'):
  98. """
  99. Helper function to log into the admin.
  100. """
  101. self.selenium.get('%s%s' % (self.live_server_url, login_url))
  102. username_input = self.selenium.find_element_by_name('username')
  103. username_input.send_keys(username)
  104. password_input = self.selenium.find_element_by_name('password')
  105. password_input.send_keys(password)
  106. login_text = _('Log in')
  107. self.selenium.find_element_by_xpath(
  108. '//input[@value="%s"]' % login_text).click()
  109. self.wait_page_loaded()
  110. def get_css_value(self, selector, attribute):
  111. """
  112. Helper function that returns the value for the CSS attribute of an
  113. DOM element specified by the given selector. Uses the jQuery that ships
  114. with Django.
  115. """
  116. return self.selenium.execute_script(
  117. 'return django.jQuery("%s").css("%s")' % (selector, attribute))
  118. def get_select_option(self, selector, value):
  119. """
  120. Returns the <OPTION> with the value `value` inside the <SELECT> widget
  121. identified by the CSS selector `selector`.
  122. """
  123. from selenium.common.exceptions import NoSuchElementException
  124. options = self.selenium.find_elements_by_css_selector('%s > option' % selector)
  125. for option in options:
  126. if option.get_attribute('value') == value:
  127. return option
  128. raise NoSuchElementException('Option "%s" not found in "%s"' % (value, selector))
  129. def assertSelectOptions(self, selector, values):
  130. """
  131. Asserts that the <SELECT> widget identified by `selector` has the
  132. options with the given `values`.
  133. """
  134. options = self.selenium.find_elements_by_css_selector('%s > option' % selector)
  135. actual_values = []
  136. for option in options:
  137. actual_values.append(option.get_attribute('value'))
  138. self.assertEqual(values, actual_values)
  139. def has_css_class(self, selector, klass):
  140. """
  141. Returns True if the element identified by `selector` has the CSS class
  142. `klass`.
  143. """
  144. return (self.selenium.find_element_by_css_selector(selector)
  145. .get_attribute('class').find(klass) != -1)