diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index c26f9d63..246be6ff 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -40,25 +40,17 @@ jobs: - name: Checkout uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + # https://docs.astral.sh/uv/guides/integration/github/ + - name: Install uv and set the python version + uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 # v6.5.0 with: python-version: ${{ matrix.python-version }} - - - name: Set up pip cache - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 - with: - path: | - ~/.cache/pip - key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/pyproject.toml') }} - restore-keys: | - ${{ runner.os }}-pip-${{ matrix.python-version }}- - ${{ runner.os }}-pip- + activate-environment: true - name: Install dependencies and application # without --editable the coverage report is not generated correctly run: | - pip install --editable .[dev] + uv pip install --editable .[dev] - name: Test with pytest id: pytest @@ -67,7 +59,7 @@ jobs: export LIBGL_ALWAYS_SOFTWARE=1 export DISPLAY=:99 Xvfb :99 -screen 0 1024x768x16 & - pytest --cov=ardupilot_methodic_configurator --cov-report=xml:tests/coverage.xml --md=tests/results-${{ matrix.python-version }}.md --junit-xml=tests/results-junit.xml + uv run pytest --cov=ardupilot_methodic_configurator --cov-report=xml:tests/coverage.xml --md=tests/results-${{ matrix.python-version }}.md --junit-xml=tests/results-junit.xml - name: Fix coverage paths run: | diff --git a/tests/test_frontend_tkinter_component_editor_base.py b/tests/test_frontend_tkinter_component_editor_base.py index 11ade0d4..bbb8a612 100755 --- a/tests/test_frontend_tkinter_component_editor_base.py +++ b/tests/test_frontend_tkinter_component_editor_base.py @@ -12,6 +12,7 @@ import tkinter as tk from argparse import ArgumentParser +from collections.abc import Generator from tkinter import ttk from typing import Union, get_args, get_origin from unittest.mock import MagicMock, patch @@ -34,13 +35,13 @@ # pylint: disable=protected-access, too-many-lines, redefined-outer-name, unused-argument, too-few-public-methods -def setup_common_editor_mocks(editor) -> ComponentEditorWindowBase: +def setup_common_editor_mocks(editor, root=None) -> ComponentEditorWindowBase: """Set up common mock attributes and methods for editor fixtures.""" # Set up all required attributes manually - editor.root = MagicMock() - editor.main_frame = MagicMock() + editor.root = root if root is not None else MagicMock() + editor.main_frame = ttk.Frame(editor.root) if root is not None else MagicMock() editor.scroll_frame = MagicMock() - editor.scroll_frame.view_port = MagicMock() + editor.scroll_frame.view_port = ttk.Frame(editor.root) if root is not None else MagicMock() editor.version = "1.0.0" # Mock filesystem and methods with proper schema loading @@ -125,14 +126,14 @@ def test_argument_parser_with_skip_component_editor(self) -> None: @pytest.fixture -def editor_with_mocked_root() -> ComponentEditorWindowBase: +def editor_with_mocked_root(root) -> Generator[ComponentEditorWindowBase, None, None]: """Create a mock ComponentEditorWindowBase for testing.""" # Create the class without initialization with patch.object(ComponentEditorWindowBase, "__init__", return_value=None): editor = ComponentEditorWindowBase() # pylint: disable=no-value-for-parameter - # Set up common mocks and helper methods - setup_common_editor_mocks(editor) + # Set up common mocks and helper methods with real root + setup_common_editor_mocks(editor, root) add_editor_helper_methods(editor) yield editor @@ -1046,7 +1047,6 @@ def test_user_sees_introduction_frame_with_explanations( mock_intro_frame = MagicMock() mock_frame_class.return_value = mock_intro_frame - # Mock the methods that would be called editor_for_ui_tests._add_explanation_text = MagicMock() editor_for_ui_tests._add_vehicle_image = MagicMock() diff --git a/tests/test_frontend_tkinter_component_editor_integration.py b/tests/test_frontend_tkinter_component_editor_integration.py index a172300c..8a0c27d9 100755 --- a/tests/test_frontend_tkinter_component_editor_integration.py +++ b/tests/test_frontend_tkinter_component_editor_integration.py @@ -284,20 +284,18 @@ def test_editor_initialization_process(self, temp_vehicle_dir, root) -> None: save_component_to_system_templates=False, ) - # Mock only the UI rendering parts, use the real root from conftest.py + # Mock tkinter creation to use the provided session root instead with ( patch.object(ComponentEditorWindow, "_create_scroll_frame") as mock_scroll_frame, patch.object(ComponentEditorWindow, "_create_intro_frame") as mock_intro_frame, patch.object(ComponentEditorWindow, "_create_save_frame") as mock_save_frame, patch("tkinter.PhotoImage"), patch("PIL.ImageTk.PhotoImage"), + patch("tkinter.Tk", return_value=root), # Use the session root instead of creating new one ): # Create the editor with real filesystem and data model editor = ComponentEditorWindow("1.0.0", filesystem) - # Use the real root from conftest.py - editor.root = root - # Check editor has been properly initialized assert editor.version == "1.0.0" assert editor.local_filesystem == filesystem @@ -342,11 +340,11 @@ def test_editor_with_real_data_model(self, temp_vehicle_dir, root) -> None: patch.object(ComponentEditorWindow, "_initialize_ui"), patch("tkinter.PhotoImage"), patch("PIL.ImageTk.PhotoImage"), + patch("tkinter.Tk", return_value=root), # Use the session root instead of creating new one ): # Initialize with existing data_model using dependency injection editor = ComponentEditorWindow("1.0.0", filesystem) editor.data_model = data_model # Override the data model - editor.root = root # Use the real root from conftest.py # Test data model integration assert editor.data_model is data_model