import { DingTalkService } from '../integration/dingtalk.service'; describe('DingTalkService — attendance records', () => { const originalAppKey = process.env.DINGTALK_APP_KEY; const originalAppSecret = process.env.DINGTALK_APP_SECRET; let service: DingTalkService; beforeEach(() => { process.env.DINGTALK_APP_KEY = 'test-app-key'; process.env.DINGTALK_APP_SECRET = 'test-app-secret'; service = new DingTalkService({} as never, {} as never); Object.assign(service, { accessToken: 'test-token', accessTokenCredentialKey: 'test-app-key:test-app-secret', tokenExpiresAt: Date.now() + 3_600_000, }); }); afterEach(() => { jest.restoreAllMocks(); global.fetch = undefined as unknown as typeof fetch; }); afterAll(() => { if (originalAppKey === undefined) delete process.env.DINGTALK_APP_KEY; else process.env.DINGTALK_APP_KEY = originalAppKey; if (originalAppSecret === undefined) delete process.env.DINGTALK_APP_SECRET; else process.env.DINGTALK_APP_SECRET = originalAppSecret; }); it('sends the required userIds and does not send unsupported offset/limit fields', async () => { global.fetch = jest.fn().mockResolvedValue({ json: jest.fn().mockResolvedValue({ errcode: 0, errmsg: 'ok', recordresult: [] }), }) as jest.MockedFunction; await service.fetchAttendanceResults({ startDate: '2026-07-01', endDate: '2026-07-07', userIds: ['ding-1', 'ding-2'], }); expect(JSON.parse((global.fetch as jest.Mock).mock.calls[0][1].body)).toEqual({ checkDateFrom: '2026-07-01 00:00:00', checkDateTo: '2026-07-07 23:59:59', userIds: ['ding-1', 'ding-2'], }); }); it('rejects missing userIds before calling DingTalk', async () => { await expect( service.fetchAttendanceResults({ startDate: '2026-07-01', endDate: '2026-07-01', }), ).rejects.toThrow('userIds'); expect(global.fetch).toBeUndefined(); }); it('keeps DingTalk work dates in China local time', async () => { global.fetch = jest.fn().mockResolvedValue({ json: jest.fn().mockResolvedValue({ errcode: 0, errmsg: 'ok', recordresult: [ { id: 1, userId: 'ding-1', workDate: Date.parse('2026-07-12T00:00:00+08:00'), userCheckTime: Date.parse('2026-07-12T21:05:00+08:00'), sourceType: 'ATM', checkType: 'OnDuty', deviceName: '东门考勤机', deviceId: 'ATM-01', timeResult: 'Normal', }, ], }), }) as jest.MockedFunction; const [record] = await service.fetchAttendanceResults({ startDate: '2026-07-12', endDate: '2026-07-12', userIds: ['ding-1'], }); expect(record.workDate).toBe('2026-07-12'); expect(record).toEqual( expect.objectContaining({ checkType: 'OnDuty', sourceType: 'ATM', deviceName: '东门考勤机', deviceId: 'ATM-01', }), ); }); });