test(e2e): hand-made schemas follow the new columns; placing entries never blocks the refresh

This commit is contained in:
Maurice
2026-10-01 15:18:30 +02:00
parent 39074f6d46
commit 62950aed24
6 changed files with 27 additions and 8 deletions
@@ -75,7 +75,14 @@ export class JourneyPhotoCaptureService {
* which the owner can still name by hand.
*/
async placeEntries(trekPhotoIds: number[]): Promise<number> {
const placed = this.journey.placeEntriesFromPhotos(trekPhotoIds);
let placed: ReturnType<JourneyDomainService['placeEntriesFromPhotos']>;
try {
placed = this.journey.placeEntriesFromPhotos(trekPhotoIds);
} catch (err) {
// An extra on top of the capture times: it must never cost the refresh below it.
console.error('[Journey] placing entries from photos failed:', err instanceof Error ? err.message : err);
return 0;
}
if (!placed.length) return 0;
await Promise.all(placed.map(async (p) => {
try {
+4 -5
View File
@@ -486,12 +486,11 @@ describe('Journey e2e (real auth guard + temp SQLite)', () => {
try {
expect(res.status).toBe(201);
expect(res.body.photos).toHaveLength(1);
// The plain backfill, the same one the provider adds run...
expect(backfillSchedule).toHaveBeenCalledWith([90], 1);
// ...but not the refreshing run behind it: a bulk upload would otherwise
// reload every open client once per photo.
// The capture backfill runs for the upload (and may place its entry, #1003)...
await new Promise(resolve => setTimeout(resolve, 10));
expect(backfillRun).not.toHaveBeenCalled();
expect(backfillRun).toHaveBeenCalledWith([90], 1);
// ...but no journey refresh follows: a bulk upload would otherwise reload
// every open client once per photo.
expect(jsvc.broadcastJourneyEvent).not.toHaveBeenCalled();
} finally {
const storage = app.get(StorageService);
+4 -1
View File
@@ -90,7 +90,10 @@ const { db } = vi.hoisted(() => {
id INTEGER PRIMARY KEY AUTOINCREMENT,
category_id INTEGER NOT NULL,
name TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0
sort_order INTEGER NOT NULL DEFAULT 0,
weight_grams INTEGER,
quantity INTEGER NOT NULL DEFAULT 1,
bag_name TEXT
);`);
// StorageRegistryService (behind StorageModule, now in this module chain) reads
// this at onModuleInit.
+1 -1
View File
@@ -28,7 +28,7 @@ const { db } = vi.hoisted(() => {
description TEXT, lat REAL, lng REAL, address TEXT, category_id INTEGER, price REAL, currency TEXT,
place_time TEXT, end_time TEXT, duration_minutes INTEGER, notes TEXT, image_url TEXT,
google_place_id TEXT, google_ftid TEXT, osm_id TEXT, amap_poi_id TEXT, website TEXT, phone TEXT, transport_mode TEXT,
route_geometry TEXT, route_color TEXT, stop_type TEXT, fill_percent INTEGER,
route_geometry TEXT, route_color TEXT, stop_type TEXT, fill_percent INTEGER, email TEXT, opening_hours TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP);`);
tmp.exec(`CREATE TABLE categories (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, color TEXT, icon TEXT);`);
tmp.exec(`CREATE TABLE tags (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, color TEXT,
@@ -23,6 +23,7 @@ const { db } = vi.hoisted(() => {
email TEXT NOT NULL UNIQUE, role TEXT NOT NULL DEFAULT 'user', password_version INTEGER NOT NULL DEFAULT 0,
maps_api_key TEXT, unsplash_api_key TEXT);`);
tmp.exec('CREATE TABLE app_settings (key TEXT PRIMARY KEY, value TEXT);');
tmp.exec('CREATE TABLE google_api_usage (day TEXT PRIMARY KEY, calls INTEGER NOT NULL DEFAULT 0);');
return { db: tmp };
});
vi.mock('../../src/db/database', () => ({ db, closeDb: () => {}, reinitialize: () => {} }));
@@ -156,6 +156,15 @@ describe('JourneyPhotoCaptureService', () => {
expect(nameEntryLocation).toHaveBeenCalledWith(7, 'Somewhere Road');
});
it('JPCAP-1003d: placing entries that throws never costs the refresh of the gallery order', async () => {
const { svc, placeEntriesFromPhotos, broadcastJourneyEvent } = build(true);
placeEntriesFromPhotos.mockImplementation(() => { throw new Error('no such column'); });
const error = vi.spyOn(console, 'error').mockImplementation(() => {});
await expect(svc.fill(9, [11], 3)).resolves.toBe(true);
expect(broadcastJourneyEvent).toHaveBeenCalledWith(9, 'journey:photos:updated', {});
expect(error).toHaveBeenCalledWith('[Journey] placing entries from photos failed:', 'no such column');
});
it('JPCAP-1003c: an upload whose backfill throws is logged', async () => {
const { svc } = build(new Error('disk'));
const error = vi.spyOn(console, 'error').mockImplementation(() => {});