mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
@
test(calendar): cover the window paths the split added The domain branch ratchet went from 93 to 92.3: the new hand-over code brought branches with no case behind them. Three cases and one simplification, no threshold touched. Covered: a split rental whose endpoints carry no IANA zone and fall back to their coordinates; a bare end clock, which resolves against the start date and therefore does NOT split; and an unsplit rental with a day but no clock, whose hand-over has nothing to place and correctly emits nothing. The metadata parse now happens once, inside describeReservation, rather than three times. The two extra copies were only there to hand `meta` to it, and one of their arms is unreachable from SQLite, where the column is always text. @
This commit is contained in:
@@ -503,13 +503,12 @@ export class CalendarService {
|
||||
if (windowSplit.has(r.id)) continue;
|
||||
const timeLines = buildReservationTimeLines(r);
|
||||
if (!timeLines) continue;
|
||||
const meta = r.metadata ? (typeof r.metadata === 'string' ? JSON.parse(r.metadata) : r.metadata) : {};
|
||||
|
||||
let ev = `BEGIN:VEVENT\r\nUID:${uid(r.id, 'res')}\r\nDTSTAMP:${now}\r\n`;
|
||||
ev += timeLines;
|
||||
ev += `SUMMARY:${esc(r.title)}\r\n`;
|
||||
|
||||
const desc = describeReservation(r, meta);
|
||||
const desc = describeReservation(r);
|
||||
if (desc) ev += `DESCRIPTION:${esc(desc)}\r\n`;
|
||||
if (r.location) ev += `LOCATION:${esc(r.location)}\r\n`;
|
||||
ev += `END:VEVENT\r\n`;
|
||||
@@ -520,7 +519,8 @@ export class CalendarService {
|
||||
// event loop because a window booking's two hand-over events carry the same
|
||||
// lines: dropping the block must not drop the route or the confirmation with
|
||||
// it (#2068).
|
||||
function describeReservation(r: any, meta: any): string {
|
||||
function describeReservation(r: any): string {
|
||||
const meta = r.metadata ? (typeof r.metadata === 'string' ? JSON.parse(r.metadata) : r.metadata) : {};
|
||||
let desc = r.type ? `Type: ${r.type}` : '';
|
||||
if (r.confirmation_number) desc += `\nConfirmation: ${r.confirmation_number}`;
|
||||
if (meta.airline) desc += `\nAirline: ${meta.airline}`;
|
||||
@@ -627,8 +627,7 @@ export class CalendarService {
|
||||
if (!split && r.type !== 'car') continue;
|
||||
|
||||
const { start, end } = split ?? windowSidesOf(r);
|
||||
const meta = r.metadata ? (typeof r.metadata === 'string' ? JSON.parse(r.metadata) : r.metadata) : {};
|
||||
const desc = split ? describeReservation(r, meta) : '';
|
||||
const desc = split ? describeReservation(r) : '';
|
||||
|
||||
const handover = (kind: 'pickup' | 'dropoff', side: WindowSide, summary: string) => {
|
||||
let ev = `BEGIN:VEVENT\r\nUID:${uid(r.id, kind)}\r\nDTSTAMP:${now}\r\n`;
|
||||
|
||||
@@ -1192,6 +1192,55 @@ describe('car rentals', () => {
|
||||
expect(ics).toContain('DTEND;VALUE=DATE:20260705');
|
||||
expect(ics).not.toContain('Pickup: Night Bus');
|
||||
});
|
||||
|
||||
it('CAL-052: a split rental whose endpoints carry no zone falls back to their coordinates', () => {
|
||||
const { user } = createUser(testDb);
|
||||
const trip = createTrip(testDb, user.id, { title: 'Road Trip' });
|
||||
const rental = createReservation(testDb, trip.id, { title: 'Europcar', type: 'car' });
|
||||
testDb.prepare('UPDATE reservations SET reservation_time=NULL, reservation_end_time=NULL WHERE id=?').run(rental.id);
|
||||
// An older import that geocoded both ends but stored no IANA zone.
|
||||
insertEndpoint(rental.id, 'from', 0, 'Paris Office', 48.8566, 2.3522, null, '09:00', '2026-07-07');
|
||||
insertEndpoint(rental.id, 'to', 1, 'Berlin Office', 52.5, 13.4, null, '10:30', '2026-07-14');
|
||||
|
||||
const { ics } = svc.exportICS(trip.id);
|
||||
|
||||
expect(ics).toContain('DTSTART;TZID=Europe/Paris:20260707T090000');
|
||||
expect(ics).toContain('DTSTART;TZID=Europe/Berlin:20260714T103000');
|
||||
});
|
||||
|
||||
// reservation_end_time is frequently a bare clock next to the booking's own
|
||||
// date, which puts both hand-overs on the same day — so it is one sitting.
|
||||
it('CAL-053: a bare end clock resolves against the start date rather than splitting', () => {
|
||||
const { user } = createUser(testDb);
|
||||
const trip = createTrip(testDb, user.id, { title: 'Road Trip' });
|
||||
const parking = createReservation(testDb, trip.id, { title: 'Street Bay', type: 'parking' });
|
||||
testDb.prepare('UPDATE reservations SET reservation_time=?, reservation_end_time=? WHERE id=?')
|
||||
.run('2026-07-01T08:00', '18:30', parking.id);
|
||||
|
||||
const { ics } = svc.exportICS(trip.id);
|
||||
|
||||
expect(ics).toContain('SUMMARY:Street Bay\r\n');
|
||||
expect(ics).not.toContain('Drop-off: Street Bay');
|
||||
expect(ics).not.toContain('Pickup: Street Bay');
|
||||
});
|
||||
|
||||
it('CAL-054: an unsplit rental with a day but no clock emits no hand-over of its own', () => {
|
||||
const { user } = createUser(testDb);
|
||||
const trip = createTrip(testDb, user.id, { title: 'Road Trip' });
|
||||
const day = createDay(testDb, trip.id, { date: '2026-07-03' });
|
||||
const rental = createReservation(testDb, trip.id, { title: 'Dayless', type: 'car' });
|
||||
// A day but no end day and no clock: one side resolves, and it has no time,
|
||||
// so there is nothing to place — the all-day block carries it instead.
|
||||
testDb.prepare('UPDATE reservations SET reservation_time=NULL, reservation_end_time=NULL, day_id=?, end_day_id=NULL WHERE id=?')
|
||||
.run(day.id, rental.id);
|
||||
|
||||
const { ics } = svc.exportICS(trip.id);
|
||||
|
||||
expect(ics).toContain('SUMMARY:Dayless\r\n');
|
||||
expect(ics).toContain('DTSTART;VALUE=DATE:20260703');
|
||||
expect(ics).not.toContain('Pickup: Dayless');
|
||||
expect(ics).not.toContain('Drop-off: Dayless');
|
||||
});
|
||||
});
|
||||
|
||||
describe('folded quirk branches', () => {
|
||||
|
||||
Reference in New Issue
Block a user