mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-03-12 18:41:50 +01:00
205 lines
6.0 KiB
Python
205 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.utils import loggers
|
|
from kleinanzeigen_bot.extract import AdExtractor
|
|
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
|
|
]
|