Repository: openwisp/openwisp-users (language: python)

Issue:
[deps] Add support for Django 4.1.0 and Django 4.2.0
- [Django 4.1.0 release notes](https://docs.djangoproject.com/en/4.1/releases/4.1/)
- [Django 4.2.0 release notes](https://docs.djangoproject.com/en/4.2/releases/4.2/)

We need to ensure that other project dependencies are updated accordingly.

**Depends on**

- [x] https://github.com/openwisp/openwisp-utils/issues/337


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9fe1fbd6..7102c101 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -31,10 +31,8 @@ jobs:
           - "3.10"
         django-version:
           - django~=3.2.0
-          - django~=4.0.0
-        include:
-          - django-version: django~=3.2.0
-            python-version: 3.7
+          - django~=4.1.0
+          - django~=4.2.0
 
     steps:
       - uses: actions/checkout@v2
diff --git a/openwisp_users/__init__.py b/openwisp_users/__init__.py
index 6474acef..1761fe99 100644
--- a/openwisp_users/__init__.py
+++ b/openwisp_users/__init__.py
@@ -1,8 +1,6 @@
 VERSION = (1, 1, 0, 'alpha')
 __version__ = VERSION  # alias
 
-default_app_config = 'openwisp_users.apps.OpenwispUsersConfig'
-
 
 def get_version():
     version = '%s.%s.%s' % (VERSION[0], VERSION[1], VERSION[2])
diff --git a/requirements.txt b/requirements.txt
index b7ddd424..77dec47e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,8 +1,8 @@
-django-organizations~=2.0.1
-django-extensions~=3.1.0
-django-allauth~=0.51.0
-django-phonenumber-field~=6.0.0
-phonenumbers>=8.11.0,<8.13.0
+django-organizations~=2.1.0
+django-extensions~=3.2.2
+django-allauth~=0.54.0
+django-phonenumber-field~=6.1.0
+phonenumbers~=8.13.0
 openwisp-utils[rest] @ https://github.com/openwisp/openwisp-utils/tarball/master
 packaging
 django-sesame~=2.4.0


Test patch:
diff --git a/requirements-test.txt b/requirements-test.txt
index 6334ab71..e76912de 100644
--- a/requirements-test.txt
+++ b/requirements-test.txt
@@ -1,5 +1,3 @@
-openwisp-utils[qa] @ https://github.com/openwisp/openwisp-utils/tarball/master
-redis~=4.3.4
-django-redis~=5.0.0
-django-reversion~=4.0.1
-selenium~=4.9.0
+openwisp-utils[qa,selenium] @ https://github.com/openwisp/openwisp-utils/tarball/master
+django-redis~=5.2.0
+django-reversion~=5.0.4
diff --git a/tests/openwisp2/sample_users/__init__.py b/tests/openwisp2/sample_users/__init__.py
index c1888087..e69de29b 100644
--- a/tests/openwisp2/sample_users/__init__.py
+++ b/tests/openwisp2/sample_users/__init__.py
@@ -1,1 +0,0 @@
-default_app_config = 'openwisp2.sample_users.apps.SampleUsersConfig'
diff --git a/tests/openwisp2/sample_users/apps.py b/tests/openwisp2/sample_users/apps.py
index 7ff65a7f..4e388240 100644
--- a/tests/openwisp2/sample_users/apps.py
+++ b/tests/openwisp2/sample_users/apps.py
@@ -4,3 +4,6 @@
 class SampleUsersConfig(OpenwispUsersConfig):
     name = 'openwisp2.sample_users'
     label = 'sample_users'
+
+
+del OpenwispUsersConfig
diff --git a/tests/testapp/tests/mixins.py b/tests/testapp/tests/mixins.py
index 03bfa578..8753f7db 100644
--- a/tests/testapp/tests/mixins.py
+++ b/tests/testapp/tests/mixins.py
@@ -1,5 +1,3 @@
-from selenium.webdriver.common.by import By
-
 from openwisp_users.tests.test_api import AuthenticationMixin
 from openwisp_users.tests.utils import TestMultitenantAdminMixin, TestOrganizationMixin
 
@@ -10,41 +8,3 @@ class TestMultitenancyMixin(
     CreateMixin, TestMultitenantAdminMixin, AuthenticationMixin, TestOrganizationMixin
 ):
     pass
-
-
-class SeleniumTestMixin:
-    """
-    A base test case for Selenium, providing helped methods for generating
-    clients and logging in profiles.
-    """
-
-    def open(self, url, driver=None):
-        """
-        Opens a URL
-        Argument:
-            url: URL to open
-            driver: selenium driver (default: cls.base_driver)
-        """
-        if not driver:
-            driver = self.web_driver
-        driver.get(f'{self.live_server_url}{url}')
-
-    def login(self, username=None, password=None, driver=None):
-        """
-        Log in to the admin dashboard
-        Argument:
-            driver: selenium driver (default: cls.web_driver)
-            username: username to be used for login (default: cls.admin.username)
-            password: password to be used for login (default: cls.admin.password)
-        """
-        if not driver:
-            driver = self.web_driver
-        if not username:
-            username = self.admin_username
-        if not password:
-            password = self.admin_password
-        driver.get(f'{self.live_server_url}/admin/login/')
-        if 'admin/login' in driver.current_url:
-            driver.find_element(By.NAME, 'username').send_keys(username)
-            driver.find_element(By.NAME, 'password').send_keys(password)
-            driver.find_element(By.XPATH, '//input[@type="submit"]').click()
diff --git a/tests/testapp/tests/test_selenium.py b/tests/testapp/tests/test_selenium.py
index 22ebf1c2..923cfcf7 100644
--- a/tests/testapp/tests/test_selenium.py
+++ b/tests/testapp/tests/test_selenium.py
@@ -1,17 +1,15 @@
-from django.conf import settings
 from django.contrib.auth.models import Permission
 from django.contrib.staticfiles.testing import StaticLiveServerTestCase
 from django.db.models import Q
 from django.urls import reverse
-from selenium import webdriver
+from openwisp_utils.test_selenium_mixins import SeleniumTestMixin
 from selenium.webdriver.common.by import By
-from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
 from selenium.webdriver.support import expected_conditions as EC
 from selenium.webdriver.support.select import Select
 from selenium.webdriver.support.ui import WebDriverWait
 from swapper import load_model
 
-from .mixins import SeleniumTestMixin, TestMultitenancyMixin
+from .mixins import TestMultitenancyMixin
 
 Organization = load_model('openwisp_users', 'Organization')
 
@@ -19,29 +17,6 @@
 class TestOrganizationAutocompleteField(
     SeleniumTestMixin, TestMultitenancyMixin, StaticLiveServerTestCase
 ):
-    admin_username = 'admin'
-    admin_password = 'password'
-
-    @classmethod
-    def setUpClass(cls):
-        super().setUpClass()
-        chrome_options = webdriver.ChromeOptions()
-        if getattr(settings, 'SELENIUM_HEADLESS', True):
-            chrome_options.add_argument('--headless')
-        chrome_options.add_argument('--window-size=1366,768')
-        chrome_options.add_argument('--ignore-certificate-errors')
-        chrome_options.add_argument('--remote-debugging-port=9222')
-        capabilities = DesiredCapabilities.CHROME
-        capabilities['goog:loggingPrefs'] = {'browser': 'ALL'}
-        cls.web_driver = webdriver.Chrome(
-            options=chrome_options, desired_capabilities=capabilities
-        )
-
-    @classmethod
-    def tearDownClass(cls):
-        cls.web_driver.quit()
-        super().tearDownClass()
-
     def setUp(self):
         self.admin = self._create_admin(
             username=self.admin_username, password=self.admin_password