Full-stack flight price scanner built on fast-flights v3 (SOCS cookie bypass): Backend (FastAPI + SQLite): - REST API with rate limiting, Pydantic v2 validation, paginated responses - Scan pipeline: resolves airports, queries every day in the window, saves individual flights + aggregate route stats to SQLite - Background async scan processor with real-time progress tracking - Airport search endpoint backed by OpenFlights dataset - Daily scan window (all dates, not monthly samples) Frontend (React 19 + TypeScript + Tailwind CSS v4): - Dashboard with live scan status and recent scans - Create scan form: country mode or specific airports (searchable dropdown) - Scan detail page with expandable route rows showing individual flights (date, airline, departure, arrival, price) loaded on demand - AirportSearch component with debounced live search and multi-select Database: - scans → routes → flights schema with FK cascade and auto-update triggers - Migrations for schema evolution (relaxed country constraint) Tests: - 74 tests: unit + integration, isolated per-test SQLite DB - Confirmed flight fixtures in tests/confirmed_flights.json (50 real flights, BDS→FMM Ryanair + BDS→DUS Eurowings, scraped Feb 2026) - Integration tests parametrized from confirmed routes Docker: - Multi-stage builds, Compose orchestration, Nginx reverse proxy Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
65 lines
2.0 KiB
Python
65 lines
2.0 KiB
Python
"""
|
|
Smoke tests for date_resolver module.
|
|
"""
|
|
|
|
from datetime import date
|
|
from dateutil.relativedelta import relativedelta
|
|
import sys
|
|
sys.path.insert(0, '..')
|
|
|
|
from date_resolver import resolve_dates, detect_new_connections, SEARCH_WINDOW_MONTHS
|
|
|
|
|
|
def test_resolve_dates_with_specific_date():
|
|
"""Test that a specific date returns only that date."""
|
|
result = resolve_dates("2026-06-15", 6)
|
|
assert result == ["2026-06-15"]
|
|
print("✓ Specific date resolution works")
|
|
|
|
|
|
def test_resolve_dates_seasonal():
|
|
"""Test that seasonal mode generates one date per month."""
|
|
result = resolve_dates(None, 3)
|
|
assert len(result) == 3
|
|
# All should be valid date strings
|
|
for date_str in result:
|
|
assert len(date_str) == 10 # YYYY-MM-DD format
|
|
assert date_str.count('-') == 2
|
|
print(f"✓ Seasonal resolution works: {result}")
|
|
|
|
|
|
def test_detect_new_connections():
|
|
"""Test new connection detection logic."""
|
|
monthly_results = {
|
|
"2026-03": [
|
|
{"origin": "FRA", "destination": "JFK"},
|
|
{"origin": "MUC", "destination": "JFK"},
|
|
],
|
|
"2026-04": [
|
|
{"origin": "FRA", "destination": "JFK"},
|
|
{"origin": "MUC", "destination": "JFK"},
|
|
{"origin": "BER", "destination": "JFK"}, # NEW
|
|
],
|
|
"2026-05": [
|
|
{"origin": "FRA", "destination": "JFK"},
|
|
{"origin": "BER", "destination": "JFK"},
|
|
{"origin": "HAM", "destination": "JFK"}, # NEW
|
|
],
|
|
}
|
|
|
|
new = detect_new_connections(monthly_results)
|
|
assert "BER->JFK" in new
|
|
assert new["BER->JFK"] == "2026-04"
|
|
assert "HAM->JFK" in new
|
|
assert new["HAM->JFK"] == "2026-05"
|
|
assert "FRA->JFK" not in new # Was in first month
|
|
assert "MUC->JFK" not in new # Was in first month
|
|
print(f"✓ New connection detection works: {new}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_resolve_dates_with_specific_date()
|
|
test_resolve_dates_seasonal()
|
|
test_detect_new_connections()
|
|
print("\n✅ All date_resolver tests passed!")
|