Files
TREK/client/tests/unit/utils/placeFiles.test.ts
Maurice 07e4a558e6 fix(bookings): the phone keeps a booking's stop and shows the files it already has (#2216, #2217)
Editing a booking on the phone erased the stop it was linked to. The sheet
seeded its assignment from the create-for-a-stop flag, which is null on an
edit, and saved that straight back over a link the user had made on the
desktop; the server writes the field whenever the key is present. It now
seeds from the booking being edited, and the picker the desktop dialog has
always had sits in the sheet too, so a stop can be seen, changed and cleared
from a phone. The option list moved to its own module rather than being
copied.

Two more of the same shape, found on the way. The endpoint set was sent as an
empty list on every save, and the server swaps the whole set when that key is
present, so editing a transit booking dropped its stations; neither form
edits endpoints, so an edit no longer sends the key at all. And the sheet's
Files block listed only what was picked in this session, so a file uploaded
from the desktop was invisible on the phone. It lists what is attached now,
resolved the way the desktop resolves it.

A place also shows the files of the bookings that sit on it, on the phone and
on the desktop: a confirmation lives on the booking, and the place card was
the one screen that could not reach it.
2026-09-03 15:51:13 +02:00

58 lines
2.7 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { filesForPlace } from '../../../src/utils/placeFiles'
import type { Reservation, TripFile } from '../../../src/types'
// FE-UTIL-PLACEFILES-001 to FE-UTIL-PLACEFILES-006
const file = (over: Partial<TripFile>): TripFile => ({
id: 1, trip_id: 5, original_name: 'a.pdf', url: '/uploads/a.pdf',
place_id: null, reservation_id: null, deleted_at: null,
...over,
} as unknown as TripFile)
const booking = (over: Partial<Reservation>): Reservation => ({
id: 90, trip_id: 5, title: 'Table', type: 'restaurant',
place_id: null, assignment_id: null,
...over,
} as unknown as Reservation)
describe('filesForPlace', () => {
it('FE-UTIL-PLACEFILES-001: keeps the files the place owns, by column and by link', () => {
const own = file({ id: 1, place_id: 7 })
const linked = file({ id: 2, linked_place_ids: [7] })
const other = file({ id: 3, place_id: 8 })
expect(filesForPlace([own, linked, other], 7, []).map(f => f.id)).toEqual([1, 2])
})
it('FE-UTIL-PLACEFILES-002: adds the files of a booking that sits on the place (#2217)', () => {
const files = [file({ id: 4, reservation_id: 90 })]
const bookings = [booking({ id: 90, place_id: 7 })]
expect(filesForPlace(files, 7, bookings).map(f => f.id)).toEqual([4])
})
it('FE-UTIL-PLACEFILES-003: reaches a booking through the stop it hangs on, not only through place_id', () => {
const files = [file({ id: 5, reservation_id: 90 })]
const bookings = [booking({ id: 90, assignment_id: 11 })]
expect(filesForPlace(files, 7, bookings, [11]).map(f => f.id)).toEqual([5])
// Without that stop in the day, the booking is not this place's business.
expect(filesForPlace(files, 7, bookings, [12])).toEqual([])
})
it('FE-UTIL-PLACEFILES-004: a file linked to the booking counts like one stored on it', () => {
const files = [file({ id: 6, linked_reservation_ids: [90] })]
expect(filesForPlace(files, 7, [booking({ id: 90, place_id: 7 })]).map(f => f.id)).toEqual([6])
})
it('FE-UTIL-PLACEFILES-005: lists a file once when it is both the place\'s and the booking\'s', () => {
const both = file({ id: 7, place_id: 7, reservation_id: 90 })
expect(filesForPlace([both], 7, [booking({ id: 90, place_id: 7 })]).map(f => f.id)).toEqual([7])
})
it('FE-UTIL-PLACEFILES-006: drops deleted files and answers empty without a place', () => {
const gone = file({ id: 8, place_id: 7, deleted_at: '2026-09-01' })
const bookingFileGone = file({ id: 9, reservation_id: 90, deleted_at: '2026-09-01' })
expect(filesForPlace([gone, bookingFileGone], 7, [booking({ id: 90, place_id: 7 })])).toEqual([])
expect(filesForPlace([file({ id: 10, place_id: 7 })], undefined, [])).toEqual([])
})
})