File size: 7,958 Bytes
ec8acdf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import { describe, it, afterEach } from 'node:test';
import assert from 'node:assert/strict';
import { parseCallsign, toIataCallsign, icaoToIata } from '../server/_shared/airline-codes.ts';
import { getWingbitsLiveFlight } from '../server/worldmonitor/military/v1/get-wingbits-live-flight.ts';

const ECS_BASE = 'https://ecs-api.wingbits.com/v1/flights';
const PHOTOS_BASE = 'https://api.planespotters.net/pub/photos/hex';
const originalFetch = globalThis.fetch;

function jsonResp(data, status = 200) {
  return new Response(JSON.stringify(data), {
    status,
    headers: { 'content-type': 'application/json' },
  });
}

describe('parseCallsign', () => {
  it('parses standard 3-letter ICAO prefix + number', () => {
    assert.deepEqual(parseCallsign('UAE528'), { prefix: 'UAE', number: '528' });
    assert.deepEqual(parseCallsign('BAW61'), { prefix: 'BAW', number: '61' });
    assert.deepEqual(parseCallsign('EZY13BU'), { prefix: 'EZY', number: '13BU' });
    assert.deepEqual(parseCallsign('DAL123'), { prefix: 'DAL', number: '123' });
  });

  it('parses 2-letter prefixes', () => {
    assert.deepEqual(parseCallsign('LH123'), { prefix: 'LH', number: '123' });
  });

  it('parses 4-letter prefixes', () => {
    assert.deepEqual(parseCallsign('DUKE41'), { prefix: 'DUKE', number: '41' });
  });

  it('normalizes whitespace', () => {
    assert.deepEqual(parseCallsign('  UAE528  '), { prefix: 'UAE', number: '528' });
  });

  it('normalizes to uppercase', () => {
    assert.deepEqual(parseCallsign('uae528'), { prefix: 'UAE', number: '528' });
    assert.deepEqual(parseCallsign('ezy13bu'), { prefix: 'EZY', number: '13BU' });
  });

  it('returns null for callsigns starting with letter+digit (N-numbers)', () => {
    assert.equal(parseCallsign('N123AB'), null);
  });

  it('returns null for empty string', () => {
    assert.equal(parseCallsign(''), null);
  });

  it('returns null for whitespace-only', () => {
    assert.equal(parseCallsign('   '), null);
  });

  it('returns null for pure alpha (no number suffix)', () => {
    assert.equal(parseCallsign('ABCD'), null);
  });
});

describe('icaoToIata', () => {
  it('returns IATA mapping for known prefixes', () => {
    assert.deepEqual(icaoToIata('UAE'), { iata: 'EK', name: 'Emirates' });
    assert.deepEqual(icaoToIata('BAW'), { iata: 'BA', name: 'British Airways' });
    assert.deepEqual(icaoToIata('EZY'), { iata: 'U2', name: 'easyJet' });
    assert.deepEqual(icaoToIata('SWR'), { iata: 'LX', name: 'Swiss International Air Lines' });
    assert.deepEqual(icaoToIata('TGW'), { iata: 'TR', name: 'Scoot' });
  });

  it('is case-insensitive', () => {
    assert.deepEqual(icaoToIata('uae'), { iata: 'EK', name: 'Emirates' });
    assert.deepEqual(icaoToIata('Baw'), { iata: 'BA', name: 'British Airways' });
  });

  it('returns undefined for unknown prefixes', () => {
    assert.equal(icaoToIata('DUKE'), undefined);
    assert.equal(icaoToIata('ELK'), undefined);
    assert.equal(icaoToIata('XYZ'), undefined);
    assert.equal(icaoToIata(''), undefined);
  });
});

describe('toIataCallsign', () => {
  it('converts ICAO callsign to IATA equivalent', () => {
    assert.deepEqual(toIataCallsign('UAE528'), { callsign: 'EK528', name: 'Emirates' });
    assert.deepEqual(toIataCallsign('BAW61'), { callsign: 'BA61', name: 'British Airways' });
    assert.deepEqual(toIataCallsign('EZY13BU'), { callsign: 'U213BU', name: 'easyJet' });
    assert.deepEqual(toIataCallsign('THY123'), { callsign: 'TK123', name: 'Turkish Airlines' });
    assert.deepEqual(toIataCallsign('SWR42'), { callsign: 'LX42', name: 'Swiss International Air Lines' });
    assert.deepEqual(toIataCallsign('TGW42'), { callsign: 'TR42', name: 'Scoot' });
  });

  it('handles whitespace and lowercase input', () => {
    assert.deepEqual(toIataCallsign('  uae528  '), { callsign: 'EK528', name: 'Emirates' });
  });

  it('returns null for unknown ICAO prefix (military/charter)', () => {
    assert.equal(toIataCallsign('DUKE41'), null);
    assert.equal(toIataCallsign('RCH123'), null);
  });

  it('returns null for non-standard format', () => {
    assert.equal(toIataCallsign('N123AB'), null);
  });

  it('returns null for empty or whitespace input', () => {
    assert.equal(toIataCallsign(''), null);
    assert.equal(toIataCallsign('   '), null);
  });
});

