120 lines
3.8 KiB
TypeScript
120 lines
3.8 KiB
TypeScript
import { afterEach, describe, mock, test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { Op } from 'sequelize';
|
|
|
|
import db from '@/db/models';
|
|
import StaffAttendanceService from '@/services/staff_attendance';
|
|
import { FEATURE_PERMISSIONS } from '@/shared/constants/product-permissions';
|
|
import { ROLE_NAMES, ROLE_SCOPES } from '@/shared/constants/roles';
|
|
import { createTestUser } from '@/test-utils';
|
|
|
|
function permission(name: string) {
|
|
return { name };
|
|
}
|
|
|
|
function isRecord(value: unknown): value is Record<PropertyKey, unknown> {
|
|
return typeof value === 'object' && value !== null;
|
|
}
|
|
|
|
afterEach(() => {
|
|
mock.restoreAll();
|
|
});
|
|
|
|
describe('StaffAttendanceService', () => {
|
|
test('includes school-owned users and school campuses in school report scope', async () => {
|
|
const schoolUser = createTestUser({
|
|
organizationId: '11111111-1111-4111-8111-111111111111',
|
|
organizations: { id: '11111111-1111-4111-8111-111111111111' },
|
|
schoolId: '22222222-2222-4222-8222-222222222222',
|
|
campusId: null,
|
|
app_role: {
|
|
name: ROLE_NAMES.REGISTRAR,
|
|
scope: ROLE_SCOPES.SCHOOL,
|
|
globalAccess: false,
|
|
permissions: [permission(FEATURE_PERMISSIONS.READ_STAFF_ATTENDANCE_REPORTS)],
|
|
},
|
|
});
|
|
let capturedWhere: unknown = null;
|
|
|
|
mock.method(db.staff_attendance_records, 'findAndCountAll', async (options: unknown) => {
|
|
if (isRecord(options)) {
|
|
capturedWhere = options.where;
|
|
}
|
|
return { rows: [], count: 0 };
|
|
});
|
|
|
|
await StaffAttendanceService.listRecords({}, schoolUser);
|
|
|
|
assert.equal(isRecord(capturedWhere), true);
|
|
if (!isRecord(capturedWhere)) {
|
|
return;
|
|
}
|
|
assert.equal(Object.getOwnPropertySymbols(capturedWhere).includes(Op.or), true);
|
|
});
|
|
|
|
test('upserts a school office staff attendance record inside school scope', async () => {
|
|
const organizationId = '11111111-1111-4111-8111-111111111111';
|
|
const schoolId = '22222222-2222-4222-8222-222222222222';
|
|
const actor = createTestUser({
|
|
id: '44444444-4444-4444-8444-444444444444',
|
|
organizationId,
|
|
organizations: { id: organizationId },
|
|
schoolId,
|
|
campusId: null,
|
|
app_role: {
|
|
name: ROLE_NAMES.PRINCIPAL,
|
|
scope: ROLE_SCOPES.SCHOOL,
|
|
globalAccess: false,
|
|
permissions: [permission(FEATURE_PERMISSIONS.FILL_ATTENDANCE)],
|
|
},
|
|
});
|
|
let userWhere: unknown = null;
|
|
|
|
mock.method(db.users, 'findOne', async (options: unknown) => {
|
|
if (isRecord(options)) {
|
|
userWhere = options.where;
|
|
}
|
|
return {
|
|
get: () => ({
|
|
id: '55555555-5555-4555-8555-555555555555',
|
|
firstName: 'Nicole',
|
|
lastName: 'Adams',
|
|
email: 'registrar@flatlogic.com',
|
|
campusId: null,
|
|
app_role: { name: ROLE_NAMES.REGISTRAR },
|
|
}),
|
|
};
|
|
});
|
|
mock.method(db.sequelize, 'transaction', async () => ({
|
|
commit: async () => undefined,
|
|
rollback: async () => undefined,
|
|
}));
|
|
mock.method(db.staff_attendance_records, 'findOne', async () => null);
|
|
mock.method(db.staff_attendance_records, 'create', async (payload: unknown) => ({
|
|
get: () => ({
|
|
id: '66666666-6666-4666-8666-666666666666',
|
|
...(isRecord(payload) ? payload : {}),
|
|
createdAt: new Date('2026-06-17T12:00:00Z'),
|
|
updatedAt: new Date('2026-06-17T12:00:00Z'),
|
|
}),
|
|
}));
|
|
|
|
await StaffAttendanceService.upsertRecord(
|
|
{
|
|
userId: '55555555-5555-4555-8555-555555555555',
|
|
date: '2026-06-17',
|
|
status: 'present',
|
|
note: '',
|
|
},
|
|
actor,
|
|
);
|
|
|
|
assert.equal(isRecord(userWhere), true);
|
|
if (!isRecord(userWhere)) {
|
|
return;
|
|
}
|
|
assert.equal(userWhere.schoolId, schoolId);
|
|
assert.equal(userWhere.campusId, null);
|
|
});
|
|
});
|