Adding dayjs module to allow timezone handling by default and replaced node_module with this module

This commit is contained in:
Collin Duncan 2023-01-20 15:31:04 +01:00
parent 5653d98161
commit 09e4b3a1b8
No known key found for this signature in database
11 changed files with 108 additions and 47 deletions

View file

@ -8,7 +8,7 @@ services:
- 3306:3306 - 3306:3306
healthcheck: healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 20s timeout: 5s
retries: 10 retries: 10
http: http:

20
src/common/dayjs.ts Normal file
View file

@ -0,0 +1,20 @@
import dayjs from 'dayjs'
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone'
import 'dayjs/locale/nl'
dayjs.extend(isSameOrBefore)
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.locale('nl')
dayjs.tz.setDefault('Europe/Amsterdam')
const dayjsTz = (
date?: string | number | Date | dayjs.Dayjs | null | undefined
) => {
return dayjs(date).tz()
}
export default dayjsTz

View file

@ -1,8 +1,4 @@
import dayjs from 'dayjs' import dayjs from './dayjs'
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
import { hashPassword } from './password'
dayjs.extend(isSameOrBefore)
import { DateRange, Opponent, Reservation } from './reservation' import { DateRange, Opponent, Reservation } from './reservation'
export enum ValidationErrorCode { export enum ValidationErrorCode {
@ -61,9 +57,8 @@ const validateRequestBody = async (
) )
} }
const hashedPassword = await hashPassword(password)
const reservation = new Reservation( const reservation = new Reservation(
{ username, password: hashedPassword }, { username, password },
convertDateRangeStringToObject(dateRange), convertDateRangeStringToObject(dateRange),
opponent opponent
) )

View file

