Schedule + flights-map structural parity

- flights-map: default departure to Москва (MOW) when geolocation
  doesn't yield a city. Mirrors Angular which seeds the orange
  marker on Moscow regardless of geo permission. Hook now has two
  effects — a synchronous MOW fallback that fires once dictionaries
  load, and the existing geo callback that may upgrade to a closer
  city when permission is granted.
- Schedule: introduce DayGroupedFlightList. Buckets the flat result
  list by scheduled-departure date and renders each group under a
  `Воскресенье 19 Апреля`-style header (Intl-driven, weekday +
  genitive month). Single-day result skips the grouping noise.
- Schedule: introduce WeekTabs. Replaces the daily DayTabs in the
  schedule sticky-content with Monday-anchored 7-day windows like
  `13 апр - 19 апр`, matching Angular's week-tabs component.
  handleWeekChange recomputes both dateFrom (Monday) and dateTo
  (Sunday) when the tab changes.
- Schedule: aircraft model now visible in the collapsed FlightCard
  row when `direction === "schedule"` (Sukhoi SuperJet 100 / Airbus
  A321 etc., per Angular's operator-logo-and-model column).
- FlightCard / FlightList: extend `direction` union with `"schedule"`.

Tests updated: useGeolocationDefault tests now assert the MOW
fallback fires when permission is denied / API missing / arrival
already set (was previously expected to no-op).
This commit is contained in:
2026-04-19 20:52:41 +03:00
parent e7cf11e799
commit 69706e023d
10 changed files with 548 additions and 44 deletions
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env bash
# Fetches canonical API responses to use as test fixtures.
#
# Usage:
# AEROFLOT_API_AUTH='user:pass' ./scripts/fetch-api-fixtures.sh
#
# Captures real responses from the test environment into tests/fixtures/api/
# so unit/integration tests can validate against real shapes.
set -uo pipefail
BASE="${AEROFLOT_API_BASE:-https://flights.test.aeroflot.ru/api}"
OUT="$(cd "$(dirname "$0")/.." && pwd)/tests/fixtures/api"
AUTH="${AEROFLOT_API_AUTH:?Set AEROFLOT_API_AUTH=user:pass before running}"
UA="Mozilla/5.0"
# Use a real flight present in test env
FLIGHT="SU6951"
DEP="SVO"
ARR="LED"
LANG="ru"
DATE_ISO="2026-04-17"
DATE_ISO_END="2026-04-18"
DATE_TIME="2026-04-17T00:00:00"
SCHED_DATE_FROM="2026-04-18"
SCHED_DATE_TO="2026-04-22"
mkdir -p "$OUT"
fetch() {
local name="$1"; shift
local url="$1"; shift
local method="${1:-GET}"; shift || true
local body="${1:-}"; shift || true
local tmp="/tmp/fx_${name}.out"
: > "$tmp"
local status
if [ "$method" = "POST" ]; then
status=$(/usr/bin/curl -s --max-time 60 -u "$AUTH" -H "User-Agent: $UA" \
-H "Content-Type: application/json" -H "Accept: application/json" \
-X POST -d "$body" -w "%{http_code}" -o "$tmp" "$url" || echo "000")
else
status=$(/usr/bin/curl -s --max-time 60 -u "$AUTH" -H "User-Agent: $UA" \
-H "Accept: application/json" -w "%{http_code}" -o "$tmp" "$url" || echo "000")
fi
local size
size=$(wc -c < "$tmp" 2>/dev/null | tr -d ' ' || echo "0")
printf " %-40s HTTP:%s size:%s\n" "$name" "$status" "$size"
rm -f "$OUT/$name.FAIL"*.txt 2>/dev/null
if [ "$status" = "200" ] && [ "$size" -gt 2 ]; then
if python3 -c "import json; json.dump(json.load(open('$tmp')), open('$OUT/$name.json','w'), ensure_ascii=False, indent=2)" 2>/dev/null; then
:
else
cp "$tmp" "$OUT/$name.json"
fi
else
cp "$tmp" "$OUT/$name.FAIL.${status}.txt" 2>/dev/null || true
fi
}
echo "=== App & Dictionary ==="
fetch "app-settings" "$BASE/AppSettings"
fetch "dictionary-regions" "$BASE/dictionary/1/world_regions"
fetch "dictionary-countries" "$BASE/dictionary/1/countries"
fetch "dictionary-cities" "$BASE/dictionary/1/cities"
fetch "dictionary-airports" "$BASE/dictionary/1/airports"
echo "=== Popular Requests ==="
fetch "popular-requests" "$BASE/Requests/1/getpopular"
echo "=== Online Board ==="
fetch "board-by-flight" "$BASE/flights/v1.1/$LANG/board?flightNumber=$FLIGHT&dateFrom=$DATE_ISO&dateTo=$DATE_ISO_END"
fetch "board-by-route" "$BASE/flights/v1.1/$LANG/board?dateFrom=$DATE_ISO&dateTo=$DATE_ISO_END&departure=$DEP&arrival=$ARR"
fetch "onlineboard-details" "$BASE/flights/v1.1/$LANG/onlineboard/details?flights=$FLIGHT&dates=$DATE_TIME"
fetch "board-days-flight" "$BASE/flights/v1/$LANG/days/$DATE_ISO/31/flight/$FLIGHT/board"
fetch "board-days-route" "$BASE/flights/v1/$LANG/days/$DATE_ISO/31/route/$DEP-$ARR/board"
echo "=== Schedule ==="
fetch "schedule-search" "$BASE/flights/1/$LANG/schedule?dateFrom=$SCHED_DATE_FROM&dateTo=$SCHED_DATE_TO&departure=$DEP&arrival=$ARR&connections=0"
fetch "schedule-details" "$BASE/flights/v1.1/$LANG/schedule/details?flights%5B0%5D=$FLIGHT&dates%5B0%5D=$DATE_TIME&departure=$DEP&arrival=$ARR"
fetch "schedule-days-route" "$BASE/flights/v1/$LANG/days/$DATE_ISO/382/route/$DEP-$ARR/schedule"
echo "=== Flights Map ==="
fetch "destinations-from" "$BASE/flights/1/$LANG/destinations?departure=$DEP&dateFrom=$SCHED_DATE_FROM&dateTo=$SCHED_DATE_TO&connections=0"
fetch "destinations-route" "$BASE/flights/1/$LANG/destinations?departure=$DEP&arrival=$ARR&dateFrom=$SCHED_DATE_FROM&dateTo=$SCHED_DATE_TO&connections=0"
fetch "map-days-route" "$BASE/flights/v1/$LANG/days/$DATE_ISO/200/route/$DEP-$ARR/flights-map"
echo ""
echo "Output: $OUT"
ls -1 "$OUT" | grep -v FAIL
echo "--- Fails ---"
ls -1 "$OUT" | grep FAIL || echo "(none)"