Files
TREK/server/tests/unit/db/tour-break-additional-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

58 lines
2.3 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 = 'Migration20200101043000_tour_break_additional_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 breaks/additional-duration migration', () => {
it('adds nullable breaks without changing calculated or overridden Tour values', 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, planned_duration_minutes) VALUES (100, 'hike', 83, 125)",
);
await migrateTo(orm, TARGET);
expect(
await rawQuery(
orm,
'SELECT duration, planned_duration_minutes, break_additional_minutes FROM tours WHERE place_id = 100',
),
).toEqual([{ duration: 83, planned_duration_minutes: 125, break_additional_minutes: null }]);
await rawExec(orm, 'UPDATE tours SET break_additional_minutes = 35 WHERE place_id = 100');
expect(
await rawQuery(
orm,
'SELECT duration, planned_duration_minutes, break_additional_minutes FROM tours WHERE place_id = 100',
),
).toEqual([{ duration: 83, planned_duration_minutes: 125, break_additional_minutes: 35 }]);
await expect(
rawExec(orm, 'UPDATE tours SET break_additional_minutes = 1441 WHERE place_id = 100'),
).rejects.toThrow(/CHECK/);
await expect(rawExec(orm, 'UPDATE tours SET break_additional_minutes = -1 WHERE place_id = 100')).rejects.toThrow(
/CHECK/,
);
} finally {
await orm.close(true);
}
}, 30000);
});