diff --git a/.gitignore b/.gitignore index 293eb72629..51e1ff753a 100644 --- a/.gitignore +++ b/.gitignore @@ -101,3 +101,7 @@ build/ *.out *.app nimbus-build-system.paths + +# ui-tests +/test/ui-pytest/configs/_local.py +*.pyc diff --git a/test/ui-pytest/README.md b/test/ui-pytest/README.md new file mode 100644 index 0000000000..20a6939953 --- /dev/null +++ b/test/ui-pytest/README.md @@ -0,0 +1,153 @@ +# Status desktop ui-tests + +# Setup: +Skip any of the steps, if sure that you have the correct version of the required tool. +## All Platforms +### 1. Install Qt 5.15 +https://doc.qt.io/qt-6/get-and-install-qt.html +### 2. Setup Squish License Server +https://hackmd.io/@status-desktop/HkbWpk2e5 +### 3. Install PyCharm +Download and install: +https://www.jetbrains.com/pycharm/download/other.html +Please, select any build depending on OS, but NOT an Apple Silicon (dmg) + +How to: https://www.jetbrains.com/help/pycharm/installation-guide.html + +## Windows +### 4. Install Squish +https://status-misc.ams3.digitaloceanspaces.com/squish/squish-7.1-20230301-1424-qt515x-win64-msvc142.exe +### 5. Install Python +Download and install for all users: https://www.python.org/ftp/python/3.10.11/python-3.10.11-amd64.exe +### 6. Install Requirements +``` +YOUR_PYTHON_PATH/pip3.exe install -r ./requirements.txt +``` +### 7. Setup Environment Variables +Add in system environment variables: +``` +SQUISH_DIR=PATH_TO_THE_SQUISH_ROOT_FOLDER +PYTHONPATH=%SQUISH_DIR%/lib;%SQUISH_DIR%/lib/python;%PYTHONPATH% +``` +RESTART PC +### 8. Verify environment variables +``` +echo %SQUISH_DIR% +echo %PYTHONPATH% +``` +### 9. Setup Python for Squish +Download 'PythonChanger.py' in %SQUISH_DIR%: +https://kb.froglogic.com/squish/howto/changing-python-installation-used-squish-binary-packages/PythonChanger.py +``` +YOUR_PYTHON_PATH/python3.10 SQUISH_DIR/PythonChanger.py --revert +YOUR_PYTHON_PATH/python3.10 SQUISH_DIR/PythonChanger.py +``` +- Replace "YOUR PYTHON PATH" on to Python3.10 file location path +- Replace "SQUISH DIR" on to the Squish root folder path +### 10 Test: +Executing tests located in 'test_self.py' file +``` +pytest ./tests/test_self.py +``` +Executing test 'test_import_squish' from 'test_self.py' file +``` +pytest ./tests/test_self.py::test_import_squish +``` +Executing all tests with 'import_squish' in test name +``` +pytest -k import_squish +``` +Executing all tests with tag 'self' +``` +pytest -m self +``` + +## Linux +### 4. Install Squish +https://status-misc.ams3.digitaloceanspaces.com/squish/squish-7.1-20230222-1555-qt515x-linux64.run +### 5. Install Python +```bash +sudo apt-get install software-properties-common +``` +```bash +sudo add-apt-repository ppa:deadsnakes/ppa +``` +```bash +sudo apt-get update +``` +```bash +sudo apt-get install python3.10 +``` +```bash +sudo apt install python3-pip +``` +### 6. Install Requirements +```bash +sudo pip3 install -r ./requirements.txt +``` +### 7. Setup Environment Variables +```bash +gedit ~/.profile +``` +``` +export SQUISH_DIR=PATH_TO_THE_SQUISH_ROOT_FOLDER +export PYTHONPATH=$SQUISH_DIR/lib:$SQUISH_DIR/lib/python:$PYTHONPATH +export LD_LIBRARY_PATH=$SQUISH_DIR/lib:$SQUISH_DIR/python3/lib:$LD_LIBRARY_PATH +``` +RESTART PC + +## Mac +### 4. Install Squish +https://status-misc.ams3.digitaloceanspaces.com/squish/squish-7.1-20230328-1608-qt515x-macaarch64.dmg +### 5. Install Python +```bash +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` +```bash +brew update --auto-update +brew install wget +brew install python@3.10 +``` +### 6. Install Requirements +```bash +sudo pip3 install -r ./requirements.txt +``` +### 7. Setup Environment Variables +```bash +touch ~/.zprofile +open ~/.zprofile +``` +``` +export SQUISH_DIR=PATH_TO_THE_SQUISH_ROOT_FOLDER +export PYTHONPATH=$SQUISH_DIR/lib:$SQUISH_DIR/lib/python:$PYTHONPATH +export LD_LIBRARY_PATH=$SQUISH_DIR/lib:$LD_LIBRARY_PATH +``` +RESTART PC + +## Linux or MAC: +### 8. Verify environment variables +```bash +echo $USERNAME +echo $PYTHONPATH +echo $LD_LIBRARY_PATH +``` +### 9. Setup Python for Squish +https://kb.froglogic.com/squish/howto/changing-python-installation-used-squish-binary-packages/ +```bash +brew install wget +wget -O $SQUISH_DIR/PythonChanger.py https://kb.froglogic.com/squish/howto/changing-python-installation-used-squish-binary-packages/PythonChanger.py +python3.10 $SQUISH_DIR/PythonChanger.py --revert +python3.10 $SQUISH_DIR/PythonChanger.py +``` +### 10 Test: +```bash +echo "Executing tests located in 'test_self.py' file" +pytest ./tests/test_self.py +echo "Executing test 'test_import_squish' from 'test_self.py' file" +pytest ./tests/test_self.py::test_import_squish +echo "Executing all tests with 'import_squish' in test name" +pytest -k import_squish +echo "Executing all tests with tag 'self'" +pytest -m self +``` +For more info, read: https://docs.pytest.org/en/latest/getting-started.html diff --git a/test/ui-pytest/configs/__init__.py b/test/ui-pytest/configs/__init__.py new file mode 100644 index 0000000000..36bf648d5c --- /dev/null +++ b/test/ui-pytest/configs/__init__.py @@ -0,0 +1,14 @@ +import logging + +from . import testpath, timeouts + +_logger = logging.getLogger(__name__) + +try: + from ._local import * +except ImportError: + exit( + 'Config file: "_local.py" not found in "./configs".\n' + 'Please use template "_.local.py.default" to create file or execute command: \n' + rf'cp {testpath.ROOT}/configs/_local.py.default {testpath.ROOT}/configs/_local.py' + ) diff --git a/test/ui-pytest/configs/_local.py.ci b/test/ui-pytest/configs/_local.py.ci new file mode 100644 index 0000000000..46c599464a --- /dev/null +++ b/test/ui-pytest/configs/_local.py.ci @@ -0,0 +1,7 @@ +import os + +from scripts.utils.system_path import SystemPath + +LOCAL_RUN = False + +APP_DIR = SystemPath(os.getenv('APP_DIR') diff --git a/test/ui-pytest/configs/_local.py.default b/test/ui-pytest/configs/_local.py.default new file mode 100644 index 0000000000..0eae750871 --- /dev/null +++ b/test/ui-pytest/configs/_local.py.default @@ -0,0 +1,3 @@ +LOCAL_RUN = True + +APP_DIR = None diff --git a/test/ui-pytest/configs/testpath.py b/test/ui-pytest/configs/testpath.py new file mode 100644 index 0000000000..d0a8e46997 --- /dev/null +++ b/test/ui-pytest/configs/testpath.py @@ -0,0 +1,15 @@ +import os +from datetime import datetime + +from scripts.utils.system_path import SystemPath + +ROOT: SystemPath = SystemPath(__file__).resolve().parent.parent + +# Test Directories +RUN_ID = os.getenv('RUN_DIR', f'run_{datetime.now():%d%m%Y_%H%M%S}') +TEMP: SystemPath = ROOT / 'tmp' +RESULTS: SystemPath = TEMP / 'results' +RUN: SystemPath = RESULTS / RUN_ID + +# Driver Directories +SQUISH_DIR = os.getenv('RUN_DIR') diff --git a/test/ui-pytest/configs/timeouts.py b/test/ui-pytest/configs/timeouts.py new file mode 100644 index 0000000000..58d4cef638 --- /dev/null +++ b/test/ui-pytest/configs/timeouts.py @@ -0,0 +1,3 @@ +# Timoeuts before raising errors + +UI_LOAD_TIMEOUT_MSEC = 5000 diff --git a/test/ui-pytest/conftest.py b/test/ui-pytest/conftest.py new file mode 100644 index 0000000000..d393c73ade --- /dev/null +++ b/test/ui-pytest/conftest.py @@ -0,0 +1,17 @@ +import pytest + +pytest_plugins = [ + 'tests.fixtures.path', +] + + +@pytest.fixture(scope='session', autouse=True) +def setup_session_scope( + run_dir, +): + yield + + +def pytest_exception_interact(node): + """Handles test on fail.""" + pass diff --git a/test/ui-pytest/constants/__init__.py b/test/ui-pytest/constants/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/ui-pytest/driver/__init__.py b/test/ui-pytest/driver/__init__.py new file mode 100755 index 0000000000..e712a27ead --- /dev/null +++ b/test/ui-pytest/driver/__init__.py @@ -0,0 +1,17 @@ +import squishtest # noqa + +import configs + +imports = {module.__name__: module for module in [ + # import any modules from driver folder +]} + + +def __getattr__(name): + if name in imports: + return imports[name] + return getattr(squishtest, name) + + +squishtest.testSettings.waitForObjectTimeout = configs.timeouts.UI_LOAD_TIMEOUT_MSEC +squishtest.setHookSubprocesses(True) diff --git a/test/ui-pytest/gui/__init__.py b/test/ui-pytest/gui/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/ui-pytest/gui/components/__init__.py b/test/ui-pytest/gui/components/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/ui-pytest/gui/elements/__init__.py b/test/ui-pytest/gui/elements/__init__.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/test/ui-pytest/gui/elements/__init__.py @@ -0,0 +1 @@ + diff --git a/test/ui-pytest/gui/main_window.py b/test/ui-pytest/gui/main_window.py new file mode 100644 index 0000000000..ac2189fc44 --- /dev/null +++ b/test/ui-pytest/gui/main_window.py @@ -0,0 +1,9 @@ +import logging + +_logger = logging.getLogger(__name__) + + +class MainWindow: + + def __init__(self): + pass diff --git a/test/ui-pytest/gui/objects_map/__init__.py b/test/ui-pytest/gui/objects_map/__init__.py new file mode 100644 index 0000000000..80965aa260 --- /dev/null +++ b/test/ui-pytest/gui/objects_map/__init__.py @@ -0,0 +1,5 @@ +from .component_names import * +from .main_window_names import * +from .messages_names import * +from .onboarding_names import * +from .settings_names import * diff --git a/test/ui-pytest/gui/screens/__init__.py b/test/ui-pytest/gui/screens/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/ui-pytest/pytest.ini b/test/ui-pytest/pytest.ini new file mode 100644 index 0000000000..679ca18d34 --- /dev/null +++ b/test/ui-pytest/pytest.ini @@ -0,0 +1,7 @@ +[pytest] +log_format = %(asctime)s.%(msecs)03d %(levelname)7s %(name)s %(message).5000s +log_cli = true +log_cli_level = INFO + +markers = + self: framework tests diff --git a/test/ui-pytest/requirements.txt b/test/ui-pytest/requirements.txt new file mode 100644 index 0000000000..70613be0cf --- /dev/null +++ b/test/ui-pytest/requirements.txt @@ -0,0 +1 @@ +pytest==7.4.0 diff --git a/test/ui-pytest/scripts/__init__.py b/test/ui-pytest/scripts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/ui-pytest/scripts/tools/__init__.py b/test/ui-pytest/scripts/tools/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/ui-pytest/scripts/utils/__init__.py b/test/ui-pytest/scripts/utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/ui-pytest/scripts/utils/system_path.py b/test/ui-pytest/scripts/utils/system_path.py new file mode 100644 index 0000000000..a12b24ed28 --- /dev/null +++ b/test/ui-pytest/scripts/utils/system_path.py @@ -0,0 +1,14 @@ +import logging +import os +import pathlib +import shutil + +_logger = logging.getLogger(__name__) + + +class SystemPath(pathlib.Path): + _accessor = pathlib._normal_accessor # noqa + _flavour = pathlib._windows_flavour if os.name == 'nt' else pathlib._posix_flavour # noqa + + def rmtree(self, ignore_errors=False): + shutil.rmtree(self, ignore_errors=ignore_errors) diff --git a/test/ui-pytest/tests/__init__.py b/test/ui-pytest/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/ui-pytest/tests/fixtures/__init__.py b/test/ui-pytest/tests/fixtures/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/ui-pytest/tests/fixtures/path.py b/test/ui-pytest/tests/fixtures/path.py new file mode 100644 index 0000000000..71ba2ec3ed --- /dev/null +++ b/test/ui-pytest/tests/fixtures/path.py @@ -0,0 +1,38 @@ +import logging +import re + +import pytest + +import configs +from scripts.utils.system_path import SystemPath + +_logger = logging.getLogger(__name__) + + +@pytest.fixture +def generate_test_data(request): + test_path, test_name, test_params = generate_test_info(request.node) + configs.testpath.TEST = configs.testpath.RUN / test_path / test_name + _logger.info(f'Start test: {test_name}') + + +def generate_test_info(node): + pure_path = SystemPath(node.location[0]).parts[1:] + test_path = SystemPath(*pure_path).with_suffix('') + test_name = node.originalname + test_params = re.sub('[^a-zA-Z0-9\n\-_]', '', node.name.strip(test_name)) + return test_path, test_name, test_params + + +@pytest.fixture(scope='session') +def run_dir(): + keep_results = 5 + run_name_pattern = 'run_????????_??????' + runs = list(sorted(configs.testpath.RESULTS.glob(run_name_pattern))) + if len(runs) > keep_results: + del_runs = runs[:len(runs) - keep_results] + for run in del_runs: + SystemPath(run).rmtree(ignore_errors=True) + _logger.info(f"Remove old test run directory: {run.relative_to(configs.testpath.ROOT)}") + configs.testpath.RUN.mkdir(parents=True, exist_ok=True) + _logger.info(f"Created new test run directory: {configs.testpath.RUN.relative_to(configs.testpath.ROOT)}") diff --git a/test/ui-pytest/tests/test_self.py b/test/ui-pytest/tests/test_self.py new file mode 100755 index 0000000000..515e05a3f9 --- /dev/null +++ b/test/ui-pytest/tests/test_self.py @@ -0,0 +1,13 @@ +import logging + +import pytest + +import driver + +_logger = logging.getLogger(__name__) + + +@pytest.mark.self +def test_import_squish(): + _logger.info(str(driver.__dict__)) + driver.snooze(1)