forked from wangziqi/gongxue-base
215 lines
6.8 KiB
TypeScript
215 lines
6.8 KiB
TypeScript
import { DingTalkService } from './dingtalk.service';
|
|
|
|
describe('DingTalkService — queryShifts', () => {
|
|
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,
|
|
});
|
|
jest.spyOn(service, 'rateLimit').mockResolvedValue(undefined);
|
|
});
|
|
|
|
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('unwraps the paged result object returned by DingTalk', async () => {
|
|
global.fetch = jest.fn().mockResolvedValue({
|
|
json: jest.fn().mockResolvedValue({
|
|
errcode: 0,
|
|
errmsg: 'ok',
|
|
result: {
|
|
cursor: 678215070,
|
|
has_more: false,
|
|
result: [
|
|
{ id: 677995086, name: 'A' },
|
|
{ id: 678215070, name: 'B' },
|
|
],
|
|
},
|
|
}),
|
|
}) as jest.MockedFunction<typeof fetch>;
|
|
|
|
await expect(service.queryShifts('manager')).resolves.toEqual([
|
|
{ id: 677995086, name: 'A' },
|
|
{ id: 678215070, name: 'B' },
|
|
]);
|
|
});
|
|
|
|
it('requests subsequent pages using the cursor returned by DingTalk', async () => {
|
|
global.fetch = jest
|
|
.fn()
|
|
.mockResolvedValueOnce({
|
|
json: jest.fn().mockResolvedValue({
|
|
errcode: 0,
|
|
errmsg: 'ok',
|
|
result: {
|
|
cursor: 200,
|
|
has_more: true,
|
|
result: [{ id: 100, name: '早班' }],
|
|
},
|
|
}),
|
|
})
|
|
.mockResolvedValueOnce({
|
|
json: jest.fn().mockResolvedValue({
|
|
errcode: 0,
|
|
errmsg: 'ok',
|
|
result: {
|
|
cursor: 300,
|
|
has_more: false,
|
|
result: [{ id: 200, name: '晚班' }],
|
|
},
|
|
}),
|
|
}) as jest.MockedFunction<typeof fetch>;
|
|
|
|
await expect(service.queryShifts('manager')).resolves.toEqual([
|
|
{ id: 100, name: '早班' },
|
|
{ id: 200, name: '晚班' },
|
|
]);
|
|
|
|
expect(global.fetch).toHaveBeenCalledTimes(2);
|
|
expect(JSON.parse((global.fetch as jest.Mock).mock.calls[0][1].body)).toEqual({
|
|
op_user_id: 'manager',
|
|
cursor: 0,
|
|
});
|
|
expect(JSON.parse((global.fetch as jest.Mock).mock.calls[1][1].body)).toEqual({
|
|
op_user_id: 'manager',
|
|
cursor: 200,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('DingTalkService — attendance machine only group', () => {
|
|
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,
|
|
});
|
|
jest.spyOn(service, 'rateLimit').mockResolvedValue(undefined);
|
|
});
|
|
|
|
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('accepts the success envelope returned when updating an attendance group', async () => {
|
|
global.fetch = jest.fn().mockResolvedValue({
|
|
json: jest.fn().mockResolvedValue({
|
|
success: true,
|
|
result: { id: 123, name: '排课_冲刺班' },
|
|
request_id: 'request-1',
|
|
}),
|
|
}) as jest.MockedFunction<typeof fetch>;
|
|
|
|
await expect(
|
|
service.updateAttendanceGroup({
|
|
id: 123,
|
|
name: '排课_冲刺班',
|
|
type: 'TURN',
|
|
owner: 'manager',
|
|
members: [{ role: 'Attendance', type: 'StaffMember', user_id: 'student-1' }],
|
|
shift_ids: [456],
|
|
}),
|
|
).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('disables mobile-oriented punching when creating a machine-only group', async () => {
|
|
global.fetch = jest.fn().mockResolvedValue({
|
|
json: jest.fn().mockResolvedValue({
|
|
errcode: 0,
|
|
errmsg: 'ok',
|
|
result: { id: 123 },
|
|
}),
|
|
}) as jest.MockedFunction<typeof fetch>;
|
|
|
|
await service.createAttendanceGroup({
|
|
name: '排课_冲刺班',
|
|
type: 'TURN',
|
|
owner: 'manager',
|
|
members: [{ role: 'Attendance', type: 'StaffMember', user_id: 'student-1' }],
|
|
shift_ids: [456],
|
|
attendance_machine_only: true,
|
|
});
|
|
|
|
const body = JSON.parse((global.fetch as jest.Mock).mock.calls[0][1].body);
|
|
expect(body.top_group).toEqual(expect.objectContaining({
|
|
enable_emp_select_class: false,
|
|
disable_check_without_schedule: true,
|
|
enable_outside_check: false,
|
|
enable_position_ble: false,
|
|
positions: [],
|
|
wifis: [],
|
|
}));
|
|
});
|
|
});
|
|
|
|
describe('DingTalkService — department user pagination boundaries', () => {
|
|
afterEach(() => {
|
|
jest.restoreAllMocks();
|
|
global.fetch = undefined as unknown as typeof fetch;
|
|
});
|
|
|
|
it('stops when DingTalk says there is another page but omits the next cursor', async () => {
|
|
const service = new DingTalkService({} as never, {} as never);
|
|
global.fetch = jest.fn().mockResolvedValue({
|
|
json: jest.fn().mockResolvedValue({
|
|
errcode: 0,
|
|
errmsg: 'ok',
|
|
result: {
|
|
list: [{ userid: 'u1', name: 'Alice', mobile: '', dept_id_list: [1] }],
|
|
has_more: true,
|
|
},
|
|
}),
|
|
}) as jest.MockedFunction<typeof fetch>;
|
|
|
|
await expect((service as any).getDeptUsers('token', 1)).resolves.toHaveLength(1);
|
|
expect(global.fetch).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('stops when the next cursor repeats the current cursor', async () => {
|
|
const service = new DingTalkService({} as never, {} as never);
|
|
global.fetch = jest.fn().mockResolvedValue({
|
|
json: jest.fn().mockResolvedValue({
|
|
errcode: 0,
|
|
errmsg: 'ok',
|
|
result: { list: [], has_more: true, next_cursor: 0 },
|
|
}),
|
|
}) as jest.MockedFunction<typeof fetch>;
|
|
|
|
await expect((service as any).getDeptUsers('token', 1)).resolves.toEqual([]);
|
|
expect(global.fetch).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|