mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-20 14:06:27 +00:00
462a208fdf
The day's accommodation is drawn as a leg to the first and from the last waypoint. Now that a booked night puts its hotel on the check-in day as a stop of its own, that last waypoint IS the hotel on most days, and the leg drawn to it is a round trip of zero kilometres: in the map line, in the sidebar's leg list and in every exported directions link, which carried the hotel twice in a row. The defect already existed for a night booked in the road trip; the change above would have made it the normal case. Both bookend rules now decline a leg whose edge stop sits at the hotel's own coordinates, which covers the map, the sidebar, the phone route and both export links from one place. Compared by coordinates rather than ids, because the bookend comes off the stay row and the waypoint off the assignment.
438 lines
24 KiB
TypeScript
438 lines
24 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import type { Day, Accommodation } from '../types'
|
|
import { getDayOrder, isDayInAccommodationRange, getAccommodationAnchors, getDayBookendHotels, shouldDrawMorningLeg, shouldDrawEveningLeg } from './dayOrder'
|
|
|
|
const days = [
|
|
{ id: 10, day_number: 1 },
|
|
{ id: 20, day_number: 2 },
|
|
{ id: 30, day_number: 3 },
|
|
] as unknown as Day[]
|
|
|
|
const hotel = (over: Partial<Accommodation>): Accommodation =>
|
|
({ place_lat: 48.1, place_lng: 11.5, start_day_id: 10, end_day_id: 30, ...over }) as Accommodation
|
|
|
|
describe('getDayOrder', () => {
|
|
it('prefers day_number when present', () => {
|
|
expect(getDayOrder(days[1], days)).toBe(2)
|
|
})
|
|
it('falls back to array index when day_number is missing', () => {
|
|
const noNumber = [{ id: 5 }, { id: 6 }] as unknown as Day[]
|
|
expect(getDayOrder(noNumber[1], noNumber)).toBe(1)
|
|
})
|
|
})
|
|
|
|
describe('isDayInAccommodationRange', () => {
|
|
it('is inclusive of both the check-in and check-out day', () => {
|
|
expect(isDayInAccommodationRange(days[0], 10, 30, days)).toBe(true) // check-in morning
|
|
expect(isDayInAccommodationRange(days[1], 10, 30, days)).toBe(true) // mid-stay
|
|
expect(isDayInAccommodationRange(days[2], 10, 30, days)).toBe(true) // check-out day
|
|
})
|
|
it('excludes days outside the stay', () => {
|
|
expect(isDayInAccommodationRange(days[0], 20, 30, days)).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('getAccommodationAnchors', () => {
|
|
it('returns no anchors when the day has no accommodation', () => {
|
|
expect(getAccommodationAnchors(days[1], days, [])).toEqual({})
|
|
})
|
|
|
|
it('anchors both ends to the same hotel on a mid-stay day (round trip)', () => {
|
|
const accs = [hotel({ start_day_id: 10, end_day_id: 30, place_lat: 48.1, place_lng: 11.5 })]
|
|
expect(getAccommodationAnchors(days[1], days, accs)).toEqual({
|
|
start: { lat: 48.1, lng: 11.5 },
|
|
end: { lat: 48.1, lng: 11.5 },
|
|
})
|
|
})
|
|
|
|
it('loops a single hotel on its check-out day (home base for the day)', () => {
|
|
const accs = [hotel({ start_day_id: 10, end_day_id: 20, place_lat: 1, place_lng: 2 })]
|
|
expect(getAccommodationAnchors(days[1], days, accs)).toEqual({ start: { lat: 1, lng: 2 }, end: { lat: 1, lng: 2 } })
|
|
})
|
|
|
|
it('loops a single hotel on its check-in day (home base for the day)', () => {
|
|
const accs = [hotel({ start_day_id: 20, end_day_id: 30, place_lat: 3, place_lng: 4 })]
|
|
expect(getAccommodationAnchors(days[1], days, accs)).toEqual({ start: { lat: 3, lng: 4 }, end: { lat: 3, lng: 4 } })
|
|
})
|
|
|
|
it('uses the checked-out hotel as start and the checked-in hotel as end on a transfer day', () => {
|
|
const accs = [
|
|
hotel({ start_day_id: 10, end_day_id: 20, place_lat: 1, place_lng: 1 }), // checkout today
|
|
hotel({ start_day_id: 20, end_day_id: 30, place_lat: 9, place_lng: 9 }), // check-in today
|
|
]
|
|
expect(getAccommodationAnchors(days[1], days, accs)).toEqual({
|
|
start: { lat: 1, lng: 1 },
|
|
end: { lat: 9, lng: 9 },
|
|
})
|
|
})
|
|
|
|
it('ignores accommodations that have no coordinates', () => {
|
|
const accs = [hotel({ start_day_id: 10, end_day_id: 30, place_lat: null, place_lng: null })]
|
|
expect(getAccommodationAnchors(days[1], days, accs)).toEqual({})
|
|
})
|
|
|
|
it('keeps morning/evening correct on a transfer day when the morning stay runs long (#887)', () => {
|
|
const accs = [
|
|
hotel({ start_day_id: 10, end_day_id: 30, place_lat: 1, place_lng: 1 }), // slept here, checks out later
|
|
hotel({ start_day_id: 20, end_day_id: 30, place_lat: 9, place_lng: 9 }), // check-in today
|
|
]
|
|
expect(getAccommodationAnchors(days[1], days, accs)).toEqual({
|
|
start: { lat: 1, lng: 1 },
|
|
end: { lat: 9, lng: 9 },
|
|
})
|
|
})
|
|
|
|
// A Reykjavík stay checking in on day 1 and out on day 3, with neither time recorded,
|
|
// and untimed stops the optimizer is free to reorder.
|
|
const reykjavik = { lat: 64.14, lng: -21.94 }
|
|
const stay = () => hotel({ start_day_id: 10, end_day_id: 30, place_lat: reykjavik.lat, place_lng: reykjavik.lng })
|
|
const home = { lat: 50.11, lng: 8.68 }
|
|
const blueLagoon = { lat: 63.88, lng: -22.45 }
|
|
const hallgrimskirkja = { lat: 64.145, lng: -21.93 }
|
|
|
|
it('drops the check-in anchor when the day reaches past a day trip from the hotel (#2157)', () => {
|
|
// The optimizer half of the same bug. Pinning both ends to a hotel you have not
|
|
// reached yet made one click on "Optimize route" sort Home between the two Icelandic
|
|
// stops, because that is the shortest loop, and the user had to drag it back by hand.
|
|
expect(getAccommodationAnchors(days[0], days, [stay()], [home, blueLagoon, hallgrimskirkja]))
|
|
.toEqual({ end: reykjavik })
|
|
})
|
|
|
|
it('drops the check-out anchor when a carrier takes you out of the day (#2157)', () => {
|
|
// Mirror on the departure day: you woke up here, so the hotel still starts the
|
|
// route, but the flight home means nothing comes back to it.
|
|
expect(getAccommodationAnchors(days[2], days, [stay()], [hallgrimskirkja], true))
|
|
.toEqual({ start: reykjavik })
|
|
})
|
|
|
|
it('keeps the loop when every stop is a day out of the hotel (#2009 preserved)', () => {
|
|
expect(getAccommodationAnchors(days[0], days, [stay()], [blueLagoon, hallgrimskirkja]))
|
|
.toEqual({ start: reykjavik, end: reykjavik })
|
|
})
|
|
|
|
it('has nothing to weigh the anchors against when the stop list is empty', () => {
|
|
expect(getAccommodationAnchors(days[0], days, [stay()], []))
|
|
.toEqual({ start: reykjavik, end: reykjavik })
|
|
})
|
|
})
|
|
|
|
describe('getDayBookendHotels', () => {
|
|
it('returns nothing when the day has no accommodation', () => {
|
|
expect(getDayBookendHotels(days[1], days, [])).toEqual({})
|
|
})
|
|
|
|
it('bookends both ends with the single hotel on a normal stay day', () => {
|
|
const h = hotel({ start_day_id: 10, end_day_id: 30 })
|
|
const { morning, evening } = getDayBookendHotels(days[1], days, [h])
|
|
expect(morning).toBe(h)
|
|
expect(evening).toBe(h)
|
|
})
|
|
|
|
it('uses the checked-out hotel in the morning and the checked-in hotel in the evening on a transfer day', () => {
|
|
const out = hotel({ start_day_id: 10, end_day_id: 20, place_lat: 1, place_lng: 1 })
|
|
const into = hotel({ start_day_id: 20, end_day_id: 30, place_lat: 9, place_lng: 9 })
|
|
const { morning, evening } = getDayBookendHotels(days[1], days, [out, into])
|
|
expect(morning).toBe(out)
|
|
expect(evening).toBe(into)
|
|
})
|
|
|
|
it('still picks the slept-in hotel for the morning when its stay does not end on the transfer day (#887)', () => {
|
|
// The morning hotel runs long (checks out day 3) so it is not flagged as "checks out today";
|
|
// the old "ends today" rule collapsed both bookends onto the arriving hotel.
|
|
const stayed = hotel({ start_day_id: 10, end_day_id: 30, place_lat: 1, place_lng: 1 })
|
|
const into = hotel({ start_day_id: 20, end_day_id: 30, place_lat: 9, place_lng: 9 })
|
|
const { morning, evening } = getDayBookendHotels(days[1], days, [stayed, into])
|
|
expect(morning).toBe(stayed)
|
|
expect(evening).toBe(into)
|
|
})
|
|
|
|
it('ignores accommodations without coordinates', () => {
|
|
const h = hotel({ place_lat: null, place_lng: null })
|
|
expect(getDayBookendHotels(days[1], days, [h])).toEqual({})
|
|
})
|
|
|
|
it('flags an arrival/check-in day as not slept-here in the morning (#1321)', () => {
|
|
// Day 1: you arrive from home and check in tonight, so the morning hotel is only a
|
|
// check-in fallback — no hotel → departure leg should be drawn.
|
|
const into = hotel({ start_day_id: 10, end_day_id: 30, place_lat: 3, place_lng: 4 })
|
|
const r = getDayBookendHotels(days[0], days, [into])
|
|
expect(r.morning).toBe(into)
|
|
expect(r.morningIsSleptHere).toBe(false)
|
|
expect(r.eveningIsOvernight).toBe(true)
|
|
// The optimizer anchor must stay a loop on the check-in day (values unchanged).
|
|
expect(getAccommodationAnchors(days[0], days, [into])).toEqual({ start: { lat: 3, lng: 4 }, end: { lat: 3, lng: 4 } })
|
|
})
|
|
|
|
it('flags a mid-stay day as slept-here and overnight', () => {
|
|
const h = hotel({ start_day_id: 10, end_day_id: 30 })
|
|
const r = getDayBookendHotels(days[1], days, [h])
|
|
expect(r.morningIsSleptHere).toBe(true)
|
|
expect(r.eveningIsOvernight).toBe(true)
|
|
})
|
|
|
|
it('an evening departure with no replacement check-in is not overnight (S7 mirror)', () => {
|
|
// You woke up here but check out today and board an evening transport — you do not
|
|
// sleep here tonight, so the last-stop → hotel leg must be droppable.
|
|
const h = hotel({ start_day_id: 10, end_day_id: 20, place_lat: 1, place_lng: 1 })
|
|
const r = getDayBookendHotels(days[1], days, [h])
|
|
expect(r.morningIsSleptHere).toBe(true)
|
|
expect(r.eveningIsOvernight).toBe(false)
|
|
})
|
|
|
|
it('flags a transfer day as slept-here in the morning and overnight in the evening', () => {
|
|
const out = hotel({ start_day_id: 10, end_day_id: 20, place_lat: 1, place_lng: 1 })
|
|
const into = hotel({ start_day_id: 20, end_day_id: 30, place_lat: 9, place_lng: 9 })
|
|
const r = getDayBookendHotels(days[1], days, [out, into])
|
|
expect(r.morningIsSleptHere).toBe(true)
|
|
expect(r.eveningIsOvernight).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('shouldDrawMorningLeg', () => {
|
|
const checkInDay = days[0] // id 10
|
|
const into = (over: Partial<Accommodation> = {}) =>
|
|
hotel({ start_day_id: 10, end_day_id: 30, check_in: '15:00', ...over })
|
|
|
|
it('draws when you slept in the morning hotel, regardless of stop time', () => {
|
|
const bookends = { morning: into(), morningIsSleptHere: true }
|
|
// Mid-stay: even a stop at 06:00 is preceded by the hotel you woke in.
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: true, time: '06:00' })).toBe(true)
|
|
})
|
|
|
|
it('does NOT draw when the day opens on an airport you landed at (#2133)', () => {
|
|
// You flew in. Even on a night you provably slept in this hotel, nobody drove out
|
|
// of it to the airport that set you down.
|
|
const bookends = { morning: into(), morningIsSleptHere: true }
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: false, carrierEdge: 'arrival' })).toBe(false)
|
|
})
|
|
|
|
it('still draws when the day opens on an airport you departed from (#2133)', () => {
|
|
// The legitimate mirror: you woke in the hotel and drove to your outbound airport.
|
|
const bookends = { morning: into(), morningIsSleptHere: true }
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: false, carrierEdge: 'departure' })).toBe(true)
|
|
})
|
|
|
|
it('still draws for a hire-car drop-off point, which carries no carrierEdge (#2133)', () => {
|
|
// A car you keep driving is not a carrier: the hotel → drop-off depot drive is real.
|
|
const bookends = { morning: into(), morningIsSleptHere: true }
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: false, carrierEdge: null })).toBe(true)
|
|
})
|
|
|
|
it('does NOT draw on a check-in day when the first place is before check-in (#1465)', () => {
|
|
const bookends = { morning: into({ check_in: '15:00' }), morningIsSleptHere: false }
|
|
// Airport place at 10:00, check-in 15:00 — you have not reached the hotel yet.
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: true, time: '10:00' })).toBe(false)
|
|
})
|
|
|
|
it('draws on a check-in day when the first place is at/after check-in (loop preserved)', () => {
|
|
const bookends = { morning: into({ check_in: '15:00' }), morningIsSleptHere: false }
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: true, time: '19:00' })).toBe(true)
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: true, time: '15:00' })).toBe(true)
|
|
})
|
|
|
|
it('does NOT draw on a check-in day when the stop is untimed but check-in is not (#1597)', () => {
|
|
// An un-timed first place on an arrival day ("Home" before driving out) cannot prove
|
|
// you were at the hotel yet, so no hotel → first-stop leg — mirroring the evening rule.
|
|
const bookends = { morning: into({ check_in: '15:00' }), morningIsSleptHere: false }
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: true, time: null })).toBe(false)
|
|
})
|
|
|
|
it('DOES draw on a check-in day when the stay records no check-in time (#2009)', () => {
|
|
// Nothing to clear, so nothing to fail: the hotel picker leaves the time blank
|
|
// by default, and treating that as proof against left the loop open every time.
|
|
const noCheckIn = { morning: into({ check_in: null }), morningIsSleptHere: false }
|
|
expect(shouldDrawMorningLeg(noCheckIn, checkInDay, { isPlace: true, time: '19:00' })).toBe(true)
|
|
expect(shouldDrawMorningLeg(noCheckIn, checkInDay, { isPlace: true, time: null })).toBe(true)
|
|
// A transport arrival is still not a hotel departure (#1321).
|
|
expect(shouldDrawMorningLeg(noCheckIn, checkInDay, { isPlace: false, time: '19:00' })).toBe(false)
|
|
})
|
|
|
|
it('does NOT draw on a check-in day for a transport arrival (not a place, #1321)', () => {
|
|
const bookends = { morning: into({ check_in: '15:00' }), morningIsSleptHere: false }
|
|
// A late arrival (16:00) is still no morning leg — you flew in, weren't at the hotel.
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: false, time: '16:00' })).toBe(false)
|
|
})
|
|
|
|
it('does NOT draw when the morning hotel is not checking in today', () => {
|
|
// start_day_id 20 ≠ day 10, and not slept-here → no leg.
|
|
const bookends = { morning: into({ start_day_id: 20, check_in: '15:00' }), morningIsSleptHere: false }
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: true, time: '19:00' })).toBe(false)
|
|
})
|
|
|
|
it('does NOT draw on a no-check-in-time day when a carrier arrives or leaves that day (#2157)', () => {
|
|
// You fly in, so the hotel is where the day ends — the no-time loop default
|
|
// must not start the day from a hotel you only reach tonight.
|
|
const noCheckIn = { morning: into({ check_in: null }), morningIsSleptHere: false }
|
|
expect(shouldDrawMorningLeg(noCheckIn, checkInDay, { isPlace: true, time: null }, true)).toBe(false)
|
|
expect(shouldDrawMorningLeg(noCheckIn, checkInDay, { isPlace: true, time: '19:00' }, true)).toBe(false)
|
|
})
|
|
|
|
it('still closes the no-time loop when the day has no carrier (#2009 preserved)', () => {
|
|
const noCheckIn = { morning: into({ check_in: null }), morningIsSleptHere: false }
|
|
expect(shouldDrawMorningLeg(noCheckIn, checkInDay, { isPlace: true, time: null }, false)).toBe(true)
|
|
// Callers that don't know about the flag keep the old behaviour.
|
|
expect(shouldDrawMorningLeg(noCheckIn, checkInDay, { isPlace: true, time: null })).toBe(true)
|
|
})
|
|
|
|
it('a recorded check-in time keeps the timed rule even on a carrier day (#2157)', () => {
|
|
const bookends = { morning: into({ check_in: '15:00' }), morningIsSleptHere: false }
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: true, time: '19:00' }, true)).toBe(true)
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: true, time: '10:00' }, true)).toBe(false)
|
|
})
|
|
|
|
it('a carrier does not touch the slept-here morning leg (#2157)', () => {
|
|
// Mid-stay day with a day-trip by train: you still woke up in this hotel.
|
|
const bookends = { morning: into(), morningIsSleptHere: true }
|
|
expect(shouldDrawMorningLeg(bookends, checkInDay, { isPlace: true, time: '06:00' }, true)).toBe(true)
|
|
})
|
|
|
|
it('the no-time default does not reach an edge place out of day-trip range (#2157)', () => {
|
|
// "Home", an ocean away from the hotel, with no carrier recorded at all: the
|
|
// closed loop is a guess, and a guess does not get a 2400 km leg.
|
|
const noCheckIn = { morning: into({ check_in: null }), morningIsSleptHere: false }
|
|
expect(shouldDrawMorningLeg(noCheckIn, checkInDay, { isPlace: true, time: null, lat: 21.28, lng: -157.83 })).toBe(false)
|
|
// A nearby untimed place keeps the #2009 loop.
|
|
expect(shouldDrawMorningLeg(noCheckIn, checkInDay, { isPlace: true, time: null, lat: 48.2, lng: 11.6 })).toBe(true)
|
|
})
|
|
|
|
it('a drivable edge place is still out of range when no day out of the hotel reaches it (#2157)', () => {
|
|
// The issue's literal repro, driven rather than flown: hotel in Warnemünde, "Home"
|
|
// in Frankfurt, 508 km apart. The router answers that pair happily, so a
|
|
// reachability limit (2000 km, all of Europe) never fired and the arrival day kept
|
|
// starting at a hotel nobody had reached yet. What rules it out is that no day out
|
|
// of that hotel goes to Frankfurt and back.
|
|
const noCheckIn = { morning: into({ check_in: null, place_lat: 54.18, place_lng: 12.08 }), morningIsSleptHere: false }
|
|
expect(shouldDrawMorningLeg(noCheckIn, checkInDay, { isPlace: true, time: null, lat: 50.11, lng: 8.68 })).toBe(false)
|
|
// The day trip that hotel does send you on (Rostock zoo, 11 km) keeps its leg.
|
|
expect(shouldDrawMorningLeg(noCheckIn, checkInDay, { isPlace: true, time: null, lat: 54.08, lng: 12.10 })).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('the hotel is the edge stop itself', () => {
|
|
// Booking a night now puts its hotel on the check-in day as a stop of its own, so
|
|
// the day's last waypoint IS the hotel on most days. Without this the drawn line,
|
|
// the sidebar leg list and every exported directions link carry a hotel-to-hotel
|
|
// leg of zero kilometres.
|
|
const atHotel = { isPlace: true, time: null, lat: 48.1, lng: 11.5 }
|
|
|
|
it('draws no evening leg when the last stop is the hotel you sleep in tonight', () => {
|
|
const bookends = { evening: hotel({ end_day_id: 30 }), eveningIsOvernight: true }
|
|
expect(shouldDrawEveningLeg(bookends, days[0], atHotel)).toBe(false)
|
|
// A different stop at the same distance keeps its leg.
|
|
expect(shouldDrawEveningLeg(bookends, days[0], { ...atHotel, lat: 48.2 })).toBe(true)
|
|
})
|
|
|
|
it('draws no morning leg when the first stop is the hotel you woke up in', () => {
|
|
const bookends = { morning: hotel({}), morningIsSleptHere: true }
|
|
expect(shouldDrawMorningLeg(bookends, days[1], atHotel)).toBe(false)
|
|
expect(shouldDrawMorningLeg(bookends, days[1], { ...atHotel, lng: 11.6 })).toBe(true)
|
|
})
|
|
|
|
it('leaves a stop without coordinates alone', () => {
|
|
// A transport endpoint carries no lat/lng; the carrier rules below decide it.
|
|
const bookends = { evening: hotel({}), eveningIsOvernight: true }
|
|
expect(shouldDrawEveningLeg(bookends, days[0], { isPlace: false, time: null })).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('shouldDrawEveningLeg', () => {
|
|
const checkOutDay = days[2] // id 30
|
|
const out = (over: Partial<Accommodation> = {}) =>
|
|
hotel({ start_day_id: 10, end_day_id: 30, check_out: '11:00', ...over })
|
|
|
|
it('draws when you sleep in the evening hotel tonight, regardless of stop time', () => {
|
|
const bookends = { evening: out(), eveningIsOvernight: true }
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: true, time: '23:00' })).toBe(true)
|
|
})
|
|
|
|
it('does NOT draw when the day ends at an airport you took off from (#2133)', () => {
|
|
// The reported bug: an overnight flight leaves only its departure airport on the
|
|
// day it leaves, and that airport was being joined to tonight's hotel.
|
|
const bookends = { evening: out(), eveningIsOvernight: true }
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: false, carrierEdge: 'departure' })).toBe(false)
|
|
})
|
|
|
|
it('still draws when the day ends at an airport you landed at (#2133)', () => {
|
|
// The legitimate case the fix must not eat: you land, then drive to the hotel.
|
|
const bookends = { evening: out(), eveningIsOvernight: true }
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: false, carrierEdge: 'arrival' })).toBe(true)
|
|
})
|
|
|
|
it('still draws for a hire-car pickup point, which carries no carrierEdge (#2133)', () => {
|
|
// You collect the car at 18:00 and drive it to tonight's hotel — a real leg.
|
|
const bookends = { evening: out(), eveningIsOvernight: true }
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: false, carrierEdge: null })).toBe(true)
|
|
})
|
|
|
|
it('does NOT draw on a check-out day when the last place is after check-out (#1465)', () => {
|
|
const bookends = { evening: out({ check_out: '11:00' }), eveningIsOvernight: false }
|
|
// "home" place at 18:00, check-out 11:00 — you have already left the hotel.
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: true, time: '18:00' })).toBe(false)
|
|
})
|
|
|
|
it('draws on a check-out day when the last place is at/before check-out', () => {
|
|
const bookends = { evening: out({ check_out: '11:00' }), eveningIsOvernight: false }
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: true, time: '09:00' })).toBe(true)
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: true, time: '11:00' })).toBe(true)
|
|
})
|
|
|
|
it('does NOT draw on a check-out day when the stop is untimed but check-out is not', () => {
|
|
const bookends = { evening: out({ check_out: '11:00' }), eveningIsOvernight: false }
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: true, time: null })).toBe(false)
|
|
})
|
|
|
|
it('DOES draw on a check-out day when the stay records no check-out time (#2009)', () => {
|
|
const noCheckOut = { evening: out({ check_out: null }), eveningIsOvernight: false }
|
|
expect(shouldDrawEveningLeg(noCheckOut, checkOutDay, { isPlace: true, time: '09:00' })).toBe(true)
|
|
expect(shouldDrawEveningLeg(noCheckOut, checkOutDay, { isPlace: true, time: null })).toBe(true)
|
|
// An evening transport departure is still not a drive back to the hotel (S7).
|
|
expect(shouldDrawEveningLeg(noCheckOut, checkOutDay, { isPlace: false, time: '09:00' })).toBe(false)
|
|
})
|
|
|
|
it('does NOT draw on a check-out day for a transport departure (not a place, S7)', () => {
|
|
const bookends = { evening: out({ check_out: '11:00' }), eveningIsOvernight: false }
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: false, time: '09:00' })).toBe(false)
|
|
})
|
|
|
|
it('does NOT draw on a no-check-out-time day when a carrier arrives or leaves that day (#2157)', () => {
|
|
// The reported last day: fly home, then a "Home" entry — nothing drives from
|
|
// Home back to the hotel you left that morning.
|
|
const noCheckOut = { evening: out({ check_out: null }), eveningIsOvernight: false }
|
|
expect(shouldDrawEveningLeg(noCheckOut, checkOutDay, { isPlace: true, time: null }, true)).toBe(false)
|
|
expect(shouldDrawEveningLeg(noCheckOut, checkOutDay, { isPlace: true, time: '09:00' }, true)).toBe(false)
|
|
})
|
|
|
|
it('still closes the no-time loop when the day has no carrier (#2009 preserved)', () => {
|
|
const noCheckOut = { evening: out({ check_out: null }), eveningIsOvernight: false }
|
|
expect(shouldDrawEveningLeg(noCheckOut, checkOutDay, { isPlace: true, time: null }, false)).toBe(true)
|
|
expect(shouldDrawEveningLeg(noCheckOut, checkOutDay, { isPlace: true, time: null })).toBe(true)
|
|
})
|
|
|
|
it('a recorded check-out time keeps the timed rule even on a carrier day (#2157)', () => {
|
|
const bookends = { evening: out({ check_out: '11:00' }), eveningIsOvernight: false }
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: true, time: '09:00' }, true)).toBe(true)
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: true, time: '18:00' }, true)).toBe(false)
|
|
})
|
|
|
|
it('a carrier does not touch the overnight evening leg (#2157)', () => {
|
|
// You sleep here tonight — the day-trip train changes nothing about that.
|
|
const bookends = { evening: out(), eveningIsOvernight: true }
|
|
expect(shouldDrawEveningLeg(bookends, checkOutDay, { isPlace: true, time: '23:00' }, true)).toBe(true)
|
|
})
|
|
|
|
it('the no-time default does not reach an edge place out of day-trip range (#2157)', () => {
|
|
const noCheckOut = { evening: out({ check_out: null }), eveningIsOvernight: false }
|
|
expect(shouldDrawEveningLeg(noCheckOut, checkOutDay, { isPlace: true, time: null, lat: 21.28, lng: -157.83 })).toBe(false)
|
|
expect(shouldDrawEveningLeg(noCheckOut, checkOutDay, { isPlace: true, time: null, lat: 48.2, lng: 11.6 })).toBe(true)
|
|
})
|
|
|
|
it('a drivable edge place is still out of range when no day out of the hotel reaches it (#2157)', () => {
|
|
// Mirror of the morning case: the reporter drives home from Warnemünde to Frankfurt
|
|
// on the last day, and nothing routes those 508 km back to the hotel he checked
|
|
// out of that morning.
|
|
const noCheckOut = { evening: out({ check_out: null, place_lat: 54.18, place_lng: 12.08 }), eveningIsOvernight: false }
|
|
expect(shouldDrawEveningLeg(noCheckOut, checkOutDay, { isPlace: true, time: null, lat: 50.11, lng: 8.68 })).toBe(false)
|
|
expect(shouldDrawEveningLeg(noCheckOut, checkOutDay, { isPlace: true, time: null, lat: 54.08, lng: 12.10 })).toBe(true)
|
|
})
|
|
})
|