import { runInNewContext } from 'node:vm'; import { BACKUP_SCHEDULE_TIME_ZONE, isBackupDue } from './backup-due'; describe('isBackupDue', () => { it('reads the schedule in Europe/Berlin by default', () => { expect(BACKUP_SCHEDULE_TIME_ZONE).toBe('Europe/Berlin'); }); it('is due when there is no backup yet', () => { expect( isBackupDue('0 3 * * *', null, new Date('2026-10-13T00:30:00Z')), ).toBe(true); }); it('is not due again on the same day for "0 3 * * *"', () => expect( isBackupDue( '0 3 * * *', new Date('2026-10-12T01:00:00Z'), new Date('2026-10-13T00:30:00Z'), ), ).toBe(false)); it('is due after the next 03:00 Europe/Berlin', () => expect( isBackupDue( '0 3 * * *', new Date('2026-10-12T01:00:00Z'), new Date('2026-10-13T01:05:00Z'), ), ).toBe(true)); it('is due exactly at the next scheduled time', () => expect( isBackupDue( '0 3 * * *', new Date('2026-10-12T01:00:00Z'), new Date('2026-10-13T01:00:00Z'), ), ).toBe(true)); it('counts a backup written after the scheduled time (e.g. "Jetzt sichern") as covering it', () => expect( isBackupDue( '0 3 * * *', new Date('2026-10-13T01:10:00Z'), new Date('2026-10-13T02:00:00Z'), ), ).toBe(false)); it('stays due after a missed run until a backup exists', () => expect( isBackupDue( '0 3 * * *', new Date('2026-10-10T01:00:00Z'), new Date('2026-10-13T05:00:00Z'), ), ).toBe(true)); it('uses the given time zone', () => { const lastBackupAt = new Date('2026-10-12T03:00:00Z'); const now = new Date('2026-10-13T02:00:00Z'); // Next 03:00 UTC is 03:00Z, next 03:00 Berlin was 01:00Z. expect(isBackupDue('0 3 * * *', lastBackupAt, now, 'UTC')).toBe(false); expect(isBackupDue('0 3 * * *', lastBackupAt, now)).toBe(true); }); // fs.Stats.mtime is created by Node's core; under Jest it is not an // instance of the test's Date (cron checks `instanceof Date`). it('accepts a Date from another realm', () => { const foreign = runInNewContext('new Date("2026-10-12T01:00:00Z")') as Date; expect( isBackupDue('0 3 * * *', foreign, new Date('2026-10-13T00:30:00Z')), ).toBe(false); }); it('rejects an invalid schedule even without a backup', () => { expect(() => isBackupDue('every night', null, new Date())).toThrow(); }); });