mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
161 lines
5.9 KiB
TypeScript
161 lines
5.9 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { buildSavePayload } from '../../../src/services/airtrail/airtrailSync';
|
|
import type { AirtrailAirport, AirtrailFlightRaw } from '../../../src/services/airtrail/airtrailClient';
|
|
|
|
function airport(over: Partial<AirtrailAirport> = {}): AirtrailAirport {
|
|
return {
|
|
id: 1,
|
|
icao: 'KJFK',
|
|
iata: 'JFK',
|
|
name: 'John F. Kennedy Intl.',
|
|
lat: 40.6413,
|
|
lon: -73.7781,
|
|
tz: 'America/New_York',
|
|
country: 'US',
|
|
...over,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* An AirTrail flight as GET returns it, including the fields TREK doesn't model.
|
|
* Typed as the raw object (known shape + arbitrary passthrough keys) because the
|
|
* push spreads it wholesale rather than mapping each field — see buildSavePayload.
|
|
*/
|
|
function existingFlight(
|
|
over: Partial<AirtrailFlightRaw> & Record<string, unknown> = {},
|
|
): AirtrailFlightRaw & Record<string, unknown> {
|
|
return {
|
|
id: 42,
|
|
from: airport(),
|
|
to: airport({ id: 2, icao: 'EGLL', iata: 'LHR', name: 'London Heathrow', tz: 'Europe/London' }),
|
|
date: '2021-09-01',
|
|
datePrecision: 'day',
|
|
departure: '2021-09-01T23:00:00.000+00:00',
|
|
arrival: '2021-09-02T07:00:00.000+00:00',
|
|
airline: { id: 1, icao: 'BAW', iata: 'BA', name: 'British Airways' },
|
|
flightNumber: 'BA178',
|
|
aircraft: { id: 1, icao: 'B772', name: 'Boeing 777' },
|
|
aircraftReg: 'G-VIIL',
|
|
flightReason: 'leisure',
|
|
note: 'window seat',
|
|
seats: [{ userId: 'u1', guestName: null, seat: 'window', seatNumber: '12A', seatClass: 'economy' }],
|
|
// AirTrail-owned detail TREK never surfaces — must survive a writeback (#1240).
|
|
departureScheduled: '2021-09-01',
|
|
departureScheduledTime: '18:45',
|
|
arrivalScheduled: '2021-09-02',
|
|
arrivalScheduledTime: '08:10',
|
|
takeoffActual: '2021-09-01',
|
|
takeoffActualTime: '19:12',
|
|
landingActual: '2021-09-02',
|
|
landingActualTime: '07:55',
|
|
departureTerminal: '7',
|
|
departureGate: 'B22',
|
|
arrivalTerminal: '5',
|
|
arrivalGate: 'A10',
|
|
customFields: { confirmation: 'ABC123' },
|
|
track: [{ lat: 40.6, lon: -73.7 }],
|
|
...over,
|
|
};
|
|
}
|
|
|
|
/** A linked TREK reservation (the shape getReservationWithJoins returns). */
|
|
function reservation(over: Record<string, unknown> = {}): Record<string, unknown> {
|
|
return {
|
|
external_id: '42',
|
|
reservation_time: '2021-09-01T19:00',
|
|
reservation_end_time: '2021-09-02T08:00',
|
|
notes: 'window seat',
|
|
metadata: JSON.stringify({ airline: 'BAW', flight_number: 'BA178', aircraft: 'B772', aircraft_reg: 'G-VIIL', flight_reason: 'leisure', seat: '12A' }),
|
|
endpoints: [
|
|
{ role: 'from', code: 'JFK' },
|
|
{ role: 'to', code: 'LHR' },
|
|
],
|
|
...over,
|
|
};
|
|
}
|
|
|
|
describe('airtrailSync.buildSavePayload', () => {
|
|
it('round-trips the AirTrail-owned fields TREK does not model (issue #1240)', () => {
|
|
const payload = buildSavePayload(reservation(), existingFlight());
|
|
expect(payload).not.toBeNull();
|
|
expect(payload).toMatchObject({
|
|
departureScheduled: '2021-09-01',
|
|
departureScheduledTime: '18:45',
|
|
arrivalScheduled: '2021-09-02',
|
|
arrivalScheduledTime: '08:10',
|
|
takeoffActual: '2021-09-01',
|
|
takeoffActualTime: '19:12',
|
|
landingActual: '2021-09-02',
|
|
landingActualTime: '07:55',
|
|
departureTerminal: '7',
|
|
departureGate: 'B22',
|
|
arrivalTerminal: '5',
|
|
arrivalGate: 'A10',
|
|
customFields: { confirmation: 'ABC123' },
|
|
track: [{ lat: 40.6, lon: -73.7 }],
|
|
});
|
|
});
|
|
|
|
it('preserves a non-day date precision instead of resetting it to day', () => {
|
|
const payload = buildSavePayload(reservation(), existingFlight({ datePrecision: 'month' }));
|
|
expect(payload?.datePrecision).toBe('month');
|
|
});
|
|
|
|
it('still applies the TREK-owned edits on top of the preserved fields', () => {
|
|
const payload = buildSavePayload(
|
|
reservation({
|
|
reservation_time: '2021-09-01T20:30',
|
|
notes: 'changed in TREK',
|
|
metadata: JSON.stringify({ airline: 'BAW', flight_number: 'BA999', seat: '3C' }),
|
|
}),
|
|
existingFlight(),
|
|
);
|
|
expect(payload).toMatchObject({
|
|
id: 42,
|
|
from: 'JFK',
|
|
to: 'LHR',
|
|
departure: '2021-09-01',
|
|
departureTime: '20:30',
|
|
flightNumber: 'BA999',
|
|
note: 'changed in TREK',
|
|
});
|
|
// The user's seat number is pushed onto their own AirTrail seat.
|
|
expect(payload?.seats[0].seatNumber).toBe('3C');
|
|
// …without disturbing the preserved AirTrail detail.
|
|
expect(payload?.departureTerminal).toBe('7');
|
|
});
|
|
|
|
it('preserves AirTrail aircraft/airline/reason when TREK metadata omits them (#1240)', () => {
|
|
// A TREK edit can drop these AirTrail-owned fields from metadata; the writeback
|
|
// must fall back to AirTrail's current values rather than nulling them.
|
|
const payload = buildSavePayload(reservation({ metadata: JSON.stringify({}) }), existingFlight());
|
|
expect(payload).toMatchObject({
|
|
airline: 'BAW', // entityCode(existing.airline) — icao preferred
|
|
aircraft: 'B772',
|
|
aircraftReg: 'G-VIIL',
|
|
flightReason: 'leisure',
|
|
flightNumber: 'BA178',
|
|
note: 'window seat',
|
|
});
|
|
});
|
|
|
|
it('keeps the existing seat manifest rather than replacing it', () => {
|
|
const payload = buildSavePayload(
|
|
reservation({ metadata: JSON.stringify({}) }),
|
|
existingFlight({
|
|
seats: [
|
|
{ userId: 'u1', guestName: null, seat: 'window', seatNumber: '12A', seatClass: 'business' },
|
|
{ userId: null, guestName: 'Guest', seat: 'aisle', seatNumber: '12B', seatClass: 'business' },
|
|
],
|
|
}),
|
|
);
|
|
expect(payload?.seats).toHaveLength(2);
|
|
expect(payload?.seats[1]).toMatchObject({ guestName: 'Guest', seatNumber: '12B' });
|
|
});
|
|
|
|
it('returns null when an endpoint code is missing and no fallback exists', () => {
|
|
const payload = buildSavePayload(reservation({ endpoints: [] }), existingFlight({ from: airport({ iata: null, icao: null }) }));
|
|
expect(payload).toBeNull();
|
|
});
|
|
});
|