-
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.
Merge pull request #236 from ministryofjustice/EMP-434-fe-crm-4-repor…
…ting-ui-validation EMP-434: CRM 4 Reporting UI validation
- Loading branch information
Showing
23 changed files
with
617 additions
and
207 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export type ReportError = { | ||
status: number | ||
message: string | ||
} | ||
|
||
export type CrmReportResponse = { | ||
text: string | ||
error?: ReportError | ||
} |
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 |
---|---|---|
@@ -1,63 +1,144 @@ | ||
import { createMock, DeepMocked } from '@golevelup/ts-jest' | ||
import type { NextFunction, Request, Response } from 'express' | ||
import { CrmReportResponse } from '@eqApi' | ||
import CrmReportApiService from '../services/crmReportApiService' | ||
import { CrmReportResponse } from '@crmReport' | ||
import GenerateReportService from '../services/generateReportService' | ||
import GenerateReportController from './generateReportController' | ||
|
||
jest.mock('../services/crmReportApiService') | ||
jest.mock('../services/generateReportService') | ||
jest.mock('../utils/userProfileGroups', () => { | ||
return jest.fn().mockReturnValue('1,4,5,6') | ||
}) | ||
|
||
describe('downloadEvidenceController', () => { | ||
let mockCrmReportApiService: jest.Mocked<CrmReportApiService> | ||
describe('generateReportController', () => { | ||
let mockGenerateReportService: jest.Mocked<GenerateReportService> | ||
let request: DeepMocked<Request> | ||
let response: DeepMocked<Response> | ||
const next: DeepMocked<NextFunction> = createMock<NextFunction>({}) | ||
|
||
beforeEach(() => { | ||
request = createMock<Request>({}) | ||
response = createMock<Response>({}) | ||
mockCrmReportApiService = new CrmReportApiService(null) as jest.Mocked<CrmReportApiService> | ||
mockGenerateReportService = new GenerateReportService(null) as jest.Mocked<GenerateReportService> | ||
}) | ||
|
||
it('should render generate report page', async () => { | ||
const generateReportController = new GenerateReportController(mockCrmReportApiService) | ||
const generateReportController = new GenerateReportController(mockGenerateReportService) | ||
const requestHandler = generateReportController.show() | ||
|
||
await requestHandler(request, response, next) | ||
|
||
expect(response.render).toHaveBeenCalledWith('pages/generateReport') | ||
expect(response.render).toHaveBeenCalledWith('pages/generateReport', { backUrl: '/' }) | ||
}) | ||
|
||
it('should download the requested CRM file', async () => { | ||
mockCrmReportApiService.getCrmReport.mockResolvedValue(successResponse()) | ||
it('should download the requested CRM report', async () => { | ||
const crmReportResponse = getCrmReportResponse() | ||
|
||
const downloadData = | ||
' `Client UFN,Usn,Provider Account,Firm Name,Client Name,Rep Order Number,Maat ID,Prison Law,Date Received,Decision Date,Decision,Expenditure Type,Expert Name,Quantity,Rate,Unit,Total Cost,Additional Expenditure,Total Authority,Total Granted,Granting Caseworker\n' + | ||
' 031022/777,5001613,0D182J,ABELS,Joe modo,78543657,,No,2023-03-16,2023-03-16,Grant,a Psychiatrist,tyjtjtjt,4.0,50.0,Hour(s),200.0,0.0,200.0,200.0,Sym-G`' | ||
mockGenerateReportService.getCrmReport.mockResolvedValue(crmReportResponse) | ||
|
||
const generateReportController = new GenerateReportController(mockCrmReportApiService) | ||
const generateReportController = new GenerateReportController(mockGenerateReportService) | ||
const requestHandler = generateReportController.submit() | ||
request.body = { | ||
crmType: 'crm4', | ||
startDate: '2023-03-01', | ||
endDate: '2023-03-30', | ||
profileAcceptedTypes: '1,4,5,6', | ||
} | ||
|
||
await requestHandler(request, response, next) | ||
|
||
expect(response.setHeader).toHaveBeenCalledWith('Content-Disposition', 'attachment; filename=crm4Report.csv') | ||
expect(response.send).toHaveBeenCalledWith(downloadData) | ||
expect(response.send).toHaveBeenCalledWith(crmReportResponse.text) | ||
|
||
expect(mockCrmReportApiService.getCrmReport).toHaveBeenCalledWith('2023-03-01', '2023-03-30', '1,4,5,6') | ||
expect(mockGenerateReportService.getCrmReport).toHaveBeenCalledWith('2023-03-01', '2023-03-30', '1,4,5,6') | ||
}) | ||
|
||
it('should render generate report page with field errors', async () => { | ||
const generateReportController = new GenerateReportController(mockGenerateReportService) | ||
const requestHandler = generateReportController.submit() | ||
request.body = { | ||
crmType: '', | ||
startDate: '2023-03-01', | ||
endDate: '2023-03-30', | ||
} | ||
|
||
await requestHandler(request, response, next) | ||
|
||
expect(response.render).toHaveBeenCalledWith('pages/generateReport', { | ||
results: [], | ||
errors: { | ||
list: [ | ||
{ | ||
href: '#crmType', | ||
text: 'CRM type must be selected', | ||
}, | ||
], | ||
messages: { | ||
crmType: { | ||
text: 'CRM type must be selected', | ||
}, | ||
}, | ||
}, | ||
backUrl: '/', | ||
formValues: { | ||
crmType: '', | ||
startDate: '2023-03-01', | ||
endDate: '2023-03-30', | ||
}, | ||
}) | ||
}) | ||
|
||
it.each([ | ||
['Not authorised to generate report', 401], | ||
['Not authorised to generate report', 403], | ||
['No report data found', 404], | ||
['Something went wrong with generate report', 500], | ||
])('should render generate page with "%s" error for status %s', async (errorMessage, errorStatus) => { | ||
const crmReportResponse: CrmReportResponse = { | ||
text: null, | ||
error: { | ||
status: errorStatus, | ||
message: 'error', | ||
}, | ||
} | ||
|
||
mockGenerateReportService.getCrmReport.mockResolvedValue(crmReportResponse) | ||
|
||
const generateReportController = new GenerateReportController(mockGenerateReportService) | ||
const requestHandler = generateReportController.submit() | ||
request.body = { | ||
crmType: 'crm4', | ||
startDate: '2023-03-01', | ||
endDate: '2023-03-30', | ||
} | ||
|
||
await requestHandler(request, response, next) | ||
|
||
expect(response.render).toHaveBeenCalledWith('pages/generateReport', { | ||
results: [], | ||
errors: { | ||
list: [ | ||
{ | ||
href: '#', | ||
text: errorMessage, | ||
}, | ||
], | ||
}, | ||
backUrl: '/', | ||
formValues: { | ||
crmType: 'crm4', | ||
startDate: '2023-03-01', | ||
endDate: '2023-03-30', | ||
}, | ||
}) | ||
}) | ||
}) | ||
|
||
const successResponse = (): CrmReportResponse => { | ||
const getCrmReportResponse = (): CrmReportResponse => { | ||
return { | ||
text: | ||
' `Client UFN,Usn,Provider Account,Firm Name,Client Name,Rep Order Number,Maat ID,Prison Law,Date Received,Decision Date,Decision,Expenditure Type,Expert Name,Quantity,Rate,Unit,Total Cost,Additional Expenditure,Total Authority,Total Granted,Granting Caseworker\n' + | ||
' 031022/777,5001613,0D182J,ABELS,Joe modo,78543657,,No,2023-03-16,2023-03-16,Grant,a Psychiatrist,tyjtjtjt,4.0,50.0,Hour(s),200.0,0.0,200.0,200.0,Sym-G`', | ||
'Client UFN,Usn,Provider Account,Firm Name,Client Name,Rep Order Number,Maat ID,Prison Law,Date Received,' + | ||
'Decision Date,Decision,Expenditure Type,Expert Name,Quantity,Rate,Unit,Total Cost,Additional Expenditure,' + | ||
'Total Authority,Total Granted,Granting Caseworker\n' + | ||
'031022/777,123456789,1234AB,Some Firm,Some Client,999999999,,No,2023-03-16,2023-03-16,Grant,a Psychiatrist,' + | ||
'tyjtjtjt,4.0,50.0,Hour(s),200.0,0.0,200.0,200.0,Sym-G`', | ||
} | ||
} |
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 |
---|---|---|
@@ -1,25 +1,69 @@ | ||
import type { Request, RequestHandler, Response } from 'express' | ||
import getProfileAcceptedTypes from '../utils/userProfileGroups' | ||
import CrmReportApiService from '../services/crmReportApiService' | ||
import GenerateReportService from '../services/generateReportService' | ||
import validateReportParams from '../utils/generateReportValidation' | ||
import manageBackLink from '../utils/crmBackLink' | ||
import { buildErrors } from '../utils/errorDisplayHelper' | ||
|
||
const CURRENT_URL = '/generate-report' | ||
const VIEW_PATH = 'pages/generateReport' | ||
|
||
export default class GenerateReportController { | ||
constructor(private readonly crmReportApiService: CrmReportApiService) {} | ||
constructor(private readonly generateReportService: GenerateReportService) {} | ||
|
||
show(): RequestHandler { | ||
return async (req: Request, res: Response): Promise<void> => { | ||
res.render('pages/generateReport') | ||
const backUrl = manageBackLink(req, CURRENT_URL) | ||
res.render(VIEW_PATH, { backUrl }) | ||
} | ||
} | ||
|
||
submit(): RequestHandler { | ||
return async (req: Request, res: Response): Promise<void> => { | ||
const response = await this.crmReportApiService.getCrmReport( | ||
req.body.startDate, | ||
req.body.endDate, | ||
getProfileAcceptedTypes(res), | ||
) | ||
res.setHeader('Content-Disposition', `attachment; filename=crm4Report.csv`) | ||
res.send(response.text) | ||
const reportParams: Record<string, string> = { | ||
crmType: req.body.crmType as string, | ||
startDate: req.body.startDate as string, | ||
endDate: req.body.endDate as string, | ||
} | ||
const validationErrors = validateReportParams(reportParams) | ||
if (validationErrors) { | ||
res.render(VIEW_PATH, { | ||
results: [], | ||
errors: validationErrors, | ||
formValues: reportParams, | ||
backUrl: manageBackLink(req, CURRENT_URL), | ||
}) | ||
} else { | ||
const reportResponse = await this.generateReportService.getCrmReport( | ||
req.body.startDate, | ||
req.body.endDate, | ||
getProfileAcceptedTypes(res), | ||
) | ||
if (reportResponse.error) { | ||
const errors = buildErrors(reportResponse.error, this.getErrorMessage) | ||
res.render(VIEW_PATH, { | ||
results: [], | ||
errors, | ||
formValues: reportParams, | ||
backUrl: manageBackLink(req, CURRENT_URL), | ||
}) | ||
} else { | ||
res.setHeader('Content-Disposition', 'attachment; filename=crm4Report.csv') | ||
res.send(reportResponse.text) | ||
} | ||
} | ||
} | ||
} | ||
|
||
private getErrorMessage(errorStatus: number): string { | ||
switch (errorStatus) { | ||
case 401: | ||
case 403: | ||
return 'Not authorised to generate report' | ||
case 404: | ||
return 'No report data found' | ||
default: | ||
return 'Something went wrong with generate report' | ||
} | ||
} | ||
} |
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
Oops, something went wrong.