'use strict'; jest.mock('../../models/tiers/payments.mdl', () => ({ findAll: jest.fn() })); jest.mock('../../models/courses/course_purchases.mdl', () => ({ findAll: jest.fn() })); const mdl_Payments = require('../../models/tiers/payments.mdl'); const mdl_CoursePurchase = require('../../models/courses/course_purchases.mdl'); const job = require('../../cron/jobs/fail_stale_payments.cron'); beforeEach(() => jest.clearAllMocks()); test('marks stale pending payments and purchases as failed', async () => { const payment = { provider_payload: { order_id: 'O-1' }, update: jest.fn().mockResolvedValue(true) }; const purchase = { provider_payload: { order_id: 'O-2' }, update: jest.fn().mockResolvedValue(true) }; mdl_Payments.findAll.mockResolvedValue([payment]); mdl_CoursePurchase.findAll.mockResolvedValue([purchase]); await job.run(); expect(payment.update).toHaveBeenCalledWith( expect.objectContaining({ status: 'failed', provider_payload: expect.objectContaining({ failed_reason: 'abandoned_checkout' }), }) ); expect(purchase.update).toHaveBeenCalledWith( expect.objectContaining({ status: 'failed', provider_payload: expect.objectContaining({ failed_reason: 'abandoned_checkout' }), }) ); }); test('does nothing when there are no stale rows', async () => { mdl_Payments.findAll.mockResolvedValue([]); mdl_CoursePurchase.findAll.mockResolvedValue([]); await expect(job.run()).resolves.not.toThrow(); });