237 lines
5.7 KiB
Python
Executable File
237 lines
5.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Run tests for Grey Haven applications with Doppler environment variables.
|
|
|
|
Supports Vitest (TypeScript) and pytest (Python) with markers for different
|
|
test types (unit, integration, e2e, benchmark).
|
|
|
|
Usage:
|
|
# Run all tests with test environment
|
|
python scripts/run_tests.py
|
|
|
|
# Run unit tests only
|
|
python scripts/run_tests.py --type unit
|
|
|
|
# Run integration and e2e tests
|
|
python scripts/run_tests.py --type integration --type e2e
|
|
|
|
# Run tests with coverage
|
|
python scripts/run_tests.py --coverage
|
|
|
|
# Run tests in watch mode (for development)
|
|
python scripts/run_tests.py --watch
|
|
|
|
# Run pytest instead of Vitest
|
|
python scripts/run_tests.py --backend pytest
|
|
|
|
# Run with specific Doppler environment
|
|
python scripts/run_tests.py --env ci
|
|
|
|
Always run with --help first to see all options.
|
|
"""
|
|
|
|
import argparse
|
|
import subprocess
|
|
import sys
|
|
from typing import List
|
|
|
|
|
|
def run_command(cmd: str, description: str) -> bool:
|
|
"""Run a shell command and return success status."""
|
|
print(f"\n→ {description}")
|
|
print(f" Command: {cmd}\n")
|
|
|
|
result = subprocess.run(cmd, shell=True)
|
|
return result.returncode == 0
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Run tests with Doppler environment variables",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Examples:
|
|
# Run all Vitest tests
|
|
python scripts/run_tests.py
|
|
|
|
# Run unit tests only
|
|
python scripts/run_tests.py --type unit
|
|
|
|
# Run integration and e2e tests with coverage
|
|
python scripts/run_tests.py --type integration --type e2e --coverage
|
|
|
|
# Run pytest unit tests
|
|
python scripts/run_tests.py --backend pytest --type unit
|
|
|
|
# Run tests in watch mode
|
|
python scripts/run_tests.py --watch
|
|
|
|
Test Types (Markers):
|
|
unit - Unit tests (fast, isolated)
|
|
integration - Integration tests (database, external services)
|
|
e2e - End-to-end tests (full application flow)
|
|
benchmark - Performance benchmark tests
|
|
|
|
Backends:
|
|
vitest - Vitest (TypeScript/React) - default
|
|
pytest - pytest (Python/FastAPI)
|
|
|
|
Doppler Configuration:
|
|
Uses 'test' config by default.
|
|
Override with --env flag for CI environments.
|
|
"""
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--backend",
|
|
default="vitest",
|
|
choices=["vitest", "pytest"],
|
|
help="Test backend to use (default: vitest)"
|
|
)
|
|
parser.add_argument(
|
|
"--type",
|
|
action="append",
|
|
choices=["unit", "integration", "e2e", "benchmark"],
|
|
help="Test type(s) to run (can be repeated). If not specified, runs all tests."
|
|
)
|
|
parser.add_argument(
|
|
"--coverage",
|
|
action="store_true",
|
|
help="Run with coverage reporting"
|
|
)
|
|
parser.add_argument(
|
|
"--watch",
|
|
action="store_true",
|
|
help="Run in watch mode (for development)"
|
|
)
|
|
parser.add_argument(
|
|
"--env",
|
|
default="test",
|
|
help="Doppler environment config to use (default: test)"
|
|
)
|
|
parser.add_argument(
|
|
"--verbose",
|
|
action="store_true",
|
|
help="Verbose output"
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
backend = args.backend
|
|
env = args.env
|
|
test_types = args.type or []
|
|
|
|
print(f"\n{'=' * 70}")
|
|
print(f" Running {backend.upper()} Tests")
|
|
print(f" Environment: {env}")
|
|
if test_types:
|
|
print(f" Types: {', '.join(test_types)}")
|
|
print(f"{'=' * 70}")
|
|
|
|
# Construct test command based on backend
|
|
if backend == "vitest":
|
|
# Base Vitest command
|
|
cmd_parts = ["doppler", "run", "--config", env, "--", "vitest"]
|
|
|
|
# Add test types as grep patterns
|
|
if test_types:
|
|
# Vitest uses file patterns or test name patterns
|
|
# We'll use test name patterns matching our markers
|
|
patterns = "|".join(test_types)
|
|
cmd_parts.extend(["-t", f"({patterns})"])
|
|
|
|
# Add coverage flag
|
|
if args.coverage:
|
|
cmd_parts.append("--coverage")
|
|
|
|
# Add watch mode
|
|
if args.watch:
|
|
cmd_parts.append("--watch")
|
|
|
|
# Add verbose flag
|
|
if args.verbose:
|
|
cmd_parts.append("--reporter=verbose")
|
|
|
|
# Run mode (not watch)
|
|
if not args.watch:
|
|
cmd_parts.append("run")
|
|
|
|
elif backend == "pytest":
|
|
# Base pytest command
|
|
cmd_parts = ["doppler", "run", "--config", env, "--", "pytest"]
|
|
|
|
# Add test types as markers
|
|
if test_types:
|
|
markers = " or ".join(test_types)
|
|
cmd_parts.extend(["-m", markers])
|
|
|
|
# Add coverage flag
|
|
if args.coverage:
|
|
cmd_parts.extend([
|
|
"--cov=app",
|
|
"--cov-report=term-missing",
|
|
"--cov-report=html"
|
|
])
|
|
|
|
# Add verbose flag
|
|
if args.verbose:
|
|
cmd_parts.append("-vv")
|
|
|
|
# pytest doesn't have built-in watch mode
|
|
if args.watch:
|
|
print("\nWARNING: Warning: pytest doesn't support watch mode natively")
|
|
print(" Consider using pytest-watch: pip install pytest-watch")
|
|
|
|
cmd = " ".join(cmd_parts)
|
|
success = run_command(cmd, f"Running {backend} tests")
|
|
|
|
if not success:
|
|
print(f"\nERROR: Tests failed")
|
|
sys.exit(1)
|
|
|
|
# Coverage threshold check (if coverage was run)
|
|
if args.coverage and backend == "vitest":
|
|
print("\n→ Checking coverage thresholds...")
|
|
print(" Required: 80% (lines, functions, branches, statements)")
|
|
|
|
# Vitest coverage is configured in vitest.config.ts
|
|
# Thresholds are enforced automatically
|
|
print(" ✓ Coverage thresholds enforced by Vitest config")
|
|
|
|
elif args.coverage and backend == "pytest":
|
|
print("\n→ Checking coverage thresholds...")
|
|
print(" Required: 80% coverage")
|
|
|
|
# Check coverage with pytest-cov
|
|
coverage_cmd = f"doppler run --config {env} -- pytest --cov=app --cov-fail-under=80 -q"
|
|
coverage_success = run_command(coverage_cmd, "Validating coverage threshold")
|
|
|
|
if not coverage_success:
|
|
print("\nERROR: Coverage below 80% threshold")
|
|
print(" Add more tests to increase coverage")
|
|
sys.exit(1)
|
|
|
|
# Success!
|
|
print(f"\n{'=' * 70}")
|
|
print(f" SUCCESS: All tests passed!")
|
|
print(f"{'=' * 70}")
|
|
|
|
if args.coverage:
|
|
if backend == "vitest":
|
|
print("\n Coverage report: coverage/index.html")
|
|
else:
|
|
print("\n Coverage report: htmlcov/index.html")
|
|
|
|
print("\nNext steps:")
|
|
if not test_types:
|
|
print(" • All tests passed - ready to commit")
|
|
else:
|
|
print(f" • {', '.join(test_types)} tests passed")
|
|
if not args.coverage:
|
|
print(" • Run with --coverage to check code coverage")
|
|
print(" • Deploy with: python scripts/deploy.py --env staging")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|