describe('getWingbitsLiveFlight — IATA schedule fallback', () => {
  afterEach(() => {
    globalThis.fetch = originalFetch;
  });

  it('falls back to IATA callsign when ICAO schedule returns 404, populates airline fields', async () => {
    const fetchedUrls = [];

    globalThis.fetch = async (url) => {
      const u = url.toString();
      fetchedUrls.push(u);

      // Live flight endpoint
      if (u === `${ECS_BASE}/ae1234`) {
        return jsonResp({
          flight: { h: 'ae1234', f: 'UAE528', la: 25.2, lo: 55.3, ab: 35000, gs: 500, tr: 180, rs: 0, og: false, ra: '2024-01-01T12:00:00Z' },
        });
      }
      // ICAO schedule — miss
      if (u === `${ECS_BASE}/schedule/UAE528`) {
        return new Response('Not Found', { status: 404 });
      }
      // IATA schedule fallback — hit
      if (u === `${ECS_BASE}/schedule/EK528`) {
        return jsonResp({
          schedule: { depIata: 'DXB', arrIata: 'LHR', depTimeUtc: '2024-01-01T10:00:00Z', arrTimeUtc: '2024-01-01T18:00:00Z', status: 'en-route', duration: 480 },
        });
      }
      // Photo — skip cleanly
      if (u.startsWith(PHOTOS_BASE)) {
        return new Response('Not Found', { status: 404 });
      }
      return new Response('Unexpected URL', { status: 500 });
    };

    const result = await getWingbitsLiveFlight({}, { icao24: 'ae1234' });

    assert.ok(result.flight, 'flight should be present');
    // Airline fields populated from ICAO→IATA lookup
    assert.equal(result.flight.callsignIata, 'EK528');
    assert.equal(result.flight.airlineName, 'Emirates');
    // Schedule populated via IATA fallback
    assert.equal(result.flight.depIata, 'DXB');
    assert.equal(result.flight.arrIata, 'LHR');
    assert.equal(result.flight.flightStatus, 'en-route');
    assert.equal(result.flight.flightDurationMin, 480);
    // IATA fallback URL was fetched (not just ICAO)
    assert.ok(fetchedUrls.some(u => u.includes('/schedule/EK528')), 'should have fetched IATA schedule');
    // Cache key uses ICAO callsign (uppercase), not IATA
    assert.ok(fetchedUrls.some(u => u.includes('/schedule/UAE528')), 'should have tried ICAO schedule first');
  });

  it('uses ICAO schedule when available, skips IATA fallback', async () => {
    const fetchedUrls = [];

    globalThis.fetch = async (url) => {
      const u = url.toString();
      fetchedUrls.push(u);

      if (u === `${ECS_BASE}/ae1234`) {
        return jsonResp({
          flight: { h: 'ae1234', f: 'UAE528', la: 25.2, lo: 55.3, ab: 35000, gs: 500, tr: 180, rs: 0, og: false, ra: '2024-01-01T12:00:00Z' },
        });
      }
      if (u === `${ECS_BASE}/schedule/UAE528`) {
        return jsonResp({ schedule: { depIata: 'DXB', arrIata: 'LHR', status: 'en-route', duration: 480 } });
      }
      if (u.startsWith(PHOTOS_BASE)) return new Response('Not Found', { status: 404 });
      return new Response('Unexpected URL', { status: 500 });
    };

    const result = await getWingbitsLiveFlight({}, { icao24: 'ae1234' });

    assert.ok(result.flight);
    assert.equal(result.flight.depIata, 'DXB');
    // IATA fallback should NOT have been fetched
    assert.ok(!fetchedUrls.some(u => u.includes('/schedule/EK528')), 'should not fetch IATA schedule when ICAO succeeds');
  });

  it('returns no flight for unknown icao24', async () => {
    const result = await getWingbitsLiveFlight({}, { icao24: '' });
    assert.equal(result.flight, undefined);
  });

  it('returns no flight for invalid icao24 format', async () => {
    const result = await getWingbitsLiveFlight({}, { icao24: 'ZZZZZZ' });
    assert.equal(result.flight, undefined);
  });
});