All checks were successful
CI / checks (pull_request) Successful in 44s
Add DB migration (hour, minute, day_of_week, timezone columns) with idempotent ALTER TABLE upgrade path for existing databases. Extend getCronExpression with optional dayOfWeek parameter; weekly defaults to Monday (1) when not specified. Worker createJob now passes stored schedule fields to cron expression and uses the subscription's IANA timezone instead of hardcoded 'UTC'. PUT /subscription/email accepts optional hour (0-23), minute (0-59), dayOfWeek (1-7, only for weekly), timezone (IANA). GET response includes the new fields. Omitted fields fall back to defaults (17:00 UTC). Closes mailship-200
97 lines
No EOL
3.6 KiB
TypeScript
97 lines
No EOL
3.6 KiB
TypeScript
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
|
import * as db from '../src/database.js'
|
|
import { registerSubscription } from '../src/actions.js'
|
|
import { getCronExpression } from '../src/alert.js'
|
|
import { getJobCronSource, removeJob } from '../src/worker/email.js'
|
|
import { registerSubscription as regSub } from '../src/worker/index.js'
|
|
|
|
const pubkey = 'schedule-test-' + Date.now()
|
|
const email = 'schedule-test-' + Date.now() + '@example.com'
|
|
let sub: any = null
|
|
|
|
describe('Schedule fields', () => {
|
|
beforeAll(async () => {
|
|
await db.migrate()
|
|
})
|
|
|
|
it('inserts subscription with custom hour/minute/timezone', async () => {
|
|
const s = await db.insertSubscription(pubkey, email, 'daily', 7, 30, undefined, 'America/New_York')
|
|
expect(s).toBeTruthy()
|
|
expect(s!.hour).toBe(7)
|
|
expect(s!.minute).toBe(30)
|
|
expect(s!.timezone).toBe('America/New_York')
|
|
expect(s!.day_of_week).toBeNull()
|
|
sub = s
|
|
})
|
|
|
|
it('inserts subscription with custom weekly dayOfWeek', async () => {
|
|
const pk2 = 'schedule-test-weekly-' + Date.now()
|
|
const em2 = pk2 + '@example.com'
|
|
const s = await db.insertSubscription(pk2, em2, 'weekly', 9, 0, 6, 'UTC')
|
|
expect(s).toBeTruthy()
|
|
expect(s!.hour).toBe(9)
|
|
expect(s!.minute).toBe(0)
|
|
expect(s!.day_of_week).toBe(6)
|
|
expect(s!.timezone).toBe('UTC')
|
|
})
|
|
|
|
it('inserts subscription with defaults when schedule omitted', async () => {
|
|
const pk3 = 'schedule-test-defaults-' + Date.now()
|
|
const em3 = pk3 + '@example.com'
|
|
const s = await db.insertSubscription(pk3, em3, 'daily')
|
|
expect(s).toBeTruthy()
|
|
expect(s!.hour).toBe(17)
|
|
expect(s!.minute).toBe(0)
|
|
expect(s!.timezone).toBe('UTC')
|
|
expect(s!.day_of_week).toBeNull()
|
|
})
|
|
|
|
it('getCronExpression returns daily with custom hour/minute', () => {
|
|
expect(getCronExpression('daily', 7, 30)).toBe('0 30 7 * * *')
|
|
})
|
|
|
|
it('getCronExpression returns weekly with custom dayOfWeek', () => {
|
|
expect(getCronExpression('weekly', 9, 0, 6)).toBe('0 0 9 * * 6')
|
|
})
|
|
|
|
it('getCronExpression defaults to Monday for weekly', () => {
|
|
expect(getCronExpression('weekly', 17, 0)).toBe('0 0 17 * * 1')
|
|
})
|
|
|
|
it('confirms and registers job with custom schedule', async () => {
|
|
// Confirm the daily subscription created above
|
|
const confirmed = await db.confirmSubscription(sub.key)
|
|
expect(confirmed).toBeTruthy()
|
|
sub = confirmed!.sub
|
|
|
|
regSub(sub)
|
|
const dailySource = getJobCronSource(sub.id)
|
|
// Expect 0 30 7 * * * (from custom hour=7, minute=30)
|
|
expect(dailySource).toBe('0 30 7 * * *')
|
|
})
|
|
|
|
it('updateSubscription preserves schedule fields through frequency change', async () => {
|
|
const updated = await db.updateSubscription(sub, email, 'weekly', undefined, undefined, 2, undefined)
|
|
expect(updated).toBeTruthy()
|
|
expect(updated!.frequency).toBe('weekly')
|
|
// hour/minute should keep the previously set values (7/30) since we passed undefined
|
|
expect(updated!.hour).toBe(7)
|
|
expect(updated!.minute).toBe(30)
|
|
expect(updated!.day_of_week).toBe(2)
|
|
expect(updated!.timezone).toBe('America/New_York')
|
|
})
|
|
|
|
it('registerSubscription preserves schedule fields', async () => {
|
|
await registerSubscription({ pubkey, email, frequency: 'daily', hour: 10, minute: 15, timezone: 'Europe/London' })
|
|
const reloaded = await db.getSubscriptionByPubkey(pubkey)
|
|
expect(reloaded).toBeTruthy()
|
|
expect(reloaded!.hour).toBe(10)
|
|
expect(reloaded!.minute).toBe(15)
|
|
expect(reloaded!.timezone).toBe('Europe/London')
|
|
})
|
|
})
|
|
|
|
afterAll(async () => {
|
|
const updated = await db.getSubscriptionByPubkey(pubkey)
|
|
if (updated) removeJob(updated)
|
|
}) |