Files
TREK/server/tests/unit/db/tour-planned-duration-migration.test.ts
elmocito 57ea219a43 feat(tours): complete planner follow-up scope
This commit completes the reviewed Tours follow-up scope after the Tours MVP was merged into dev.

Included feature blocks:

- RC-01: identify Tours in PLAN day rows and show compact Tour facts;
- RC-06: search for a city or address in TOUR-PLANNER without hidden writes;
- RC-07: reorder Tour waypoints in the left sidebar;
- RC-08: drag Tour waypoints on Leaflet, MapLibre and Mapbox with stable viewport, history and routing behavior;
- RS-01: persist Tour descriptions and HTTPS information links with local provider classification;
- RS-02: persist breaks/additional time and calculated or manually adjusted planned Tour duration without changing scheduling semantics.
The implementation preserves:

- ordinary Place and Legacy Track behavior;
- Tours-off fallback behavior;
- existing GPX/import behavior;
- Tour assignment and deletion behavior;
- calculated routing duration as a separate value;
- existing Tour provenance fields;
- keyboard/list alternatives for waypoint editing.
Not included:

- PR1-09 trip-wide Tour summary;
- Wanderer integration;
- GPX import changes;
- new Tour types;
- Tour-to-Day drag-and-drop;
- further roadmap or Post-Release features.
Validation:

- focused RC-01/RC-06/RC-07/RC-08/RS-01/RS-02 tests passed;
- affected shared/server/client typechecks passed;
- migration and generated DB type checks passed;
- scoped ESLint passed;
- staged diff checks passed;
- owner manual tests passed for all six feature blocks.
2026-10-14 08:39:31 +02:00

49 lines
2.0 KiB
TypeScript

import { createMigrationOrm, migrateTo, pendingNames, rawExec, rawQuery } from '../../helpers/migration-step';
import type { MikroORM } from '@mikro-orm/sqlite';
import { describe, expect, it } from 'vitest';
const TARGET = 'Migration20200101042900_tour_planned_total_duration';
async function ormBeforeTarget(): Promise<MikroORM> {
const orm = await createMigrationOrm();
const names = await pendingNames(orm);
const index = names.indexOf(TARGET);
expect(index).toBeGreaterThan(0);
await migrateTo(orm, names[index - 1]);
return orm;
}
describe('Tour planned-duration migration', () => {
it('adds a nullable bounded column without changing existing Tour rows', async () => {
const orm = await ormBeforeTarget();
try {
await rawExec(
orm,
"INSERT INTO users (id, username, email, password_hash) VALUES (1, 'owner', 'owner@test', 'x')",
);
await rawExec(orm, "INSERT INTO trips (id, user_id, title) VALUES (10, 1, 'Alps')");
await rawExec(orm, "INSERT INTO places (id, trip_id, name) VALUES (100, 10, 'Ridge walk')");
await rawExec(orm, "INSERT INTO tours (place_id, tour_type, duration) VALUES (100, 'hike', 83)");
await migrateTo(orm, TARGET);
expect(await rawQuery(orm, 'SELECT duration, planned_duration_minutes FROM tours WHERE place_id = 100')).toEqual([
{ duration: 83, planned_duration_minutes: null },
]);
await rawExec(orm, 'UPDATE tours SET planned_duration_minutes = 125 WHERE place_id = 100');
expect(await rawQuery(orm, 'SELECT duration, planned_duration_minutes FROM tours WHERE place_id = 100')).toEqual([
{ duration: 83, planned_duration_minutes: 125 },
]);
await expect(
rawExec(orm, 'UPDATE tours SET planned_duration_minutes = 1441 WHERE place_id = 100'),
).rejects.toThrow(/CHECK/);
await expect(rawExec(orm, 'UPDATE tours SET planned_duration_minutes = -1 WHERE place_id = 100')).rejects.toThrow(
/CHECK/,
);
} finally {
await orm.close(true);
}
}, 30000);
});