mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
test(server): seed bookings and places the way the services store them
The converted specs wrote accommodation_id as a plain id, while the services store the legacy '<id>.0' text, and wrote read-only foreign key twins instead of their relations. The files e2e schema gains the trip columns the entity fills, and the idempotency spec seeds a real user.
This commit is contained in:
@@ -25,7 +25,11 @@ const { db } = vi.hoisted(() => {
|
||||
// FilesService runs its real SQL against these (FILE_SELECT joins reservations
|
||||
// and users; the link batch reads file_links; findForeignLinkTarget probes
|
||||
// reservations/places/day_assignments).
|
||||
tmp.exec('CREATE TABLE trips (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, title TEXT, currency TEXT);');
|
||||
// An ORM insert into trips names every column the entity gives a default
|
||||
// (is_archived, reminder_days and the two timestamps); the real schema has all four.
|
||||
tmp.exec(`CREATE TABLE trips (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, title TEXT, currency TEXT,
|
||||
is_archived INTEGER DEFAULT 0, reminder_days INTEGER DEFAULT 3,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP);`);
|
||||
// TripAccessGuard now reads TripsRepository.findAccessible directly
|
||||
// (Plan 3c Task 0b), a real join against trip_members.
|
||||
tmp.exec('CREATE TABLE trip_members (trip_id INTEGER NOT NULL, user_id INTEGER NOT NULL);');
|
||||
|
||||
@@ -40,6 +40,7 @@ import { DayAccommodations } from '../../src/db/entities/DayAccommodations.entit
|
||||
import { Days } from '../../src/db/entities/Days.entity';
|
||||
import { Reservations } from '../../src/db/entities/Reservations.entity';
|
||||
import { Trips } from '../../src/db/entities/Trips.entity';
|
||||
import { legacyBoundIntegerText } from '../../src/nest/common/row-id';
|
||||
|
||||
let nestApp: INestApplication;
|
||||
let app: Application;
|
||||
@@ -560,7 +561,7 @@ describe('Accommodations', () => {
|
||||
expect(res.status).toBe(201);
|
||||
|
||||
// Linked reservation should exist
|
||||
const reservation = await findRow(orm(), Reservations, { accommodation_id: String(res.body.accommodation.id) });
|
||||
const reservation = await findRow(orm(), Reservations, { accommodation_id: legacyBoundIntegerText(res.body.accommodation.id) });
|
||||
expect(reservation).not.toBeNull();
|
||||
expect(reservation!.type).toBe('hotel');
|
||||
expect(reservation!.confirmation_number).toBe('CONF-XYZ');
|
||||
@@ -619,7 +620,7 @@ describe('Accommodations', () => {
|
||||
.send({ place_id: place.id, start_day_id: day1.id, end_day_id: day2.id });
|
||||
|
||||
const accommodationId = createRes.body.accommodation.id;
|
||||
const reservationBefore = await findRow(orm(), Reservations, { accommodation_id: String(accommodationId) });
|
||||
const reservationBefore = await findRow(orm(), Reservations, { accommodation_id: legacyBoundIntegerText(accommodationId) });
|
||||
expect(reservationBefore).not.toBeNull();
|
||||
|
||||
const deleteRes = await request(app)
|
||||
|
||||
@@ -13,6 +13,7 @@ import { purgeExpiredIdempotencyKeys } from '../../src/nest/common/idempotency-c
|
||||
import { IdempotencyCleanupJob } from '../../src/nest/common/idempotency-cleanup.job';
|
||||
import { IdempotencyKeys } from '../../src/db/entities/IdempotencyKeys.entity';
|
||||
import { countRows, deleteRows, findRows, insertRow } from '../helpers/factories/rows';
|
||||
import { makeUser } from '../helpers/factories/users';
|
||||
import type { IdempotencyKeysRepository } from '../../src/db/repositories/IdempotencyKeys.repository';
|
||||
import type { CronRegistrarService } from '../../src/nest/scheduling/cron-registrar.service';
|
||||
|
||||
@@ -23,17 +24,20 @@ const NOW_SEC = Math.floor(NOW / 1000);
|
||||
const testDb = createSnapshotTestDb();
|
||||
let t: TestOrm;
|
||||
let idempotencyKeys: IdempotencyKeysRepository;
|
||||
/** The user every fixture key belongs to (the table's user_id is a foreign key). */
|
||||
let userId: number;
|
||||
|
||||
beforeAll(async () => {
|
||||
t = await createTestOrm(testDb);
|
||||
idempotencyKeys = t.repo(IdempotencyKeys);
|
||||
userId = (await makeUser(t)).user.id;
|
||||
});
|
||||
afterAll(async () => { await t.close(); testDb.close(); });
|
||||
|
||||
async function insertKey(key: string, ageSeconds: number, nowSec = NOW_SEC): Promise<void> {
|
||||
await insertRow(t, IdempotencyKeys, {
|
||||
key,
|
||||
user: 1,
|
||||
user: userId,
|
||||
method: 'POST',
|
||||
path: '/x',
|
||||
status_code: 200,
|
||||
@@ -48,14 +52,12 @@ async function remainingKeys(): Promise<string[]> {
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
testDb.pragma('foreign_keys = OFF'); // fixtures reference a user we don't seed here
|
||||
await deleteRows(t, IdempotencyKeys);
|
||||
t.clear();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await deleteRows(t, IdempotencyKeys);
|
||||
testDb.pragma('foreign_keys = ON');
|
||||
delete process.env.IDEMPOTENCY_TTL_SECONDS;
|
||||
});
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ import { Reservations } from '../../../src/db/entities/Reservations.entity';
|
||||
import { ReservationEndpoints } from '../../../src/db/entities/ReservationEndpoints.entity';
|
||||
import { RoadtripDayBoundaries } from '../../../src/db/entities/RoadtripDayBoundaries.entity';
|
||||
import { Trips } from '../../../src/db/entities/Trips.entity';
|
||||
import { legacyBoundIntegerText } from '../../../src/nest/common/row-id';
|
||||
|
||||
let days: DaysService;
|
||||
let journey: JourneyDomainService;
|
||||
@@ -178,7 +179,7 @@ async function bookedNight(tripId: number, startDayId: number, endDayId: number)
|
||||
const place = createPlace(testDb, tripId, { name: 'Harbour Hotel' });
|
||||
const { accommodation } = await accommodations.createAccommodation(tripId, { place_id: place.id, start_day_id: startDayId, end_day_id: endDayId });
|
||||
const stayId = (accommodation as { id: number }).id;
|
||||
const hotelBooking = await findRow(await orm(), Reservations, { accommodation_id: String(stayId) });
|
||||
const hotelBooking = await findRow(await orm(), Reservations, { accommodation_id: legacyBoundIntegerText(stayId) });
|
||||
if (!hotelBooking) throw new Error('createAccommodation should have booked the stay');
|
||||
const reservationId = hotelBooking.id;
|
||||
const budgetId = (await makeBudgetItem(await orm(), tripId, {
|
||||
|
||||
@@ -93,6 +93,7 @@ import { RealtimeService } from '../../../src/nest/realtime/realtime.service';
|
||||
import { QueryHelpersService } from '../../../src/nest/query-helpers/query-helpers.service';
|
||||
import { makeAccommodationsService } from '../../helpers/accommodations-service';
|
||||
import type { Day } from '../../../src/types';
|
||||
import { legacyBoundIntegerText } from '../../../src/nest/common/row-id';
|
||||
import {
|
||||
createTestUnitOfWork, createTestAppSettingsRepo,
|
||||
createTestDaysRepo, createTestDayAssignmentsRepo, createTestDayNotesRepo, createTestTripsRepo,
|
||||
@@ -596,7 +597,7 @@ describe('restampReservationDates', () => {
|
||||
describe('resyncAccommodationDays', () => {
|
||||
/** The hotel reservation accommodations/ auto-creates next to a stay. */
|
||||
const linkHotel = (tripId: number, accId: number, dayId: number | null, time: string | null) =>
|
||||
addReservation(tripId, { day: dayId, title: 'Hotel', type: 'hotel', accommodation_id: String(accId), reservation_time: time });
|
||||
addReservation(tripId, { day: dayId, title: 'Hotel', type: 'hotel', accommodation_id: legacyBoundIntegerText(accId), reservation_time: time });
|
||||
|
||||
it('DAY-SVC-040 — returns before touching a hotel booking when the trip has no stays', async () => {
|
||||
const { user } = createUser(testDb);
|
||||
|
||||
@@ -62,6 +62,7 @@ import fs from 'fs';
|
||||
import { PermissionsService } from '../../../src/nest/permissions/permissions.service';
|
||||
import { RealtimeService } from '../../../src/nest/realtime/realtime.service';
|
||||
import { PlacesService } from '../../../src/nest/places/places.service';
|
||||
import { legacyBoundIntegerText } from '../../../src/nest/common/row-id';
|
||||
import { MapsService } from '../../../src/nest/maps/maps.service';
|
||||
import { QueryHelpersService } from '../../../src/nest/query-helpers/query-helpers.service';
|
||||
import { JourneyDomainService } from '../../../src/nest/journey/journey-domain.service';
|
||||
@@ -208,7 +209,7 @@ describe('list', () => {
|
||||
const trip = createTrip(testDb, user.id);
|
||||
const tour = createPlace(testDb, trip.id, { name: 'Facet-backed tour' }) as any;
|
||||
const place = createPlace(testDb, trip.id, { name: 'Ordinary place' }) as any;
|
||||
await insertRow(orm, Tours, { place_id: tour.id, tourTypeRef: 'hike' });
|
||||
await insertRow(orm, Tours, { place: tour.id, tourTypeRef: 'hike' });
|
||||
|
||||
const byId = new Map(((await svc.list(String(trip.id), {})) as any[]).map(item => [item.id, item]));
|
||||
|
||||
@@ -244,7 +245,7 @@ describe('list', () => {
|
||||
const paris = createPlace(testDb, trip.id, { name: 'Louvre', lat: 48.8606, lng: 2.3376 });
|
||||
const nowhere = createPlace(testDb, trip.id, { name: 'Unplaced' });
|
||||
await updateRows(orm, Places, { id: nowhere.id }, { lat: null, lng: null, address: null });
|
||||
await insertRow(orm, PlaceRegions, { place_id: berlin.id, country_code: 'DE', region_code: 'DE-BE', region_name: 'Berlin' });
|
||||
await insertRow(orm, PlaceRegions, { place: berlin.id, country_code: 'DE', region_code: 'DE-BE', region_name: 'Berlin' });
|
||||
const byId = new Map(((await svc.list(String(trip.id), {})) as any[]).map(p => [p.id, p]));
|
||||
expect(byId.get(berlin.id)).toMatchObject({ country_code: 'DE', region_name: 'Berlin' });
|
||||
expect(byId.get(paris.id)).toMatchObject({ country_code: 'FR', region_name: null });
|
||||
@@ -680,12 +681,12 @@ describe('remove', () => {
|
||||
const { accommodation } = (await accommodations.createAccommodation(trip.id, {
|
||||
place_id: place.id, start_day_id: day.id, end_day_id: day.id,
|
||||
})) as any;
|
||||
expect(await findRow(orm, Reservations, { accommodation_id: String(accommodation.id) })).toBeTruthy();
|
||||
expect(await findRow(orm, Reservations, { accommodation_id: legacyBoundIntegerText(accommodation.id) })).toBeTruthy();
|
||||
|
||||
await svc.remove(String(trip.id), String(place.id));
|
||||
|
||||
expect(await findRow(orm, DayAccommodations, { id: accommodation.id })).toBeNull();
|
||||
expect(await findRow(orm, Reservations, { accommodation_id: String(accommodation.id) })).toBeNull();
|
||||
expect(await findRow(orm, Reservations, { accommodation_id: legacyBoundIntegerText(accommodation.id) })).toBeNull();
|
||||
expect(await findRows(orm, DayAssignments, { day: day.id })).toEqual([]);
|
||||
});
|
||||
|
||||
@@ -697,7 +698,7 @@ describe('remove', () => {
|
||||
const keptTour = createPlace(testDb, trip.id, { name: 'Tour to keep' }) as any;
|
||||
const keptPlace = createPlace(testDb, trip.id, { name: 'Ordinary place' }) as any;
|
||||
for (const place of [tour, keptTour]) {
|
||||
await insertRow(orm, Tours, { place_id: place.id, tourTypeRef: 'hike', max_hiking_difficulty: 4 });
|
||||
await insertRow(orm, Tours, { place: place.id, tourTypeRef: 'hike', max_hiking_difficulty: 4 });
|
||||
await insertRow(orm, TourWaypoints, { place: place.id, lat: 48, lng: 11, role: 'start', sequence: 0 });
|
||||
await insertRow(orm, DayAssignments, { day: day.id, place: place.id, order_index: 0 });
|
||||
}
|
||||
@@ -709,12 +710,12 @@ describe('remove', () => {
|
||||
|
||||
expect(result).toMatchObject({ deleted: true, deletedTourPlaceIds: [tour.id] });
|
||||
expect(await findRow(orm, Places, { id: tour.id })).toBeNull();
|
||||
expect(await findRow(orm, Tours, { place_id: tour.id })).toBeNull();
|
||||
expect(await findRow(orm, Tours, { place: tour.id })).toBeNull();
|
||||
expect(await findRows(orm, TourWaypoints, { place: tour.id })).toEqual([]);
|
||||
expect(await findRows(orm, DayAssignments, { place: tour.id })).toEqual([]);
|
||||
expect(await findRow(orm, TripFiles, { id: tourFileId })).toMatchObject({ id: tourFileId, place_id: null });
|
||||
expect(await findRows(orm, FileLinks, { file: tourFileId })).toEqual([]);
|
||||
expect(await findRow(orm, Tours, { place_id: keptTour.id })).toBeTruthy();
|
||||
expect(await findRow(orm, Tours, { place: keptTour.id })).toBeTruthy();
|
||||
expect(await findRows(orm, TourWaypoints, { place: keptTour.id })).toHaveLength(1);
|
||||
expect(await findRows(orm, DayAssignments, { place: keptTour.id })).toHaveLength(1);
|
||||
expect(await findRow(orm, Places, { id: keptPlace.id })).toBeTruthy();
|
||||
@@ -801,7 +802,7 @@ describe('remove', () => {
|
||||
const { accommodation } = (await accommodations.createAccommodation(trip.id, {
|
||||
place_id: hotel.id, start_day_id: day.id, end_day_id: day.id,
|
||||
})) as { accommodation: { id: number } };
|
||||
const reservation = await findRow(orm, Reservations, { accommodation_id: String(accommodation.id) }) as { id: number };
|
||||
const reservation = await findRow(orm, Reservations, { accommodation_id: legacyBoundIntegerText(accommodation.id) }) as { id: number };
|
||||
|
||||
// cancelStaysAt (PL16) calls AccommodationsService.deleteAccommodation
|
||||
// FIRST inside this transaction — its own `uow.transactional` call nests
|
||||
@@ -833,14 +834,14 @@ describe('removeMany', () => {
|
||||
const ordinary = createPlace(testDb, trip.id, { name: 'Ordinary place' }) as any;
|
||||
const keptTour = createPlace(testDb, trip.id, { name: 'Tour to keep' }) as any;
|
||||
for (const place of [tour, keptTour]) {
|
||||
await insertRow(orm, Tours, { place_id: place.id, tourTypeRef: 'hike' });
|
||||
await insertRow(orm, Tours, { place: place.id, tourTypeRef: 'hike' });
|
||||
}
|
||||
|
||||
const result = await svc.removeMany(String(trip.id), [ordinary.id, tour.id]);
|
||||
|
||||
expect(result.deleted).toEqual([ordinary.id, tour.id]);
|
||||
expect(result.deletedTourPlaceIds).toEqual([tour.id]);
|
||||
expect(await findRow(orm, Tours, { place_id: keptTour.id })).toBeTruthy();
|
||||
expect(await findRow(orm, Tours, { place: keptTour.id })).toBeTruthy();
|
||||
expect(await findRow(orm, Places, { id: keptTour.id })).toBeTruthy();
|
||||
});
|
||||
|
||||
@@ -868,7 +869,7 @@ describe('removeMany', () => {
|
||||
const { accommodation } = (await accommodations.createAccommodation(trip.id, {
|
||||
place_id: hotel.id, start_day_id: day.id, end_day_id: day.id,
|
||||
})) as { accommodation: { id: number } };
|
||||
const reservation = await findRow(orm, Reservations, { accommodation_id: String(accommodation.id) }) as { id: number };
|
||||
const reservation = await findRow(orm, Reservations, { accommodation_id: legacyBoundIntegerText(accommodation.id) }) as { id: number };
|
||||
// An expense hung off the reservation rather than the place: linkedExpenseIds
|
||||
// selects on budget_items.place_id and never finds this one.
|
||||
const itemId = Number((await insertRow(orm, BudgetItems, { trip: trip.id, name: 'Hotel stay', total_price: 240, reservation: reservation.id })));
|
||||
|
||||
Reference in New Issue
Block a user