mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 15:18:11 +00:00
169 lines
5.6 KiB
TypeScript
169 lines
5.6 KiB
TypeScript
import { Test, TestingModule } from '@nestjs/testing';
|
|
import { SeatsService } from './seats.service';
|
|
import { PrismaService } from '../../common/prisma.service';
|
|
import { ConflictException } from '@nestjs/common';
|
|
import { SegmentsService } from '../segments/segments.service';
|
|
import { SystemConfigService } from '../system-config/system-config.service';
|
|
import { AuditService } from '../../common/audit.service';
|
|
import { SmsClientService } from '../notifications/sms-client.service';
|
|
import { JourneyDirection } from './seats.dto';
|
|
|
|
describe('SeatsService - Auto Assign', () => {
|
|
let service: SeatsService;
|
|
let prisma: PrismaService;
|
|
let segmentsService: SegmentsService;
|
|
|
|
const mockPrisma = {
|
|
seat: {
|
|
findMany: jest.fn(),
|
|
updateMany: jest.fn(),
|
|
},
|
|
tripStopTime: {
|
|
findMany: jest.fn(),
|
|
},
|
|
trainSchedule: {
|
|
findUnique: jest.fn(),
|
|
},
|
|
seatBlock: {
|
|
findMany: jest.fn(),
|
|
},
|
|
};
|
|
|
|
const mockSegmentsService = {
|
|
getSeatAvailabilityMap: jest.fn(),
|
|
};
|
|
|
|
const mockSystemConfigService = {
|
|
getNumber: jest.fn().mockResolvedValue(30),
|
|
};
|
|
|
|
const mockAuditService = {
|
|
log: jest.fn(),
|
|
};
|
|
|
|
const mockSmsClientService = {
|
|
send: jest.fn(),
|
|
};
|
|
|
|
beforeEach(async () => {
|
|
const module: TestingModule = await Test.createTestingModule({
|
|
providers: [
|
|
SeatsService,
|
|
{ provide: PrismaService, useValue: mockPrisma },
|
|
{ provide: SegmentsService, useValue: mockSegmentsService },
|
|
{ provide: SystemConfigService, useValue: mockSystemConfigService },
|
|
{ provide: AuditService, useValue: mockAuditService },
|
|
{ provide: SmsClientService, useValue: mockSmsClientService },
|
|
],
|
|
}).compile();
|
|
|
|
service = module.get<SeatsService>(SeatsService);
|
|
prisma = module.get<PrismaService>(PrismaService);
|
|
segmentsService = module.get<SegmentsService>(SegmentsService);
|
|
jest.clearAllMocks();
|
|
|
|
mockPrisma.trainSchedule.findUnique.mockResolvedValue({
|
|
originStationId: 'origin-station',
|
|
destinationStationId: 'destination-station',
|
|
});
|
|
mockPrisma.tripStopTime.findMany.mockResolvedValue([
|
|
{ stationId: 'origin-station', sequence: 0 },
|
|
{ stationId: 'destination-station', sequence: 1 },
|
|
]);
|
|
mockPrisma.seatBlock.findMany.mockResolvedValue([]);
|
|
mockSegmentsService.getSeatAvailabilityMap.mockResolvedValue(new Map());
|
|
});
|
|
|
|
describe('assertNoRouteSeatConflict', () => {
|
|
it('rejects overlapping origin-destination seat reuse on the same schedule', async () => {
|
|
mockPrisma.tripStopTime.findMany.mockResolvedValue([
|
|
{ stationId: 'seb', sequence: 1 },
|
|
{ stationId: 'ada', sequence: 2 },
|
|
{ stationId: 'dd', sequence: 3 },
|
|
]);
|
|
mockSegmentsService.getSeatAvailabilityMap.mockResolvedValue(new Map([['seat-1', 'BOOKED']]));
|
|
mockPrisma.seat.findMany.mockResolvedValue([
|
|
{ id: 'seat-1', seatNumber: '12', coach: { number: 'C1' } },
|
|
]);
|
|
|
|
await expect(service.assertNoRouteSeatConflict({
|
|
scheduleId: 'sched-1',
|
|
seatIds: ['seat-1'],
|
|
originStationId: 'seb',
|
|
destinationStationId: 'dd',
|
|
journeyDirection: JourneyDirection.ONE_WAY,
|
|
})).rejects.toThrow(ConflictException);
|
|
});
|
|
|
|
it('allows the same seat number to be reused on non-overlapping legs', async () => {
|
|
mockPrisma.tripStopTime.findMany.mockResolvedValue([
|
|
{ stationId: 'seb', sequence: 1 },
|
|
{ stationId: 'ada', sequence: 2 },
|
|
{ stationId: 'dd', sequence: 3 },
|
|
]);
|
|
mockSegmentsService.getSeatAvailabilityMap.mockResolvedValue(new Map());
|
|
|
|
await expect(service.assertNoRouteSeatConflict({
|
|
scheduleId: 'sched-1',
|
|
seatIds: ['seat-1'],
|
|
originStationId: 'seb',
|
|
destinationStationId: 'ada',
|
|
journeyDirection: JourneyDirection.ONE_WAY,
|
|
})).resolves.toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('autoAssignSeats', () => {
|
|
it('should assign contiguous seats in same row', async () => {
|
|
const mockSeats = [
|
|
{ id: 'seat-1', coachId: 'coach-1', row: 1, col: 'A' },
|
|
{ id: 'seat-2', coachId: 'coach-1', row: 1, col: 'B' },
|
|
{ id: 'seat-3', coachId: 'coach-1', row: 1, col: 'C' },
|
|
{ id: 'seat-4', coachId: 'coach-1', row: 2, col: 'A' },
|
|
];
|
|
|
|
mockPrisma.seat.findMany.mockResolvedValue(mockSeats);
|
|
|
|
const result = await service.autoAssignSeats('trip-1', 2, 'ECONOMY_REGULAR');
|
|
|
|
expect(result).toHaveLength(2);
|
|
expect(result).toEqual(['seat-1', 'seat-2']);
|
|
});
|
|
|
|
it('should throw error if not enough seats available', async () => {
|
|
mockPrisma.seat.findMany.mockResolvedValue([
|
|
{ id: 'seat-1', coachId: 'coach-1', row: 1, col: 'A' },
|
|
]);
|
|
|
|
await expect(
|
|
service.autoAssignSeats('trip-1', 3, 'ECONOMY_REGULAR'),
|
|
).rejects.toThrow(ConflictException);
|
|
});
|
|
|
|
it('should respect eligibility filter', async () => {
|
|
const mockSeats = [
|
|
{ id: 'seat-1', coachId: 'coach-1', row: 1, col: 'A', eligibility: 'ACCESSIBLE' },
|
|
{ id: 'seat-2', coachId: 'coach-1', row: 1, col: 'B', eligibility: 'ACCESSIBLE' },
|
|
];
|
|
|
|
mockPrisma.seat.findMany.mockResolvedValue(mockSeats);
|
|
|
|
const result = await service.autoAssignSeats('trip-1', 2, 'ECONOMY_REGULAR');
|
|
|
|
expect(result).toHaveLength(2);
|
|
});
|
|
|
|
it('should assign single seat', async () => {
|
|
const mockSeats = [
|
|
{ id: 'seat-1', coachId: 'coach-1', row: 1, col: 'A' },
|
|
];
|
|
|
|
mockPrisma.seat.findMany.mockResolvedValue(mockSeats);
|
|
|
|
const result = await service.autoAssignSeats('trip-1', 1, 'ECONOMY_REGULAR');
|
|
|
|
expect(result).toEqual(['seat-1']);
|
|
});
|
|
});
|
|
});
|