Skip to content

Commit

Permalink
MAN-352 add unit tests for activity log middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
neil-mills committed Jan 31, 2025
1 parent cf46d5d commit d33813c
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 13 deletions.
71 changes: 71 additions & 0 deletions server/middleware/filterActivityLog.test.ts
Original file line number Diff line number Diff line change
@@ -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,
})
})
})
12 changes: 1 addition & 11 deletions server/middleware/filterActivityLog.ts
Original file line number Diff line number Diff line change
@@ -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<void> = (req, res, next) => {
if (req?.query?.submit) {
Expand All @@ -35,7 +28,6 @@ export const filterActivityLog: Route<void> = (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
Expand All @@ -56,9 +48,7 @@ export const filterActivityLog: Route<void> = (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]
Expand Down
180 changes: 180 additions & 0 deletions server/middleware/getPersonActivity.test.ts
Original file line number Diff line number Diff line change
@@ -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<HmppsAuthClient>

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)
})
})
4 changes: 2 additions & 2 deletions server/middleware/getPersonActivity.ts
Original file line number Diff line number Diff line change
@@ -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 (
Expand Down

0 comments on commit d33813c

Please sign in to comment.