mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
a910c2a837
Saved place price (#2471) - A price above zero that would be left without a currency is refused with a 400, over REST and through update_collection_place alike. A list has no base currency, so such an amount was read in each viewer's own default currency and went into a trip as the trip's. A price sent alone keeps the stored currency, and a zero price or clearing both fields still goes through. The check sits in the service because the MCP tool spreads the contract's shape, where a refine would never arrive. - An older row that holds an amount without a currency shows it as a bare number instead of in the viewer's own currency. - The Hungarian hint uses the informal register of its file, which is now prettier clean. Immich certificate switch (#2475) - The switch trusts one server. Saving a different URL without sending it turns it off; saving the same URL keeps it as before. The wiki says so. Moving day (#2476) - Google Maps and CoMaps are left out only when there is nothing to hand over. A day with a single stop opens it as a pin again, on the desktop and on the phone, as it did before. - Desktop: a moving day whose flight or train has no stations shows no route tools, since there is nothing left to draw. With stations they stay. - Phone: the drive between two stays on a day without stops or bookings shows once at the top instead of again at the bottom. - The export helpers take the carrier flags as one object instead of two booleans in a row. Import card (#2477) - The success and error marks use the theme tokens. - The e2e test names its upload with a made-up booking number. Tests: COLLECTIONS-SVC-132 and 133, COLLECTIONS-E2E-088, update_collection_place with a price and no currency, FE-COMP-COLEXTRAS-013 (011 adjusted), IMMICH-TLS-010, IMMICH-103 extended, FE-PLANNER-DAYPLAN-222 adjusted and 224, FE-MOB-PLTL-051, FE-MOB-PTLM-047, FE-W4BGT-023 and 024 check the mark colours.
115 lines
5.9 KiB
TypeScript
115 lines
5.9 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { dayCoMapsUrl, dayExportStops, dayGoogleMapsUrl } from './dayRoute'
|
|
import type { Accommodation, Assignment, Day } from '../../../../types'
|
|
|
|
// FE-MOBILE-DAYROUTE-001 to FE-MOBILE-DAYROUTE-011
|
|
|
|
const days = [
|
|
{ id: 10, day_number: 1 },
|
|
{ id: 20, day_number: 2 },
|
|
{ id: 30, day_number: 3 },
|
|
] as unknown as Day[]
|
|
|
|
const hotel = {
|
|
place_lat: 48.85, place_lng: 2.35, place_name: 'Hotel Lutetia',
|
|
start_day_id: 10, end_day_id: 30,
|
|
} as unknown as Accommodation
|
|
|
|
const stop = (id: number, name: string, lat: number, lng: number): Assignment =>
|
|
({ id, day_id: 20, order_index: id, place: { id, name, lat, lng } }) as unknown as Assignment
|
|
|
|
const louvre = stop(1, 'Louvre', 48.86, 2.34)
|
|
const orsay = stop(2, 'Orsay', 48.87, 2.33)
|
|
|
|
describe('dayExportStops', () => {
|
|
it('FE-MOBILE-DAYROUTE-001: carries the stops in planned order, hotel-bookended and named', () => {
|
|
expect(dayExportStops(days[1], days, [louvre, orsay], [hotel], true)).toEqual([
|
|
{ lat: 48.85, lng: 2.35, name: 'Hotel Lutetia' },
|
|
{ lat: 48.86, lng: 2.34, name: 'Louvre' },
|
|
{ lat: 48.87, lng: 2.33, name: 'Orsay' },
|
|
{ lat: 48.85, lng: 2.35, name: 'Hotel Lutetia' },
|
|
])
|
|
})
|
|
|
|
it('FE-MOBILE-DAYROUTE-002: drops the bookends when accommodation optimization is off', () => {
|
|
const stops = dayExportStops(days[1], days, [louvre, orsay], [hotel], false)
|
|
expect(stops.map(s => s.name)).toEqual(['Louvre', 'Orsay'])
|
|
})
|
|
|
|
it('FE-MOBILE-DAYROUTE-003: a stop without coordinates cannot be exported', () => {
|
|
const nowhere = { id: 3, day_id: 20, order_index: 3, place: { id: 3, name: 'TBD' } } as unknown as Assignment
|
|
const stops = dayExportStops(days[1], days, [louvre, nowhere], [], false)
|
|
expect(stops.map(s => s.name)).toEqual(['Louvre'])
|
|
})
|
|
|
|
// The stay above records neither check-in nor check-out time — the #2157 shape.
|
|
const homeNear = stop(4, 'Home', 48.9, 2.4)
|
|
|
|
it('FE-MOBILE-DAYROUTE-006: with a carrier on the day, the not-yet-reached check-in hotel is not prepended (#2157)', () => {
|
|
// Arrival day: you fly in, so the hotel may end the list but must not start it.
|
|
const stops = dayExportStops(days[0], days, [homeNear], [hotel], true, { located: true })
|
|
expect(stops.map(s => s.name)).toEqual(['Home', 'Hotel Lutetia'])
|
|
})
|
|
|
|
it('FE-MOBILE-DAYROUTE-007: with a carrier on the day, the already-left check-out hotel is not appended (#2157)', () => {
|
|
// Check-out day: the hotel starts the day, nothing routes back to it after the flight home.
|
|
const stops = dayExportStops(days[2], days, [homeNear], [hotel], true, { located: true })
|
|
expect(stops.map(s => s.name)).toEqual(['Hotel Lutetia', 'Home'])
|
|
})
|
|
|
|
it('FE-MOBILE-DAYROUTE-008: without a carrier the no-time loop still closes (#2009 preserved)', () => {
|
|
const stops = dayExportStops(days[0], days, [louvre], [hotel], true, { located: false })
|
|
expect(stops.map(s => s.name)).toEqual(['Hotel Lutetia', 'Louvre', 'Hotel Lutetia'])
|
|
})
|
|
|
|
it('FE-MOBILE-DAYROUTE-009: an edge stop out of drive range keeps the no-time hotel out even without a carrier (#2157)', () => {
|
|
// No flight recorded, but "Home" is an ocean away — the loop default is a guess
|
|
// and does not get to route back across it.
|
|
const farHome = stop(5, 'Home', 21.28, -157.83)
|
|
const stops = dayExportStops(days[2], days, [farHome], [hotel], true)
|
|
expect(stops.map(s => s.name)).toEqual(['Hotel Lutetia', 'Home'])
|
|
})
|
|
|
|
// Day 2 checks out of one stay and into the next, with no stop of its own.
|
|
const hotelA = { ...hotel, place_name: 'Hotel A', start_day_id: 10, end_day_id: 20 } as Accommodation
|
|
const hotelB = { ...hotel, place_lat: 53.55, place_lng: 9.99, place_name: 'Hotel B', start_day_id: 20, end_day_id: 30 } as Accommodation
|
|
|
|
it('FE-MOBILE-DAYROUTE-010: a flight between the two stays leaves nothing to export (#2476)', () => {
|
|
// Located or not, the flight is how the day gets from one hotel to the other; a
|
|
// driving route between them is the stretch nobody drives.
|
|
expect(dayExportStops(days[1], days, [], [hotelA, hotelB], true, { located: true, booked: true })).toEqual([])
|
|
expect(dayExportStops(days[1], days, [], [hotelA, hotelB], true, { booked: true })).toEqual([])
|
|
expect(dayGoogleMapsUrl(days[1], days, [], [hotelA, hotelB], true, { booked: true })).toBeNull()
|
|
expect(dayCoMapsUrl(days[1], days, [], [hotelA, hotelB], true, 'driving', { booked: true })).toBeNull()
|
|
})
|
|
|
|
it('FE-MOBILE-DAYROUTE-011: without a booking the move is still the drive from one stay to the next (#1297)', () => {
|
|
expect(dayExportStops(days[1], days, [], [hotelA, hotelB], true).map(s => s.name)).toEqual(['Hotel A', 'Hotel B'])
|
|
// A stop of its own keeps the day exportable even with the flight booked.
|
|
expect(dayExportStops(days[1], days, [louvre], [hotelA, hotelB], true, { located: true, booked: true }).map(s => s.name)).toContain('Louvre')
|
|
})
|
|
})
|
|
|
|
describe('day map links', () => {
|
|
it('FE-MOBILE-DAYROUTE-004: both exports read the same stop list', () => {
|
|
// One source for the bookend rules, so the two links can never disagree
|
|
// about which hotel legs are real.
|
|
const google = dayGoogleMapsUrl(days[1], days, [louvre, orsay], [hotel], true)!
|
|
const coMaps = dayCoMapsUrl(days[1], days, [louvre, orsay], [hotel], true, 'walking')!
|
|
for (const ll of ['48.85,2.35', '48.86,2.34', '48.87,2.33']) {
|
|
expect(google).toContain(ll)
|
|
expect(coMaps).toContain(ll)
|
|
}
|
|
})
|
|
|
|
it('FE-MOBILE-DAYROUTE-005: the CoMaps link travels in the mode it was given', () => {
|
|
// Four bookended stops is more than a CoMaps route link can hold, so it
|
|
// becomes pins — which is also why no mode appears here.
|
|
expect(dayCoMapsUrl(days[1], days, [louvre, orsay], [hotel], true, 'walking'))
|
|
.toMatch(/^https:\/\/comaps\.at\/map\?v=1&/)
|
|
// Two stops fit a route, and then the mode does apply.
|
|
expect(dayCoMapsUrl(days[1], days, [louvre, orsay], [], false, 'walking'))
|
|
.toContain('type=pedestrian')
|
|
})
|
|
})
|