Files
ApiCore/ApiCore-Backend/src/jobs/daily-evaluation.job.spec.ts
T
Nick SzaunigandClaude Opus 5.5 d99a697739 feat: T4 waves 1-2 - rule configs, schema, suggestions core, season, rule forms
- Rule configs with typed parsers and registry; Berlin day helpers
- Schema: T4 enums, Suggestion table, feed vocabulary (feedStatus as
  ColonyCondition with legacy text mapping), split queen source,
  varroa sample size; migration harness for data migrations
- SuggestionsService: propose/refresh/resolve/obsolete/expire,
  accept/dismiss/reopen incl. bulk, lock order, concurrency e2e
- SeasonService: phenology-based segments, inspection/varroa due dates,
  queen age; TimeEventsStep with JobPartialFailure
- Frontend: per-rule settings forms with visible value sources

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-14 13:42:32 +02:00

65 lines
2.0 KiB
TypeScript

import { Logger } from '@nestjs/common';
import { JobPartialFailure } from '../system/job-run.service';
import { DailyEvaluationJob } from './daily-evaluation.job';
import type { TimeEventsStep } from './steps/time-events.step';
describe('DailyEvaluationJob', () => {
const COUNTS = {
WithdrawalEnded: 1,
TaskDue: 1,
QueenAged: 0,
VarroaMeasurementDue: 0,
InspectionOverdue: 0,
};
let timeEvents: { name: 'time-events'; run: jest.Mock };
let job: DailyEvaluationJob;
beforeEach(() => {
jest.useFakeTimers({ now: new Date('2026-06-10T02:30:00.000Z') });
timeEvents = { name: 'time-events', run: jest.fn() };
timeEvents.run.mockResolvedValue(COUNTS);
job = new DailyEvaluationJob(timeEvents as unknown as TimeEventsStep);
});
afterEach(() => {
jest.useRealTimers();
jest.restoreAllMocks();
});
it('is the daily-evaluation job', () => {
expect(job.name).toBe('daily-evaluation');
});
it('runs the steps for the Berlin day of the run and reports their counters', async () => {
expect(await job.run()).toEqual(COUNTS);
expect(timeEvents.run).toHaveBeenCalledWith('2026-06-10');
});
it('takes the Berlin day, not the UTC day, around midnight', async () => {
jest.setSystemTime(new Date('2026-06-09T22:30:00.000Z'));
await job.run();
expect(timeEvents.run).toHaveBeenCalledWith('2026-06-10');
});
it('a failing step fails the run with the counters of all steps', async () => {
jest.spyOn(Logger.prototype, 'error').mockImplementation(() => undefined);
timeEvents.run.mockRejectedValue(
new JobPartialFailure({ WithdrawalEnded: 1 }, ['TaskDue']),
);
const failure = await job.run().then(
() => null,
(error: unknown) => error,
);
expect(failure).toBeInstanceOf(JobPartialFailure);
expect(failure).toMatchObject({
failedSteps: ['time-events'],
result: { WithdrawalEnded: 1 },
message: 'Daily evaluation failed for: time-events: TaskDue',
});
});
});