diff --git a/server/middleware/filterActivityLog.test.ts b/server/middleware/filterActivityLog.test.ts new file mode 100644 index 00000000..ca286446 --- /dev/null +++ b/server/middleware/filterActivityLog.test.ts @@ -0,0 +1,71 @@ +import { Request } from 'express' +import { filterActivityLog } from './filterActivityLog' +import { AppResponse } from '../@types' + +describe('/middleware/filterActivityLog', () => { + const nextSpy = jest.fn() + const crn = 'X756510' + const res = { + locals: {}, + redirect: jest.fn().mockReturnThis(), + } as unknown as AppResponse + + const req = { + body: {}, + params: {}, + query: {}, + session: { + cache: { + activityLog: { + results: null, + filters: null, + }, + }, + }, + method: 'GET', + } as Request + + it(`should redirect the page if 'submit' is in the request query`, () => { + req.url = `case/${crn}/activity-log?keywords=&dateFrom=&dateTo=&submit=true&page=2` + req.params.crn = crn + req.query = { keywords: '', dateFrom: '', dateTo: '', submit: 'true' } + req.session.cache.activityLog.filters = { + keywords: 'some keywords', + dateFrom: '21/1/2025', + dateTo: '31/1/2025', + compliance: ['Option 1', 'Option 2', 'Option 3'], + } + const redirectSpy = jest.spyOn(res, 'redirect') + filterActivityLog(req, res, nextSpy) + expect(redirectSpy).toHaveBeenCalledWith(`case/${crn}/activity-log?keywords=&dateFrom=&dateTo=`) + }) + + it(`should hydrate the selected filter values from cache, if the cache exists, no values exist in the query and form has not been submitted`, () => { + req.url = `case/${crn}/activity-log?keywords=&dateFrom=&dateTo=&page=2` + req.query = { keywords: '', dateFrom: '', dateTo: '' } + req.session.cache.activityLog.filters = { + keywords: 'some keywords', + dateFrom: '12/1/2025', + dateTo: '27/1/2025', + compliance: ['no outcome', 'complied'], + } + filterActivityLog(req, res, nextSpy) + expect(res.locals.filters.query).toEqual({ + ...req.session.cache.activityLog.filters, + }) + }) + + it('should hydrate the selected filter values from the request query if form has been submitted but query exists', () => { + req.url = `case/${crn}/activity-log?keywords=some+keyword&dateFrom=12/1/2025&dateTo=27/1/2025&compliance=no+outcome&compliance=complied&page=2` + req.query = { + keywords: 'some keyword', + dateFrom: '12/1/2025', + dateTo: '27/1/2025', + compliance: ['no outcome', 'complied'], + } + filterActivityLog(req, res, nextSpy) + expect(res.locals.filters.query).toEqual({ + ...req.query, + }) + }) +}) diff --git a/server/middleware/filterActivityLog.ts b/server/middleware/filterActivityLog.ts index 7eeee4fc..05454a3d 100644 --- a/server/middleware/filterActivityLog.ts +++ b/server/middleware/filterActivityLog.ts @@ -1,14 +1,7 @@ /* eslint-disable no-param-reassign */ import { DateTime } from 'luxon' -import { - Route, - ActivityLogCacheItem, - ActivityLogFilters, - ActivityLogFiltersResponse, - SelectedFilterItem, - Option, -} from '../@types' +import { Route, ActivityLogFilters, ActivityLogFiltersResponse, SelectedFilterItem, Option } from '../@types' export const filterActivityLog: Route = (req, res, next) => { if (req?.query?.submit) { @@ -35,7 +28,6 @@ export const filterActivityLog: Route = (req, res, next) => { let query: ActivityLogFilters = { keywords, dateFrom, dateTo, compliance } const hasQuery = keywords || (dateFrom && dateTo) || compliance?.length - // if not submitted and no query values exist, then attempt to hydrate from cache if (req?.session?.cache?.activityLog?.filters && !req?.query?.submit && !hasQuery) { query = req?.session?.cache?.activityLog?.filters @@ -56,9 +48,7 @@ export const filterActivityLog: Route = (req, res, next) => { } query = { ...query, clearFilterKey, clearFilterValue } - console.log(query) const errors = req?.session?.errors - const baseUrl = `/case/${crn}/activity-log` if (!Array.isArray(query.compliance)) { query.compliance = [query.compliance] diff --git a/server/middleware/getPersonActivity.test.ts b/server/middleware/getPersonActivity.test.ts new file mode 100644 index 00000000..e95a246b --- /dev/null +++ b/server/middleware/getPersonActivity.test.ts @@ -0,0 +1,180 @@ +import { Request } from 'express' +import { getPersonActivity } from './getPersonActivity' +import { AppResponse } from '../@types' +import HmppsAuthClient from '../data/hmppsAuthClient' + +const crn = 'X756510' +const mockPersonActivityResponse = { + size: 10, + page: 1, + totalResults: 20, + totalPages: 2, + personSummary: { + crn, + name: { + forename: 'Eula', + surname: 'Schmeler', + }, + dateOfBirth: '', + }, + activities: [ + { + id: '11', + type: 'Phone call', + startDateTime: '2044-12-22T09:15:00.382936Z[Europe/London]', + endDateTime: '2044-12-22T09:30:00.382936Z[Europe/London]', + rarToolKit: 'Choices and Changes', + rarCategory: 'Stepping Stones', + isSensitive: false, + hasOutcome: false, + wasAbsent: true, + notes: '', + + isCommunication: true, + isPhoneCallFromPop: true, + officerName: { + forename: 'Terry', + surname: 'Jones', + }, + lastUpdated: '2023-03-20', + lastUpdatedBy: { + forename: 'Paul', + surname: 'Smith', + }, + }, + ], +} +const mockTierCalculationResponse = { + tierScore: '1', + calculationId: '1', + calculationDate: '', + data: { + protect: { + tier: '', + points: 1, + pointsBreakdown: { + NEEDS: 1, + NO_MANDATE_FOR_CHANGE: 1, + NO_VALID_ASSESSMENT: 1, + OGRS: 1, + IOM: 1, + RSR: 1, + ROSH: 1, + MAPPA: 1, + COMPLEXITY: 1, + ADDITIONAL_FACTORS_FOR_WOMEN: 1, + }, + }, + change: { + tier: '', + points: 1, + pointsBreakdown: { + NEEDS: 1, + NO_MANDATE_FOR_CHANGE: 1, + NO_VALID_ASSESSMENT: 1, + OGRS: 1, + IOM: 1, + RSR: 1, + ROSH: 1, + MAPPA: 1, + COMPLEXITY: 1, + ADDITIONAL_FACTORS_FOR_WOMEN: 1, + }, + }, + calculationVersion: '', + }, +} + +jest.mock('../data/hmppsAuthClient', () => { + return jest.fn().mockImplementation(() => { + return { + getSystemClientToken: jest.fn().mockImplementation(() => Promise.resolve('token-1')), + } + }) +}) +jest.mock('../data/masApiClient', () => { + return jest.fn().mockImplementation(() => { + return { + postPersonActivityLog: jest.fn().mockImplementation(() => Promise.resolve(mockPersonActivityResponse)), + } + }) +}) + +jest.mock('../data/tierApiClient', () => { + return jest.fn().mockImplementation(() => { + return { + getCalculationDetails: jest.fn().mockImplementation(() => Promise.resolve(mockTierCalculationResponse)), + } + }) +}) + +const hmppsAuthClient = new HmppsAuthClient(null) as jest.Mocked + +describe('/middleware/getPersonActivity', () => { + const req = { + body: {}, + params: {}, + query: {}, + session: { + cache: { + activityLog: { + results: null, + filters: null, + }, + }, + }, + method: 'GET', + } as Request + + const res = { + locals: { + filters: {}, + user: { + username: 'user-1', + }, + }, + redirect: jest.fn().mockReturnThis(), + } as unknown as AppResponse + + const filterVals = { + keywords: 'Some keywords', + dateFrom: '14/1/2025', + dateTo: '21/1/2025', + compliance: ['complied', 'not complied'], + } + + it('should request the filtered results from the api, if matching cache does not exist', async () => { + req.query = { page: '0' } + res.locals.filters = { + ...filterVals, + complianceOptions: [], + errors: null, + selectedFilterItems: [], + baseUrl: '', + query: { ...filterVals }, + queryStr: '', + queryStrPrefix: '', + queryStrSuffix: '', + maxDate: '21/1/2025', + } + + const [_tierCalculation, personActivity] = await getPersonActivity(req, res, hmppsAuthClient) + expect(personActivity).toEqual(mockPersonActivityResponse) + }) + it('should return the cached person activity data if matching cache exists', async () => { + req.session.cache = { + activityLog: { + results: [ + { + crn, + personActivity: mockPersonActivityResponse, + tierCalculation: mockTierCalculationResponse, + ...filterVals, + }, + ], + }, + } + const [_tierCalculation, personActivity] = await getPersonActivity(req, res, hmppsAuthClient) + expect(personActivity).toEqual(req.session.cache.activityLog.results[0].personActivity) + }) +}) diff --git a/server/middleware/getPersonActivity.ts b/server/middleware/getPersonActivity.ts index 9dad445e..4735ad59 100644 --- a/server/middleware/getPersonActivity.ts +++ b/server/middleware/getPersonActivity.ts @@ -1,9 +1,9 @@ import { Request } from 'express' import { HmppsAuthClient } from '../data' -import MasApiClient from '../data/masApiClient' -import { ActivityLogCache, ActivityLogCacheItem, ActivityLogRequestBody, AppResponse } from '../@types' +import { ActivityLogCacheItem, ActivityLogRequestBody, AppResponse } from '../@types' import { PersonActivity } from '../data/model/activityLog' import { toISODate, toCamelCase } from '../utils/utils' +import MasApiClient from '../data/masApiClient' import TierApiClient, { TierCalculation } from '../data/tierApiClient' export const getPersonActivity = async (