Files
kleinanzeigen-bot/tests/conftest.py
2025-04-28 12:55:28 +02:00

203 lines
6.0 KiB
Python

# SPDX-FileCopyrightText: © Jens Bergmann and contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
# SPDX-ArtifactOfProjectHomePage: https://github.com/Second-Hand-Friends/kleinanzeigen-bot/
import os
from typing import Any, Final
from unittest.mock import MagicMock
import pytest
from kleinanzeigen_bot import KleinanzeigenBot
from kleinanzeigen_bot.extract import AdExtractor
from kleinanzeigen_bot.utils import loggers
from kleinanzeigen_bot.utils.web_scraping_mixin import Browser
loggers.configure_console_logging()
LOG:Final[loggers.Logger] = loggers.get_logger("kleinanzeigen_bot")
LOG.setLevel(loggers.DEBUG)
@pytest.fixture
def test_data_dir(tmp_path:str) -> str:
"""Provides a temporary directory for test data.
This fixture uses pytest's built-in tmp_path fixture to create a temporary
directory that is automatically cleaned up after each test.
"""
return str(tmp_path)
@pytest.fixture
def sample_config() -> dict[str, Any]:
"""Provides a basic sample configuration for testing.
This configuration includes all required fields for the bot to function:
- Login credentials (username/password)
- Browser settings
- Ad defaults (description prefix/suffix)
- Publishing settings
"""
return {
"login": {
"username": "testuser",
"password": "testpass"
},
"browser": {
"arguments": [],
"binary_location": None,
"extensions": [],
"use_private_window": True,
"user_data_dir": None,
"profile_name": None
},
"ad_defaults": {
"description": {
"prefix": "Test Prefix",
"suffix": "Test Suffix"
}
},
"publishing": {
"delete_old_ads": "BEFORE_PUBLISH",
"delete_old_ads_by_title": False
}
}
@pytest.fixture
def test_bot(sample_config:dict[str, Any]) -> KleinanzeigenBot:
"""Provides a fresh KleinanzeigenBot instance for all test classes.
Dependencies:
- sample_config: Used to initialize the bot with a valid configuration
"""
bot_instance = KleinanzeigenBot()
bot_instance.config = sample_config
return bot_instance
@pytest.fixture
def browser_mock() -> MagicMock:
"""Provides a mock browser instance for testing.
This mock is configured with the Browser spec to ensure it has all
the required methods and attributes of a real Browser instance.
"""
return MagicMock(spec = Browser)
@pytest.fixture
def log_file_path(test_data_dir:str) -> str:
"""Provides a temporary path for log files.
Dependencies:
- test_data_dir: Used to create the log file in the temporary test directory
"""
return os.path.join(str(test_data_dir), "test.log")
@pytest.fixture
def test_extractor(browser_mock:MagicMock, sample_config:dict[str, Any]) -> AdExtractor:
"""Provides a fresh AdExtractor instance for testing.
Dependencies:
- browser_mock: Used to mock browser interactions
- sample_config: Used to initialize the extractor with a valid configuration
"""
return AdExtractor(browser_mock, sample_config)
@pytest.fixture
def description_test_cases() -> list[tuple[dict[str, Any], str, str]]:
"""Provides test cases for description prefix/suffix handling.
Returns tuples of (config, raw_description, expected_description)
"""
return [
# Test case 1: New flattened format
(
{
"ad_defaults": {
"description_prefix": "Global Prefix\n",
"description_suffix": "\nGlobal Suffix"
}
},
"Original Description", # Raw description without affixes
"Global Prefix\nOriginal Description\nGlobal Suffix" # Expected with affixes
),
# Test case 2: Legacy nested format
(
{
"ad_defaults": {
"description": {
"prefix": "Legacy Prefix\n",
"suffix": "\nLegacy Suffix"
}
}
},
"Original Description",
"Legacy Prefix\nOriginal Description\nLegacy Suffix"
),
# Test case 3: Both formats - new format takes precedence
(
{
"ad_defaults": {
"description_prefix": "New Prefix\n",
"description_suffix": "\nNew Suffix",
"description": {
"prefix": "Legacy Prefix\n",
"suffix": "\nLegacy Suffix"
}
}
},
"Original Description",
"New Prefix\nOriginal Description\nNew Suffix"
),
# Test case 4: Empty config
(
{"ad_defaults": {}},
"Original Description",
"Original Description"
),
# Test case 5: None values in config
(
{
"ad_defaults": {
"description_prefix": None,
"description_suffix": None,
"description": {
"prefix": None,
"suffix": None
}
}
},
"Original Description",
"Original Description"
),
# Test case 6: Non-string values in config
(
{
"ad_defaults": {
"description_prefix": 123,
"description_suffix": True,
"description": {
"prefix": [],
"suffix": {}
}
}
},
"Original Description",
"Original Description"
)
]
@pytest.fixture
def mock_web_text_responses() -> list[str]:
"""Provides common mock responses for web_text calls."""
return [
"Test Title", # Title
"Test Description", # Description
"03.02.2025" # Creation date
]