Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
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.

selenium.py 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import sys
  2. import unittest
  3. from contextlib import contextmanager
  4. from django.test import LiveServerTestCase, tag
  5. from django.utils.functional import classproperty
  6. from django.utils.module_loading import import_string
  7. from django.utils.text import capfirst
  8. class SeleniumTestCaseBase(type(LiveServerTestCase)):
  9. # List of browsers to dynamically create test classes for.
  10. browsers = []
  11. # A selenium hub URL to test against.
  12. selenium_hub = None
  13. # The external host Selenium Hub can reach.
  14. external_host = None
  15. # Sentinel value to differentiate browser-specific instances.
  16. browser = None
  17. # Run browsers in headless mode.
  18. headless = False
  19. def __new__(cls, name, bases, attrs):
  20. """
  21. Dynamically create new classes and add them to the test module when
  22. multiple browsers specs are provided (e.g. --selenium=firefox,chrome).
  23. """
  24. test_class = super().__new__(cls, name, bases, attrs)
  25. # If the test class is either browser-specific or a test base, return it.
  26. if test_class.browser or not any(
  27. name.startswith("test") and callable(value) for name, value in attrs.items()
  28. ):
  29. return test_class
  30. elif test_class.browsers:
  31. # Reuse the created test class to make it browser-specific.
  32. # We can't rename it to include the browser name or create a
  33. # subclass like we do with the remaining browsers as it would
  34. # either duplicate tests or prevent pickling of its instances.
  35. first_browser = test_class.browsers[0]
  36. test_class.browser = first_browser
  37. # Listen on an external interface if using a selenium hub.
  38. host = test_class.host if not test_class.selenium_hub else "0.0.0.0"
  39. test_class.host = host
  40. test_class.external_host = cls.external_host
  41. # Create subclasses for each of the remaining browsers and expose
  42. # them through the test's module namespace.
  43. module = sys.modules[test_class.__module__]
  44. for browser in test_class.browsers[1:]:
  45. browser_test_class = cls.__new__(
  46. cls,
  47. "%s%s" % (capfirst(browser), name),
  48. (test_class,),
  49. {
  50. "browser": browser,
  51. "host": host,
  52. "external_host": cls.external_host,
  53. "__module__": test_class.__module__,
  54. },
  55. )
  56. setattr(module, browser_test_class.__name__, browser_test_class)
  57. return test_class
  58. # If no browsers were specified, skip this class (it'll still be discovered).
  59. return unittest.skip("No browsers specified.")(test_class)
  60. @classmethod
  61. def import_webdriver(cls, browser):
  62. return import_string("selenium.webdriver.%s.webdriver.WebDriver" % browser)
  63. @classmethod
  64. def import_options(cls, browser):
  65. return import_string("selenium.webdriver.%s.options.Options" % browser)
  66. @classmethod
  67. def get_capability(cls, browser):
  68. from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
  69. return getattr(DesiredCapabilities, browser.upper())
  70. def create_options(self):
  71. options = self.import_options(self.browser)()
  72. if self.headless:
  73. try:
  74. options.headless = True
  75. except AttributeError:
  76. pass # Only Chrome and Firefox support the headless mode.
  77. return options
  78. def create_webdriver(self):
  79. if self.selenium_hub:
  80. from selenium import webdriver
  81. return webdriver.Remote(
  82. command_executor=self.selenium_hub,
  83. desired_capabilities=self.get_capability(self.browser),
  84. )
  85. return self.import_webdriver(self.browser)(options=self.create_options())
  86. @tag("selenium")
  87. class SeleniumTestCase(LiveServerTestCase, metaclass=SeleniumTestCaseBase):
  88. implicit_wait = 10
  89. external_host = None
  90. @classproperty
  91. def live_server_url(cls):
  92. return "http://%s:%s" % (cls.external_host or cls.host, cls.server_thread.port)
  93. @classproperty
  94. def allowed_host(cls):
  95. return cls.external_host or cls.host
  96. @classmethod
  97. def setUpClass(cls):
  98. cls.selenium = cls.create_webdriver()
  99. cls.selenium.implicitly_wait(cls.implicit_wait)
  100. super().setUpClass()
  101. @classmethod
  102. def _tearDownClassInternal(cls):
  103. # quit() the WebDriver before attempting to terminate and join the
  104. # single-threaded LiveServerThread to avoid a dead lock if the browser
  105. # kept a connection alive.
  106. if hasattr(cls, "selenium"):
  107. cls.selenium.quit()
  108. super()._tearDownClassInternal()
  109. @contextmanager
  110. def disable_implicit_wait(self):
  111. """Disable the default implicit wait."""
  112. self.selenium.implicitly_wait(0)
  113. try:
  114. yield
  115. finally:
  116. self.selenium.implicitly_wait(self.implicit_wait)