Changing speedy reservation to use court ranking and adding some tests for selection of court
This commit is contained in:
parent
6dfe776b14
commit
696aa590ab
2 changed files with 147 additions and 8 deletions
|
|
@ -12,7 +12,7 @@ import { MonitorType } from '../../monitoring/entity'
|
|||
import { Opponent, Reservation } from '../../reservations/entity'
|
||||
import { EmptyPage } from '../pages/empty'
|
||||
|
||||
const BAAN_RESERVEREN_ROOT_URL = 'https://squashcity.baanreserveren.nl'
|
||||
export const BAAN_RESERVEREN_ROOT_URL = 'https://squashcity.baanreserveren.nl'
|
||||
|
||||
export enum BaanReserverenUrls {
|
||||
Reservations = '/reservations',
|
||||
|
|
@ -33,7 +33,7 @@ interface BaanReserverenSession {
|
|||
}
|
||||
|
||||
// TODO: Add to DB to make configurable
|
||||
enum CourtSlot {
|
||||
export enum CourtSlot {
|
||||
One = '51',
|
||||
Two = '52',
|
||||
Three = '53',
|
||||
|
|
@ -67,8 +67,8 @@ const CourtSlotToNumber: Record<CourtSlot, number> = {
|
|||
|
||||
// Lower is better
|
||||
const CourtRank: Record<CourtSlot, number> = {
|
||||
[CourtSlot.One]: 0,
|
||||
[CourtSlot.Two]: 0,
|
||||
[CourtSlot.One]: 2,
|
||||
[CourtSlot.Two]: 1,
|
||||
[CourtSlot.Three]: 0,
|
||||
[CourtSlot.Four]: 0,
|
||||
[CourtSlot.Five]: 99, // shitty
|
||||
|
|
@ -77,9 +77,9 @@ const CourtRank: Record<CourtSlot, number> = {
|
|||
[CourtSlot.Eight]: 0,
|
||||
[CourtSlot.Nine]: 0,
|
||||
[CourtSlot.Ten]: 0,
|
||||
[CourtSlot.Eleven]: 1, // no one likes upstairs
|
||||
[CourtSlot.Twelve]: 1, // no one likes upstairs
|
||||
[CourtSlot.Thirteen]: 1, // no one likes upstairs
|
||||
[CourtSlot.Eleven]: 10, // no one likes upstairs
|
||||
[CourtSlot.Twelve]: 9, // no one likes upstairs
|
||||
[CourtSlot.Thirteen]: 9, // no one likes upstairs
|
||||
} as const
|
||||
|
||||
enum StartTimeClass {
|
||||
|
|
@ -680,7 +680,11 @@ export class BaanReserverenService {
|
|||
const time = date.format('HH:mm')
|
||||
for (const [timeClass, times] of Object.entries(StartTimeClassStartTimes)) {
|
||||
if (times.includes(time)) {
|
||||
return StartTimeClassCourtSlots[timeClass as StartTimeClass]
|
||||
const courtSlots = [
|
||||
...StartTimeClassCourtSlots[timeClass as StartTimeClass],
|
||||
]
|
||||
// sort by ranking
|
||||
return courtSlots.sort((a, b) => CourtRank[a] - CourtRank[b])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
135
test/unit/baanreserveren/service.spec.ts
Normal file
135
test/unit/baanreserveren/service.spec.ts
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
import { getQueueToken } from '@nestjs/bull'
|
||||
import { ConfigService } from '@nestjs/config'
|
||||
import { Test, TestingModule } from '@nestjs/testing'
|
||||
|
||||
import dayjs from '../../../src/common/dayjs'
|
||||
import { LoggerService } from '../../../src/logger/service.logger'
|
||||
import { MONITORING_QUEUE_NAME } from '../../../src/monitoring/config'
|
||||
import { Reservation } from '../../../src/reservations/entity'
|
||||
import {
|
||||
BAAN_RESERVEREN_ROOT_URL,
|
||||
BaanReserverenService,
|
||||
CourtSlot,
|
||||
} from '../../../src/runner/baanreserveren/service'
|
||||
import { EmptyPage } from '../../../src/runner/pages/empty'
|
||||
|
||||
describe('baanreserveren.service', () => {
|
||||
let module: TestingModule
|
||||
let pageGotoSpy: jest.SpyInstance
|
||||
let brService: BaanReserverenService
|
||||
|
||||
beforeAll(async () => {
|
||||
pageGotoSpy = jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve({ status: () => 200 }))
|
||||
module = await Test.createTestingModule({
|
||||
providers: [
|
||||
BaanReserverenService,
|
||||
{
|
||||
provide: ConfigService,
|
||||
useValue: { getOrThrow: jest.fn().mockReturnValue('test') },
|
||||
},
|
||||
{
|
||||
provide: LoggerService,
|
||||
useValue: { debug: jest.fn(), warn: jest.fn() },
|
||||
},
|
||||
{
|
||||
provide: EmptyPage,
|
||||
useValue: {
|
||||
waitForNetworkIdle: jest.fn().mockResolvedValue(null),
|
||||
waitForSelector: jest.fn().mockResolvedValue(undefined),
|
||||
goto: pageGotoSpy,
|
||||
url: jest
|
||||
.fn()
|
||||
.mockReturnValue({ includes: jest.fn().mockReturnValue(true) }),
|
||||
$: jest.fn().mockResolvedValue(undefined),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: getQueueToken(MONITORING_QUEUE_NAME),
|
||||
useValue: { add: jest.fn() },
|
||||
},
|
||||
],
|
||||
}).compile()
|
||||
brService = module.get<BaanReserverenService>(BaanReserverenService)
|
||||
})
|
||||
|
||||
describe('performSpeedyReservation', () => {
|
||||
it.each([
|
||||
[18, 15, CourtSlot.Seven, CourtSlot.Six],
|
||||
[18, 30, CourtSlot.Three, CourtSlot.One],
|
||||
[18, 45, CourtSlot.Twelve, CourtSlot.Thirteen],
|
||||
])(
|
||||
'should try highest ranked court first',
|
||||
async (startHour, startMinute, preferredCourt, backupCourt) => {
|
||||
const start = dayjs()
|
||||
.set('hour', startHour)
|
||||
.set('minute', startMinute)
|
||||
.set('second', 0)
|
||||
.set('millisecond', 0)
|
||||
const reservation = new Reservation({
|
||||
id: '1',
|
||||
ownerId: '1',
|
||||
dateRangeStart: start,
|
||||
dateRangeEnd: start.add(45, 'minute'),
|
||||
opponents: [],
|
||||
})
|
||||
await brService.performSpeedyReservation(reservation)
|
||||
expect(pageGotoSpy).toHaveBeenCalledWith(
|
||||
`${BAAN_RESERVEREN_ROOT_URL}/reservations/make/${preferredCourt}/${
|
||||
start.valueOf() / 1000
|
||||
}`,
|
||||
)
|
||||
expect(pageGotoSpy).not.toHaveBeenCalledWith(
|
||||
`${BAAN_RESERVEREN_ROOT_URL}/reservations/make/${backupCourt}/${
|
||||
start.valueOf() / 1000
|
||||
}`,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
it.each([
|
||||
[18, 15, CourtSlot.Seven, CourtSlot.Eight],
|
||||
[18, 30, CourtSlot.Three, CourtSlot.Four],
|
||||
[18, 45, CourtSlot.Twelve, CourtSlot.Thirteen],
|
||||
])(
|
||||
'should try backup if first rank is taken',
|
||||
async (startHour, startMinute, preferredCourt, backupCourt) => {
|
||||
pageGotoSpy.mockImplementation((url: string) => {
|
||||
if (
|
||||
url ===
|
||||
`${BAAN_RESERVEREN_ROOT_URL}/reservations/make/${preferredCourt}/${
|
||||
start.valueOf() / 1000
|
||||
}`
|
||||
) {
|
||||
return Promise.resolve({ status: () => 400 }) // fail on the preferred court
|
||||
}
|
||||
return Promise.resolve({ status: () => 200 })
|
||||
})
|
||||
const start = dayjs()
|
||||
.set('hour', startHour)
|
||||
.set('minute', startMinute)
|
||||
.set('second', 0)
|
||||
.set('millisecond', 0)
|
||||
const reservation = new Reservation({
|
||||
id: '1',
|
||||
ownerId: '1',
|
||||
dateRangeStart: start,
|
||||
dateRangeEnd: start.add(45, 'minute'),
|
||||
opponents: [],
|
||||
})
|
||||
await brService.performSpeedyReservation(reservation)
|
||||
expect(pageGotoSpy).toHaveBeenCalledWith(
|
||||
`${BAAN_RESERVEREN_ROOT_URL}/reservations/make/${preferredCourt}/${
|
||||
start.valueOf() / 1000
|
||||
}`,
|
||||
)
|
||||
expect(pageGotoSpy).toHaveBeenCalledWith(
|
||||
`${BAAN_RESERVEREN_ROOT_URL}/reservations/make/${backupCourt}/${
|
||||
start.valueOf() / 1000
|
||||
}`,
|
||||
)
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Reference in a new issue