@ -1,7 +1,6 @@
import dayjs, { Dayjs } from 'dayjs' import { Dayjs } from 'dayjs'
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore' import dayjs from './dayjs'
import { query } from './database' import { query } from './database'
dayjs.extend(isSameOrBefore)
const RESERVATION_AVAILABLE_WITHIN_DAYS = 7 const RESERVATION_AVAILABLE_WITHIN_DAYS = 7
@ -16,8 +15,8 @@ export interface Opponent {
} }
export interface DateRange { export interface DateRange {
start: dayjs.Dayjs start: Dayjs
end: dayjs.Dayjs end: Dayjs
} }
export class Reservation { export class Reservation {
@ -81,7 +80,7 @@ export class Reservation {
return { return {
user: { user: {
username: this.user.username, username: this.user.username,
password: this.user.password ? '?' : null, password: this.user.password,
}, },
opponent: this.opponent, opponent: this.opponent,
booked: this.booked, booked: this.booked,

View file

@ -4,7 +4,10 @@ import { Runner } from './runner'
let runner: Runner | undefined let runner: Runner | undefined
const getRunner = () => { const getRunner = () => {
if (!runner) { if (!runner) {
runner = new Runner({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }) runner = new Runner({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox'],
})
} }
return runner return runner
} }

View file

@ -1,4 +1,5 @@
import dayjs, { Dayjs } from 'dayjs' import { Dayjs } from 'dayjs'
import dayjs from './dayjs'
import puppeteer, { import puppeteer, {
Browser, Browser,
BrowserConnectOptions, BrowserConnectOptions,
@ -36,7 +37,7 @@ export class Runner {
} }
private async login(username: string, password: string) { private async login(username: string, password: string) {
asyncLocalStorage.getStore()?.debug('Logging in') asyncLocalStorage.getStore()?.debug('Logging in', { username })
await this.page?.goto('https://squashcity.baanreserveren.nl/') await this.page?.goto('https://squashcity.baanreserveren.nl/')
await this.page await this.page
?.waitForSelector('input[name=username]') ?.waitForSelector('input[name=username]')
@ -53,10 +54,11 @@ export class Runner {
await this.confirmReservation() await this.confirmReservation()
reservation.booked = true reservation.booked = true
return true return true
} catch (err) { } catch (err: unknown) {
asyncLocalStorage asyncLocalStorage.getStore()?.error('Error making reservation', {
.getStore() reservation: reservation.format(),
?.error('Error making reservation', reservation.format()) error: err,
})
return false return false
} }
} }
@ -82,7 +84,12 @@ export class Runner {
asyncLocalStorage asyncLocalStorage
.getStore() .getStore()
?.debug('Date is on different page, increase month') ?.debug('Date is on different page, increase month')
await this.page?.waitForSelector('td.month.next').then((d) => d?.click()) await this.page
?.waitForSelector('td.month.next')
.then((d) => d?.click())
.catch(() => {
throw new Error('Could not click correct month')
})
} }
await this.page await this.page
@ -92,11 +99,18 @@ export class Runner {
)}` )}`
) )
.then((d) => d?.click()) .then((d) => d?.click())
await this.page?.waitForSelector( .catch(() => {
`td#cal_${date.get('year')}_${date.get('month') + 1}_${date.get( throw new Error('Could not click correct day')
'date' })
)}.selected` await this.page
) ?.waitForSelector(
`td#cal_${date.get('year')}_${date.get('month') + 1}_${date.get(
'date'
)}.selected`
)
.catch(() => {
throw new Error("Selected day didn't change")
})
} }
private async selectAvailableTime(res: Reservation): Promise<void> { private async selectAvailableTime(res: Reservation): Promise<void> {

View file

@ -1,4 +1,4 @@
import dayjs from 'dayjs' import dayjs from '../common/dayjs'
import { Reservation } from '../common/reservation' import { Reservation } from '../common/reservation'
import { Runner } from '../common/runner' import { Runner } from '../common/runner'

View file

@ -9,27 +9,35 @@ exports[`scheduler should handle valid requests outside of reservation window 1`
"end": { "end": {
"$D": 16, "$D": 16,
"$H": 1, "$H": 1,
"$L": "en", "$L": "nl",
"$M": 0, "$M": 0,
"$W": 0, "$W": 0,
"$d": {}, "$d": {},
"$m": 15, "$m": 15,
"$ms": 0, "$ms": 0,
"$offset": 60,
"$s": 0, "$s": 0,
"$x": {}, "$u": false,
"$x": {
"$timezone": "Europe/Amsterdam",
},
"$y": 2022, "$y": 2022,
}, },
"start": { "start": {
"$D": 16, "$D": 16,
"$H": 1, "$H": 1,
"$L": "en", "$L": "nl",
"$M": 0, "$M": 0,
"$W": 0, "$W": 0,
"$d": {}, "$d": {},
"$m": 0, "$m": 0,
"$ms": 0, "$ms": 0,
"$offset": 60,
"$s": 0, "$s": 0,
"$x": {}, "$u": false,
"$x": {
"$timezone": "Europe/Amsterdam",
},
"$y": 2022, "$y": 2022,
}, },
}, },
@ -41,27 +49,33 @@ exports[`scheduler should handle valid requests outside of reservation window 1`
{ {
"$D": 16, "$D": 16,
"$H": 1, "$H": 1,
"$L": "en", "$L": "nl",
"$M": 0, "$M": 0,
"$W": 0, "$W": 0,
"$d": {}, "$d": {},
"$m": 0, "$m": 0,
"$ms": 0, "$ms": 0,
"$offset": 60,
"$s": 0, "$s": 0,
"$x": {}, "$x": {
"$timezone": "Europe/Amsterdam",
},
"$y": 2022, "$y": 2022,
}, },
{ {
"$D": 16, "$D": 16,
"$H": 1, "$H": 1,
"$L": "en", "$L": "nl",
"$M": 0, "$M": 0,
"$W": 0, "$W": 0,
"$d": {}, "$d": {},
"$m": 15, "$m": 15,
"$ms": 0, "$ms": 0,
"$offset": 60,
"$s": 0, "$s": 0,
"$x": {}, "$x": {
"$timezone": "Europe/Amsterdam",
},
"$y": 2022, "$y": 2022,
}, },
], ],
@ -73,14 +87,17 @@ exports[`scheduler should handle valid requests outside of reservation window 1`
"scheduledFor": { "scheduledFor": {
"$D": 9, "$D": 9,
"$H": 0, "$H": 0,
"$L": "en", "$L": "nl",
"$M": 0, "$M": 0,
"$W": 0, "$W": 0,
"$d": {}, "$d": {},
"$m": 0, "$m": 0,
"$ms": 0, "$ms": 0,
"$offset": 60,
"$s": 0, "$s": 0,
"$x": {}, "$x": {
"$timezone": "Europe/Amsterdam",
},
"$y": 2022, "$y": 2022,
}, },
}, },
@ -96,27 +113,35 @@ exports[`scheduler should handle valid requests within reservation window 1`] =
"end": { "end": {
"$D": 1, "$D": 1,
"$H": 1, "$H": 1,
"$L": "en", "$L": "nl",
"$M": 0, "$M": 0,
"$W": 6, "$W": 6,
"$d": {}, "$d": {},
"$m": 30, "$m": 30,
"$ms": 0, "$ms": 0,
"$offset": 60,
"$s": 0, "$s": 0,
"$x": {}, "$u": false,
"$x": {
"$timezone": "Europe/Amsterdam",
},
"$y": 2022, "$y": 2022,
}, },
"start": { "start": {
"$D": 1, "$D": 1,
"$H": 1, "$H": 1,
"$L": "en", "$L": "nl",
"$M": 0, "$M": 0,
"$W": 6, "$W": 6,
"$d": {}, "$d": {},
"$m": 15, "$m": 15,
"$ms": 0, "$ms": 0,
"$offset": 60,
"$s": 0, "$s": 0,
"$x": {}, "$u": false,
"$x": {
"$timezone": "Europe/Amsterdam",
},
"$y": 2022, "$y": 2022,
}, },
}, },

