generated from ministryofjustice/hmpps-template-typescript
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1d0b938
commit b199698
Showing
8 changed files
with
188 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { type DeepMocked, createMock } from '@golevelup/ts-jest' | ||
import type { NextFunction, Request, Response } from 'express' | ||
|
||
import type { StatisticsService } from '../services' | ||
import ReportsController from './reportsController' | ||
import { reportContentFactory } from '../testutils/factories' | ||
import { StatisticsReportUtils } from '../utils' | ||
|
||
jest.mock('../utils/statisticsReportUtils') | ||
|
||
const mockStatisticsReportUtils = StatisticsReportUtils as jest.Mocked<typeof StatisticsReportUtils> | ||
|
||
describe('ReportsController', () => { | ||
const username = 'USERNAME' | ||
const mockTodaysDate = new Date('2024-02-14') | ||
|
||
let request: DeepMocked<Request> | ||
let response: DeepMocked<Response> | ||
const next: DeepMocked<NextFunction> = createMock<NextFunction>({}) | ||
|
||
const statisticsService = createMock<StatisticsService>({}) | ||
|
||
const reportDataBlock = { | ||
date: 'January 2024', | ||
testId: 'referral-count', | ||
title: 'Total referrals submitted', | ||
value: '123', | ||
} | ||
|
||
let controller: ReportsController | ||
|
||
beforeEach(() => { | ||
mockStatisticsReportUtils.reportContentDataBlock.mockReturnValue(reportDataBlock) | ||
|
||
controller = new ReportsController(statisticsService) | ||
|
||
request = createMock<Request>({ | ||
user: { username }, | ||
}) | ||
response = createMock<Response>() | ||
|
||
jest.useFakeTimers().setSystemTime(mockTodaysDate) | ||
}) | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks() | ||
jest.useRealTimers() | ||
}) | ||
|
||
describe('show', () => { | ||
it('should render the reports/show view with the correct data', async () => { | ||
statisticsService.getReport.mockResolvedValue(reportContentFactory.build()) | ||
|
||
const requestHandler = controller.show() | ||
await requestHandler(request, response, next) | ||
|
||
const expectedQuery = { | ||
endDate: '2024-01-31', | ||
startDate: '2024-01-01', | ||
} | ||
|
||
const reportTypes = [ | ||
'REFERRAL_COUNT', | ||
'PROGRAMME_COMPLETE_COUNT', | ||
'NOT_ELIGIBLE_COUNT', | ||
'WITHDRAWN_COUNT', | ||
'DESELECTED_COUNT', | ||
] | ||
|
||
expect(statisticsService.getReport).toHaveBeenCalledTimes(reportTypes.length) | ||
reportTypes.forEach(reportType => { | ||
expect(statisticsService.getReport).toHaveBeenCalledWith(username, reportType, expectedQuery) | ||
}) | ||
|
||
expect(StatisticsReportUtils.reportContentDataBlock).toHaveBeenCalledTimes(reportTypes.length) | ||
expect(StatisticsReportUtils.reportContentDataBlock).toHaveBeenCalledWith( | ||
expect.anything(), | ||
new Date(expectedQuery.startDate), | ||
) | ||
|
||
expect(response.render).toHaveBeenCalledWith('reports/show', { | ||
pageHeading: 'Accredited Programmes data', | ||
reportDataBlocks: [reportDataBlock, reportDataBlock, reportDataBlock, reportDataBlock, reportDataBlock], | ||
}) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import type { Request, Response, TypedRequestHandler } from 'express' | ||
|
||
import type { StatisticsService } from '../services' | ||
import { DateUtils, StatisticsReportUtils, TypeUtils } from '../utils' | ||
|
||
export default class ReportsController { | ||
constructor(private readonly statisticsService: StatisticsService) {} | ||
|
||
show(): TypedRequestHandler<Request, Response> { | ||
return async (req: Request, res: Response) => { | ||
TypeUtils.assertHasUser(req) | ||
|
||
const now = new Date() | ||
const startDateOfLastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1) | ||
const endDateOfLastMonth = new Date(now.getFullYear(), now.getMonth(), 0) | ||
|
||
const reportTypes = [ | ||
'REFERRAL_COUNT', | ||
'PROGRAMME_COMPLETE_COUNT', | ||
'NOT_ELIGIBLE_COUNT', | ||
'WITHDRAWN_COUNT', | ||
'DESELECTED_COUNT', | ||
] | ||
|
||
const reports = await Promise.all( | ||
reportTypes.map(reportType => | ||
this.statisticsService.getReport(req.user.username, reportType, { | ||
endDate: DateUtils.isoDateOnly(endDateOfLastMonth), | ||
startDate: DateUtils.isoDateOnly(startDateOfLastMonth), | ||
}), | ||
), | ||
) | ||
|
||
res.render('reports/show', { | ||
pageHeading: 'Accredited Programmes data', | ||
reportDataBlocks: reports.map(report => | ||
StatisticsReportUtils.reportContentDataBlock(report, startDateOfLastMonth), | ||
), | ||
}) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { path } from 'static-path' | ||
|
||
const reportsPathBase = path('/reports') | ||
|
||
export default { | ||
show: reportsPathBase, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import type { Router } from 'express' | ||
|
||
import type { Controllers } from '../controllers' | ||
import { reportsPaths } from '../paths' | ||
import { RouteUtils } from '../utils' | ||
|
||
export default function routes(controllers: Controllers, router: Router): Router { | ||
const { get } = RouteUtils.actions(router) | ||
const { reportsController } = controllers | ||
|
||
get(reportsPaths.show.pattern, reportsController.show()) | ||
|
||
return router | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{% from "govuk/components/back-link/macro.njk" import govukBackLink %} | ||
{% from "./_reportDataBlock.njk" import reportDataBlock %} | ||
|
||
{% extends "../partials/layout.njk" %} | ||
|
||
{% block backLink %} | ||
{{ govukBackLink({ | ||
text: "Back", | ||
href: "/" | ||
}) }} | ||
{% endblock backLink %} | ||
|
||
{% block content %} | ||
<h1 class="govuk-heading-l">{{ pageHeading }}</h1> | ||
|
||
<div class="govuk-grid-row"> | ||
<div class="govuk-grid-column-two-thirds"> | ||
{% if reportDataBlocks | length %} | ||
{% for items in reportDataBlocks | slice(2) %} | ||
<div class="govuk-grid-row govuk-!-margin-bottom-6"> | ||
{% for item in items %} | ||
<div class="govuk-grid-column-one-third"> | ||
{{ reportDataBlock(item) }} | ||
</div> | ||
{% endfor %} | ||
</div> | ||
{% endfor %} | ||
{% endif %} | ||
</div> | ||
</div> | ||
{% endblock content %} |