forked from Rockachopa/Timmy-time-dashboard
* CI/CD Optimization: Guard Rails, Black Linting, and Pre-commit Hooks - Fixed all test collection errors (Selenium imports, fixture paths, syntax) - Implemented pre-commit hooks with Black formatting and isort - Created comprehensive Makefile with test targets (unit, integration, functional, e2e) - Added pytest.ini with marker definitions for test categorization - Established guard rails to prevent future collection errors - Wrapped optional dependencies (Selenium, MoviePy) in try-except blocks - Added conftest_markers for automatic test categorization This ensures a smooth development stream with: - Fast feedback loops (pre-commit checks before push) - Consistent code formatting (Black) - Reliable CI/CD (no collection errors, proper test isolation) - Clear test organization (unit, integration, functional, E2E) * Fix CI/CD test failures: - Export templates from dashboard.app - Fix model name assertion in test_agent.py - Fix platform-agnostic path resolution in test_path_resolution.py - Skip Docker tests in test_docker_deployment.py if docker not available - Fix test_model_fallback_chain logic in test_ollama_integration.py * Add preventative pre-commit checks and Docker test skipif decorators: - Create pre_commit_checks.py script for common CI failures - Add skipif decorators to Docker tests - Improve test robustness for CI environments
103 lines
3.0 KiB
Python
103 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Add pytest markers to test files based on naming conventions and content.
|
|
|
|
Usage:
|
|
python scripts/add_pytest_markers.py
|
|
"""
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
def categorize_test(file_path: Path) -> str:
|
|
"""Determine test category based on file path and content."""
|
|
path_str = str(file_path)
|
|
content = file_path.read_text()
|
|
|
|
# E2E tests
|
|
if "e2e" in path_str or "end_to_end" in path_str:
|
|
return "e2e"
|
|
|
|
# Functional tests
|
|
if "functional" in path_str:
|
|
return "functional"
|
|
|
|
# Integration tests
|
|
if "integration" in path_str or "_integration" in file_path.stem:
|
|
return "integration"
|
|
|
|
# Selenium/browser tests
|
|
if "selenium" in path_str or "ui" in path_str or "browser" in path_str:
|
|
return "selenium"
|
|
|
|
# Docker tests
|
|
if "docker" in path_str:
|
|
return "docker"
|
|
|
|
# Default to unit
|
|
return "unit"
|
|
|
|
|
|
def add_marker_to_file(file_path: Path, marker: str) -> bool:
|
|
"""Add pytest marker to file if not already present."""
|
|
content = file_path.read_text()
|
|
|
|
# Check if marker already exists
|
|
if f'@pytest.mark.{marker}' in content or f'pytestmark = pytest.mark.{marker}' in content:
|
|
return False
|
|
|
|
# Check if file has any pytest imports
|
|
if "import pytest" not in content:
|
|
# Add pytest import at the top
|
|
lines = content.split("\n")
|
|
# Find the right place to add import (after docstring/comments)
|
|
insert_idx = 0
|
|
for i, line in enumerate(lines):
|
|
if line.startswith('"""') or line.startswith("'''") or line.startswith("#"):
|
|
insert_idx = i + 1
|
|
elif line.strip() and not line.startswith(("import", "from")):
|
|
break
|
|
|
|
lines.insert(insert_idx, "import pytest")
|
|
content = "\n".join(lines)
|
|
|
|
# Add pytestmark at module level (after imports)
|
|
lines = content.split("\n")
|
|
insert_idx = 0
|
|
for i, line in enumerate(lines):
|
|
if line.startswith(("import ", "from ")):
|
|
insert_idx = i + 1
|
|
|
|
# Add blank line and pytestmark
|
|
pytestmark_line = f"pytestmark = pytest.mark.{marker}"
|
|
if insert_idx < len(lines) and lines[insert_idx].strip():
|
|
lines.insert(insert_idx, "")
|
|
lines.insert(insert_idx + 1, pytestmark_line)
|
|
|
|
file_path.write_text("\n".join(lines))
|
|
return True
|
|
|
|
|
|
def main():
|
|
"""Add markers to all test files."""
|
|
test_dir = Path("tests")
|
|
marked_count = 0
|
|
|
|
for test_file in sorted(test_dir.rglob("test_*.py")):
|
|
marker = categorize_test(test_file)
|
|
rel_path = str(test_file.relative_to(test_dir))
|
|
if add_marker_to_file(test_file, marker):
|
|
print(f"✅ {rel_path:<50} -> @pytest.mark.{marker}")
|
|
marked_count += 1
|
|
else:
|
|
print(f"⏭️ {rel_path:<50} (already marked)")
|
|
|
|
print(f"\n📊 Total files marked: {marked_count}")
|
|
print(f"\n✨ Pytest markers configured. Run 'pytest -m unit' to test specific categories.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
sys.path.insert(0, "src")
|
|
main()
|