Ctrl K
ComunidadGuías…

__tests__/schedule-due.test.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/*
 * WHEN A WATCHER IS DUE — and, for a daily one, why a single minute was not enough.
 *
 * The daily rule used to be due only ON its minute: hours === hh && minutes === mm. The scheduler
 * ticks once a minute, so that is ONE chance a day, and it is lost whenever another pass holds the
 * browser at that minute (four watchers on this box run every 10 to 20 minutes), whenever the pod
 * rolls through it, or whenever a tick lands a second late. The property then goes unread for the day,
 * silently, while the card shows the previous reading as the newest there is.
 *
 * These tests pin the window that replaced it, and the gap gate that keeps a window from being a loop.
 */
import { describe, it, expect } from 'vitest';
import { createRequire } from 'module';

const require = createRequire(import.meta.url);
const wfs = require('../src/workflows');

const at = (s) => new Date(s);
const HOUR = 3600e3;
const daily = { type: 'schedule', every: 'day', at: '07:20' };

describe('a daily watcher', () => {
  /* Yesterday evening at 20:01, so the 22-hour gap is open by 07:20 the day after tomorrow. */
  const lastNight = at('2026-09-20T20:01:00').getTime();

  it('fires on its minute', () => {
    expect(wfs.scheduleDue(daily, lastNight, at('2026-09-22T07:20:30'))).toBe(true);
  });

  /* THE BUG: at 07:21 the old rule said no, and the next yes was twenty-four hours later. */
  it('still fires a minute late, because the browser was busy on the minute', () => {
    expect(wfs.scheduleDue(daily, lastNight, at('2026-09-22T07:21:00'))).toBe(true);
  });

  it('and hours late, because reading late beats not reading', () => {
    expect(wfs.scheduleDue(daily, lastNight, at('2026-09-22T14:00:00'))).toBe(true);
    expect(wfs.scheduleDue(daily, lastNight, at('2026-09-22T23:59:00'))).toBe(true);
  });

  it('does not fire before its time', () => {
    expect(wfs.scheduleDue(daily, lastNight, at('2026-09-22T07:19:00'))).toBe(false);
    expect(wfs.scheduleDue(daily, lastNight, at('2026-09-22T00:05:00'))).toBe(false);
  });

  /* The gap is what makes the window one pass rather than every tick for the rest of the day. */
  it('fires once, not on every tick after its time', () => {
    const ranToday = at('2026-09-22T07:20:10').getTime();
    expect(wfs.scheduleDue(daily, ranToday, at('2026-09-22T07:21:00'))).toBe(false);
    expect(wfs.scheduleDue(daily, ranToday, at('2026-09-22T18:00:00'))).toBe(false);
    /* And the next day it is due again. */
    expect(wfs.scheduleDue(daily, ranToday, at('2026-09-23T07:20:05'))).toBe(true);
  });

  it('is due as soon as it may be when it has never run', () => {
    expect(wfs.scheduleDue(daily, 0, at('2026-09-22T07:20:00'))).toBe(true);
    expect(wfs.scheduleDue(daily, 0, at('2026-09-22T06:00:00'))).toBe(false);
  });

  it('defaults to 08:00 when no time is set', () => {
    const noTime = { type: 'schedule', every: 'day' };
    expect(wfs.scheduleDue(noTime, 0, at('2026-09-22T07:59:00'))).toBe(false);
    expect(wfs.scheduleDue(noTime, 0, at('2026-09-22T08:00:00'))).toBe(true);
  });
});

describe('the interval watchers, unchanged', () => {
  it('fires once its interval has passed', () => {
    const t = at('2026-09-22T08:00:00');
    const fifteen = { type: 'schedule', every: 'minute', n: 15 };
    expect(wfs.scheduleDue(fifteen, t.getTime() - 14 * 60e3, t)).toBe(false);
    expect(wfs.scheduleDue(fifteen, t.getTime() - 15 * 60e3, t)).toBe(true);
    const hourly = { type: 'schedule', every: 'hour', n: 2 };
    expect(wfs.scheduleDue(hourly, t.getTime() - HOUR, t)).toBe(false);
    expect(wfs.scheduleDue(hourly, t.getTime() - 2 * HOUR, t)).toBe(true);
  });

  it('treats a missing n as one, and an unknown unit as never', () => {
    const t = at('2026-09-22T08:00:00');
    expect(wfs.scheduleDue({ type: 'schedule', every: 'minute' }, t.getTime() - 60e3, t)).toBe(true);
    expect(wfs.scheduleDue({ type: 'schedule', every: 'fortnight' }, 0, t)).toBe(false);
    expect(wfs.scheduleDue(null, 0, t)).toBe(false);
  });
});