View file

@ -1,4 +1,4 @@
import dayjs from 'dayjs' import dayjs from '../../../src/common/dayjs'
import { import {
validateJSONRequest, validateJSONRequest,
@ -9,7 +9,7 @@ describe('request', () => {
const testDate = dayjs().add(1, 'day') const testDate = dayjs().add(1, 'day')
describe('validateJSONRequest', () => { describe('validateJSONRequest', () => {
test('should return ReservationRequest', () => { test('should return ReservationRequest', async () => {
const body = { const body = {
username: 'collin', username: 'collin',
password: '123abc', password: '123abc',
@ -23,7 +23,9 @@ describe('request', () => {
}, },
} }
expect(() => validateJSONRequest(body)).not.toThrow() const res = await validateJSONRequest(body)
expect(res).toBeDefined()
expect(res.dateRange.start.format()).toEqual(testDate.format())
}) })
test('should throw error for undefined body', async () => { test('should throw error for undefined body', async () => {

View file

@ -1,4 +1,5 @@
import dayjs, { Dayjs } from 'dayjs' import { Dayjs } from 'dayjs'
import dayjs from '../../../src/common/dayjs'
import { DateRange, Reservation } from '../../../src/common/reservation' import { DateRange, Reservation } from '../../../src/common/reservation'
describe('Reservation', () => { describe('Reservation', () => {
@ -20,6 +21,7 @@ describe('Reservation', () => {
expect(res.possibleDates).toHaveLength(5) expect(res.possibleDates).toHaveLength(5)
console.log(res.possibleDates[0].format())
expect(res.possibleDates[0]).toEqual(startDate) expect(res.possibleDates[0]).toEqual(startDate)
expect(res.possibleDates[1]).toEqual(startDate.add(15, 'minute')) expect(res.possibleDates[1]).toEqual(startDate.add(15, 'minute'))
expect(res.possibleDates[2]).toEqual(startDate.add(30, 'minute')) expect(res.possibleDates[2]).toEqual(startDate.add(30, 'minute'))
@ -45,6 +47,7 @@ describe('Reservation', () => {
const zeroTime = (date: Dayjs): Dayjs => const zeroTime = (date: Dayjs): Dayjs =>
date.hour(0).minute(0).second(0).millisecond(0) date.hour(0).minute(0).second(0).millisecond(0)
test.each([ test.each([
{ {
date: dayjs().add(8, 'days'), date: dayjs().add(8, 'days'),

View file

@ -1,4 +1,4 @@
import dayjs from 'dayjs' import dayjs from '../../../src/common/dayjs'
import { import {
ValidationError, ValidationError,
ValidationErrorCode, ValidationErrorCode,