mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
Cover the fallback branches the moved handlers brought with them
The branch threshold over src/nest/** dipped to 79.89% after the move: the new *.rpc.ts files carry the defensive branches the router closures had (?? '', || current, optional cascades), and none of them were exercised. Adds the cases that reach them: a booking whose cascade does not fire, an update that keeps the stored title, a bag colour of the wrong type, a non-array userIds, a missing bag across all three bag writes, and the block delete without a partner reservation. Also corrects two assumptions I had written into the booking tests: title and type are required by the shared schema, so the handler's own fallbacks sit behind it as defence in depth rather than as the first line.
This commit is contained in:
@@ -115,6 +115,43 @@ describe('PackingRpc through the router', () => {
|
||||
expect(f.data.setBagMembers).toHaveBeenCalledWith('1', '80', [5, 6]);
|
||||
});
|
||||
|
||||
it('PACKING-RPC-007b a non-string bag colour is dropped rather than stored', async () => {
|
||||
const f = build();
|
||||
await f.host('db:write:packing').dispatch(req('packing.createBag', { tripId: 1, input: { name: 'Bag', color: 42 } }), 42);
|
||||
expect(f.data.createBag).toHaveBeenCalledWith('1', { name: 'Bag', color: undefined });
|
||||
});
|
||||
|
||||
it('PACKING-RPC-007c a non-array userIds becomes an empty list', async () => {
|
||||
const f = build();
|
||||
await f.host('db:write:packing').dispatch(req('packing.setBagMembers', { tripId: 1, bagId: 80, userIds: 'nope' }), 42);
|
||||
expect(f.data.setBagMembers).toHaveBeenCalledWith('1', '80', []);
|
||||
});
|
||||
|
||||
it('PACKING-RPC-007d a missing bag is refused across every bag write', async () => {
|
||||
const f = build();
|
||||
const host = f.host('db:write:packing');
|
||||
for (const [method, params] of [
|
||||
['packing.updateBag', { tripId: 1, bagId: 404, input: {} }],
|
||||
['packing.deleteBag', { tripId: 1, bagId: 404 }],
|
||||
['packing.setBagMembers', { tripId: 1, bagId: 404, userIds: [] }],
|
||||
] as const) {
|
||||
expect(((await host.dispatch(req(method, params), 42)) as RpcError).error.message).toBe('no packing bag 404 on trip 1');
|
||||
}
|
||||
});
|
||||
|
||||
it('PACKING-RPC-007e an invalid item payload is BAD_PARAMS on create and update alike', async () => {
|
||||
const f = build();
|
||||
const host = f.host('db:write:packing');
|
||||
expect(((await host.dispatch(req('packing.create', { tripId: 1, input: { name: 42 } }), 42)) as RpcError).error.code).toBe('BAD_PARAMS');
|
||||
expect(((await host.dispatch(req('packing.update', { tripId: 1, itemId: 70, input: { name: 42 } }), 42)) as RpcError).error.code).toBe('BAD_PARAMS');
|
||||
});
|
||||
|
||||
it('PACKING-RPC-007f deleting a missing item is refused', async () => {
|
||||
const f = build();
|
||||
const res = (await f.host('db:write:packing').dispatch(req('packing.delete', { tripId: 1, itemId: 404 }), 42)) as RpcError;
|
||||
expect(res.error.message).toBe('no packing item 404 on trip 1');
|
||||
});
|
||||
|
||||
it('PACKING-RPC-008 the class is listed in its module providers', () => {
|
||||
expect(Reflect.getMetadata('providers', PackingModule) as unknown[]).toContain(PackingRpc);
|
||||
});
|
||||
|
||||
@@ -132,6 +132,43 @@ describe('ReservationsRpc', () => {
|
||||
expect(f.reservations.notifyBookingChange).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('BOOK-RPC-008b title and type are required by the shared schema', async () => {
|
||||
const f = build();
|
||||
// The handler still carries ?? '' fallbacks behind this, kept from the router as
|
||||
// defence in depth, but the schema is what a plugin actually hits first.
|
||||
const res = (await f.host().dispatch(req('reservations.create', { tripId: 1, input: {} }), 42)) as RpcError;
|
||||
expect(res.error.code).toBe('BAD_PARAMS');
|
||||
expect(f.reservations.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('BOOK-RPC-008c an update without a title keeps the current one', async () => {
|
||||
const f = build();
|
||||
await f.host().dispatch(req('reservations.update', { tripId: 1, reservationId: 5, input: {} }), 42);
|
||||
// Falls back to the stored title and type rather than blanking them.
|
||||
expect(f.reservations.notifyBookingChange).toHaveBeenCalledWith(1, 42, 'Hotel', 'lodging');
|
||||
});
|
||||
|
||||
it('BOOK-RPC-008d a non-lodging booking cascades nothing', async () => {
|
||||
const f = build();
|
||||
await f.host().dispatch(req('reservations.create', { tripId: 1, input: { title: 'Museum', type: 'activity' } }), 42);
|
||||
expect(events(f.realtime)).toEqual(['reservation:created']);
|
||||
f.realtime.broadcast.mockClear();
|
||||
await f.host().dispatch(req('reservations.update', { tripId: 1, reservationId: 5, input: { title: 'x', type: 'activity' } }), 42);
|
||||
expect(events(f.realtime)).toEqual(['reservation:updated']);
|
||||
f.realtime.broadcast.mockClear();
|
||||
await f.host().dispatch(req('reservations.delete', { tripId: 1, reservationId: 5 }), 42);
|
||||
expect(events(f.realtime)).toEqual(['reservation:deleted']);
|
||||
});
|
||||
|
||||
it('BOOK-RPC-008e an update with a malformed endpoints array is BAD_PARAMS too', async () => {
|
||||
const f = build();
|
||||
const res = (await f.host().dispatch(
|
||||
req('reservations.update', { tripId: 1, reservationId: 5, input: { title: 'x', type: 'lodging', endpoints: [{ nonsense: true }] } }), 42,
|
||||
)) as RpcError;
|
||||
expect(res.error.code).toBe('BAD_PARAMS');
|
||||
expect(f.reservations.update).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('BOOK-RPC-009 the class is listed in its module providers', () => {
|
||||
expect(Reflect.getMetadata('providers', ReservationsModule) as unknown[]).toContain(ReservationsRpc);
|
||||
});
|
||||
@@ -185,6 +222,25 @@ describe('AccommodationsRpc', () => {
|
||||
.toBe('no accommodation 404 on trip 1');
|
||||
});
|
||||
|
||||
it('BOOK-RPC-015b optional block fields are passed through, absent ones as undefined', async () => {
|
||||
const f = build();
|
||||
await f.host().dispatch(req('accommodations.create', { tripId: 1, input: { place_id: 7, start_day_id: 3, end_day_id: 4, check_in: '15:00', notes: 'late' } }), 42);
|
||||
expect(f.days.createAccommodation).toHaveBeenCalledWith(1, expect.objectContaining({ check_in: '15:00', notes: 'late', check_out: undefined }));
|
||||
});
|
||||
|
||||
it('BOOK-RPC-015c an update with a bad ref is refused before the write', async () => {
|
||||
const f = build();
|
||||
const res = (await f.host().dispatch(req('accommodations.update', { tripId: 1, accommodationId: 11, input: { place_id: 404 } }), 42)) as RpcError;
|
||||
expect(res.error.message).toBe('place 404 is not on this trip');
|
||||
expect(f.days.updateAccommodation).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('BOOK-RPC-015d deleting a block without a partner cascades only its own event', async () => {
|
||||
const f = build();
|
||||
await f.host().dispatch(req('accommodations.delete', { tripId: 1, accommodationId: 11 }), 42);
|
||||
expect(events(f.realtime)).toEqual(['accommodation:deleted']);
|
||||
});
|
||||
|
||||
it('BOOK-RPC-016 the class is listed in its module providers', () => {
|
||||
expect(Reflect.getMetadata('providers', DaysModule) as unknown[]).toContain(AccommodationsRpc);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user