From 7703a362516d6d9be2be19445472c844507b4e13 Mon Sep 17 00:00:00 2001
From: Brandon Rodriguez <brodriguez8774@gmail.com>
Date: Sun, 5 Nov 2023 00:47:30 -0400
Subject: [PATCH] Add selenium option to specify browser open location on
 screen

---
 django_expanded_test_cases/constants.py       | 12 +++++++++--
 .../mixins/live_server_mixin.py               | 21 +++++++++++++++++++
 .../channels_live_server_test_case.py         | 11 +++++++++-
 .../test_cases/live_server_test_case.py       | 11 +++++++++-
 runpytests.py                                 |  1 -
 5 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/django_expanded_test_cases/constants.py b/django_expanded_test_cases/constants.py
index dd506ed..f66d1f1 100644
--- a/django_expanded_test_cases/constants.py
+++ b/django_expanded_test_cases/constants.py
@@ -227,7 +227,7 @@ ETC_SELENIUM_HEADLESS = bool(getattr(
 # Using the cache can sometimes lead to incorrect/failing tests when running selenium in a multi-threaded environment.
 ETC_SELENIUM_DISABLE_CACHE = bool(getattr(
     settings,
-    'DJANGO_EXPANDED_TESTCASES_DISABLE_CACHE',
+    'DJANGO_EXPANDED_TESTCASES_SELENIUM_DISABLE_CACHE',
     False,
 ))
 # Starting debug port, to get around remote-debugging-port option using the same value for all generated drivers,
@@ -238,10 +238,18 @@ ETC_SELENIUM_DEBUG_PORT_START_VALUE = int(getattr(
     'DJANGO_EXPANDED_TESTCASES_SELENIUM_DEBUG_PORT_START_VALUE',
     9221,
 ))
+# A list of lists, comprised of desired (x, y) window positions to spawn selenium browsers at.
+# If not provided, then defaults to however the OS spawns windows in.
+# Ex: [(0, 0), (960, 0)] for a standard 1920 x 1080 landscape display.
+ETC_SELENIUM_WINDOW_POSITIONS = getattr(
+    settings,
+    'DJANGO_EXPANDED_TESTCASES_SELENIUM_WINDOW_POSITIONS',
+    None,
+)
 # Extra options to pass into browser. Should be some iterable, such as a list or tuple of strings.
 ETC_SELENIUM_EXTRA_BROWSER_OPTIONS = getattr(
     settings,
-    'DJANGO_EXPANDED_TESTCASES_EXTRA_BROWSER_OPTIONS',
+    'DJANGO_EXPANDED_TESTCASES_SELENIUM_EXTRA_BROWSER_OPTIONS',
     None,
 )
 # Number of seconds to wait on selenium page load before giving up.
diff --git a/django_expanded_test_cases/mixins/live_server_mixin.py b/django_expanded_test_cases/mixins/live_server_mixin.py
index e0bd19e..0864bc1 100644
--- a/django_expanded_test_cases/mixins/live_server_mixin.py
+++ b/django_expanded_test_cases/mixins/live_server_mixin.py
@@ -47,6 +47,27 @@ class LiveServerMixin(ResponseTestCaseMixin):
         """
         try:
 
+            # Handle window positions, if set.
+            # If not provided, then defaults to however the OS spawns windows in.
+
+            # cls._window_positions = ETC_SELENIUM_WINDOW_POSITIONS
+            # cls._window_position_index = 0
+            if self._window_positions:
+                # Window position value exists. Attempt to read in.
+                try:
+                    # Pull x and y pixel location from provided data.
+                    window_x, window_y = self._window_positions[self._window_position_index]
+                except IndexError:
+                    # Must have gone through all provided values. Loop back to first index.
+                    self._window_position_index = 0
+                    window_x, window_y = self._window_positions[self._window_position_index]
+
+                # Rotate through provided values so that no consecutive two window spawns use the same location.
+                self._window_position_index += 1
+
+                # Add window position data to driver options.
+                self._options.add_argument('window-position={0},{1}'.format(window_x, window_y))
+
             # Create instance, based on selected driver type.
             if self._browser == 'chrome':
                 # # Avoid possible error when many drivers are opened.
diff --git a/django_expanded_test_cases/test_cases/channels_live_server_test_case.py b/django_expanded_test_cases/test_cases/channels_live_server_test_case.py
index ac365e6..61d52d6 100644
--- a/django_expanded_test_cases/test_cases/channels_live_server_test_case.py
+++ b/django_expanded_test_cases/test_cases/channels_live_server_test_case.py
@@ -18,6 +18,7 @@ from django_expanded_test_cases.constants import (
     ETC_SELENIUM_BROWSER,
     ETC_SELENIUM_HEADLESS,
     ETC_SELENIUM_DISABLE_CACHE,
+    ETC_SELENIUM_WINDOW_POSITIONS,
     ETC_SELENIUM_EXTRA_BROWSER_OPTIONS,
 )
 from django_expanded_test_cases.mixins.live_server_mixin import LiveServerMixin
@@ -117,7 +118,15 @@ class ChannelsLiveServerTestCase(DjangoChannelsLiveServerTestCase, LiveServerMix
         if ETC_SELENIUM_DISABLE_CACHE:
             cls._options.add_argument('disable-application-cache')
 
-        # Create initial testing driver, one for each test.
+        # Handle window position values.
+        cls._window_positions = None
+        if ETC_SELENIUM_WINDOW_POSITIONS:
+            window_positions = list(ETC_SELENIUM_WINDOW_POSITIONS)
+            if len(window_positions) > 0:
+                cls._window_positions = window_positions
+                cls._window_position_index = 0
+
+        # Create initial testing driver.
         cls.driver = cls.create_driver(cls)
 
     def setUp(self):
diff --git a/django_expanded_test_cases/test_cases/live_server_test_case.py b/django_expanded_test_cases/test_cases/live_server_test_case.py
index 7dfdd2b..80e8cc2 100644
--- a/django_expanded_test_cases/test_cases/live_server_test_case.py
+++ b/django_expanded_test_cases/test_cases/live_server_test_case.py
@@ -18,6 +18,7 @@ from django_expanded_test_cases.constants import (
     ETC_SELENIUM_BROWSER,
     ETC_SELENIUM_HEADLESS,
     ETC_SELENIUM_DISABLE_CACHE,
+    ETC_SELENIUM_WINDOW_POSITIONS,
     ETC_SELENIUM_EXTRA_BROWSER_OPTIONS,
 )
 from django_expanded_test_cases.mixins.live_server_mixin import LiveServerMixin
@@ -117,7 +118,15 @@ class LiveServerTestCase(DjangoLiveServerTestCase, LiveServerMixin):
         if ETC_SELENIUM_DISABLE_CACHE:
             cls._options.add_argument('disable-application-cache')
 
-        # Create initial testing driver, one for each test.
+        # Handle window position values.
+        cls._window_positions = None
+        if ETC_SELENIUM_WINDOW_POSITIONS:
+            window_positions = list(ETC_SELENIUM_WINDOW_POSITIONS)
+            if len(window_positions) > 0:
+                cls._window_positions = window_positions
+                cls._window_position_index = 0
+
+        # Create initial testing driver.
         cls.driver = cls.create_driver(cls)
 
     def setUp(self):
diff --git a/runpytests.py b/runpytests.py
index 16dbe55..4ec03c1 100755
--- a/runpytests.py
+++ b/runpytests.py
@@ -15,7 +15,6 @@ def runtests():
     os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tests.settings')
     os.environ.setdefault('PYTHONPATH', ROOT_DIR)
 
-    # os.environ.setdefault('EXPANDED_TEST_CASES_SELENIUM_BROWSER', 'firefox')
     argv = ['pytest'] + sys.argv[1:] + ['--asyncio-mode=auto']
     subprocess.run(argv, check=False)
 
-- 
GitLab