import * as assert from 'node:assert'; import fs from 'node:fs'; import { lotNameSortNameFunction } from '../data/config.cemetery.ssm.js'; import * as cacheFunctions from '../helpers/functions.cache.js'; import * as iconFunctions from '../helpers/functions.icons.js'; import * as sqlFilterFunctions from '../helpers/functions.sqlFilters.js'; import * as userFunctions from '../helpers/functions.user.js'; import * as polyfills from '../helpers/polyfills.js'; describe('config.cemetery.ssm', () => { it('Sorts burial site names', () => { const grave2 = 'XX-B1-G2A'; const grave10 = 'XX-B1-G10'; assert.ok(lotNameSortNameFunction(grave2) < lotNameSortNameFunction(grave10)); }); }); describe('functions.cache', () => { const badId = -3; const badName = 'qwertyuiopasdfghjklzxcvbnm'; describe('Lot Occupant Types', () => { it('returns Lot Occupant Types', async () => { cacheFunctions.clearCacheByTableName('LotOccupantTypes'); const lotOccupantTypes = await cacheFunctions.getLotOccupantTypes(); assert.ok(lotOccupantTypes.length > 0); for (const lotOccupantType of lotOccupantTypes) { const byId = await cacheFunctions.getLotOccupantTypeById(lotOccupantType.lotOccupantTypeId); assert.strictEqual(lotOccupantType.lotOccupantTypeId, byId?.lotOccupantTypeId); const byName = await cacheFunctions.getLotOccupantTypeByLotOccupantType(lotOccupantType.lotOccupantType); assert.strictEqual(lotOccupantType.lotOccupantType, byName?.lotOccupantType); } }); it('returns undefined with a bad lotOccupantTypeId', async () => { const byBadId = await cacheFunctions.getLotOccupantTypeById(badId); assert.ok(byBadId === undefined); }); it('returns undefined with a bad lotOccupantType', async () => { const byBadName = await cacheFunctions.getLotOccupantTypeByLotOccupantType(badName); assert.ok(byBadName === undefined); }); }); describe('Lot Statuses', () => { it('returns Lot Statuses', async () => { cacheFunctions.clearCacheByTableName('LotStatuses'); const lotStatuses = await cacheFunctions.getLotStatuses(); assert.ok(lotStatuses.length > 0); for (const lotStatus of lotStatuses) { const byId = await cacheFunctions.getLotStatusById(lotStatus.lotStatusId); assert.strictEqual(lotStatus.lotStatusId, byId?.lotStatusId); const byName = await cacheFunctions.getLotStatusByLotStatus(lotStatus.lotStatus); assert.strictEqual(lotStatus.lotStatus, byName?.lotStatus); } }); it('returns undefined with a bad lotStatusId', async () => { const byBadId = await cacheFunctions.getLotStatusById(badId); assert.ok(byBadId === undefined); }); it('returns undefined with a bad lotStatus', async () => { const byBadName = await cacheFunctions.getLotStatusByLotStatus(badName); assert.ok(byBadName === undefined); }); }); describe('Lot Types', () => { it('returns Lot Types', async () => { cacheFunctions.clearCacheByTableName('LotTypes'); const lotTypes = await cacheFunctions.getLotTypes(); assert.ok(lotTypes.length > 0); for (const lotType of lotTypes) { const byId = await cacheFunctions.getLotTypeById(lotType.lotTypeId); assert.strictEqual(lotType.lotTypeId, byId?.lotTypeId); const byName = await cacheFunctions.getLotTypesByLotType(lotType.lotType); assert.strictEqual(lotType.lotType, byName?.lotType); } }); it('returns undefined with a bad lotTypeId', async () => { const byBadId = await cacheFunctions.getLotTypeById(badId); assert.ok(byBadId === undefined); }); it('returns undefined with a bad lotType', async () => { const byBadName = await cacheFunctions.getLotTypesByLotType(badName); assert.ok(byBadName === undefined); }); }); describe('Occupancy Types', () => { it('returns Occupancy Types', async () => { cacheFunctions.clearCacheByTableName('OccupancyTypes'); const occupancyTypes = await cacheFunctions.getOccupancyTypes(); assert.ok(occupancyTypes.length > 0); for (const occupancyType of occupancyTypes) { const byId = await cacheFunctions.getOccupancyTypeById(occupancyType.occupancyTypeId); assert.strictEqual(occupancyType.occupancyTypeId, byId?.occupancyTypeId); const byName = await cacheFunctions.getOccupancyTypeByOccupancyType(occupancyType.occupancyType); assert.strictEqual(occupancyType.occupancyType, byName?.occupancyType); } }); it('returns undefined with a bad occupancyTypeId', async () => { const byBadId = await cacheFunctions.getOccupancyTypeById(badId); assert.ok(byBadId === undefined); }); it('returns undefined with a bad occupancyType', async () => { const byBadName = await cacheFunctions.getOccupancyTypeByOccupancyType(badName); assert.ok(byBadName === undefined); }); }); describe('Work Order Types', () => { it('returns Work Order Types', async () => { cacheFunctions.clearCacheByTableName('WorkOrderTypes'); const workOrderTypes = await cacheFunctions.getWorkOrderTypes(); assert.ok(workOrderTypes.length > 0); for (const workOrderType of workOrderTypes) { const byId = await cacheFunctions.getWorkOrderTypeById(workOrderType.workOrderTypeId); assert.strictEqual(workOrderType.workOrderTypeId, byId?.workOrderTypeId); } }); it('returns undefined with a bad workOrderTypeId', async () => { const byBadId = await cacheFunctions.getWorkOrderTypeById(badId); assert.ok(byBadId === undefined); }); }); describe('Work Order Milestone Types', () => { it('returns Work Order Milestone Types', async () => { cacheFunctions.clearCacheByTableName('WorkOrderMilestoneTypes'); const workOrderMilestoneTypes = await cacheFunctions.getWorkOrderMilestoneTypes(); assert.ok(workOrderMilestoneTypes.length > 0); for (const workOrderMilestoneType of workOrderMilestoneTypes) { const byId = await cacheFunctions.getWorkOrderMilestoneTypeById(workOrderMilestoneType.workOrderMilestoneTypeId); assert.strictEqual(workOrderMilestoneType.workOrderMilestoneTypeId, byId?.workOrderMilestoneTypeId); const byName = await cacheFunctions.getWorkOrderMilestoneTypeByWorkOrderMilestoneType(workOrderMilestoneType.workOrderMilestoneType); assert.strictEqual(workOrderMilestoneType.workOrderMilestoneType, byName?.workOrderMilestoneType); } }); it('returns undefined with a bad workOrderMilestoneTypeId', async () => { const byBadId = await cacheFunctions.getWorkOrderMilestoneTypeById(badId); assert.ok(byBadId === undefined); }); it('returns undefined with a bad workOrderMilestoneType', async () => { const byBadName = await cacheFunctions.getWorkOrderMilestoneTypeByWorkOrderMilestoneType(badName); assert.ok(byBadName === undefined); }); }); }); describe('functions.icons', () => { it('returns a list of icon classes', async () => { const iconClasses = await iconFunctions.getSolidIconClasses(); assert.ok(iconClasses.includes('save')); }); }); describe('functions.sqlFilters', () => { describe('LotName filter', () => { it('returns startsWith filter', () => { const filter = sqlFilterFunctions.getLotNameWhereClause('TEST1 TEST2', 'startsWith', 'l'); assert.strictEqual(filter.sqlWhereClause, " and l.lotName like ? || '%'"); assert.strictEqual(filter.sqlParameters.length, 1); assert.ok(filter.sqlParameters.includes('TEST1 TEST2')); }); it('returns endsWith filter', () => { const filter = sqlFilterFunctions.getLotNameWhereClause('TEST1 TEST2', 'endsWith', 'l'); assert.strictEqual(filter.sqlWhereClause, " and l.lotName like '%' || ?"); assert.strictEqual(filter.sqlParameters.length, 1); assert.strictEqual(filter.sqlParameters[0], 'TEST1 TEST2'); }); it('returns contains filter', () => { const filter = sqlFilterFunctions.getLotNameWhereClause('TEST1 TEST2', '', 'l'); assert.strictEqual(filter.sqlWhereClause, ' and instr(lower(l.lotName), ?) and instr(lower(l.lotName), ?)'); assert.ok(filter.sqlParameters.includes('test1')); assert.ok(filter.sqlParameters.includes('test2')); }); it('handles empty filter', () => { const filter = sqlFilterFunctions.getLotNameWhereClause('', ''); assert.strictEqual(filter.sqlWhereClause, ''); assert.strictEqual(filter.sqlParameters.length, 0); }); it('handles undefined filter', () => { const filter = sqlFilterFunctions.getLotNameWhereClause(undefined, undefined, 'l'); assert.strictEqual(filter.sqlWhereClause, ''); assert.strictEqual(filter.sqlParameters.length, 0); }); }); describe('OccupancyTime filter', () => { it('creates three different filters', () => { const currentFilter = sqlFilterFunctions.getOccupancyTimeWhereClause('current'); assert.notStrictEqual(currentFilter.sqlWhereClause, ''); const pastFilter = sqlFilterFunctions.getOccupancyTimeWhereClause('past'); assert.notStrictEqual(pastFilter.sqlWhereClause, ''); const futureFilter = sqlFilterFunctions.getOccupancyTimeWhereClause('future'); assert.notStrictEqual(futureFilter, ''); assert.notStrictEqual(currentFilter.sqlWhereClause, pastFilter.sqlWhereClause); assert.notStrictEqual(currentFilter.sqlWhereClause, futureFilter.sqlWhereClause); assert.notStrictEqual(pastFilter.sqlWhereClause, futureFilter.sqlWhereClause); }); it('handles empty filter', () => { const filter = sqlFilterFunctions.getOccupancyTimeWhereClause(''); assert.strictEqual(filter.sqlWhereClause, ''); assert.strictEqual(filter.sqlParameters.length, 0); }); it('handles undefined filter', () => { const filter = sqlFilterFunctions.getOccupancyTimeWhereClause(undefined, 'o'); assert.strictEqual(filter.sqlWhereClause, ''); assert.strictEqual(filter.sqlParameters.length, 0); }); }); describe('OccupantName filter', () => { it('returns filter', () => { const filter = sqlFilterFunctions.getOccupantNameWhereClause('TEST1 TEST2', 'o'); assert.strictEqual(filter.sqlWhereClause, ' and (instr(lower(o.occupantName), ?) or instr(lower(o.occupantFamilyName), ?)) and (instr(lower(o.occupantName), ?) or instr(lower(o.occupantFamilyName), ?))'); assert.ok(filter.sqlParameters.length === 4); assert.ok(filter.sqlParameters.includes('test1')); assert.ok(filter.sqlParameters.includes('test2')); }); it('handles empty filter', () => { const filter = sqlFilterFunctions.getOccupantNameWhereClause(''); assert.strictEqual(filter.sqlWhereClause, ''); assert.strictEqual(filter.sqlParameters.length, 0); }); it('handles undefined filter', () => { const filter = sqlFilterFunctions.getOccupantNameWhereClause(undefined, 'o'); assert.strictEqual(filter.sqlWhereClause, ''); assert.strictEqual(filter.sqlParameters.length, 0); }); }); }); describe('functions.user', () => { describe('unauthenticated, no user in session', () => { const noUserRequest = { session: {} }; it('can not update', () => { assert.strictEqual(userFunctions.userCanUpdate(noUserRequest), false); }); it('is not admin', () => { assert.strictEqual(userFunctions.userIsAdmin(noUserRequest), false); }); }); describe('read only user, no update, no admin', () => { const readOnlyRequest = { session: { user: { userName: '*test', userProperties: { canUpdate: false, isAdmin: false, apiKey: '' } } } }; it('can not update', () => { assert.strictEqual(userFunctions.userCanUpdate(readOnlyRequest), false); }); it('is not admin', () => { assert.strictEqual(userFunctions.userIsAdmin(readOnlyRequest), false); }); }); describe('update only user, no admin', () => { const updateOnlyRequest = { session: { user: { userName: '*test', userProperties: { canUpdate: true, isAdmin: false, apiKey: '' } } } }; it('can update', () => { assert.strictEqual(userFunctions.userCanUpdate(updateOnlyRequest), true); }); it('is not admin', () => { assert.strictEqual(userFunctions.userIsAdmin(updateOnlyRequest), false); }); }); describe('admin only user, no update', () => { const adminOnlyRequest = { session: { user: { userName: '*test', userProperties: { canUpdate: false, isAdmin: true, apiKey: '' } } } }; it('can not update', () => { assert.strictEqual(userFunctions.userCanUpdate(adminOnlyRequest), false); }); it('is admin', () => { assert.strictEqual(userFunctions.userIsAdmin(adminOnlyRequest), true); }); }); describe('update admin user', () => { const updateAdminRequest = { session: { user: { userName: '*test', userProperties: { canUpdate: true, isAdmin: true, apiKey: '' } } } }; it('can update', () => { assert.strictEqual(userFunctions.userCanUpdate(updateAdminRequest), true); }); it('is admin', () => { assert.strictEqual(userFunctions.userIsAdmin(updateAdminRequest), true); }); }); describe('API key check', () => { it('authenticates with a valid API key', async () => { const apiKeysJSON = JSON.parse(fs.readFileSync('data/apiKeys.json', 'utf8')); const apiKey = Object.values(apiKeysJSON)[0]; const apiRequest = { params: { apiKey } }; assert.strictEqual(await userFunctions.apiKeyIsValid(apiRequest), true); }); it('fails to authenticate with an invalid API key', async () => { const apiRequest = { params: { apiKey: 'badKey' } }; assert.strictEqual(await userFunctions.apiKeyIsValid(apiRequest), false); }); it('fails to authenticate with no API key', async () => { const apiRequest = { params: {} }; assert.strictEqual(await userFunctions.apiKeyIsValid(apiRequest), false); }); }); }); describe('polyfills', () => { it('applys Object.hasOwn polyfill', () => { delete Object.hasOwn; assert.ok(Object.hasOwn === undefined); polyfills.applyPolyfills(); assert.ok(Object.hasOwn !== undefined); const testObject = { foo: 'bar' }; assert.ok(Object.hasOwn(testObject, 'foo')); }); });