From 2fb699189e8d2a03689ae941d4e7dfe9a477b56b Mon Sep 17 00:00:00 2001 From: Maurice Date: Thu, 8 Oct 2026 15:56:18 +0200 Subject: [PATCH] test(journey): add gallery and entry photos concurrently uploadGalleryPhotos and addPhoto read MAX(sort_order) inside the transaction that inserts, but the only gallery test ran its uploads one after another and would pass without that. These cases run several uploads, and several photos added to one entry, at once and expect consecutive positions in the gallery and on the entry, as JOURNEY-SVC-030b does for entries. --- .../unit/nest/journey-domain.service.test.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/server/tests/unit/nest/journey-domain.service.test.ts b/server/tests/unit/nest/journey-domain.service.test.ts index 1f388da15..b3c98c37a 100644 --- a/server/tests/unit/nest/journey-domain.service.test.ts +++ b/server/tests/unit/nest/journey-domain.service.test.ts @@ -2624,6 +2624,40 @@ describe('journey gallery', () => { expect(await svc.uploadGalleryPhotos(journey.id, stranger.id, [{ path: 'journey/x.jpg' }])).toEqual([]); }); + it('JOURNEY-SVC-PHOTO-003b: gallery uploads at the same time take one position each', async () => { + const { user } = createUser(testDb); + const journey = await svc.createJourney(user.id, { title: 'J' }); + + // Each upload reads MAX(sort_order) inside the transaction that inserts. Read + // outside it, every upload saw the same MAX and the batches overlapped. + const batches = await Promise.all([1, 2, 3].map((n) => svc.uploadGalleryPhotos(journey.id, user.id, [ + { path: `journey/c${n}-a.jpg` }, + { path: `journey/c${n}-b.jpg` }, + ]))); + expect(batches.map((b) => b.length)).toEqual([2, 2, 2]); + + const orders = testDb + .prepare('SELECT sort_order FROM journey_photos WHERE journey_id = ? ORDER BY sort_order') + .all(journey.id) as { sort_order: number }[]; + expect(orders.map((o) => o.sort_order)).toEqual([0, 1, 2, 3, 4, 5]); + }); + + it('JOURNEY-SVC-PHOTO-003c: photos added to one entry at the same time take one gallery and one entry position each', async () => { + const { user, journey, entry } = await ownedEntry(); + + const photos = await Promise.all(['a', 'b', 'c'].map((n) => svc.addPhoto(entry.id, user.id, `journey/e-${n}.jpg`))); + expect(photos.every(Boolean)).toBe(true); + + const gallery = testDb + .prepare('SELECT sort_order FROM journey_photos WHERE journey_id = ? ORDER BY sort_order') + .all(journey.id) as { sort_order: number }[]; + expect(gallery.map((o) => o.sort_order)).toEqual([0, 1, 2]); + const linked = testDb + .prepare('SELECT sort_order FROM journey_entry_photos WHERE entry_id = ? ORDER BY sort_order') + .all(entry.id) as { sort_order: number }[]; + expect(linked.map((o) => o.sort_order)).toEqual([0, 1, 2]); + }); + it('JOURNEY-SVC-PHOTO-004: linkPhotoToEntry attaches a gallery row, unlinkPhotoFromEntry detaches it', async () => { const { user, journey, entry } = await ownedEntry(); const [gallery] = await svc.uploadGalleryPhotos(journey.id, user.id, [{ path: 'journey/a.jpg' }]);