From b5a5d9f4ad59645be4967c09b0b6b136a84cd51a Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Fri, 23 Aug 2024 16:27:35 +0100 Subject: [PATCH 01/53] Add reveal to care cert question --- .../care-certificate.component.html | 15 ++++++++++++ .../care-certificate.component.spec.ts | 24 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/features/workers/care-certificate/care-certificate.component.html b/frontend/src/app/features/workers/care-certificate/care-certificate.component.html index ca29a30213..c7fb88b26b 100644 --- a/frontend/src/app/features/workers/care-certificate/care-certificate.component.html +++ b/frontend/src/app/features/workers/care-certificate/care-certificate.component.html @@ -11,6 +11,21 @@

Have they completed, started or partially completed their Care Certificate?

+
+ The Care Certificate is not the same thing as the Level 2 Adult Social Care Certificate, introduced in 2024. +
+
+ + What’s the Care Certificate? + +
+

+ The Care Certificate is an agreed set of standards that define the knowledge, skills and behaviours + expected of specific job roles in the health and social care sectors. It’s made up of the 15 standards + that should be covered as part of a robust induction programme. +

+
+
{ +fdescribe('CareCertificateComponent', () => { async function setup(insideFlow = true) { const { fixture, getByText, getAllByText, getByLabelText, getByTestId, queryByTestId } = await render( CareCertificateComponent, @@ -78,6 +78,28 @@ describe('CareCertificateComponent', () => { expect(getByLabelText('No')).toBeTruthy(); }); + it('should render a inset text to explain Care Certificate is not the same as L2 CC certificate', async () => { + const { getByText } = await setup(); + + const explanationText = getByText( + 'The Care Certificate is not the same thing as the Level 2 Adult Social Care Certificate, introduced in 2024.', + ); + + expect(explanationText).toBeTruthy(); + }); + + it('should render a reveal text about what is the Care Certification', async () => { + const { getByText } = await setup(); + + const reveal = getByText('What’s the Care Certificate?'); + const revealText = getByText( + 'The Care Certificate is an agreed set of standards that define the knowledge, skills and behaviours expected of specific job roles in the health and social care sectors. It’s made up of the 15 standards that should be covered as part of a robust induction programme.', + ); + + expect(reveal).toBeTruthy(); + expect(revealText).toBeTruthy(); + }); + describe('submit buttons', () => { it(`should show 'Save and continue' cta button, skip this question and 'View this staff record' link, if a return url is not provided`, async () => { const { getByText } = await setup(); From 47c29a147523d1cb86980df395e8a697faa4745f Mon Sep 17 00:00:00 2001 From: Sabrina Date: Fri, 23 Aug 2024 16:37:37 +0100 Subject: [PATCH 02/53] Create initial page for level 2 adult social care certificate --- ...ult-social-care-certificate.component.html | 58 ++++++++ ...-social-care-certificate.component.spec.ts | 128 ++++++++++++++++++ ...adult-social-care-certificate.component.ts | 38 ++++++ .../workers/workers-routing.module.ts | 15 +- .../app/features/workers/workers.module.ts | 2 + 5 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html create mode 100644 frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts create mode 100644 frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html new file mode 100644 index 0000000000..0780a4ac72 --- /dev/null +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html @@ -0,0 +1,58 @@ +
+
+
+
+
+ +

+ {{ section }} + Have they completed or started their Level 2 Adult Social Care Certificate? +

+
+ +
+ The Level 2 Adult Social Care Certificate qualification, introduced in 2024, is not the same thing as the + existing standards based Care Certificate. +
+ + +

+ The Level 2 Adult Social Care Certificate is a qualification based on the existing Care Certificate + standards. It was introduced into the adult social care sector in 2024 as a new qualification for care + workers to work towards. +

+
+
+
+ + +
+
+
+
+
+
+
+ +
+
+
+ + +
diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts new file mode 100644 index 0000000000..978b99721a --- /dev/null +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts @@ -0,0 +1,128 @@ +import { getTestBed } from '@angular/core/testing'; +import { render } from '@testing-library/angular'; +import { Level2AdultSocialCareCertificateComponent } from './level-2-adult-social-care-certificate.component'; +import { SharedModule } from '@shared/shared.module'; +import { ActivatedRoute, RouterModule } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; +import { WorkerService } from '@core/services/worker.service'; +import { MockWorkerServiceWithUpdateWorker } from '@core/test-utils/MockWorkerService'; + +fdescribe('Level2AdultSocialCareCertificateComponent', () => { + async function setup(insideFlow = true) { + const { fixture, getByText, getAllByText, getByLabelText, getByTestId, queryByTestId } = await render( + Level2AdultSocialCareCertificateComponent, + { + imports: [SharedModule, RouterModule, RouterTestingModule, HttpClientTestingModule, ReactiveFormsModule], + providers: [ + UntypedFormBuilder, + { + provide: ActivatedRoute, + useValue: { + parent: { + snapshot: { + url: [{ path: insideFlow ? 'staff-uid' : 'staff-record-summary' }], + data: { + establishment: { uid: 'mocked-uid' }, + primaryWorkplace: {}, + }, + }, + }, + snapshot: { + params: {}, + }, + }, + }, + { + provide: WorkerService, + useClass: MockWorkerServiceWithUpdateWorker, + }, + ], + declarations: [], + }, + ); + const injector = getTestBed(); + + const component = fixture.componentInstance; + + return { + component, + fixture, + getByText, + getAllByText, + getByLabelText, + getByTestId, + queryByTestId, + }; + } + + it('should render the Level2AdultSocialCareCertificateComponent', async () => { + const { component } = await setup(); + expect(component).toBeTruthy(); + }); + + it('should show the caption', async () => { + const { getByTestId } = await setup(); + + const sectionHeading = getByTestId('section-heading'); + const captionText = 'Training and qualifications'; + + expect(sectionHeading.textContent).toEqual(captionText); + }); + + it('should show the heading', async () => { + const { getByText } = await setup(); + + const headingText = getByText('Have they completed or started their Level 2 Adult Social Care Certificate?'); + + expect(headingText).toBeTruthy(); + }); + + it('should show the reveal', async () => { + const { getByTestId } = await setup(); + + const reveal = getByTestId('reveal-whatIsLevel2CC'); + + expect(reveal).toBeTruthy(); + }); + + it('should show the radio buttons', async () => { + const { getByLabelText } = await setup(); + + expect(getByLabelText('Yes, completed')).toBeTruthy(); + expect(getByLabelText('Yes, started')).toBeTruthy(); + expect(getByLabelText('No')).toBeTruthy(); + }); + + describe('submit buttons', () => { + it(`should show 'Save and continue' cta button, skip this question and 'View this staff record' link, if a return url is not provided`, async () => { + const { getByText } = await setup(); + + expect(getByText('Save and continue')).toBeTruthy(); + expect(getByText('Skip this question')).toBeTruthy(); + expect(getByText('View this staff record')).toBeTruthy(); + }); + + it(`should show 'Save and return' cta button and 'Cancel' link if a return url is provided`, async () => { + const { getByText } = await setup(false); + + expect(getByText('Save and return')).toBeTruthy(); + expect(getByText('Cancel')).toBeTruthy(); + }); + }); + + describe('progress bar', () => { + it('should render the workplace progress bar', async () => { + const { getByTestId } = await setup(); + + expect(getByTestId('progress-bar')).toBeTruthy(); + }); + + it('should not render the progress bars when accessed from outside the flow', async () => { + const { queryByTestId } = await setup(false); + + expect(queryByTestId('progress-bar')).toBeFalsy(); + }); + }); +}); diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts new file mode 100644 index 0000000000..1c6d4824da --- /dev/null +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts @@ -0,0 +1,38 @@ +import { Component } from '@angular/core'; +import { QuestionComponent } from '../question/question.component'; +import { UntypedFormBuilder } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { BackLinkService } from '@core/services/backLink.service'; +import { ErrorSummaryService } from '@core/services/error-summary.service'; +import { WorkerService } from '@core/services/worker.service'; +import { EstablishmentService } from '@core/services/establishment.service'; + +@Component({ + selector: 'app-level-2-adult-social-care-certificate', + templateUrl: './level-2-adult-social-care-certificate.component.html', +}) +export class Level2AdultSocialCareCertificateComponent extends QuestionComponent { + public answersAvailable = [ + { value: 'Yes, completed', tag: 'Yes, completed' }, + { value: 'Yes, in progress or partially completed', tag: 'Yes, started' }, + { value: 'No', tag: 'No' }, + ]; + + public section = 'Training and qualifications'; + + constructor( + protected formBuilder: UntypedFormBuilder, + protected router: Router, + protected route: ActivatedRoute, + protected backLinkService: BackLinkService, + protected errorSummaryService: ErrorSummaryService, + protected workerService: WorkerService, + protected establishmentService: EstablishmentService, + ) { + super(formBuilder, router, route, backLinkService, errorSummaryService, workerService, establishmentService); + + this.form = this.formBuilder.group({ + level2AdultSocialCareCertificate: null, + }); + } +} diff --git a/frontend/src/app/features/workers/workers-routing.module.ts b/frontend/src/app/features/workers/workers-routing.module.ts index deaf3ac145..aeba06e791 100644 --- a/frontend/src/app/features/workers/workers-routing.module.ts +++ b/frontend/src/app/features/workers/workers-routing.module.ts @@ -52,6 +52,7 @@ import { TotalStaffChangeComponent } from './total-staff-change/total-staff-chan import { WeeklyContractedHoursComponent } from './weekly-contracted-hours/weekly-contracted-hours.component'; import { YearArrivedUkComponent } from './year-arrived-uk/year-arrived-uk.component'; import { EmployedFromOutsideUkComponent } from './employed-from-outside-uk/employed-from-outside-uk.component'; +import { Level2AdultSocialCareCertificateComponent } from './level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component'; const routes: Routes = [ { @@ -202,7 +203,7 @@ const routes: Routes = [ { path: 'inside-or-outside-of-uk', component: EmployedFromOutsideUkComponent, - data: { title: 'Inside or Outside UK'} + data: { title: 'Inside or Outside UK' }, }, { path: 'adult-social-care-started', @@ -239,6 +240,11 @@ const routes: Routes = [ component: CareCertificateComponent, data: { title: 'Care Certificate' }, }, + { + path: 'level-2-adult-social-care-certificate', + component: Level2AdultSocialCareCertificateComponent, + data: { title: 'Level 2 Adult Social Care Certificate' }, + }, { path: 'apprenticeship-training', component: ApprenticeshipTrainingComponent, @@ -446,7 +452,7 @@ const routes: Routes = [ { path: 'inside-or-outside-of-uk', component: EmployedFromOutsideUkComponent, - data: { title: 'Inside or Outside UK'} + data: { title: 'Inside or Outside UK' }, }, { path: 'adult-social-care-started', @@ -483,6 +489,11 @@ const routes: Routes = [ component: CareCertificateComponent, data: { title: 'Care Certificate' }, }, + { + path: 'level-2-adult-social-care-certificate', + component: Level2AdultSocialCareCertificateComponent, + data: { title: 'Level 2 Adult Social Care Certificate' }, + }, { path: 'apprenticeship-training', component: ApprenticeshipTrainingComponent, diff --git a/frontend/src/app/features/workers/workers.module.ts b/frontend/src/app/features/workers/workers.module.ts index 68fa810554..dc3b0275ca 100644 --- a/frontend/src/app/features/workers/workers.module.ts +++ b/frontend/src/app/features/workers/workers.module.ts @@ -65,6 +65,7 @@ import { WeeklyContractedHoursComponent } from './weekly-contracted-hours/weekly import { WorkersRoutingModule } from './workers-routing.module'; import { YearArrivedUkComponent } from './year-arrived-uk/year-arrived-uk.component'; import { EmployedFromOutsideUkComponent } from './employed-from-outside-uk/employed-from-outside-uk.component'; +import { Level2AdultSocialCareCertificateComponent } from './level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component'; @NgModule({ imports: [CommonModule, OverlayModule, FormsModule, ReactiveFormsModule, SharedModule, WorkersRoutingModule], @@ -119,6 +120,7 @@ import { EmployedFromOutsideUkComponent } from './employed-from-outside-uk/emplo DownloadPdfTrainingAndQualificationComponent, HealthAndCareVisaComponent, EmployedFromOutsideUkComponent, + Level2AdultSocialCareCertificateComponent, ], providers: [ DialogService, From 989c3738a3f7471559ae04ada7477d39240b516d Mon Sep 17 00:00:00 2001 From: Sabrina Date: Fri, 23 Aug 2024 17:53:02 +0100 Subject: [PATCH 03/53] Change next route path for care certificate page --- .../care-certificate.component.spec.ts | 10 +++++----- .../care-certificate/care-certificate.component.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts b/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts index 05a88f9d4a..0de465904c 100644 --- a/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts +++ b/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts @@ -109,8 +109,8 @@ describe('CareCertificateComponent', () => { }); }); - describe('navigation', () => { - it('should navigate to apprenticeship-training page when submitting from flow', async () => { + fdescribe('navigation', () => { + it('should navigate to level-2-adult-social-care-certificate page when submitting from flow', async () => { const { component, routerSpy, getByText } = await setup(); const workerId = component.worker.uid; @@ -126,11 +126,11 @@ describe('CareCertificateComponent', () => { workplaceId, 'staff-record', workerId, - 'apprenticeship-training', + 'level-2-adult-social-care-certificate', ]); }); - it('should navigate to apprenticeship-training page when skipping the question in the flow', async () => { + it('should navigate to level-2-adult-social-care-certificate page when skipping the question in the flow', async () => { const { component, routerSpy, getByText } = await setup(); const workerId = component.worker.uid; @@ -144,7 +144,7 @@ describe('CareCertificateComponent', () => { workplaceId, 'staff-record', workerId, - 'apprenticeship-training', + 'level-2-adult-social-care-certificate', ]); }); diff --git a/frontend/src/app/features/workers/care-certificate/care-certificate.component.ts b/frontend/src/app/features/workers/care-certificate/care-certificate.component.ts index 19ad711575..75cbf43bf4 100644 --- a/frontend/src/app/features/workers/care-certificate/care-certificate.component.ts +++ b/frontend/src/app/features/workers/care-certificate/care-certificate.component.ts @@ -37,7 +37,7 @@ export class CareCertificateComponent extends QuestionComponent { } init() { - this.next = this.getRoutePath('apprenticeship-training'); + this.next = this.getRoutePath('level-2-adult-social-care-certificate'); if (this.worker.careCertificate) { this.prefill(); } From 6eae33e3c79cd07b7b003c11ee31fb92d68f2348 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Fri, 23 Aug 2024 17:54:50 +0100 Subject: [PATCH 04/53] Add conditional input for year achieved --- ...ult-social-care-certificate.component.html | 59 +++++- ...-social-care-certificate.component.spec.ts | 189 +++++++++++++++++- ...adult-social-care-certificate.component.ts | 5 + 3 files changed, 243 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html index 0780a4ac72..01a8531cdf 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html @@ -25,18 +25,65 @@

workers to work towards.

-
-
+
+
-
+ +
+
+ + +
+
+
+ + +
+
+ +
diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts index 978b99721a..24c5b0e6fd 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts @@ -1,17 +1,18 @@ import { getTestBed } from '@angular/core/testing'; -import { render } from '@testing-library/angular'; -import { Level2AdultSocialCareCertificateComponent } from './level-2-adult-social-care-certificate.component'; +import { fireEvent, render } from '@testing-library/angular'; import { SharedModule } from '@shared/shared.module'; -import { ActivatedRoute, RouterModule } from '@angular/router'; +import { ActivatedRoute, Router, RouterModule } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; import { WorkerService } from '@core/services/worker.service'; import { MockWorkerServiceWithUpdateWorker } from '@core/test-utils/MockWorkerService'; +import { Level2AdultSocialCareCertificateComponent } from './level-2-adult-social-care-certificate.component'; + fdescribe('Level2AdultSocialCareCertificateComponent', () => { async function setup(insideFlow = true) { - const { fixture, getByText, getAllByText, getByLabelText, getByTestId, queryByTestId } = await render( + const { fixture, getByText, getAllByText, getByLabelText, getByTestId, queryByTestId, queryByText } = await render( Level2AdultSocialCareCertificateComponent, { imports: [SharedModule, RouterModule, RouterTestingModule, HttpClientTestingModule, ReactiveFormsModule], @@ -46,6 +47,10 @@ fdescribe('Level2AdultSocialCareCertificateComponent', () => { const component = fixture.componentInstance; + const router = injector.inject(Router) as Router; + + const routerSpy = spyOn(router, 'navigate').and.returnValue(Promise.resolve(true)); + return { component, fixture, @@ -54,6 +59,9 @@ fdescribe('Level2AdultSocialCareCertificateComponent', () => { getByLabelText, getByTestId, queryByTestId, + queryByText, + router, + routerSpy, }; } @@ -125,4 +133,177 @@ fdescribe('Level2AdultSocialCareCertificateComponent', () => { expect(queryByTestId('progress-bar')).toBeFalsy(); }); }); + + describe('year achieved input', () => { + describe('should not show', () => { + it('when the page is loaded', async () => { + const { fixture } = await setup(); + + const yearAchievedInput = fixture.nativeElement.querySelector('div[id="certification-achieved"]'); + + expect(yearAchievedInput.getAttribute('class')).toContain('hidden'); + }); + + it('when "Yes, started" is clicked', async () => { + const { fixture, getByLabelText } = await setup(); + + const yesStartedRadioButton = getByLabelText('Yes, started'); + + fireEvent.click(yesStartedRadioButton); + fixture.detectChanges(); + + const yearAchievedInput = fixture.nativeElement.querySelector('div[id="certification-achieved"]'); + + expect(yearAchievedInput.getAttribute('class')).toContain('hidden'); + }); + + it('when "no" is clicked', async () => { + const { fixture, getByLabelText } = await setup(); + + const noRadioButton = getByLabelText('No'); + + fireEvent.click(noRadioButton); + fixture.detectChanges(); + + const yearAchievedInput = fixture.nativeElement.querySelector('div[id="certification-achieved"]'); + + expect(yearAchievedInput.getAttribute('class')).toContain('hidden'); + }); + }); + + it('should show when "yes, completed" is clicked', async () => { + const { fixture, getByLabelText } = await setup(); + + const yesCompletedRadioButton = getByLabelText('Yes, completed'); + + fireEvent.click(yesCompletedRadioButton); + fixture.detectChanges(); + + const yearAchievedInput = fixture.nativeElement.querySelector('div[id="certification-achieved"]'); + + expect(yearAchievedInput.getAttribute('class')).not.toContain('hidden'); + }); + }); + + describe('navigation', () => { + // it('should navigate to apprenticeship-training page when submitting from flow', async () => { + // const { component, routerSpy, getByText } = await setup(); + + // const workerId = component.worker.uid; + // const workplaceId = component.workplace.uid; + + // const saveButton = getByText('Save and continue'); + // fireEvent.click(saveButton); + + // expect(getByText('Save and continue')).toBeTruthy(); + + // expect(routerSpy).toHaveBeenCalledWith([ + // '/workplace', + // workplaceId, + // 'staff-record', + // workerId, + // 'apprenticeship-training', + // ]); + // }); + + // it('should navigate to apprenticeship-training page when skipping the question in the flow', async () => { + // const { component, routerSpy, getByText } = await setup(); + + // const workerId = component.worker.uid; + // const workplaceId = component.workplace.uid; + + // const link = getByText('Skip this question'); + // fireEvent.click(link); + + // expect(routerSpy).toHaveBeenCalledWith([ + // '/workplace', + // workplaceId, + // 'staff-record', + // workerId, + // 'apprenticeship-training', + // ]); + // }); + + // it('should navigate to staff-summary-page page when pressing view this staff record', async () => { + // const { component, routerSpy, getByText } = await setup(); + + // const workerId = component.worker.uid; + // const workplaceId = component.workplace.uid; + + // const link = getByText('View this staff record'); + // fireEvent.click(link); + + // expect(routerSpy).toHaveBeenCalledWith([ + // '/workplace', + // workplaceId, + // 'staff-record', + // workerId, + // 'staff-record-summary', + // ]); + // }); + + // it('should navigate to staff-summary-page page when pressing save and return', async () => { + // const { component, routerSpy, getByText } = await setup(false); + + // const workerId = component.worker.uid; + // const workplaceId = component.workplace.uid; + + // const saveButton = getByText('Save and return'); + // fireEvent.click(saveButton); + + // expect(routerSpy).toHaveBeenCalledWith([ + // '/workplace', + // workplaceId, + // 'staff-record', + // workerId, + // 'staff-record-summary', + // ]); + // }); + + it('should navigate to staff-summary-page page when pressing cancel', async () => { + const { component, routerSpy, getByText } = await setup(false); + + const workerId = component.worker.uid; + const workplaceId = component.workplace.uid; + + const link = getByText('Cancel'); + fireEvent.click(link); + + expect(routerSpy).toHaveBeenCalledWith([ + '/workplace', + workplaceId, + 'staff-record', + workerId, + 'staff-record-summary', + ]); + }); + + // it('should navigate to wdf staff-summary-page page when pressing save and return in wdf version of page', async () => { + // const { component, router, fixture, routerSpy, getByText } = await setup(false); + // spyOnProperty(router, 'url').and.returnValue('/wdf/staff-record'); + // component.returnUrl = undefined; + // component.ngOnInit(); + // fixture.detectChanges(); + // const workerId = component.worker.uid; + + // const saveButton = getByText('Save and return'); + // fireEvent.click(saveButton); + + // expect(routerSpy).toHaveBeenCalledWith(['/wdf', 'staff-record', workerId]); + // }); + + // it('should navigate to wdf staff-summary-page page when pressing cancel in wdf version of page', async () => { + // const { component, router, fixture, routerSpy, getByText } = await setup(false); + // spyOnProperty(router, 'url').and.returnValue('/wdf/staff-record'); + // component.returnUrl = undefined; + // component.ngOnInit(); + // fixture.detectChanges(); + // const workerId = component.worker.uid; + + // const link = getByText('Cancel'); + // fireEvent.click(link); + + // expect(routerSpy).toHaveBeenCalledWith(['/wdf', 'staff-record', workerId]); + // }); + }); }); diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts index 1c6d4824da..71856fea33 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts @@ -33,6 +33,11 @@ export class Level2AdultSocialCareCertificateComponent extends QuestionComponent this.form = this.formBuilder.group({ level2AdultSocialCareCertificate: null, + level2AdultSocialCareCertificateYearAchieved: null, }); } + + init() { + this.next = this.getRoutePath('apprenticeship-training'); + } } From 91b69d310f88ac55adbf27963ea7656c9052835c Mon Sep 17 00:00:00 2001 From: Sabrina Date: Fri, 23 Aug 2024 17:55:39 +0100 Subject: [PATCH 05/53] Remove test isolation --- .../workers/care-certificate/care-certificate.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts b/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts index 0de465904c..bd126cef7e 100644 --- a/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts +++ b/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts @@ -109,7 +109,7 @@ describe('CareCertificateComponent', () => { }); }); - fdescribe('navigation', () => { + describe('navigation', () => { it('should navigate to level-2-adult-social-care-certificate page when submitting from flow', async () => { const { component, routerSpy, getByText } = await setup(); From d2ac1137bc809c6d92b9aed851065d6c42f9e386 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Tue, 27 Aug 2024 10:29:22 +0100 Subject: [PATCH 06/53] add css class to align border thickness of inset-text and details-text --- .../workers/care-certificate/care-certificate.component.html | 2 +- .../care-certificate/care-certificate.component.spec.ts | 2 +- frontend/src/assets/scss/components/_inset-text.scss | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/features/workers/care-certificate/care-certificate.component.html b/frontend/src/app/features/workers/care-certificate/care-certificate.component.html index c7fb88b26b..5eb1e7f461 100644 --- a/frontend/src/app/features/workers/care-certificate/care-certificate.component.html +++ b/frontend/src/app/features/workers/care-certificate/care-certificate.component.html @@ -11,7 +11,7 @@

Have they completed, started or partially completed their Care Certificate?

-
+
The Care Certificate is not the same thing as the Level 2 Adult Social Care Certificate, introduced in 2024.
diff --git a/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts b/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts index 358457e511..f0997982a8 100644 --- a/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts +++ b/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts @@ -10,7 +10,7 @@ import { fireEvent, render } from '@testing-library/angular'; import { CareCertificateComponent } from './care-certificate.component'; -fdescribe('CareCertificateComponent', () => { +describe('CareCertificateComponent', () => { async function setup(insideFlow = true) { const { fixture, getByText, getAllByText, getByLabelText, getByTestId, queryByTestId } = await render( CareCertificateComponent, diff --git a/frontend/src/assets/scss/components/_inset-text.scss b/frontend/src/assets/scss/components/_inset-text.scss index 7ddd43752e..b6f9a42845 100644 --- a/frontend/src/assets/scss/components/_inset-text.scss +++ b/frontend/src/assets/scss/components/_inset-text.scss @@ -18,4 +18,9 @@ border-color: govuk-colour('blue'); background-color: rgba(govuk-colour('blue'), 0.15); } + + &.thin-border { + border-width: 5px; + padding-left: 20px; + } } From 44afd48dc106b964a5912fd7b242beadbca928b0 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Tue, 27 Aug 2024 10:54:03 +0100 Subject: [PATCH 07/53] Add to wdf routing --- .../wdf/wdf-data-change/wdf-routing.module.ts | 11 +++++++++++ .../app/features/workers/workers-routing.module.ts | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/features/wdf/wdf-data-change/wdf-routing.module.ts b/frontend/src/app/features/wdf/wdf-data-change/wdf-routing.module.ts index b26f741f2e..22236acb8d 100644 --- a/frontend/src/app/features/wdf/wdf-data-change/wdf-routing.module.ts +++ b/frontend/src/app/features/wdf/wdf-data-change/wdf-routing.module.ts @@ -40,6 +40,7 @@ import { WdfDataComponent } from './wdf-data/wdf-data.component'; import { WdfOverviewComponent } from './wdf-overview/wdf-overview.component'; import { WdfStaffRecordComponent } from './wdf-staff-record/wdf-staff-record.component'; import { WdfWorkplacesSummaryComponent } from './wdf-workplaces-summary/wdf-workplaces-summary.component'; +import { Level2AdultSocialCareCertificateComponent } from '@features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component'; const routes: Routes = [ { @@ -200,6 +201,11 @@ const routes: Routes = [ component: CareCertificateComponent, data: { title: 'Care Certificate' }, }, + { + path: 'level-2-care-certificate', + component: Level2AdultSocialCareCertificateComponent, + data: { title: 'Level 2 Adult Social Care Certificate' }, + }, { path: 'apprenticeship-training', component: ApprenticeshipTrainingComponent, @@ -389,6 +395,11 @@ const routes: Routes = [ component: CareCertificateComponent, data: { title: 'Care Certificate' }, }, + { + path: 'level-2-care-certificate', + component: Level2AdultSocialCareCertificateComponent, + data: { title: 'Level 2 Adult Social Care Certificate' }, + }, { path: 'apprenticeship-training', component: ApprenticeshipTrainingComponent, diff --git a/frontend/src/app/features/workers/workers-routing.module.ts b/frontend/src/app/features/workers/workers-routing.module.ts index aeba06e791..f4c5ce0778 100644 --- a/frontend/src/app/features/workers/workers-routing.module.ts +++ b/frontend/src/app/features/workers/workers-routing.module.ts @@ -241,7 +241,7 @@ const routes: Routes = [ data: { title: 'Care Certificate' }, }, { - path: 'level-2-adult-social-care-certificate', + path: 'level-2-care-certificate', component: Level2AdultSocialCareCertificateComponent, data: { title: 'Level 2 Adult Social Care Certificate' }, }, @@ -490,7 +490,7 @@ const routes: Routes = [ data: { title: 'Care Certificate' }, }, { - path: 'level-2-adult-social-care-certificate', + path: 'level-2-care-certificate', component: Level2AdultSocialCareCertificateComponent, data: { title: 'Level 2 Adult Social Care Certificate' }, }, From 228ae99b8ff14e520999014b558215bc8ce88092 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Tue, 27 Aug 2024 12:03:45 +0100 Subject: [PATCH 08/53] Add migrations and new properties to models --- ...20240827102746-addLevel2CareCertificate.js | 78 +++++++++++++++++++ backend/server/models/classes/worker.js | 20 +++++ .../level2CareCertificateProperty.js | 60 ++++++++++++++ .../models/classes/worker/workerProperties.js | 5 +- backend/server/models/establishment.js | 1 + backend/server/models/worker.js | 31 ++++++++ frontend/src/app/core/model/worker.model.ts | 4 + .../app/core/test-utils/MockWorkerService.ts | 4 + ...-social-care-certificate.component.spec.ts | 2 +- 9 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 backend/migrations/20240827102746-addLevel2CareCertificate.js create mode 100644 backend/server/models/classes/worker/properties/level2CareCertificateProperty.js diff --git a/backend/migrations/20240827102746-addLevel2CareCertificate.js b/backend/migrations/20240827102746-addLevel2CareCertificate.js new file mode 100644 index 0000000000..11d7ce9a3e --- /dev/null +++ b/backend/migrations/20240827102746-addLevel2CareCertificate.js @@ -0,0 +1,78 @@ +'use strict'; + +const table = { tableName: 'Worker', schema: 'cqc' }; + +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction((transaction) => { + return Promise.all([ + queryInterface.addColumn( + table, + 'Level2CareCertificateValue', + { + type: Sequelize.DataTypes.TEXT, + allowNull: true, + }, + { transaction }, + ), + queryInterface.addColumn( + table, + 'Level2CareCertificateYear', + { + type: Sequelize.DataTypes.INTEGER, + allowNull: true, + }, + { transaction }, + ), + queryInterface.addColumn( + table, + 'Level2CareCertificateSavedAt', + { + type: Sequelize.DataTypes.DATE, + allowNull: true, + }, + { transaction }, + ), + queryInterface.addColumn( + table, + 'Level2CareCertificateChangedAt', + { + type: Sequelize.DataTypes.DATE, + allowNull: true, + }, + { transaction }, + ), + queryInterface.addColumn( + table, + 'Level2CareCertificateSavedBy', + { + type: Sequelize.DataTypes.TEXT, + allowNull: true, + }, + { transaction }, + ), + queryInterface.addColumn( + table, + 'Level2CareCertificateChangedBy', + { + type: Sequelize.DataTypes.TEXT, + allowNull: true, + }, + { transaction }, + ), + ]); + }); + }, + down: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction((transaction) => { + return Promise.all([ + queryInterface.removeColumn(table, 'Level2CareCertificateValue', { transaction }), + queryInterface.removeColumn(table, 'Level2CareCertificateYear', { transaction }), + queryInterface.removeColumn(table, 'Level2CareCertificateSavedAt', { transaction }), + queryInterface.removeColumn(table, 'Level2CareCertificateChangedAt', { transaction }), + queryInterface.removeColumn(table, 'Level2CareCertificateSavedBy', { transaction }), + queryInterface.removeColumn(table, 'Level2CareCertificateChangedBy', { transaction }), + ]); + }); + }, +}; diff --git a/backend/server/models/classes/worker.js b/backend/server/models/classes/worker.js index d8b10e2a96..32ae83862d 100644 --- a/backend/server/models/classes/worker.js +++ b/backend/server/models/classes/worker.js @@ -218,6 +218,12 @@ class Worker extends EntityValidator { return this._properties.get('CareCertificate') ? this._properties.get('CareCertificate').property : null; } + get level2CareCertificate() { + return this._properties.get('Level2CareCertificate') + ? this._properties.get('Level2CareCertificate').property + : null; + } + get approvedMentalHealthWorker() { return this._properties.get('ApprovedMentalHealthWorker') ? this._properties.get('ApprovedMentalHealthWorker').property @@ -391,6 +397,11 @@ class Worker extends EntityValidator { document.employedFromOutsideUk = null; } + // Remove year if level 2 care certificate isn't completed + if (document.level2CareCertificate.value !== 'Yes, completed') { + document.level2CareCertificate.year = null; + } + // Remove year arrived if born in the UK or setting to Don't know if (document.countryOfBirth) { if (document.countryOfBirth.value === 'United Kingdom' || document.countryOfBirth.value === "Don't know") { @@ -1717,6 +1728,15 @@ class Worker extends EntityValidator { .toJSON(false, true, WdfCalculator.effectiveDate), }; + myWdf.level2CareCertificate = { + isEligible: this._isPropertyWdfBasicEligible(effectiveFromEpoch, this._properties.get('Level2CareCertificate')) + ? 'Yes' + : 'No', + updatedSinceEffectiveDate: this._properties + .get('Level2CareCertificate') + .toJSON(false, true, WdfCalculator.effectiveDate), + }; + myWdf.qualificationInSocialCare = { isEligible: this._isPropertyWdfBasicEligible( effectiveFromEpoch, diff --git a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js new file mode 100644 index 0000000000..4319e8c0c5 --- /dev/null +++ b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js @@ -0,0 +1,60 @@ +// the level 2 care certificate property is an enumeration +const ChangePropertyPrototype = require('../../properties/changePrototype').ChangePropertyPrototype; + +const LEVEL_2_CARE_CERTIFICATE_TYPE = ['Yes, completed', 'Yes, started', 'No']; +exports.WorkerLevel2CareCertificateProperty = class WorkerLevel2CareCertificateProperty extends ( + ChangePropertyPrototype +) { + constructor() { + super('Level2CareCertificate'); + } + + static clone() { + return new WorkerLevel2CareCertificateProperty(); + } + + // concrete implementations + async restoreFromJson(document) { + if (document.careCertificate) { + if (LEVEL_2_CARE_CERTIFICATE_TYPE.includes(document.level2CareCertificate)) { + this.property = document.level2CareCertificate; + } else { + this.property = null; + } + } + } + + restorePropertyFromSequelize(document) { + return document.Level2CareCertificateValue; + } + savePropertyToSequelize() { + return { + Level2CareCertificateValue: this.property, + }; + } + + isEqual(currentValue, newValue) { + // Level 2 Care Certificate is a simple (enum'd) string + return currentValue && newValue && currentValue === newValue; + } + + toJSON(withHistory = false, showPropertyHistoryOnly = true, wdfEffectiveDate = false) { + if (wdfEffectiveDate) { + return this._savedAt ? this._savedAt > wdfEffectiveDate : false; + } + + if (!withHistory) { + // simple form + return { + level2CareCertificate: this.property, + }; + } + + return { + level2CareCertificate: { + currentValue: this.property, + ...this.changePropsToJSON(showPropertyHistoryOnly), + }, + }; + } +}; diff --git a/backend/server/models/classes/worker/workerProperties.js b/backend/server/models/classes/worker/workerProperties.js index 845ea85b63..3bbf9e0487 100644 --- a/backend/server/models/classes/worker/workerProperties.js +++ b/backend/server/models/classes/worker/workerProperties.js @@ -48,6 +48,8 @@ const establishmentFkProperty = require('./properties/establishmentFkProperty'). const longTermAbsenceProperty = require('./properties/longTermAbsenceProperty').LongTermAbsenceProperty; const healthAndCareVisaProperty = require('./properties/healthAndCareVisa').HealthAndCareVisaProperty; const employedFromOutsideUkProperty = require('./properties/employedFromOutsideUk').EmployedFromOutsideUkProperty; +const level2CareCertificateProperty = + require('./properties/level2CareCertificateProperty').Level2CareCertificateProperty; class WorkerPropertyManager { constructor() { @@ -78,6 +80,7 @@ class WorkerPropertyManager { this._thisManager.registerProperty(weeklyHoursContractedProperty); this._thisManager.registerProperty(annualHourlyPayProperty); this._thisManager.registerProperty(careCertificateProperty); + this._thisManager.registerProperty(level2CareCertificateProperty); this._thisManager.registerProperty(apprenticeshipProperty); this._thisManager.registerProperty(qualificationInSocialCareProperty); this._thisManager.registerProperty(socialCareQualificationProperty); @@ -90,7 +93,7 @@ class WorkerPropertyManager { this._thisManager.registerProperty(establishmentFkProperty); this._thisManager.registerProperty(longTermAbsenceProperty); this._thisManager.registerProperty(healthAndCareVisaProperty); - this._thisManager.registerProperty(employedFromOutsideUkProperty) + this._thisManager.registerProperty(employedFromOutsideUkProperty); } get manager() { diff --git a/backend/server/models/establishment.js b/backend/server/models/establishment.js index 2ce64e0108..4ae391b013 100644 --- a/backend/server/models/establishment.js +++ b/backend/server/models/establishment.js @@ -1503,6 +1503,7 @@ module.exports = function (sequelize, DataTypes) { 'ApprovedMentalHealthWorkerValue', 'QualificationInSocialCareValue', 'OtherQualificationsValue', + 'Level2CareCertificateValue', ], as: 'workers', where: { diff --git a/backend/server/models/worker.js b/backend/server/models/worker.js index c3a73d07c6..ae00616807 100644 --- a/backend/server/models/worker.js +++ b/backend/server/models/worker.js @@ -768,6 +768,37 @@ module.exports = function (sequelize, DataTypes) { allowNull: true, field: '"CareCertificateChangedBy"', }, + Level2CareCertificateValue: { + type: DataTypes.ENUM, + allowNull: true, + values: ['Yes, completed', 'Yes, started', 'No'], + field: '"Level2CareCertificateValue"', + }, + Level2CareCertificateYear: { + type: DataTypes.INTEGER, + allowNull: true, + field: '"Level2CareCertificateYear"', + }, + Level2CareCertificateSavedAt: { + type: DataTypes.DATE, + allowNull: true, + field: '"Level2CareCertificateSavedAt"', + }, + Level2CareCertificateChangedAt: { + type: DataTypes.DATE, + allowNull: true, + field: '"Level2CareCertificateChangedAt"', + }, + Level2CareCertificateSavedBy: { + type: DataTypes.TEXT, + allowNull: true, + field: '"Level2CareCertificateSavedBy"', + }, + Level2CareCertificateChangedBy: { + type: DataTypes.TEXT, + allowNull: true, + field: '"Level2CareCertificateChangedBy"', + }, HealthAndCareVisaValue: { type: DataTypes.ENUM, allowNull: true, diff --git a/frontend/src/app/core/model/worker.model.ts b/frontend/src/app/core/model/worker.model.ts index 58e71396eb..3649b63a04 100644 --- a/frontend/src/app/core/model/worker.model.ts +++ b/frontend/src/app/core/model/worker.model.ts @@ -68,6 +68,10 @@ export interface Worker { }; annualHourlyPay: WorkerPay; careCertificate: string; + level2CareCertificate: { + value: string; + year: number; + }; apprenticeshipTraining: string; qualificationInSocialCare: string; socialCareQualification: { diff --git a/frontend/src/app/core/test-utils/MockWorkerService.ts b/frontend/src/app/core/test-utils/MockWorkerService.ts index e4bd442568..b429a781aa 100644 --- a/frontend/src/app/core/test-utils/MockWorkerService.ts +++ b/frontend/src/app/core/test-utils/MockWorkerService.ts @@ -33,6 +33,10 @@ export const workerBuilder = build('Worker', { rate: 8.98, }, careCertificate: 'Yes', + level2CareCertificate: { + value: 'Yes, completed', + year: 2023, + }, apprenticeshipTraining: null, qualificationInSocialCare: 'No', otherQualification: 'Yes', diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts index 24c5b0e6fd..e69cd642d9 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts @@ -10,7 +10,7 @@ import { MockWorkerServiceWithUpdateWorker } from '@core/test-utils/MockWorkerSe import { Level2AdultSocialCareCertificateComponent } from './level-2-adult-social-care-certificate.component'; -fdescribe('Level2AdultSocialCareCertificateComponent', () => { +describe('Level2AdultSocialCareCertificateComponent', () => { async function setup(insideFlow = true) { const { fixture, getByText, getAllByText, getByLabelText, getByTestId, queryByTestId, queryByText } = await render( Level2AdultSocialCareCertificateComponent, From 6a24b39110d711101168ddbe09bd7d9241718b43 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Tue, 27 Aug 2024 12:11:43 +0100 Subject: [PATCH 09/53] Update form value --- .../level-2-adult-social-care-certificate.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts index 71856fea33..2a31c381f7 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts @@ -14,7 +14,7 @@ import { EstablishmentService } from '@core/services/establishment.service'; export class Level2AdultSocialCareCertificateComponent extends QuestionComponent { public answersAvailable = [ { value: 'Yes, completed', tag: 'Yes, completed' }, - { value: 'Yes, in progress or partially completed', tag: 'Yes, started' }, + { value: 'Yes, started', tag: 'Yes, started' }, { value: 'No', tag: 'No' }, ]; From da6d7ab7455c065fb4eb1254465479d58509d15c Mon Sep 17 00:00:00 2001 From: Sabrina Date: Tue, 27 Aug 2024 12:20:16 +0100 Subject: [PATCH 10/53] Update property in worker class --- .../worker/properties/level2CareCertificateProperty.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js index 4319e8c0c5..23310cc548 100644 --- a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js +++ b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js @@ -2,15 +2,13 @@ const ChangePropertyPrototype = require('../../properties/changePrototype').ChangePropertyPrototype; const LEVEL_2_CARE_CERTIFICATE_TYPE = ['Yes, completed', 'Yes, started', 'No']; -exports.WorkerLevel2CareCertificateProperty = class WorkerLevel2CareCertificateProperty extends ( - ChangePropertyPrototype -) { +exports.Level2CareCertificateProperty = class Level2CareCertificateProperty extends ChangePropertyPrototype { constructor() { super('Level2CareCertificate'); } static clone() { - return new WorkerLevel2CareCertificateProperty(); + return new Level2CareCertificateProperty(); } // concrete implementations From 888a47bd9ea015b5fbaa7025e943141514272a21 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Tue, 27 Aug 2024 12:44:16 +0100 Subject: [PATCH 11/53] Update property model to show level 2 care cert value --- .../properties/level2CareCertificateProperty.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js index 23310cc548..53e431437d 100644 --- a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js +++ b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js @@ -14,8 +14,11 @@ exports.Level2CareCertificateProperty = class Level2CareCertificateProperty exte // concrete implementations async restoreFromJson(document) { if (document.careCertificate) { - if (LEVEL_2_CARE_CERTIFICATE_TYPE.includes(document.level2CareCertificate)) { - this.property = document.level2CareCertificate; + if (LEVEL_2_CARE_CERTIFICATE_TYPE.includes(document.level2CareCertificate.value)) { + this.property = { + value: document.level2CareCertificate.value, + year: document.level2CareCertificate.year, + }; } else { this.property = null; } @@ -23,11 +26,17 @@ exports.Level2CareCertificateProperty = class Level2CareCertificateProperty exte } restorePropertyFromSequelize(document) { - return document.Level2CareCertificateValue; + let level2CareCertificateDocument = { + value: document.Level2CareCertificateValue, + year: document.Level2CareCertificateYear, + }; + return level2CareCertificateDocument; } + savePropertyToSequelize() { return { - Level2CareCertificateValue: this.property, + Level2CareCertificateValue: this.property.value, + Level2CareCertificateYear: this.property.value === 'Yes, completed' ? this.property.year : null, }; } From af0ba54347a555b943bf7d1fb5a4116d29f91cf0 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Tue, 27 Aug 2024 14:47:04 +0100 Subject: [PATCH 12/53] add unit test for level 2 care certificate links at summary page --- ...lifications-and-training.component.spec.ts | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts diff --git a/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts new file mode 100644 index 0000000000..f985bf8767 --- /dev/null +++ b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts @@ -0,0 +1,114 @@ +import { HttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { RouterModule } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { Establishment } from '@core/model/establishment.model'; +import { Worker } from '@core/model/worker.model'; +import { PermissionsService } from '@core/services/permissions/permissions.service'; +import { establishmentBuilder } from '@core/test-utils/MockEstablishmentService'; +import { MockPermissionsService } from '@core/test-utils/MockPermissionsService'; +import { workerWithWdf } from '@core/test-utils/MockWorkerService'; +import { SummaryRecordChangeComponent } from '@shared/components/summary-record-change/summary-record-change.component'; +import { SharedModule } from '@shared/shared.module'; +import { render, getByTestId, within } from '@testing-library/angular'; + +import { QualificationsAndTrainingComponent } from './qualifications-and-training.component'; +import { InternationalRecruitmentService } from '@core/services/international-recruitment.service'; + +fdescribe('QualificationsAndTrainingComponent', () => { + async function setup() { + const { fixture, getByText } = await render(QualificationsAndTrainingComponent, { + imports: [SharedModule, RouterModule, RouterTestingModule, HttpClientTestingModule], + declarations: [SummaryRecordChangeComponent], + providers: [ + InternationalRecruitmentService, + { + provide: PermissionsService, + useFactory: MockPermissionsService.factory(['canEditWorker']), + deps: [HttpClient], + }, + ], + componentProperties: { + canEditWorker: true, + workplace: establishmentBuilder() as Establishment, + worker: workerWithWdf() as Worker, + wdfView: false, + }, + }); + + const component = fixture.componentInstance; + + return { + component, + fixture, + getByText, + }; + } + + it('should render a QualificationsAndTrainingComponent', async () => { + const { component } = await setup(); + expect(component).toBeTruthy(); + }); + + describe('care certificate', () => { + it('should render Add link with the staff-record-summary/care-certificate url when care certificate is not answered', async () => { + const { fixture, component, getByText } = await setup(); + + component.worker.careCertificate = null; + fixture.detectChanges(); + + const careCertificateSection = getByText('Care Certificate').parentElement; + const addLink = within(careCertificateSection).getByText('Add'); + + expect(addLink.getAttribute('href')).toBe( + `/workplace/${component.workplace.uid}/staff-record/${component.worker.uid}/staff-record-summary/care-certificate`, + ); + }); + + it('should render Change link with the staff-record-summary/care-certificate url when care certificate is already answered', async () => { + const { fixture, component, getByText } = await setup(); + + component.worker.careCertificate = 'Yes, completed'; + fixture.detectChanges(); + + const careCertificateSection = getByText('Care Certificate').parentElement; + const currentAnswer = within(careCertificateSection).getByText('Yes, completed'); + const changeLink = within(careCertificateSection).getByText('Change'); + + expect(currentAnswer).toBeTruthy(); + expect(changeLink.getAttribute('href')).toBe( + `/workplace/${component.workplace.uid}/staff-record/${component.worker.uid}/staff-record-summary/care-certificate`, + ); + }); + }); + + describe('level 2 care certificate', () => { + it('should render Add link with the staff-record-summary/level-2-adult-social-care-certificate url when level 2 care certificate is not answered', async () => { + const { fixture, component, getByText } = await setup(); + + component.worker.level2CareCertificate = null; + fixture.detectChanges(); + + const level2CareCertificateSection = getByText('Level 2 Adult Social Care Certificate').parentElement; + const addLink = within(level2CareCertificateSection).getByText('Add'); + + expect(addLink.getAttribute('href')).toBe( + `/workplace/${component.workplace.uid}/staff-record/${component.worker.uid}/staff-record-summary/level-2-adult-social-care-certificate`, + ); + }); + + xit('should render Change link with the staff-record-summary/level-2-adult-social-care-certificate url when care certificate is already answered', async () => { + const { fixture, component, getByText } = await setup(); + + component.worker.level2CareCertificate.value = 'Yes, started'; + fixture.detectChanges(); + + const level2CareCertificateSection = getByText('Level 2 Adult Social Care Certificate').parentElement; + const changeLink = within(level2CareCertificateSection).getByText('Change'); + + expect(changeLink.getAttribute('href')).toBe( + `/workplace/${component.workplace.uid}/staff-record/${component.worker.uid}/staff-record-summary/level-2-adult-social-care-certificate`, + ); + }); + }); +}); From 0e52ab03e43c5c3a6accb5182c7a779c5bb36a1d Mon Sep 17 00:00:00 2001 From: Sabrina Date: Tue, 27 Aug 2024 15:04:54 +0100 Subject: [PATCH 13/53] Update check on worker class --- backend/server/models/classes/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/server/models/classes/worker.js b/backend/server/models/classes/worker.js index 32ae83862d..b53f84a511 100644 --- a/backend/server/models/classes/worker.js +++ b/backend/server/models/classes/worker.js @@ -398,7 +398,7 @@ class Worker extends EntityValidator { } // Remove year if level 2 care certificate isn't completed - if (document.level2CareCertificate.value !== 'Yes, completed') { + if (document.level2CareCertificate && document.level2CareCertificate.value !== 'Yes, completed') { document.level2CareCertificate.year = null; } From a1a1ae3596287ed41bc7582c51bf70d9146e8f2b Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Tue, 27 Aug 2024 15:15:23 +0100 Subject: [PATCH 14/53] add new row at summary page for level 2 care cert --- ...qualifications-and-training.component.html | 53 +++++++++++++++++-- ...lifications-and-training.component.spec.ts | 6 +-- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.html b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.html index a864317e5f..e2f1f46bea 100644 --- a/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.html +++ b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.html @@ -19,7 +19,7 @@

Training and qualifications

!worker.wdf?.careCertificate.updatedSinceEffectiveDate && worker.careCertificate !== 'Yes, completed' " - [changeLink]="getRoutePath('care-certificate',wdfView)" + [changeLink]="getRoutePath('care-certificate', wdfView)" (fieldConfirmation)="this.confirmField('careCertificate')" (setReturnClicked)="this.setReturn()" [workerUid]="worker.uid" @@ -43,6 +43,49 @@

Training and qualifications

+
+
Level 2 Adult Social Care Certificate
+ +
+ + {{ worker.careCertificate || '-' }} + + +
+
+ +
+
+
Apprenticeship training
@@ -76,7 +119,7 @@

Training and qualifications

!worker.wdf?.qualificationInSocialCare.updatedSinceEffectiveDate && worker.qualificationInSocialCare !== 'Yes' " - [changeLink]="getRoutePath('social-care-qualification',wdfView)" + [changeLink]="getRoutePath('social-care-qualification', wdfView)" (fieldConfirmation)="this.confirmField('qualificationInSocialCare')" (setReturnClicked)="this.setReturn()" [workerUid]="worker.uid" @@ -117,7 +160,7 @@

Training and qualifications

worker.wdf?.socialCareQualification.isEligible === 'Yes' && !worker.wdf?.socialCareQualification.updatedSinceEffectiveDate " - [changeLink]="getRoutePath('social-care-qualification-level',wdfView)" + [changeLink]="getRoutePath('social-care-qualification-level', wdfView)" (fieldConfirmation)=" this.confirmField('socialCareQualification'); this.confirmField('qualificationInSocialCare') " @@ -160,7 +203,7 @@

Training and qualifications

!worker.wdf?.otherQualification.updatedSinceEffectiveDate && worker.otherQualification !== 'Yes' " - [changeLink]="getRoutePath('other-qualifications',wdfView)" + [changeLink]="getRoutePath('other-qualifications', wdfView)" (fieldConfirmation)="this.confirmField('otherQualification')" (setReturnClicked)="this.setReturn()" [workerUid]="worker.uid" @@ -193,7 +236,7 @@

Training and qualifications

worker.wdf?.highestQualification.isEligible === 'Yes' && !worker.wdf?.highestQualification.updatedSinceEffectiveDate " - [changeLink]="getRoutePath('other-qualifications-level',wdfView)" + [changeLink]="getRoutePath('other-qualifications-level', wdfView)" (fieldConfirmation)="this.confirmField('highestQualification'); this.confirmField('otherQualification')" (setReturnClicked)="this.setReturn()" [workerUid]="worker.uid" diff --git a/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts index f985bf8767..00e2d2c5ff 100644 --- a/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts +++ b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts @@ -93,11 +93,11 @@ fdescribe('QualificationsAndTrainingComponent', () => { const addLink = within(level2CareCertificateSection).getByText('Add'); expect(addLink.getAttribute('href')).toBe( - `/workplace/${component.workplace.uid}/staff-record/${component.worker.uid}/staff-record-summary/level-2-adult-social-care-certificate`, + `/workplace/${component.workplace.uid}/staff-record/${component.worker.uid}/staff-record-summary/level-2-care-certificate`, ); }); - xit('should render Change link with the staff-record-summary/level-2-adult-social-care-certificate url when care certificate is already answered', async () => { + it('should render Change link with the staff-record-summary/level-2-adult-social-care-certificate url when care certificate is already answered', async () => { const { fixture, component, getByText } = await setup(); component.worker.level2CareCertificate.value = 'Yes, started'; @@ -107,7 +107,7 @@ fdescribe('QualificationsAndTrainingComponent', () => { const changeLink = within(level2CareCertificateSection).getByText('Change'); expect(changeLink.getAttribute('href')).toBe( - `/workplace/${component.workplace.uid}/staff-record/${component.worker.uid}/staff-record-summary/level-2-adult-social-care-certificate`, + `/workplace/${component.workplace.uid}/staff-record/${component.worker.uid}/staff-record-summary/level-2-care-certificate`, ); }); }); From bde2b5275d6abd30aa244f7f2c12e59aa7cb4b5b Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Tue, 27 Aug 2024 16:41:15 +0100 Subject: [PATCH 15/53] remove wdf related ngif from level2 care certificate row --- ...qualifications-and-training.component.html | 29 +------------------ ...lifications-and-training.component.spec.ts | 4 ++- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.html b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.html index e2f1f46bea..cb4c0834ba 100644 --- a/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.html +++ b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.html @@ -47,37 +47,10 @@

Training and qualifications

Level 2 Adult Social Care Certificate
- - {{ worker.careCertificate || '-' }} - - + {{ worker.level2CareCertificate?.value || '-' }}
{ fixture.detectChanges(); const level2CareCertificateSection = getByText('Level 2 Adult Social Care Certificate').parentElement; + const currentAnswer = within(level2CareCertificateSection).getByText('Yes, started'); const changeLink = within(level2CareCertificateSection).getByText('Change'); + expect(currentAnswer).toBeTruthy(); expect(changeLink.getAttribute('href')).toBe( `/workplace/${component.workplace.uid}/staff-record/${component.worker.uid}/staff-record-summary/level-2-care-certificate`, ); From 1efefc9cc5ee03ca1607a6b58a30f3e3c8697ea6 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Tue, 27 Aug 2024 16:45:12 +0100 Subject: [PATCH 16/53] remove f from describe block --- .../qualifications-and-training.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts index f96bb1ff5d..6c0944902c 100644 --- a/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts +++ b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts @@ -15,7 +15,7 @@ import { render, within } from '@testing-library/angular'; import { QualificationsAndTrainingComponent } from './qualifications-and-training.component'; import { InternationalRecruitmentService } from '@core/services/international-recruitment.service'; -fdescribe('QualificationsAndTrainingComponent', () => { +describe('QualificationsAndTrainingComponent', () => { async function setup() { const { fixture, getByText } = await render(QualificationsAndTrainingComponent, { imports: [SharedModule, RouterModule, RouterTestingModule, HttpClientTestingModule], From 01ac8719420ed1d5433f24484e103ee600617eb8 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Tue, 27 Aug 2024 17:30:29 +0100 Subject: [PATCH 17/53] Update level2CareCertificate property on worker class --- .../worker/properties/level2CareCertificateProperty.js | 2 +- backend/server/models/establishment.js | 1 + frontend/src/app/core/model/worker.model.ts | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js index 53e431437d..34e7558289 100644 --- a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js +++ b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js @@ -13,7 +13,7 @@ exports.Level2CareCertificateProperty = class Level2CareCertificateProperty exte // concrete implementations async restoreFromJson(document) { - if (document.careCertificate) { + if (document.level2CareCertificate) { if (LEVEL_2_CARE_CERTIFICATE_TYPE.includes(document.level2CareCertificate.value)) { this.property = { value: document.level2CareCertificate.value, diff --git a/backend/server/models/establishment.js b/backend/server/models/establishment.js index 4ae391b013..b95c3224ee 100644 --- a/backend/server/models/establishment.js +++ b/backend/server/models/establishment.js @@ -1504,6 +1504,7 @@ module.exports = function (sequelize, DataTypes) { 'QualificationInSocialCareValue', 'OtherQualificationsValue', 'Level2CareCertificateValue', + 'Level2CareCertificateYear', ], as: 'workers', where: { diff --git a/frontend/src/app/core/model/worker.model.ts b/frontend/src/app/core/model/worker.model.ts index 3649b63a04..bd59a866df 100644 --- a/frontend/src/app/core/model/worker.model.ts +++ b/frontend/src/app/core/model/worker.model.ts @@ -68,9 +68,9 @@ export interface Worker { }; annualHourlyPay: WorkerPay; careCertificate: string; - level2CareCertificate: { + level2CareCertificate?: { value: string; - year: number; + year?: number; }; apprenticeshipTraining: string; qualificationInSocialCare: string; From 65eedcf2ae6bc96f10e75ba8afe0786b766015ef Mon Sep 17 00:00:00 2001 From: Sabrina Date: Tue, 27 Aug 2024 17:35:45 +0100 Subject: [PATCH 18/53] Update level 2 care cert to prefill and save --- ...ult-social-care-certificate.component.html | 39 ++- ...-social-care-certificate.component.spec.ts | 242 ++++++++++-------- ...adult-social-care-certificate.component.ts | 26 +- 3 files changed, 181 insertions(+), 126 deletions(-) diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html index 01a8531cdf..9475c14c25 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html @@ -1,4 +1,4 @@ -
+
@@ -29,32 +29,30 @@

-
- +
@@ -62,27 +60,26 @@

-
-
diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts index e69cd642d9..fd243ee514 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts @@ -6,12 +6,15 @@ import { RouterTestingModule } from '@angular/router/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ReactiveFormsModule, UntypedFormBuilder } from '@angular/forms'; import { WorkerService } from '@core/services/worker.service'; -import { MockWorkerServiceWithUpdateWorker } from '@core/test-utils/MockWorkerService'; +import { Worker } from '@core/model/worker.model'; +import { MockWorkerServiceWithUpdateWorker, workerBuilder } from '@core/test-utils/MockWorkerService'; import { Level2AdultSocialCareCertificateComponent } from './level-2-adult-social-care-certificate.component'; +import { HttpClient } from '@angular/common/http'; describe('Level2AdultSocialCareCertificateComponent', () => { - async function setup(insideFlow = true) { + const workerFieldsNoLevel2CareCertificate = { level2CareCertificate: { value: null, year: null } }; + async function setup(insideFlow = true, workerFields = workerFieldsNoLevel2CareCertificate) { const { fixture, getByText, getAllByText, getByLabelText, getByTestId, queryByTestId, queryByText } = await render( Level2AdultSocialCareCertificateComponent, { @@ -37,7 +40,8 @@ describe('Level2AdultSocialCareCertificateComponent', () => { }, { provide: WorkerService, - useClass: MockWorkerServiceWithUpdateWorker, + useFactory: MockWorkerServiceWithUpdateWorker.factory({ ...workerBuilder(), ...workerFields } as Worker), + deps: [HttpClient], }, ], declarations: [], @@ -186,79 +190,79 @@ describe('Level2AdultSocialCareCertificateComponent', () => { }); describe('navigation', () => { - // it('should navigate to apprenticeship-training page when submitting from flow', async () => { - // const { component, routerSpy, getByText } = await setup(); - - // const workerId = component.worker.uid; - // const workplaceId = component.workplace.uid; - - // const saveButton = getByText('Save and continue'); - // fireEvent.click(saveButton); - - // expect(getByText('Save and continue')).toBeTruthy(); - - // expect(routerSpy).toHaveBeenCalledWith([ - // '/workplace', - // workplaceId, - // 'staff-record', - // workerId, - // 'apprenticeship-training', - // ]); - // }); - - // it('should navigate to apprenticeship-training page when skipping the question in the flow', async () => { - // const { component, routerSpy, getByText } = await setup(); - - // const workerId = component.worker.uid; - // const workplaceId = component.workplace.uid; - - // const link = getByText('Skip this question'); - // fireEvent.click(link); - - // expect(routerSpy).toHaveBeenCalledWith([ - // '/workplace', - // workplaceId, - // 'staff-record', - // workerId, - // 'apprenticeship-training', - // ]); - // }); - - // it('should navigate to staff-summary-page page when pressing view this staff record', async () => { - // const { component, routerSpy, getByText } = await setup(); - - // const workerId = component.worker.uid; - // const workplaceId = component.workplace.uid; - - // const link = getByText('View this staff record'); - // fireEvent.click(link); - - // expect(routerSpy).toHaveBeenCalledWith([ - // '/workplace', - // workplaceId, - // 'staff-record', - // workerId, - // 'staff-record-summary', - // ]); - // }); - - // it('should navigate to staff-summary-page page when pressing save and return', async () => { - // const { component, routerSpy, getByText } = await setup(false); - - // const workerId = component.worker.uid; - // const workplaceId = component.workplace.uid; - - // const saveButton = getByText('Save and return'); - // fireEvent.click(saveButton); - - // expect(routerSpy).toHaveBeenCalledWith([ - // '/workplace', - // workplaceId, - // 'staff-record', - // workerId, - // 'staff-record-summary', - // ]); - // }); + it('should navigate to apprenticeship-training page when submitting from flow', async () => { + const { component, routerSpy, getByText } = await setup(); + + const workerId = component.worker.uid; + const workplaceId = component.workplace.uid; + + const saveButton = getByText('Save and continue'); + fireEvent.click(saveButton); + + expect(getByText('Save and continue')).toBeTruthy(); + + expect(routerSpy).toHaveBeenCalledWith([ + '/workplace', + workplaceId, + 'staff-record', + workerId, + 'apprenticeship-training', + ]); + }); + + it('should navigate to apprenticeship-training page when skipping the question in the flow', async () => { + const { component, routerSpy, getByText } = await setup(); + + const workerId = component.worker.uid; + const workplaceId = component.workplace.uid; + + const link = getByText('Skip this question'); + fireEvent.click(link); + + expect(routerSpy).toHaveBeenCalledWith([ + '/workplace', + workplaceId, + 'staff-record', + workerId, + 'apprenticeship-training', + ]); + }); + + it('should navigate to staff-summary-page page when pressing view this staff record', async () => { + const { component, routerSpy, getByText } = await setup(); + + const workerId = component.worker.uid; + const workplaceId = component.workplace.uid; + + const link = getByText('View this staff record'); + fireEvent.click(link); + + expect(routerSpy).toHaveBeenCalledWith([ + '/workplace', + workplaceId, + 'staff-record', + workerId, + 'staff-record-summary', + ]); + }); + + it('should navigate to staff-summary-page page when pressing save and return', async () => { + const { component, routerSpy, getByText } = await setup(false); + + const workerId = component.worker.uid; + const workplaceId = component.workplace.uid; + + const saveButton = getByText('Save and return'); + fireEvent.click(saveButton); + + expect(routerSpy).toHaveBeenCalledWith([ + '/workplace', + workplaceId, + 'staff-record', + workerId, + 'staff-record-summary', + ]); + }); it('should navigate to staff-summary-page page when pressing cancel', async () => { const { component, routerSpy, getByText } = await setup(false); @@ -278,32 +282,64 @@ describe('Level2AdultSocialCareCertificateComponent', () => { ]); }); - // it('should navigate to wdf staff-summary-page page when pressing save and return in wdf version of page', async () => { - // const { component, router, fixture, routerSpy, getByText } = await setup(false); - // spyOnProperty(router, 'url').and.returnValue('/wdf/staff-record'); - // component.returnUrl = undefined; - // component.ngOnInit(); - // fixture.detectChanges(); - // const workerId = component.worker.uid; - - // const saveButton = getByText('Save and return'); - // fireEvent.click(saveButton); - - // expect(routerSpy).toHaveBeenCalledWith(['/wdf', 'staff-record', workerId]); - // }); - - // it('should navigate to wdf staff-summary-page page when pressing cancel in wdf version of page', async () => { - // const { component, router, fixture, routerSpy, getByText } = await setup(false); - // spyOnProperty(router, 'url').and.returnValue('/wdf/staff-record'); - // component.returnUrl = undefined; - // component.ngOnInit(); - // fixture.detectChanges(); - // const workerId = component.worker.uid; - - // const link = getByText('Cancel'); - // fireEvent.click(link); - - // expect(routerSpy).toHaveBeenCalledWith(['/wdf', 'staff-record', workerId]); - // }); + it('should navigate to wdf staff-summary-page page when pressing save and return in wdf version of page', async () => { + const { component, router, fixture, routerSpy, getByText } = await setup(false); + spyOnProperty(router, 'url').and.returnValue('/wdf/staff-record'); + component.returnUrl = undefined; + component.ngOnInit(); + fixture.detectChanges(); + const workerId = component.worker.uid; + + const saveButton = getByText('Save and return'); + fireEvent.click(saveButton); + + expect(routerSpy).toHaveBeenCalledWith(['/wdf', 'staff-record', workerId]); + }); + + it('should navigate to wdf staff-summary-page page when pressing cancel in wdf version of page', async () => { + const { component, router, fixture, routerSpy, getByText } = await setup(false); + spyOnProperty(router, 'url').and.returnValue('/wdf/staff-record'); + component.returnUrl = undefined; + component.ngOnInit(); + fixture.detectChanges(); + const workerId = component.worker.uid; + + const link = getByText('Cancel'); + fireEvent.click(link); + + expect(routerSpy).toHaveBeenCalledWith(['/wdf', 'staff-record', workerId]); + }); + }); + + describe('pre-fill', () => { + it('should only show radio button checked', async () => { + const workerFields = { level2CareCertificate: { value: 'No', year: null } }; + const { component, fixture } = await setup(false, workerFields); + + fixture.detectChanges(); + + const form = component.form; + const radioBtn = fixture.nativeElement.querySelector('input[id="level2CareCertificate-no"]'); + const yearAchievedInput = fixture.nativeElement.querySelector('div[id="certification-achieved"]'); + + expect(radioBtn.checked).toBeTruthy(); + expect(yearAchievedInput.getAttribute('class')).toContain('hidden'); + expect(form.value).toEqual({ level2CareCertificate: 'No', level2CareCertificateYearAchieved: null }); + }); + + it('should show radio and year input', async () => { + const workerFields = { level2CareCertificate: { value: 'Yes, completed', year: 2023 } }; + const { component, fixture } = await setup(false, workerFields); + + fixture.detectChanges(); + + const form = component.form; + const radioBtn = fixture.nativeElement.querySelector('input[id="level2CareCertificate-yesCompleted"]'); + const yearAchievedInput = fixture.nativeElement.querySelector('div[id="certification-achieved"]'); + + expect(radioBtn.checked).toBeTruthy(); + expect(yearAchievedInput.getAttribute('class')).not.toContain('hidden'); + expect(form.value).toEqual({ level2CareCertificate: 'Yes, completed', level2CareCertificateYearAchieved: 2023 }); + }); }); }); diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts index 2a31c381f7..6c3103a2c5 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts @@ -32,12 +32,34 @@ export class Level2AdultSocialCareCertificateComponent extends QuestionComponent super(formBuilder, router, route, backLinkService, errorSummaryService, workerService, establishmentService); this.form = this.formBuilder.group({ - level2AdultSocialCareCertificate: null, - level2AdultSocialCareCertificateYearAchieved: null, + level2CareCertificate: null, + level2CareCertificateYearAchieved: null, }); } init() { this.next = this.getRoutePath('apprenticeship-training'); + + if (this.worker.level2CareCertificate && this.worker.level2CareCertificate.value) { + this.form.patchValue({ + level2CareCertificate: this.worker.level2CareCertificate.value, + level2CareCertificateYearAchieved: this.worker.level2CareCertificate.year, + }); + } + } + + generateUpdateProps() { + const { level2CareCertificate, level2CareCertificateYearAchieved } = this.form.value; + + if (!level2CareCertificate) { + return null; + } + + return { + level2CareCertificate: { + value: level2CareCertificate, + year: level2CareCertificateYearAchieved, + }, + }; } } From c408067140687a58da3292a7429adab2f4b6cd31 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Wed, 28 Aug 2024 09:27:42 +0100 Subject: [PATCH 19/53] Update next route path for care cert --- .../care-certificate/care-certificate.component.spec.ts | 8 ++++---- .../care-certificate/care-certificate.component.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts b/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts index bd126cef7e..cc22a34669 100644 --- a/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts +++ b/frontend/src/app/features/workers/care-certificate/care-certificate.component.spec.ts @@ -110,7 +110,7 @@ describe('CareCertificateComponent', () => { }); describe('navigation', () => { - it('should navigate to level-2-adult-social-care-certificate page when submitting from flow', async () => { + it('should navigate to level-2-care-certificate page when submitting from flow', async () => { const { component, routerSpy, getByText } = await setup(); const workerId = component.worker.uid; @@ -126,11 +126,11 @@ describe('CareCertificateComponent', () => { workplaceId, 'staff-record', workerId, - 'level-2-adult-social-care-certificate', + 'level-2-care-certificate', ]); }); - it('should navigate to level-2-adult-social-care-certificate page when skipping the question in the flow', async () => { + it('should navigate to level-2-care-certificate page when skipping the question in the flow', async () => { const { component, routerSpy, getByText } = await setup(); const workerId = component.worker.uid; @@ -144,7 +144,7 @@ describe('CareCertificateComponent', () => { workplaceId, 'staff-record', workerId, - 'level-2-adult-social-care-certificate', + 'level-2-care-certificate', ]); }); diff --git a/frontend/src/app/features/workers/care-certificate/care-certificate.component.ts b/frontend/src/app/features/workers/care-certificate/care-certificate.component.ts index 75cbf43bf4..4961b3d7cc 100644 --- a/frontend/src/app/features/workers/care-certificate/care-certificate.component.ts +++ b/frontend/src/app/features/workers/care-certificate/care-certificate.component.ts @@ -37,7 +37,7 @@ export class CareCertificateComponent extends QuestionComponent { } init() { - this.next = this.getRoutePath('level-2-adult-social-care-certificate'); + this.next = this.getRoutePath('level-2-care-certificate'); if (this.worker.careCertificate) { this.prefill(); } From 2f7b00301bd19a4ae43c9e4535ff0ad25fb62454 Mon Sep 17 00:00:00 2001 From: Jonathan Hardy Date: Wed, 28 Aug 2024 10:32:37 +0100 Subject: [PATCH 20/53] removed notes column from quals table --- .../new-qualifications/new-qualifications.component.html | 4 ---- .../new-qualifications/new-qualifications.spec.ts | 4 ---- 2 files changed, 8 deletions(-) diff --git a/frontend/src/app/features/training-and-qualifications/new-training-qualifications-record/new-qualifications/new-qualifications.component.html b/frontend/src/app/features/training-and-qualifications/new-training-qualifications-record/new-qualifications/new-qualifications.component.html index bded6b1ddb..4d7862ca28 100644 --- a/frontend/src/app/features/training-and-qualifications/new-training-qualifications-record/new-qualifications/new-qualifications.component.html +++ b/frontend/src/app/features/training-and-qualifications/new-training-qualifications-record/new-qualifications/new-qualifications.component.html @@ -13,7 +13,6 @@

Qualifications

Certificate name Year achieved - Notes @@ -34,9 +33,6 @@

Qualifications

{{ qualificationRecord?.year ? qualificationRecord.year : '-' }} - - {{ qualificationRecord?.notes ? qualificationRecord.notes : 'None' }} - diff --git a/frontend/src/app/features/training-and-qualifications/new-training-qualifications-record/new-qualifications/new-qualifications.spec.ts b/frontend/src/app/features/training-and-qualifications/new-training-qualifications-record/new-qualifications/new-qualifications.spec.ts index 1ddeef8433..22ed7a4d2d 100644 --- a/frontend/src/app/features/training-and-qualifications/new-training-qualifications-record/new-qualifications/new-qualifications.spec.ts +++ b/frontend/src/app/features/training-and-qualifications/new-training-qualifications-record/new-qualifications/new-qualifications.spec.ts @@ -39,7 +39,6 @@ describe('NewQualificationsComponent', () => { expect(getAllByText('Certificate name').length).toBe(2); expect(getAllByText('Year achieved').length).toBe(2); - expect(getAllByText('Notes').length).toBe(2); }); it('should show Health table row with details of record', async () => { @@ -47,7 +46,6 @@ describe('NewQualificationsComponent', () => { expect(getByText('Health qualification')).toBeTruthy(); expect(getByText('2020')).toBeTruthy(); - expect(getByText('This is a test note for the first row in the Health group')).toBeTruthy(); }); it('should show Certificate table first row with details of record', async () => { @@ -55,7 +53,6 @@ describe('NewQualificationsComponent', () => { expect(getByText('Cert qualification')).toBeTruthy(); expect(getByText('2021')).toBeTruthy(); - expect(getByText('Test notes needed')).toBeTruthy(); }); it('should show Certificate table second row with details of record', async () => { @@ -63,7 +60,6 @@ describe('NewQualificationsComponent', () => { expect(getByText('Another name for qual')).toBeTruthy(); expect(getByText('2012')).toBeTruthy(); - expect(getByText('These are some more notes in the second row of the cert table')).toBeTruthy(); }); describe('no qualifications', async () => { From b7e98e673db83f45f2590f514eadc83dc91e2ed8 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Wed, 28 Aug 2024 12:06:15 +0100 Subject: [PATCH 21/53] Add validation to level 2 care cert page --- ...ult-social-care-certificate.component.html | 25 ++++++- ...-social-care-certificate.component.spec.ts | 72 +++++++++++++++++-- ...adult-social-care-certificate.component.ts | 38 +++++++++- 3 files changed, 129 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html index 9475c14c25..b36eb8021b 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html @@ -1,7 +1,12 @@ + +
-
+

@@ -48,6 +53,24 @@

>
+ + + Error: + {{ getFormErrorMessage('level2CareCertificateYearAchieved', 'required') }} + + + Error: + {{ getFormErrorMessage('level2CareCertificateYearAchieved', 'min') }} + + + Error: + {{ getFormErrorMessage('level2CareCertificateYearAchieved', 'max') }} + + { const workerFieldsNoLevel2CareCertificate = { level2CareCertificate: { value: null, year: null } }; @@ -191,13 +192,16 @@ describe('Level2AdultSocialCareCertificateComponent', () => { describe('navigation', () => { it('should navigate to apprenticeship-training page when submitting from flow', async () => { - const { component, routerSpy, getByText } = await setup(); + const { component, fixture, routerSpy, getByText } = await setup(); const workerId = component.worker.uid; const workplaceId = component.workplace.uid; - + const radioBtn = fixture.nativeElement.querySelector('input[id="level2CareCertificate-yesStarted"]'); const saveButton = getByText('Save and continue'); + + fireEvent.click(radioBtn); fireEvent.click(saveButton); + fixture.detectChanges(); expect(getByText('Save and continue')).toBeTruthy(); @@ -247,13 +251,16 @@ describe('Level2AdultSocialCareCertificateComponent', () => { }); it('should navigate to staff-summary-page page when pressing save and return', async () => { - const { component, routerSpy, getByText } = await setup(false); + const { component, fixture, routerSpy, getByText } = await setup(false); const workerId = component.worker.uid; const workplaceId = component.workplace.uid; - + const radioBtn = fixture.nativeElement.querySelector('input[id="level2CareCertificate-yesStarted"]'); const saveButton = getByText('Save and return'); + + fireEvent.click(radioBtn); fireEvent.click(saveButton); + fixture.detectChanges(); expect(routerSpy).toHaveBeenCalledWith([ '/workplace', @@ -290,8 +297,12 @@ describe('Level2AdultSocialCareCertificateComponent', () => { fixture.detectChanges(); const workerId = component.worker.uid; + const radioBtn = fixture.nativeElement.querySelector('input[id="level2CareCertificate-yesStarted"]'); const saveButton = getByText('Save and return'); + + fireEvent.click(radioBtn); fireEvent.click(saveButton); + fixture.detectChanges(); expect(routerSpy).toHaveBeenCalledWith(['/wdf', 'staff-record', workerId]); }); @@ -342,4 +353,57 @@ describe('Level2AdultSocialCareCertificateComponent', () => { expect(form.value).toEqual({ level2CareCertificate: 'Yes, completed', level2CareCertificateYearAchieved: 2023 }); }); }); + + describe('errors', () => { + it('should show if a year has not been entered when "Yes, completed" has been selected', async () => { + const { component, fixture, getByText, getAllByText } = await setup(false); + + const form = component.form; + const radioBtn = fixture.nativeElement.querySelector('input[id="level2CareCertificate-yesCompleted"]'); + const saveButton = getByText('Save and return'); + const expectedErrorMessage = 'Enter the year'; + + fireEvent.click(radioBtn); + fireEvent.click(saveButton); + + expect(form.invalid).toBeTruthy(); + expect(getAllByText(expectedErrorMessage, { exact: false }).length).toBe(2); + }); + + it('should show if the entered year is in the future', async () => { + const { component, fixture, getByText, getAllByText } = await setup(false); + + const form = component.form; + const radioBtn = fixture.nativeElement.querySelector('input[id="level2CareCertificate-yesCompleted"]'); + const saveButton = getByText('Save and return'); + const expectedErrorMessage = 'Year cannot be in the future'; + const nextYear = dayjs().year() + 1; + + form.get('level2CareCertificateYearAchieved').setValue(nextYear); + form.markAsDirty(); + fireEvent.click(radioBtn); + fireEvent.click(saveButton); + + expect(form.invalid).toBeTruthy(); + expect(getAllByText(expectedErrorMessage, { exact: false }).length).toBe(2); + }); + + it('should error if entered year is before the qualification was introduced', async () => { + const { component, fixture, getByText, getAllByText } = await setup(false); + + const form = component.form; + const radioBtn = fixture.nativeElement.querySelector('input[id="level2CareCertificate-yesCompleted"]'); + const saveButton = getByText('Save and return'); + + form.get('level2CareCertificateYearAchieved').setValue(2023); + form.markAsDirty(); + fireEvent.click(radioBtn); + fireEvent.click(saveButton); + + const expectedErrorMessage = 'Year cannot be before 2024'; + + expect(form.invalid).toBeTruthy(); + expect(getAllByText(expectedErrorMessage, { exact: false }).length).toBe(2); + }); + }); }); diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts index 6c3103a2c5..f52681737d 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts @@ -1,11 +1,12 @@ import { Component } from '@angular/core'; import { QuestionComponent } from '../question/question.component'; -import { UntypedFormBuilder } from '@angular/forms'; +import { UntypedFormBuilder, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { BackLinkService } from '@core/services/backLink.service'; import { ErrorSummaryService } from '@core/services/error-summary.service'; import { WorkerService } from '@core/services/worker.service'; import { EstablishmentService } from '@core/services/establishment.service'; +import dayjs from 'dayjs'; @Component({ selector: 'app-level-2-adult-social-care-certificate', @@ -40,6 +41,19 @@ export class Level2AdultSocialCareCertificateComponent extends QuestionComponent init() { this.next = this.getRoutePath('apprenticeship-training'); + this.subscriptions.add( + this.form.get('level2CareCertificate').valueChanges.subscribe((value) => { + this.form.get('level2CareCertificateYearAchieved').clearValidators(); + + if (value === 'Yes, completed') { + this.form + .get('level2CareCertificateYearAchieved') + .setValidators([Validators.required, Validators.min(2024), Validators.max(dayjs().year())]); + } + this.form.get('level2CareCertificateYearAchieved').updateValueAndValidity(); + }), + ); + if (this.worker.level2CareCertificate && this.worker.level2CareCertificate.value) { this.form.patchValue({ level2CareCertificate: this.worker.level2CareCertificate.value, @@ -62,4 +76,26 @@ export class Level2AdultSocialCareCertificateComponent extends QuestionComponent }, }; } + + setupFormErrorsMap(): void { + this.formErrorsMap = [ + { + item: 'level2CareCertificateYearAchieved', + type: [ + { + name: 'required', + message: 'Enter the year', + }, + { + name: 'min', + message: `Year cannot be before 2024`, + }, + { + name: 'max', + message: `Year cannot be in the future`, + }, + ], + }, + ]; + } } From fbacf77922166df85eaf41428eef0f82897c6fc4 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Wed, 28 Aug 2024 12:19:06 +0100 Subject: [PATCH 22/53] add new column for L2CareCert in bulk upload download, amend workerCSV toCSV function for new field --- .../bulkUpload/data/workerHeaders.js | 1 + .../bulkUpload/download/workerCSV.js | 17 ++++++++++++++++- .../server/test/integration/utils/worker.js | 1 + backend/server/test/unit/mockdata/workers.js | 1 + .../bulkUpload/download/workerCSV.spec.js | 18 +++++++++++++++++- 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/backend/server/routes/establishments/bulkUpload/data/workerHeaders.js b/backend/server/routes/establishments/bulkUpload/data/workerHeaders.js index 4fe04c34dd..c016b83b4c 100644 --- a/backend/server/routes/establishments/bulkUpload/data/workerHeaders.js +++ b/backend/server/routes/establishments/bulkUpload/data/workerHeaders.js @@ -15,6 +15,7 @@ const workerHeaders = [ 'YEAROFENTRY', 'DISABLED', 'CARECERT', + 'L2CARECERT', 'RECSOURCE', 'HANDCVISA', 'INOUTUK', diff --git a/backend/server/routes/establishments/bulkUpload/download/workerCSV.js b/backend/server/routes/establishments/bulkUpload/download/workerCSV.js index 3425379c1a..e1075b7b26 100644 --- a/backend/server/routes/establishments/bulkUpload/download/workerCSV.js +++ b/backend/server/routes/establishments/bulkUpload/download/workerCSV.js @@ -32,7 +32,7 @@ const _convertYesNoDontKnow = (value) => { // takes the given Worker entity and writes it out to CSV string (one line) const toCSV = (establishmentId, entity, MAX_QUALIFICATIONS, downloadType) => { // ["LOCALESTID","UNIQUEWORKERID","STATUS","DISPLAYID","NINUMBER","POSTCODE","DOB","GENDER","ETHNICITY","NATIONALITY","BRITISHCITIZENSHIP","COUNTRYOFBIRTH","YEAROFENTRY","DISABLED", - // "CARECERT","RECSOURCE","HANDCVISA","INOUTUK","STARTDATE","STARTINSECT","APPRENTICE","EMPLSTATUS","ZEROHRCONT","DAYSSICK","SALARYINT","SALARY","HOURLYRATE","MAINJOBROLE","MAINJRDESC","CONTHOURS","AVGHOURS", + // "CARECERT","L2CARECERT","RECSOURCE","HANDCVISA","INOUTUK","STARTDATE","STARTINSECT","APPRENTICE","EMPLSTATUS","ZEROHRCONT","DAYSSICK","SALARYINT","SALARY","HOURLYRATE","MAINJOBROLE","MAINJRDESC","CONTHOURS","AVGHOURS", // "NMCREG","NURSESPEC","AMHP","SCQUAL","NONSCQUAL","QUALACH01","QUALACH01NOTES","QUALACH02","QUALACH02NOTES","QUALACH03","QUALACH03NOTES"]; const columns = []; @@ -175,6 +175,21 @@ const toCSV = (establishmentId, entity, MAX_QUALIFICATIONS, downloadType) => { } columns.push(careCert); + // "L2CARECERT" + let l2CareCert = ''; + switch (entity.Level2CareCertificateValue) { + case 'Yes, completed': + l2CareCert = 1; + break; + case 'Yes, started': + l2CareCert = 2; + break; + case 'No': + l2CareCert = 3; + break; + } + columns.push(l2CareCert); + // "RECSOURCE" let recruitmentSource = ''; switch (entity.RecruitedFromValue) { diff --git a/backend/server/test/integration/utils/worker.js b/backend/server/test/integration/utils/worker.js index 9f0ab7e97b..ca08ec7920 100644 --- a/backend/server/test/integration/utils/worker.js +++ b/backend/server/test/integration/utils/worker.js @@ -39,6 +39,7 @@ module.exports.apiWorkerBuilder = build('Worker', { YearArrivedValue: oneOf('Yes', 'No', "Don't know"), DisabilityValue: oneOf('Yes', 'No', "Don't know", 'Undisclosed'), CareCertificateValue: oneOf('Yes, completed', 'No', 'Yes, in progress or partially completed'), + Level2CareCertificateValue: oneOf('Yes, completed', 'Yes, started', 'No'), RecruitedFromValue: oneOf('Yes', 'No'), MainJobStartDateValue: fake((f) => f.helpers.replaceSymbolWithNumber('####-##-##')), recruitedFrom: { diff --git a/backend/server/test/unit/mockdata/workers.js b/backend/server/test/unit/mockdata/workers.js index 5c572cb938..91dcc4a785 100644 --- a/backend/server/test/unit/mockdata/workers.js +++ b/backend/server/test/unit/mockdata/workers.js @@ -150,6 +150,7 @@ exports.knownHeaders = [ 'YEAROFENTRY', 'DISABLED', 'CARECERT', + 'L2CARECERT', 'RECSOURCE', 'HANDCVISA', 'INOUTUK', diff --git a/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js b/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js index 92de6ae763..5f11b459d9 100644 --- a/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js +++ b/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js @@ -19,7 +19,7 @@ const establishment = { LocalIdentifierValue: 'Test McTestface', }; -describe('workerCSV', () => { +describe.only('workerCSV', () => { describe('toCSV', () => { beforeEach(() => { sandbox.stub(BUDI, 'ethnicity').callsFake((method, value) => value); @@ -308,6 +308,22 @@ describe('workerCSV', () => { expect(csvAsArray[getWorkerColumnIndex('CARECERT')]).to.equal(careCert.code); }); }); + + [ + { name: 'Yes, completed', code: '1' }, + { name: 'Yes, started', code: '2' }, + { name: 'No', code: '3' }, + ].forEach((level2CareCert) => { + it('should return the correct code for level 2 care certificate ' + level2CareCert.name, async () => { + worker.Level2CareCertificateValue = level2CareCert.name; + + const csv = toCSV(establishment.LocalIdentifierValue, worker, 3); + const csvAsArray = csv.split(','); + + expect(csvAsArray[getWorkerColumnIndex('L2CARECERT')]).to.equal(level2CareCert.code); + }); + }); + it('should return the correct code for no in recruitment source', async () => { worker.RecruitedFromValue = 'No'; worker.recruitedFrom = null; From c1072d6f4d6bcbc58ee055e78dd3d4d71363cfd5 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Wed, 28 Aug 2024 14:41:10 +0100 Subject: [PATCH 23/53] Add additional validation Level2CareCertificateProperty --- .../level2CareCertificateProperty.js | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js index 34e7558289..a765133ce7 100644 --- a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js +++ b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js @@ -13,15 +13,32 @@ exports.Level2CareCertificateProperty = class Level2CareCertificateProperty exte // concrete implementations async restoreFromJson(document) { + const yearLevel2CareCertificateIntroduced = 2024; if (document.level2CareCertificate) { if (LEVEL_2_CARE_CERTIFICATE_TYPE.includes(document.level2CareCertificate.value)) { - this.property = { - value: document.level2CareCertificate.value, - year: document.level2CareCertificate.year, - }; - } else { - this.property = null; + if (document.level2CareCertificate.value === 'Yes, completed') { + const thisYear = new Date().getFullYear(); + if ( + document.level2CareCertificate.year && + Number.isInteger(document.level2CareCertificate.year) && + document.level2CareCertificate.year >= yearLevel2CareCertificateIntroduced && + document.level2CareCertificate.year < thisYear + 1 + ) { + this.property = { + value: document.level2CareCertificate.value, + year: document.level2CareCertificate.year, + }; + } else { + this.property = null; + } + } else { + this.property = { + value: document.level2CareCertificate.value, + }; + } } + } else { + this.property = null; } } From 6ffd0ea12f7906b48d923a62f7559fc3087af037 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Wed, 28 Aug 2024 16:59:57 +0100 Subject: [PATCH 24/53] add happy path test for level2carecert validator --- .../unit/classes/workerCSVValidator.spec.js | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index 48f0a34b55..5e66fedc4a 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -1222,5 +1222,29 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { expect(validator._validationErrors.length).to.equal(1); }); }); + + describe('_validateLevel2CareCert', () => { + [ + { l2CareCert: '1', mapping: 'Yes, completed' }, + { l2CareCert: '2', mapping: 'Yes, started' }, + { l2CareCert: '3', mapping: 'No' }, + ].forEach((answer) => { + it(`should not add warning when valid (${answer.l2CareCert}) level 2 care certificate value provided`, async () => { + const worker = buildWorkerCsv({ + overrides: { + STATUS: 'NEW', + L2CARECERT: answer.l2CareCert, + }, + }); + const validator = new WorkerCsvValidator(worker, 2, null, mappings); + + await validator.validate(); + await validator.transform(); + + expect(validator._validationErrors).to.deep.equal([]); + expect(validator._validationErrors.length).to.equal(0); + }); + }); + }); }); }); From 197614e31c5c85dcd6fe094f4c38e1ffe5cc3a20 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Wed, 28 Aug 2024 17:22:18 +0100 Subject: [PATCH 25/53] Remove required validation from level 2 care cert question --- .../worker/properties/level2CareCertificateProperty.js | 5 +++++ ...evel-2-adult-social-care-certificate.component.html | 6 +----- ...l-2-adult-social-care-certificate.component.spec.ts | 10 +++++----- .../level-2-adult-social-care-certificate.component.ts | 8 ++------ 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js index a765133ce7..8f1c342255 100644 --- a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js +++ b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js @@ -28,6 +28,11 @@ exports.Level2CareCertificateProperty = class Level2CareCertificateProperty exte value: document.level2CareCertificate.value, year: document.level2CareCertificate.year, }; + } else if (!document.level2CareCertificate.year) { + this.property = { + value: document.level2CareCertificate.value, + year: null, + }; } else { this.property = null; } diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html index b36eb8021b..f72d723703 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html @@ -15,7 +15,7 @@

-
+
The Level 2 Adult Social Care Certificate qualification, introduced in 2024, is not the same thing as the existing standards based Care Certificate.
@@ -58,10 +58,6 @@

id="level2CareCertificateYearAchieved-error" class="govuk-error-message" > - - Error: - {{ getFormErrorMessage('level2CareCertificateYearAchieved', 'required') }} - Error: {{ getFormErrorMessage('level2CareCertificateYearAchieved', 'min') }} diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts index 3d18c0ed08..95b4c3e51b 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts @@ -355,19 +355,19 @@ describe('Level2AdultSocialCareCertificateComponent', () => { }); describe('errors', () => { - it('should show if a year has not been entered when "Yes, completed" has been selected', async () => { - const { component, fixture, getByText, getAllByText } = await setup(false); + it('should not show if "Yes, completed" is clicked but no year entered', async () => { + const { component, fixture, getByText, queryByText } = await setup(false); const form = component.form; const radioBtn = fixture.nativeElement.querySelector('input[id="level2CareCertificate-yesCompleted"]'); const saveButton = getByText('Save and return'); - const expectedErrorMessage = 'Enter the year'; fireEvent.click(radioBtn); fireEvent.click(saveButton); + fixture.detectChanges(); - expect(form.invalid).toBeTruthy(); - expect(getAllByText(expectedErrorMessage, { exact: false }).length).toBe(2); + expect(form.valid).toBeTruthy(); + expect(queryByText('There is a problem')).toBeFalsy(); }); it('should show if the entered year is in the future', async () => { diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts index f52681737d..94714551b5 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts @@ -34,7 +34,7 @@ export class Level2AdultSocialCareCertificateComponent extends QuestionComponent this.form = this.formBuilder.group({ level2CareCertificate: null, - level2CareCertificateYearAchieved: null, + level2CareCertificateYearAchieved: [null, { validators: null, updateOn: 'submit' }], }); } @@ -48,7 +48,7 @@ export class Level2AdultSocialCareCertificateComponent extends QuestionComponent if (value === 'Yes, completed') { this.form .get('level2CareCertificateYearAchieved') - .setValidators([Validators.required, Validators.min(2024), Validators.max(dayjs().year())]); + .setValidators([Validators.min(2024), Validators.max(dayjs().year())]); } this.form.get('level2CareCertificateYearAchieved').updateValueAndValidity(); }), @@ -82,10 +82,6 @@ export class Level2AdultSocialCareCertificateComponent extends QuestionComponent { item: 'level2CareCertificateYearAchieved', type: [ - { - name: 'required', - message: 'Enter the year', - }, { name: 'min', message: `Year cannot be before 2024`, From ef83e7e8f27e00d87036e75a3e5ec3efa400bbc7 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Thu, 29 Aug 2024 11:07:27 +0100 Subject: [PATCH 26/53] add more tests for _validateLevel2CareCert, implement _validateLevel2CareCert --- .../bulkUpload/classes/workerCSVValidator.js | 46 +++++++++++++++++ .../unit/classes/workerCSVValidator.spec.js | 51 +++++++++++++++++-- 2 files changed, 94 insertions(+), 3 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index bdb4ed832b..10546f69b4 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -34,6 +34,7 @@ class WorkerCsvValidator { this._disabled = null; this._careCert = null; + this._level2CareCert = null; this._recSource = null; this._startDate = null; @@ -358,6 +359,10 @@ class WorkerCsvValidator { return 5580; } + static get LEVEL_2_CARE_CERT_WARNING() { + return 5590; + } + get lineNumber() { return this._lineNumber; } @@ -438,6 +443,10 @@ class WorkerCsvValidator { return this._careCert; } + get level2CareCert() { + return this._level2CareCert; + } + get recSource() { return this._recSource; } @@ -1221,6 +1230,42 @@ class WorkerCsvValidator { } } + _validateLevel2CareCert() { + const level2CareCertValues = [1, 2, 3]; + const myLevel2CareCert = parseInt(this._currentLine.L2CARECERT, 10); + + if (this._currentLine.CARECERT && this._currentLine.CARECERT.length > 0) { + if (isNaN(myLevel2CareCert) || !level2CareCertValues.includes(myLevel2CareCert)) { + this._validationErrors.push({ + worker: this._currentLine.UNIQUEWORKERID, + name: this._currentLine.LOCALESTID, + lineNumber: this._lineNumber, + warnCode: WorkerCsvValidator.LEVEL_2_CARE_CERT_WARNING, + warnType: 'L2CARECERT_WARNING', + warning: 'The code you have entered for L2CARECERT is incorrect and will be ignored', + source: this._currentLine.L2CARECERT, + column: 'L2CARECERT', + }); + return false; + } else { + switch (myLevel2CareCert) { + case 1: + this._level2CareCert = 'Yes, completed'; + break; + case 2: + this._level2CareCert = 'Yes, started'; + break; + case 3: + this._level2CareCert = 'No'; + break; + } + return true; + } + } else { + return true; + } + } + _validateRecSource() { const myRecSource = parseInt(this._currentLine.RECSOURCE, 10); @@ -2775,6 +2820,7 @@ class WorkerCsvValidator { status = !this._validateEmployedFromOutsideUk() ? false : status; status = !this._validateDisabled() ? false : status; status = !this._validateCareCert() ? false : status; + status = !this._validateLevel2CareCert() ? false : status; status = !this._validateRecSource() ? false : status; status = !this._validateStartDate() ? false : status; status = !this._validateStartInsect() ? false : status; diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index 5e66fedc4a..52a296e8b7 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -11,6 +11,7 @@ const buildWorkerCsv = build('WorkerCSV', { AVGHOURS: '', BRITISHCITIZENSHIP: '', CARECERT: '3', + L2CARECERT: '3', CONTHOURS: '23', COUNTRYOFBIRTH: '826', DAYSSICK: '1', @@ -1223,7 +1224,7 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { }); }); - describe('_validateLevel2CareCert', () => { + describe.only('_validateLevel2CareCert()', () => { [ { l2CareCert: '1', mapping: 'Yes, completed' }, { l2CareCert: '2', mapping: 'Yes, started' }, @@ -1238,12 +1239,56 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { }); const validator = new WorkerCsvValidator(worker, 2, null, mappings); - await validator.validate(); - await validator.transform(); + validator.validate(); + validator.transform(); expect(validator._validationErrors).to.deep.equal([]); expect(validator._validationErrors.length).to.equal(0); }); + + it(`should set level 2 care certificate value field with database mapping (${answer.mapping}) when valid (${answer.l2CareCert}) L2CARECERT provided`, () => { + const worker = buildWorkerCsv({ + overrides: { + STATUS: 'NEW', + L2CARECERT: answer.l2CareCert, + }, + }); + const validator = new WorkerCsvValidator(worker, 2, null, mappings); + + validator.validate(); + validator.transform(); + + expect(validator._level2CareCert).to.equal(answer.mapping); + }); + }); + + it('should add warning when the L2CARECERT value is invalid', async () => { + const invalidLevel2CareCertValue = '12345'; + const worker = buildWorkerCsv({ + overrides: { + STATUS: 'NEW', + L2CARECERT: invalidLevel2CareCertValue, + }, + }); + const expectedWarning = { + column: 'L2CARECERT', + lineNumber: 2, + name: 'MARMA', + source: '12345', + warnCode: WorkerCsvValidator.LEVEL_2_CARE_CERT_WARNING, + warnType: 'L2CARECERT_WARNING', + warning: 'The code you have entered for L2CARECERT is incorrect and will be ignored', + worker: '3', + }; + + const validator = new WorkerCsvValidator(worker, 2, null, mappings); + + validator.validate(); + validator.transform(); + + expect(validator._validationErrors).to.deep.equal([expectedWarning]); + expect(validator._validationErrors.length).to.equal(1); + expect(validator._level2CareCert).to.equal(null); }); }); }); From 6bf4a9a710deaf99fc06f839ad3f1e7e16bc675a Mon Sep 17 00:00:00 2001 From: Sabrina Date: Thu, 29 Aug 2024 11:42:48 +0100 Subject: [PATCH 27/53] Update validation messages --- .../level-2-adult-social-care-certificate.component.spec.ts | 4 ++-- .../level-2-adult-social-care-certificate.component.ts | 4 ++-- frontend/src/assets/scss/partials/_radios.scss | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts index 95b4c3e51b..39ff83c334 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.spec.ts @@ -376,7 +376,7 @@ describe('Level2AdultSocialCareCertificateComponent', () => { const form = component.form; const radioBtn = fixture.nativeElement.querySelector('input[id="level2CareCertificate-yesCompleted"]'); const saveButton = getByText('Save and return'); - const expectedErrorMessage = 'Year cannot be in the future'; + const expectedErrorMessage = 'Year achieved cannot be in the future'; const nextYear = dayjs().year() + 1; form.get('level2CareCertificateYearAchieved').setValue(nextYear); @@ -400,7 +400,7 @@ describe('Level2AdultSocialCareCertificateComponent', () => { fireEvent.click(radioBtn); fireEvent.click(saveButton); - const expectedErrorMessage = 'Year cannot be before 2024'; + const expectedErrorMessage = 'Year achieved cannot be before 2024'; expect(form.invalid).toBeTruthy(); expect(getAllByText(expectedErrorMessage, { exact: false }).length).toBe(2); diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts index 94714551b5..574a0a1012 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts @@ -84,11 +84,11 @@ export class Level2AdultSocialCareCertificateComponent extends QuestionComponent type: [ { name: 'min', - message: `Year cannot be before 2024`, + message: `Year achieved cannot be before 2024`, }, { name: 'max', - message: `Year cannot be in the future`, + message: `Year achieved cannot be in the future`, }, ], }, diff --git a/frontend/src/assets/scss/partials/_radios.scss b/frontend/src/assets/scss/partials/_radios.scss index 1fa574f5f7..81b56897a2 100644 --- a/frontend/src/assets/scss/partials/_radios.scss +++ b/frontend/src/assets/scss/partials/_radios.scss @@ -21,3 +21,7 @@ vertical-align: middle; padding: 5px 0px 5px 10px; } + +.govuk-radios__conditional { + border-left: 5px solid #b1b4b6; +} From a136ca6fa10bbbb28f964a93718dbd6e1af5771d Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Thu, 29 Aug 2024 11:47:51 +0100 Subject: [PATCH 28/53] refactor to use _generateWarning function --- .../bulkUpload/classes/workerCSVValidator.js | 19 +++++++------------ .../unit/classes/workerCSVValidator.spec.js | 4 ++-- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index 10546f69b4..8e7aa79355 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -359,7 +359,7 @@ class WorkerCsvValidator { return 5580; } - static get LEVEL_2_CARE_CERT_WARNING() { + static get L2CARECERT_WARNING() { return 5590; } @@ -1199,7 +1199,7 @@ class WorkerCsvValidator { const myCareCert = parseInt(this._currentLine.CARECERT, 10); if (this._currentLine.CARECERT && this._currentLine.CARECERT.length > 0) { - if (isNaN(myCareCert) || !careCertValues.includes(parseInt(myCareCert, 10))) { + if (isNaN(myCareCert) || !careCertValues.includes(myCareCert)) { this._validationErrors.push({ worker: this._currentLine.UNIQUEWORKERID, name: this._currentLine.LOCALESTID, @@ -1236,16 +1236,11 @@ class WorkerCsvValidator { if (this._currentLine.CARECERT && this._currentLine.CARECERT.length > 0) { if (isNaN(myLevel2CareCert) || !level2CareCertValues.includes(myLevel2CareCert)) { - this._validationErrors.push({ - worker: this._currentLine.UNIQUEWORKERID, - name: this._currentLine.LOCALESTID, - lineNumber: this._lineNumber, - warnCode: WorkerCsvValidator.LEVEL_2_CARE_CERT_WARNING, - warnType: 'L2CARECERT_WARNING', - warning: 'The code you have entered for L2CARECERT is incorrect and will be ignored', - source: this._currentLine.L2CARECERT, - column: 'L2CARECERT', - }); + const warning = this._generateWarning( + 'The code you have entered for L2CARECERT is incorrect and will be ignored', + 'L2CARECERT', + ); + this._validationErrors.push(warning); return false; } else { switch (myLevel2CareCert) { diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index 52a296e8b7..b193a5bf85 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -1224,7 +1224,7 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { }); }); - describe.only('_validateLevel2CareCert()', () => { + describe('_validateLevel2CareCert()', () => { [ { l2CareCert: '1', mapping: 'Yes, completed' }, { l2CareCert: '2', mapping: 'Yes, started' }, @@ -1275,7 +1275,7 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { lineNumber: 2, name: 'MARMA', source: '12345', - warnCode: WorkerCsvValidator.LEVEL_2_CARE_CERT_WARNING, + warnCode: WorkerCsvValidator.L2CARECERT_WARNING, warnType: 'L2CARECERT_WARNING', warning: 'The code you have entered for L2CARECERT is incorrect and will be ignored', worker: '3', From 1c0dedd52aade3ef468ae20ce39dfe59b04d0607 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Thu, 29 Aug 2024 11:56:22 +0100 Subject: [PATCH 29/53] add L2CARECERT to mock data of backend tests --- .../establishments/bulkUpload/download/workerCSV.spec.js | 2 +- .../unit/routes/establishments/bulkUpload/uploadFiles.spec.js | 2 +- .../establishments/bulkUpload/validate/headers/worker.spec.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js b/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js index 5f11b459d9..8bb0ad2faa 100644 --- a/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js +++ b/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js @@ -19,7 +19,7 @@ const establishment = { LocalIdentifierValue: 'Test McTestface', }; -describe.only('workerCSV', () => { +describe('workerCSV', () => { describe('toCSV', () => { beforeEach(() => { sandbox.stub(BUDI, 'ethnicity').callsFake((method, value) => value); diff --git a/backend/server/test/unit/routes/establishments/bulkUpload/uploadFiles.spec.js b/backend/server/test/unit/routes/establishments/bulkUpload/uploadFiles.spec.js index 122ed4cd2f..5f9a0dab8c 100644 --- a/backend/server/test/unit/routes/establishments/bulkUpload/uploadFiles.spec.js +++ b/backend/server/test/unit/routes/establishments/bulkUpload/uploadFiles.spec.js @@ -16,7 +16,7 @@ describe('/server/routes/establishment/uploadFiles.js', () => { const EstablishmentFile = 'LOCALESTID,STATUS,ESTNAME,ADDRESS1,ADDRESS2,ADDRESS3,POSTTOWN,POSTCODE,ESTTYPE,OTHERTYPE,PERMCQC,PERMLA,REGTYPE,PROVNUM,LOCATIONID,MAINSERVICE,ALLSERVICES,CAPACITY,UTILISATION,SERVICEDESC,SERVICEUSERS,OTHERUSERDESC,TOTALPERMTEMP,ALLJOBROLES,STARTERS,LEAVERS,VACANCIES,REASONS,REASONNOS,ADVERTISING,INTERVIEWS,REPEATTRAINING,ACCEPTCARECERT,BENEFITS,SICKPAY,PENSION,HOLIDAY'; const WorkerFile = - 'LOCALESTID,UNIQUEWORKERID,STATUS,DISPLAYID,NINUMBER,POSTCODE,DOB,GENDER,ETHNICITY,NATIONALITY,BRITISHCITIZENSHIP,COUNTRYOFBIRTH,YEAROFENTRY,DISABLED,CARECERT,RECSOURCE,HANDCVISA,INOUTUK,STARTDATE,STARTINSECT,APPRENTICE,EMPLSTATUS,ZEROHRCONT,DAYSSICK,SALARYINT,SALARY,HOURLYRATE,MAINJOBROLE,MAINJRDESC,CONTHOURS,AVGHOURS,NMCREG,NURSESPEC,AMHP,SCQUAL,NONSCQUAL,QUALACH01,QUALACH01NOTES,QUALACH02,QUALACH02NOTES,QUALACH03,QUALACH03NOTES'; + 'LOCALESTID,UNIQUEWORKERID,STATUS,DISPLAYID,NINUMBER,POSTCODE,DOB,GENDER,ETHNICITY,NATIONALITY,BRITISHCITIZENSHIP,COUNTRYOFBIRTH,YEAROFENTRY,DISABLED,CARECERT,L2CARECERT,RECSOURCE,HANDCVISA,INOUTUK,STARTDATE,STARTINSECT,APPRENTICE,EMPLSTATUS,ZEROHRCONT,DAYSSICK,SALARYINT,SALARY,HOURLYRATE,MAINJOBROLE,MAINJRDESC,CONTHOURS,AVGHOURS,NMCREG,NURSESPEC,AMHP,SCQUAL,NONSCQUAL,QUALACH01,QUALACH01NOTES,QUALACH02,QUALACH02NOTES,QUALACH03,QUALACH03NOTES'; const OtherFile = 'Test,This,is,NOT,A,BULK,UPLOAD,FILE'; sinon.stub(S3.s3, 'putObject').returns({ diff --git a/backend/server/test/unit/routes/establishments/bulkUpload/validate/headers/worker.spec.js b/backend/server/test/unit/routes/establishments/bulkUpload/validate/headers/worker.spec.js index 938b4d6b72..9e52900a63 100644 --- a/backend/server/test/unit/routes/establishments/bulkUpload/validate/headers/worker.spec.js +++ b/backend/server/test/unit/routes/establishments/bulkUpload/validate/headers/worker.spec.js @@ -7,7 +7,7 @@ const expect = require('chai').expect; const workerHeadersWithCHGUNIQUEWRKID = 'LOCALESTID,UNIQUEWORKERID,CHGUNIQUEWRKID,STATUS,DISPLAYID,NINUMBER,' + 'POSTCODE,DOB,GENDER,ETHNICITY,NATIONALITY,BRITISHCITIZENSHIP,COUNTRYOFBIRTH,YEAROFENTRY,' + - 'DISABLED,CARECERT,RECSOURCE,HANDCVISA,INOUTUK,STARTDATE,STARTINSECT,APPRENTICE,EMPLSTATUS,ZEROHRCONT,' + + 'DISABLED,CARECERT,L2CARECERT,RECSOURCE,HANDCVISA,INOUTUK,STARTDATE,STARTINSECT,APPRENTICE,EMPLSTATUS,ZEROHRCONT,' + 'DAYSSICK,SALARYINT,SALARY,HOURLYRATE,MAINJOBROLE,MAINJRDESC,CONTHOURS,AVGHOURS,' + 'NMCREG,NURSESPEC,AMHP,SCQUAL,NONSCQUAL,QUALACH01,QUALACH01NOTES,' + 'QUALACH02,QUALACH02NOTES,QUALACH03,QUALACH03NOTES'; @@ -15,7 +15,7 @@ const workerHeadersWithCHGUNIQUEWRKID = const workerHeadersWithoutCHGUNIQUEWRKID = 'LOCALESTID,UNIQUEWORKERID,STATUS,DISPLAYID,NINUMBER,' + 'POSTCODE,DOB,GENDER,ETHNICITY,NATIONALITY,BRITISHCITIZENSHIP,COUNTRYOFBIRTH,YEAROFENTRY,' + - 'DISABLED,CARECERT,RECSOURCE,HANDCVISA,INOUTUK,STARTDATE,STARTINSECT,APPRENTICE,EMPLSTATUS,ZEROHRCONT,' + + 'DISABLED,CARECERT,L2CARECERT,RECSOURCE,HANDCVISA,INOUTUK,STARTDATE,STARTINSECT,APPRENTICE,EMPLSTATUS,ZEROHRCONT,' + 'DAYSSICK,SALARYINT,SALARY,HOURLYRATE,MAINJOBROLE,MAINJRDESC,CONTHOURS,AVGHOURS,' + 'NMCREG,NURSESPEC,AMHP,SCQUAL,NONSCQUAL,QUALACH01,QUALACH01NOTES,' + 'QUALACH02,QUALACH02NOTES,QUALACH03,QUALACH03NOTES'; From 8a0fe4efaba0e68aca5b0c7455bbe4adfe439abd Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Thu, 29 Aug 2024 12:13:03 +0100 Subject: [PATCH 30/53] add level2 care cert to toAPI() --- lambdas/bulkUpload/classes/workerCSVValidator.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index 8e7aa79355..1131181165 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -2981,6 +2981,7 @@ class WorkerCsvValidator { employedFromOutsideUk: this._employedFromOutsideUk ? this._employedFromOutsideUk : undefined, disability: this._disabled ? this._disabled : undefined, careCertificate: this._careCert ? this._careCert : undefined, + level2CareCertificate: this._level2CareCert ? this._level2CareCert : undefined, apprenticeshipTraining: this._apprentice ? this._apprentice : undefined, zeroHoursContract: this._zeroHourContract ? this._zeroHourContract : undefined, registeredNurse: this._registeredNurse ? this._registeredNurse : undefined, From a404bdc1574a4c18e8f8a71b0c72a08001cd0bc8 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Thu, 29 Aug 2024 13:15:07 +0100 Subject: [PATCH 31/53] bugfix --- lambdas/bulkUpload/classes/workerCSVValidator.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index 1131181165..0c86a3e00d 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -1234,7 +1234,7 @@ class WorkerCsvValidator { const level2CareCertValues = [1, 2, 3]; const myLevel2CareCert = parseInt(this._currentLine.L2CARECERT, 10); - if (this._currentLine.CARECERT && this._currentLine.CARECERT.length > 0) { + if (this._currentLine.L2CARECERT && this._currentLine.L2CARECERT.length > 0) { if (isNaN(myLevel2CareCert) || !level2CareCertValues.includes(myLevel2CareCert)) { const warning = this._generateWarning( 'The code you have entered for L2CARECERT is incorrect and will be ignored', @@ -2899,6 +2899,7 @@ class WorkerCsvValidator { value: this._careCert, } : undefined, + level2CareCertificate: this._level2CareCert ? { value: this._level2CareCert } : undefined, recruitmentSource: this._recSource ? this._recSource : undefined, startDate: this._startDate ? this._startDate.format('DD/MM/YYYY') : undefined, startedInSector: this._startInsect ? this._startInsect : undefined, @@ -2981,7 +2982,7 @@ class WorkerCsvValidator { employedFromOutsideUk: this._employedFromOutsideUk ? this._employedFromOutsideUk : undefined, disability: this._disabled ? this._disabled : undefined, careCertificate: this._careCert ? this._careCert : undefined, - level2CareCertificate: this._level2CareCert ? this._level2CareCert : undefined, + level2CareCertificate: this._level2CareCert ? { value: this._level2CareCert } : undefined, apprenticeshipTraining: this._apprentice ? this._apprentice : undefined, zeroHoursContract: this._zeroHourContract ? this._zeroHourContract : undefined, registeredNurse: this._registeredNurse ? this._registeredNurse : undefined, From cd1e9b7d548eb07e07605cf9ef7ed20996049e61 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Thu, 29 Aug 2024 14:48:52 +0100 Subject: [PATCH 32/53] Update workerProperties and added tests --- backend/server/models/classes/worker.js | 9 --- .../level2CareCertificateProperty.js | 7 ++- .../models/classes/worker/workerProperties.js | 2 +- .../test/unit/models/classes/worker.spec.js | 62 +++++++++++++++++++ 4 files changed, 68 insertions(+), 12 deletions(-) diff --git a/backend/server/models/classes/worker.js b/backend/server/models/classes/worker.js index b53f84a511..a66fe9429e 100644 --- a/backend/server/models/classes/worker.js +++ b/backend/server/models/classes/worker.js @@ -1728,15 +1728,6 @@ class Worker extends EntityValidator { .toJSON(false, true, WdfCalculator.effectiveDate), }; - myWdf.level2CareCertificate = { - isEligible: this._isPropertyWdfBasicEligible(effectiveFromEpoch, this._properties.get('Level2CareCertificate')) - ? 'Yes' - : 'No', - updatedSinceEffectiveDate: this._properties - .get('Level2CareCertificate') - .toJSON(false, true, WdfCalculator.effectiveDate), - }; - myWdf.qualificationInSocialCare = { isEligible: this._isPropertyWdfBasicEligible( effectiveFromEpoch, diff --git a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js index 8f1c342255..c5c21d584e 100644 --- a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js +++ b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js @@ -2,13 +2,16 @@ const ChangePropertyPrototype = require('../../properties/changePrototype').ChangePropertyPrototype; const LEVEL_2_CARE_CERTIFICATE_TYPE = ['Yes, completed', 'Yes, started', 'No']; -exports.Level2CareCertificateProperty = class Level2CareCertificateProperty extends ChangePropertyPrototype { +exports.WorkerLevel2CareCertificateProperty = class WorkerLevel2CareCertificateProperty extends ( + ChangePropertyPrototype +) { constructor() { super('Level2CareCertificate'); + this._allowNull = true; } static clone() { - return new Level2CareCertificateProperty(); + return new WorkerLevel2CareCertificateProperty(); } // concrete implementations diff --git a/backend/server/models/classes/worker/workerProperties.js b/backend/server/models/classes/worker/workerProperties.js index 3bbf9e0487..fd08b7994c 100644 --- a/backend/server/models/classes/worker/workerProperties.js +++ b/backend/server/models/classes/worker/workerProperties.js @@ -49,7 +49,7 @@ const longTermAbsenceProperty = require('./properties/longTermAbsenceProperty'). const healthAndCareVisaProperty = require('./properties/healthAndCareVisa').HealthAndCareVisaProperty; const employedFromOutsideUkProperty = require('./properties/employedFromOutsideUk').EmployedFromOutsideUkProperty; const level2CareCertificateProperty = - require('./properties/level2CareCertificateProperty').Level2CareCertificateProperty; + require('./properties/level2CareCertificateProperty').WorkerLevel2CareCertificateProperty; class WorkerPropertyManager { constructor() { diff --git a/backend/server/test/unit/models/classes/worker.spec.js b/backend/server/test/unit/models/classes/worker.spec.js index 47776de0ac..7762c2ebda 100644 --- a/backend/server/test/unit/models/classes/worker.spec.js +++ b/backend/server/test/unit/models/classes/worker.spec.js @@ -369,6 +369,68 @@ describe('Worker Class', () => { expect(document).to.deep.equal({ healthAndCareVisa: 'Yes' }); }); }); + + describe('Level 2 care certificate', () => { + it('should not set year to null if value is "Yes, completed" and there is a year value', async () => { + const document = { + level2CareCertificate: { + value: 'Yes, completed', + year: 2024, + }, + }; + + await worker.load(document); + + expect(document.level2CareCertificate).to.deep.equal({ + value: 'Yes, completed', + year: 2024, + }); + }); + + it('should not set year to null if value is "Yes, completed" and no year', async () => { + const document = { + level2CareCertificate: { + value: 'Yes, completed', + }, + }; + + await worker.load(document); + + expect(document.level2CareCertificate).to.deep.equal({ + value: 'Yes, completed', + }); + }); + + it('should set year to null if value is "Yes, started"', async () => { + const document = { + level2CareCertificate: { + value: 'Yes, started', + }, + }; + + await worker.load(document); + + expect(document.level2CareCertificate).to.deep.equal({ + value: 'Yes, started', + year: null, + }); + }); + + it('should set year to null if value is "No"', async () => { + const document = { + level2CareCertificate: { + value: 'No', + }, + }; + + await worker.load(document); + + expect(document.level2CareCertificate).to.deep.equal({ + value: 'No', + year: null, + }); + }); + }); }); describe('setWdfProperties()', async () => { From f25080925c424f302f0d9be6aac931f7cf63e351 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Thu, 29 Aug 2024 15:46:28 +0100 Subject: [PATCH 33/53] Update level2CareCertificateProperty logic --- .../level2CareCertificateProperty.js | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js index c5c21d584e..8f114275ea 100644 --- a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js +++ b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js @@ -16,16 +16,21 @@ exports.WorkerLevel2CareCertificateProperty = class WorkerLevel2CareCertificateP // concrete implementations async restoreFromJson(document) { - const yearLevel2CareCertificateIntroduced = 2024; + const completedInYearSinceLevel2CareCertIntroduced = (year) => { + const yearLevel2CareCertificateIntroduced = 2024; + const thisYear = new Date().getFullYear(); + return year >= yearLevel2CareCertificateIntroduced && document.level2CareCertificate.year < thisYear + ? true + : false; + }; + if (document.level2CareCertificate) { if (LEVEL_2_CARE_CERTIFICATE_TYPE.includes(document.level2CareCertificate.value)) { if (document.level2CareCertificate.value === 'Yes, completed') { - const thisYear = new Date().getFullYear(); if ( document.level2CareCertificate.year && Number.isInteger(document.level2CareCertificate.year) && - document.level2CareCertificate.year >= yearLevel2CareCertificateIntroduced && - document.level2CareCertificate.year < thisYear + 1 + completedInYearSinceLevel2CareCertIntroduced(document.level2CareCertificate.year) ) { this.property = { value: document.level2CareCertificate.value, @@ -66,15 +71,18 @@ exports.WorkerLevel2CareCertificateProperty = class WorkerLevel2CareCertificateP } isEqual(currentValue, newValue) { - // Level 2 Care Certificate is a simple (enum'd) string - return currentValue && newValue && currentValue === newValue; - } - - toJSON(withHistory = false, showPropertyHistoryOnly = true, wdfEffectiveDate = false) { - if (wdfEffectiveDate) { - return this._savedAt ? this._savedAt > wdfEffectiveDate : false; + // not a simple (enum'd) string compare; if "Yes, completed", also need to compare the year (just an integer) + let yearEqual = false; + if (currentValue && newValue && currentValue.value === 'Yes, completed') { + if (currentValue.year && newValue.year && currentValue.year === newValue.year) yearEqual = true; + } else { + yearEqual = true; } + return currentValue && newValue && currentValue.value === newValue.value && yearEqual; + } + + toJSON(withHistory = false, showPropertyHistoryOnly = true) { if (!withHistory) { // simple form return { From d903785388394bbea3be365fc904acec3b4e86a0 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Thu, 29 Aug 2024 15:47:09 +0100 Subject: [PATCH 34/53] Update answersAvailable to an array --- ...el-2-adult-social-care-certificate.component.html | 12 ++++++------ ...evel-2-adult-social-care-certificate.component.ts | 6 +----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html index f72d723703..f5e99e3200 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.html @@ -38,11 +38,11 @@

id="level2CareCertificate-yesCompleted" name="level2CareCertificate" type="radio" - [value]="answersAvailable[0].value" + [value]="answersAvailable[0]" data-aria-controls="conditional-certification-achieved" />

@@ -83,10 +83,10 @@

id="level2CareCertificate-yesStarted" name="level2CareCertificate" type="radio" - [value]="answersAvailable[1].value" + [value]="answersAvailable[1]" />

@@ -96,10 +96,10 @@

id="level2CareCertificate-no" name="level2CareCertificate" type="radio" - [value]="answersAvailable[2].value" + [value]="answersAvailable[2]" />

diff --git a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts index 574a0a1012..10ef395367 100644 --- a/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts +++ b/frontend/src/app/features/workers/level-2-adult-social-care-certificate/level-2-adult-social-care-certificate.component.ts @@ -13,11 +13,7 @@ import dayjs from 'dayjs'; templateUrl: './level-2-adult-social-care-certificate.component.html', }) export class Level2AdultSocialCareCertificateComponent extends QuestionComponent { - public answersAvailable = [ - { value: 'Yes, completed', tag: 'Yes, completed' }, - { value: 'Yes, started', tag: 'Yes, started' }, - { value: 'No', tag: 'No' }, - ]; + public answersAvailable = ['Yes, completed', 'Yes, started', 'No']; public section = 'Training and qualifications'; From d58572a7e8070113e0638f28892a0a83d7ba641f Mon Sep 17 00:00:00 2001 From: Sabrina Date: Thu, 29 Aug 2024 15:50:30 +0100 Subject: [PATCH 35/53] Update check on property --- .../classes/worker/properties/level2CareCertificateProperty.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js index 8f114275ea..7bd7e1d1cc 100644 --- a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js +++ b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js @@ -19,7 +19,7 @@ exports.WorkerLevel2CareCertificateProperty = class WorkerLevel2CareCertificateP const completedInYearSinceLevel2CareCertIntroduced = (year) => { const yearLevel2CareCertificateIntroduced = 2024; const thisYear = new Date().getFullYear(); - return year >= yearLevel2CareCertificateIntroduced && document.level2CareCertificate.year < thisYear + return year >= yearLevel2CareCertificateIntroduced && document.level2CareCertificate.year <= thisYear ? true : false; }; From c8683c3bb35d39dd084a3109b01283b870bbd86d Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Thu, 29 Aug 2024 17:06:12 +0100 Subject: [PATCH 36/53] start adding logic to handle l2 care cert year in bulk upload --- lambdas/bulkUpload/classes/workerCSVValidator.js | 9 ++++++--- .../test/unit/classes/workerCSVValidator.spec.js | 13 +++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index 0c86a3e00d..764fc3892b 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -1232,7 +1232,10 @@ class WorkerCsvValidator { _validateLevel2CareCert() { const level2CareCertValues = [1, 2, 3]; - const myLevel2CareCert = parseInt(this._currentLine.L2CARECERT, 10); + + const [valueString, yearString] = this._currentLine.L2CARECERT.split(';'); + + const myLevel2CareCert = parseInt(valueString, 10); if (this._currentLine.L2CARECERT && this._currentLine.L2CARECERT.length > 0) { if (isNaN(myLevel2CareCert) || !level2CareCertValues.includes(myLevel2CareCert)) { @@ -1248,10 +1251,10 @@ class WorkerCsvValidator { this._level2CareCert = 'Yes, completed'; break; case 2: - this._level2CareCert = 'Yes, started'; + this._level2CareCert = { value: 'Yes, started', year: null }; break; case 3: - this._level2CareCert = 'No'; + this._level2CareCert = { value: 'No', year: null }; break; } return true; diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index b193a5bf85..d20e9ff155 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -66,7 +66,7 @@ const buildWorkerRecord = build('WorkerRecord', { }, }); -describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { +describe.only('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { describe('validations', () => { describe('days sick', () => { it('should emit a warning when days sick not already changed today', async () => { @@ -1224,11 +1224,12 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { }); }); - describe('_validateLevel2CareCert()', () => { + describe.only('_validateLevel2CareCert()', () => { [ - { l2CareCert: '1', mapping: 'Yes, completed' }, - { l2CareCert: '2', mapping: 'Yes, started' }, - { l2CareCert: '3', mapping: 'No' }, + { l2CareCert: '1;', mapping: { value: 'Yes, completed', year: null } }, + { l2CareCert: '1;2024', mapping: { value: 'Yes, completed', year: 2024 } }, + { l2CareCert: '2;', mapping: { value: 'Yes, started', year: null } }, + { l2CareCert: '3;', mapping: { value: 'No', year: null } }, ].forEach((answer) => { it(`should not add warning when valid (${answer.l2CareCert}) level 2 care certificate value provided`, async () => { const worker = buildWorkerCsv({ @@ -1258,7 +1259,7 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { validator.validate(); validator.transform(); - expect(validator._level2CareCert).to.equal(answer.mapping); + expect(validator._level2CareCert).to.deep.equal(answer.mapping); }); }); From c8e69d3fc1a7b37b6bd10eb0fff64a9077b38f20 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Fri, 30 Aug 2024 09:41:29 +0100 Subject: [PATCH 37/53] pass happy path unit tests for level2 care cert year parsing --- lambdas/bulkUpload/classes/workerCSVValidator.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index 764fc3892b..383bc910f2 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -1236,6 +1236,7 @@ class WorkerCsvValidator { const [valueString, yearString] = this._currentLine.L2CARECERT.split(';'); const myLevel2CareCert = parseInt(valueString, 10); + const myLevel2CareCertYear = parseInt(yearString, 10) || null; if (this._currentLine.L2CARECERT && this._currentLine.L2CARECERT.length > 0) { if (isNaN(myLevel2CareCert) || !level2CareCertValues.includes(myLevel2CareCert)) { @@ -1248,7 +1249,7 @@ class WorkerCsvValidator { } else { switch (myLevel2CareCert) { case 1: - this._level2CareCert = 'Yes, completed'; + this._level2CareCert = { value: 'Yes, completed', year: myLevel2CareCertYear }; break; case 2: this._level2CareCert = { value: 'Yes, started', year: null }; From 7c92b924088e8cbb6a39990d941369fc1ab6c7f7 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Fri, 30 Aug 2024 11:30:41 +0100 Subject: [PATCH 38/53] add logic to ignore the input when option 2 or 3 is provided with a year --- .../bulkUpload/classes/workerCSVValidator.js | 17 +- .../unit/classes/workerCSVValidator.spec.js | 169 ++++++++++++------ 2 files changed, 132 insertions(+), 54 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index 383bc910f2..f8b88b2b7a 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -1236,7 +1236,15 @@ class WorkerCsvValidator { const [valueString, yearString] = this._currentLine.L2CARECERT.split(';'); const myLevel2CareCert = parseInt(valueString, 10); - const myLevel2CareCertYear = parseInt(yearString, 10) || null; + + const parseAndValidateYear = (yearString) => { + const yearLevel2CareCertificateIntroduced = 2024; + const parsedYear = parseInt(yearString, 10); + + return parsedYear >= yearLevel2CareCertificateIntroduced ? parsedYear : null; + }; + + const myLevel2CareCertYear = parseAndValidateYear(yearString); // parseInt(yearString, 10) || null; if (this._currentLine.L2CARECERT && this._currentLine.L2CARECERT.length > 0) { if (isNaN(myLevel2CareCert) || !level2CareCertValues.includes(myLevel2CareCert)) { @@ -1246,6 +1254,13 @@ class WorkerCsvValidator { ); this._validationErrors.push(warning); return false; + } else if ([2, 3].includes(myLevel2CareCert) && yearString) { + const warning = this._generateWarning( + 'Dummy msg: Option 2 or 3 for L2CARECERT cannot have a year, your input will be ignored', + 'L2CARECERT', + ); + this._validationErrors.push(warning); + return false; } else { switch (myLevel2CareCert) { case 1: diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index d20e9ff155..cbaeece803 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -1225,71 +1225,134 @@ describe.only('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { }); describe.only('_validateLevel2CareCert()', () => { - [ - { l2CareCert: '1;', mapping: { value: 'Yes, completed', year: null } }, - { l2CareCert: '1;2024', mapping: { value: 'Yes, completed', year: 2024 } }, - { l2CareCert: '2;', mapping: { value: 'Yes, started', year: null } }, - { l2CareCert: '3;', mapping: { value: 'No', year: null } }, - ].forEach((answer) => { - it(`should not add warning when valid (${answer.l2CareCert}) level 2 care certificate value provided`, async () => { - const worker = buildWorkerCsv({ - overrides: { - STATUS: 'NEW', - L2CARECERT: answer.l2CareCert, - }, + describe('Valid inputs', () => { + [ + { l2CareCert: '1;', mapping: { value: 'Yes, completed', year: null } }, + { l2CareCert: '1;2024', mapping: { value: 'Yes, completed', year: 2024 } }, + { l2CareCert: '2;', mapping: { value: 'Yes, started', year: null } }, + { l2CareCert: '3;', mapping: { value: 'No', year: null } }, + ].forEach((answer) => { + it(`should not add warning when valid (${answer.l2CareCert}) level 2 care certificate value provided`, async () => { + const worker = buildWorkerCsv({ + overrides: { + STATUS: 'NEW', + L2CARECERT: answer.l2CareCert, + }, + }); + const validator = new WorkerCsvValidator(worker, 2, null, mappings); + + validator.validate(); + validator.transform(); + + expect(validator._validationErrors).to.deep.equal([]); + expect(validator._validationErrors.length).to.equal(0); }); - const validator = new WorkerCsvValidator(worker, 2, null, mappings); - validator.validate(); - validator.transform(); + it(`should set level 2 care certificate value field with database mapping (${JSON.stringify( + answer.mapping, + )}) when valid (${answer.l2CareCert}) L2CARECERT provided`, () => { + const worker = buildWorkerCsv({ + overrides: { + STATUS: 'NEW', + L2CARECERT: answer.l2CareCert, + }, + }); + const validator = new WorkerCsvValidator(worker, 2, null, mappings); - expect(validator._validationErrors).to.deep.equal([]); - expect(validator._validationErrors.length).to.equal(0); - }); + validator.validate(); + validator.transform(); - it(`should set level 2 care certificate value field with database mapping (${answer.mapping}) when valid (${answer.l2CareCert}) L2CARECERT provided`, () => { - const worker = buildWorkerCsv({ - overrides: { - STATUS: 'NEW', - L2CARECERT: answer.l2CareCert, - }, + expect(validator._level2CareCert).to.deep.equal(answer.mapping); }); - const validator = new WorkerCsvValidator(worker, 2, null, mappings); + }); + }); - validator.validate(); - validator.transform(); + describe('Partially accepted inputs', () => { + // TODO: warning message about ignoring the year input + const testCasesWithInvalidYears = ['1;2000', '1;2023']; + testCasesWithInvalidYears.forEach((l2CareCertInput) => { + it(`given a valid value but incorrect year: (${l2CareCertInput}), ignore the year`, () => { + const expected = { value: 'Yes, completed', year: null }; + + const worker = buildWorkerCsv({ + overrides: { + STATUS: 'NEW', + L2CARECERT: l2CareCertInput, + }, + }); + + const validator = new WorkerCsvValidator(worker, 2, null, mappings); + + validator.validate(); + validator.transform(); - expect(validator._level2CareCert).to.deep.equal(answer.mapping); + expect(validator._level2CareCert).to.deep.equal(expected); + }); }); }); - - it('should add warning when the L2CARECERT value is invalid', async () => { - const invalidLevel2CareCertValue = '12345'; - const worker = buildWorkerCsv({ - overrides: { - STATUS: 'NEW', - L2CARECERT: invalidLevel2CareCertValue, - }, + describe('Invalid inputs', () => { + const invalidInputs = ['12345', '12345;2024']; + invalidInputs.forEach((invalidLevel2CareCertValue) => { + it(`should add warning when the L2CARECERT value is invalid: (${invalidLevel2CareCertValue})`, async () => { + const worker = buildWorkerCsv({ + overrides: { + STATUS: 'NEW', + L2CARECERT: invalidLevel2CareCertValue, + }, + }); + const expectedWarning = { + column: 'L2CARECERT', + lineNumber: 2, + name: 'MARMA', + source: invalidLevel2CareCertValue, + warnCode: WorkerCsvValidator.L2CARECERT_WARNING, + warnType: 'L2CARECERT_WARNING', + warning: 'The code you have entered for L2CARECERT is incorrect and will be ignored', + worker: '3', + }; + + const validator = new WorkerCsvValidator(worker, 2, null, mappings); + + validator.validate(); + validator.transform(); + + expect(validator._validationErrors).to.deep.equal([expectedWarning]); + expect(validator._validationErrors.length).to.equal(1); + expect(validator._level2CareCert).to.equal(null); + }); }); - const expectedWarning = { - column: 'L2CARECERT', - lineNumber: 2, - name: 'MARMA', - source: '12345', - warnCode: WorkerCsvValidator.L2CARECERT_WARNING, - warnType: 'L2CARECERT_WARNING', - warning: 'The code you have entered for L2CARECERT is incorrect and will be ignored', - worker: '3', - }; - - const validator = new WorkerCsvValidator(worker, 2, null, mappings); - validator.validate(); - validator.transform(); + const invalidInputsWithYear = ['2;2024', '3;2024', '2;2000', '3;2000']; - expect(validator._validationErrors).to.deep.equal([expectedWarning]); - expect(validator._validationErrors.length).to.equal(1); - expect(validator._level2CareCert).to.equal(null); + invalidInputsWithYear.forEach((invalidLevel2CareCertValue) => { + it(`should add warning and ignore the whole input when option 2 or 3 are given with a year: (${invalidLevel2CareCertValue})`, () => { + const worker = buildWorkerCsv({ + overrides: { + STATUS: 'NEW', + L2CARECERT: invalidLevel2CareCertValue, + }, + }); + const expectedWarning = { + column: 'L2CARECERT', + lineNumber: 2, + name: 'MARMA', + source: invalidLevel2CareCertValue, + warnCode: WorkerCsvValidator.L2CARECERT_WARNING, + warnType: 'L2CARECERT_WARNING', + warning: 'Dummy msg: Option 2 or 3 for L2CARECERT cannot have a year, your input will be ignored', + worker: '3', + }; + + const validator = new WorkerCsvValidator(worker, 2, null, mappings); + + validator.validate(); + validator.transform(); + + expect(validator._validationErrors).to.deep.equal([expectedWarning]); + expect(validator._validationErrors.length).to.equal(1); + expect(validator._level2CareCert).to.equal(null); + }); + }); }); }); }); From cf9ee312bad6eb72d22db1bd081ea571de806460 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Fri, 30 Aug 2024 11:41:30 +0100 Subject: [PATCH 39/53] refactor code to reduce if-else nesting --- .../bulkUpload/classes/workerCSVValidator.js | 71 ++++++++++--------- .../unit/classes/workerCSVValidator.spec.js | 1 + 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index f8b88b2b7a..3ef3491170 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -1231,51 +1231,54 @@ class WorkerCsvValidator { } _validateLevel2CareCert() { - const level2CareCertValues = [1, 2, 3]; + const allowedLevel2CareCertValues = [1, 2, 3]; + const yearLevel2CareCertificateIntroduced = 2024; + + const inputIsEmpty = !(this._currentLine.L2CARECERT && this._currentLine.L2CARECERT.length > 0); + + if (inputIsEmpty) { + return true; + } const [valueString, yearString] = this._currentLine.L2CARECERT.split(';'); + const myLevel2CareCertValue = parseInt(valueString, 10); + const inputValueIsInvalid = !allowedLevel2CareCertValues.includes(myLevel2CareCertValue); - const myLevel2CareCert = parseInt(valueString, 10); + if (inputValueIsInvalid) { + const warning = this._generateWarning( + 'The code you have entered for L2CARECERT is incorrect and will be ignored', + 'L2CARECERT', + ); + this._validationErrors.push(warning); + return false; + } const parseAndValidateYear = (yearString) => { - const yearLevel2CareCertificateIntroduced = 2024; const parsedYear = parseInt(yearString, 10); return parsedYear >= yearLevel2CareCertificateIntroduced ? parsedYear : null; }; + const myLevel2CareCertYear = parseAndValidateYear(yearString); - const myLevel2CareCertYear = parseAndValidateYear(yearString); // parseInt(yearString, 10) || null; - - if (this._currentLine.L2CARECERT && this._currentLine.L2CARECERT.length > 0) { - if (isNaN(myLevel2CareCert) || !level2CareCertValues.includes(myLevel2CareCert)) { - const warning = this._generateWarning( - 'The code you have entered for L2CARECERT is incorrect and will be ignored', - 'L2CARECERT', - ); - this._validationErrors.push(warning); - return false; - } else if ([2, 3].includes(myLevel2CareCert) && yearString) { - const warning = this._generateWarning( - 'Dummy msg: Option 2 or 3 for L2CARECERT cannot have a year, your input will be ignored', - 'L2CARECERT', - ); - this._validationErrors.push(warning); - return false; - } else { - switch (myLevel2CareCert) { - case 1: - this._level2CareCert = { value: 'Yes, completed', year: myLevel2CareCertYear }; - break; - case 2: - this._level2CareCert = { value: 'Yes, started', year: null }; - break; - case 3: - this._level2CareCert = { value: 'No', year: null }; - break; - } - return true; - } + if ([2, 3].includes(myLevel2CareCertValue) && yearString) { + const warning = this._generateWarning( + 'Dummy msg: Option 2 or 3 for L2CARECERT cannot have a year, your input will be ignored', + 'L2CARECERT', + ); + this._validationErrors.push(warning); + return false; } else { + switch (myLevel2CareCertValue) { + case 1: + this._level2CareCert = { value: 'Yes, completed', year: myLevel2CareCertYear }; + break; + case 2: + this._level2CareCert = { value: 'Yes, started', year: null }; + break; + case 3: + this._level2CareCert = { value: 'No', year: null }; + break; + } return true; } } diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index cbaeece803..1e0f0f992b 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -1290,6 +1290,7 @@ describe.only('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { }); }); }); + describe('Invalid inputs', () => { const invalidInputs = ['12345', '12345;2024']; invalidInputs.forEach((invalidLevel2CareCertValue) => { From f438c598ff7b93e2cb9a092d6944c3e8d21e40dd Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Fri, 30 Aug 2024 12:28:52 +0100 Subject: [PATCH 40/53] refactor to reduce nesting, add error message when given year is before 2024 --- .../bulkUpload/classes/workerCSVValidator.js | 73 +++++++++++++------ .../unit/classes/workerCSVValidator.spec.js | 51 ++++++++++--- 2 files changed, 91 insertions(+), 33 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index 3ef3491170..e79439aaf9 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -1242,9 +1242,8 @@ class WorkerCsvValidator { const [valueString, yearString] = this._currentLine.L2CARECERT.split(';'); const myLevel2CareCertValue = parseInt(valueString, 10); - const inputValueIsInvalid = !allowedLevel2CareCertValues.includes(myLevel2CareCertValue); - if (inputValueIsInvalid) { + if (!allowedLevel2CareCertValues.includes(myLevel2CareCertValue)) { const warning = this._generateWarning( 'The code you have entered for L2CARECERT is incorrect and will be ignored', 'L2CARECERT', @@ -1256,30 +1255,58 @@ class WorkerCsvValidator { const parseAndValidateYear = (yearString) => { const parsedYear = parseInt(yearString, 10); - return parsedYear >= yearLevel2CareCertificateIntroduced ? parsedYear : null; + if (yearString === '') { + return { + myLevel2CareCertYear: null, + }; + } + + if (parsedYear < yearLevel2CareCertificateIntroduced) { + return { + myLevel2CareCertYear: null, + warningMessage: 'The year achieved for L2CARECERT cannot be before 2024. The year value will be ignored', + }; + } + return { myLevel2CareCertYear: parsedYear }; }; - const myLevel2CareCertYear = parseAndValidateYear(yearString); - if ([2, 3].includes(myLevel2CareCertValue) && yearString) { - const warning = this._generateWarning( - 'Dummy msg: Option 2 or 3 for L2CARECERT cannot have a year, your input will be ignored', - 'L2CARECERT', - ); - this._validationErrors.push(warning); - return false; - } else { - switch (myLevel2CareCertValue) { - case 1: - this._level2CareCert = { value: 'Yes, completed', year: myLevel2CareCertYear }; - break; - case 2: - this._level2CareCert = { value: 'Yes, started', year: null }; - break; - case 3: - this._level2CareCert = { value: 'No', year: null }; - break; + const { myLevel2CareCertYear, warningMessage } = parseAndValidateYear(yearString); + + if (myLevel2CareCertValue === 1) { + if (myLevel2CareCertYear === null) { + // value is correct but year is invalid + this._level2CareCert = { value: 'Yes, completed', year: null }; + if (warningMessage) { + const warning = this._generateWarning(warningMessage, 'L2CARECERT'); + this._validationErrors.push(warning); + return false; + } + return true; + } else { + this._level2CareCert = { value: 'Yes, completed', year: myLevel2CareCertYear }; + return true; + } + } + + if ([2, 3].includes(myLevel2CareCertValue)) { + if (yearString) { + const warning = this._generateWarning( + 'Dummy msg: Option 2 or 3 for L2CARECERT cannot have achieved year. Your input will be ignored', + 'L2CARECERT', + ); + this._validationErrors.push(warning); + return false; + } else { + switch (myLevel2CareCertValue) { + case 2: + this._level2CareCert = { value: 'Yes, started', year: null }; + break; + case 3: + this._level2CareCert = { value: 'No', year: null }; + break; + } + return true; } - return true; } } diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index 1e0f0f992b..3ef18d3fb5 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -1288,24 +1288,55 @@ describe.only('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { expect(validator._level2CareCert).to.deep.equal(expected); }); + + it('add a warning message about year being invalid', () => { + const worker = buildWorkerCsv({ + overrides: { + STATUS: 'NEW', + L2CARECERT: l2CareCertInput, + }, + }); + + const expectedParsedValue = { value: 'Yes, completed', year: null }; + + const expectedWarning = { + column: 'L2CARECERT', + lineNumber: 2, + name: 'MARMA', + source: l2CareCertInput, + warnCode: WorkerCsvValidator.L2CARECERT_WARNING, + warnType: 'L2CARECERT_WARNING', + warning: 'The year achieved for L2CARECERT cannot be before 2024. The year value will be ignored', + worker: '3', + }; + + const validator = new WorkerCsvValidator(worker, 2, null, mappings); + + validator.validate(); + validator.transform(); + + expect(validator._validationErrors).to.deep.equal([expectedWarning]); + expect(validator._validationErrors.length).to.equal(1); + expect(validator._level2CareCert).to.deep.equal(expectedParsedValue); + }); }); }); describe('Invalid inputs', () => { - const invalidInputs = ['12345', '12345;2024']; - invalidInputs.forEach((invalidLevel2CareCertValue) => { - it(`should add warning when the L2CARECERT value is invalid: (${invalidLevel2CareCertValue})`, async () => { + const invalidInputs = ['12345', '12345;2024', 'abc', 'abc;2024']; + invalidInputs.forEach((invalidLevel2CareCertInput) => { + it(`should add warning when the L2CARECERT value is invalid: (${invalidLevel2CareCertInput})`, async () => { const worker = buildWorkerCsv({ overrides: { STATUS: 'NEW', - L2CARECERT: invalidLevel2CareCertValue, + L2CARECERT: invalidLevel2CareCertInput, }, }); const expectedWarning = { column: 'L2CARECERT', lineNumber: 2, name: 'MARMA', - source: invalidLevel2CareCertValue, + source: invalidLevel2CareCertInput, warnCode: WorkerCsvValidator.L2CARECERT_WARNING, warnType: 'L2CARECERT_WARNING', warning: 'The code you have entered for L2CARECERT is incorrect and will be ignored', @@ -1325,22 +1356,22 @@ describe.only('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { const invalidInputsWithYear = ['2;2024', '3;2024', '2;2000', '3;2000']; - invalidInputsWithYear.forEach((invalidLevel2CareCertValue) => { - it(`should add warning and ignore the whole input when option 2 or 3 are given with a year: (${invalidLevel2CareCertValue})`, () => { + invalidInputsWithYear.forEach((invalidLevel2CareCertInput) => { + it(`should add warning and ignore the whole input when option 2 or 3 are given with achieved year: (${invalidLevel2CareCertInput})`, () => { const worker = buildWorkerCsv({ overrides: { STATUS: 'NEW', - L2CARECERT: invalidLevel2CareCertValue, + L2CARECERT: invalidLevel2CareCertInput, }, }); const expectedWarning = { column: 'L2CARECERT', lineNumber: 2, name: 'MARMA', - source: invalidLevel2CareCertValue, + source: invalidLevel2CareCertInput, warnCode: WorkerCsvValidator.L2CARECERT_WARNING, warnType: 'L2CARECERT_WARNING', - warning: 'Dummy msg: Option 2 or 3 for L2CARECERT cannot have a year, your input will be ignored', + warning: 'Dummy msg: Option 2 or 3 for L2CARECERT cannot have achieved year. Your input will be ignored', worker: '3', }; From 243f31a49de3a1cb77f5b3db7000cb82aa7e06cf Mon Sep 17 00:00:00 2001 From: Sabrina Date: Fri, 30 Aug 2024 12:58:39 +0100 Subject: [PATCH 41/53] Remove level2CareCertificate logic form worker class --- backend/server/models/classes/worker.js | 5 -- .../test/unit/models/classes/worker.spec.js | 62 ------------------- 2 files changed, 67 deletions(-) diff --git a/backend/server/models/classes/worker.js b/backend/server/models/classes/worker.js index a66fe9429e..d4df1905a0 100644 --- a/backend/server/models/classes/worker.js +++ b/backend/server/models/classes/worker.js @@ -397,11 +397,6 @@ class Worker extends EntityValidator { document.employedFromOutsideUk = null; } - // Remove year if level 2 care certificate isn't completed - if (document.level2CareCertificate && document.level2CareCertificate.value !== 'Yes, completed') { - document.level2CareCertificate.year = null; - } - // Remove year arrived if born in the UK or setting to Don't know if (document.countryOfBirth) { if (document.countryOfBirth.value === 'United Kingdom' || document.countryOfBirth.value === "Don't know") { diff --git a/backend/server/test/unit/models/classes/worker.spec.js b/backend/server/test/unit/models/classes/worker.spec.js index 7762c2ebda..47776de0ac 100644 --- a/backend/server/test/unit/models/classes/worker.spec.js +++ b/backend/server/test/unit/models/classes/worker.spec.js @@ -369,68 +369,6 @@ describe('Worker Class', () => { expect(document).to.deep.equal({ healthAndCareVisa: 'Yes' }); }); }); - - describe('Level 2 care certificate', () => { - it('should not set year to null if value is "Yes, completed" and there is a year value', async () => { - const document = { - level2CareCertificate: { - value: 'Yes, completed', - year: 2024, - }, - }; - - await worker.load(document); - - expect(document.level2CareCertificate).to.deep.equal({ - value: 'Yes, completed', - year: 2024, - }); - }); - - it('should not set year to null if value is "Yes, completed" and no year', async () => { - const document = { - level2CareCertificate: { - value: 'Yes, completed', - }, - }; - - await worker.load(document); - - expect(document.level2CareCertificate).to.deep.equal({ - value: 'Yes, completed', - }); - }); - - it('should set year to null if value is "Yes, started"', async () => { - const document = { - level2CareCertificate: { - value: 'Yes, started', - }, - }; - - await worker.load(document); - - expect(document.level2CareCertificate).to.deep.equal({ - value: 'Yes, started', - year: null, - }); - }); - - it('should set year to null if value is "No"', async () => { - const document = { - level2CareCertificate: { - value: 'No', - }, - }; - - await worker.load(document); - - expect(document.level2CareCertificate).to.deep.equal({ - value: 'No', - year: null, - }); - }); - }); }); describe('setWdfProperties()', async () => { From 668559409ae19d842d5b93b24c1ff9bac0040ac1 Mon Sep 17 00:00:00 2001 From: Sabrina Date: Fri, 30 Aug 2024 13:21:08 +0100 Subject: [PATCH 42/53] Refactor level2CareCertificateProperty and add tests --- .../level2CareCertificateProperty.js | 63 ++++--- .../level2CareCertificateProperty.spec.js | 154 ++++++++++++++++++ 2 files changed, 190 insertions(+), 27 deletions(-) create mode 100644 backend/server/test/unit/models/classes/worker/properties/level2CareCertificateProperty.spec.js diff --git a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js index 7bd7e1d1cc..2707bc6b4a 100644 --- a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js +++ b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js @@ -25,61 +25,70 @@ exports.WorkerLevel2CareCertificateProperty = class WorkerLevel2CareCertificateP }; if (document.level2CareCertificate) { - if (LEVEL_2_CARE_CERTIFICATE_TYPE.includes(document.level2CareCertificate.value)) { - if (document.level2CareCertificate.value === 'Yes, completed') { - if ( - document.level2CareCertificate.year && - Number.isInteger(document.level2CareCertificate.year) && - completedInYearSinceLevel2CareCertIntroduced(document.level2CareCertificate.year) - ) { - this.property = { - value: document.level2CareCertificate.value, - year: document.level2CareCertificate.year, - }; - } else if (!document.level2CareCertificate.year) { - this.property = { - value: document.level2CareCertificate.value, - year: null, - }; - } else { - this.property = null; - } + if ( + [LEVEL_2_CARE_CERTIFICATE_TYPE[1], LEVEL_2_CARE_CERTIFICATE_TYPE[2]].includes( + document.level2CareCertificate.value, + ) + ) { + this.property = { + value: document.level2CareCertificate.value, + year: null, + }; + return; + } + + if (document.level2CareCertificate.value === LEVEL_2_CARE_CERTIFICATE_TYPE[0]) { + if ( + document.level2CareCertificate.year && + Number.isInteger(document.level2CareCertificate.year) && + completedInYearSinceLevel2CareCertIntroduced(document.level2CareCertificate.year) + ) { + this.property = { + value: document.level2CareCertificate.value, + year: document.level2CareCertificate.year, + }; } else { this.property = { value: document.level2CareCertificate.value, + year: null, }; } + return; } - } else { this.property = null; } } restorePropertyFromSequelize(document) { - let level2CareCertificateDocument = { + let level2CareCertificate = { value: document.Level2CareCertificateValue, year: document.Level2CareCertificateYear, }; - return level2CareCertificateDocument; + return level2CareCertificate; } savePropertyToSequelize() { return { Level2CareCertificateValue: this.property.value, - Level2CareCertificateYear: this.property.value === 'Yes, completed' ? this.property.year : null, + Level2CareCertificateYear: + this.property.value === 'Yes, completed' && this.property.year ? this.property.year : null, }; } isEqual(currentValue, newValue) { // not a simple (enum'd) string compare; if "Yes, completed", also need to compare the year (just an integer) + let yearEqual = false; if (currentValue && newValue && currentValue.value === 'Yes, completed') { - if (currentValue.year && newValue.year && currentValue.year === newValue.year) yearEqual = true; - } else { - yearEqual = true; + if (currentValue.year && newValue.year && currentValue.year === newValue.year) { + yearEqual = true; + return currentValue && newValue && currentValue.value === newValue.value && yearEqual; + } + yearEqual = false; + return currentValue && newValue && currentValue.value === newValue.value && yearEqual; } - return currentValue && newValue && currentValue.value === newValue.value && yearEqual; + return currentValue && newValue && currentValue.value === newValue.value; } toJSON(withHistory = false, showPropertyHistoryOnly = true) { diff --git a/backend/server/test/unit/models/classes/worker/properties/level2CareCertificateProperty.spec.js b/backend/server/test/unit/models/classes/worker/properties/level2CareCertificateProperty.spec.js new file mode 100644 index 0000000000..c56b37b824 --- /dev/null +++ b/backend/server/test/unit/models/classes/worker/properties/level2CareCertificateProperty.spec.js @@ -0,0 +1,154 @@ +const expect = require('chai').expect; +const level2CareCertificatePropertyClass = + require('../../../../../../models/classes/worker/properties/level2CareCertificateProperty').WorkerLevel2CareCertificateProperty; + +const level2CareCertificateValues = [ + { value: 'Yes, completed', year: null }, + { value: 'Yes, completed', year: 2024 }, + { value: 'Yes, started' }, + { value: 'No' }, +]; + +const level2CareCertificateReturnedValues = [ + { value: 'Yes, completed', year: null }, + { value: 'Yes, completed', year: 2024 }, + { value: 'Yes, started', year: null }, + { value: 'No', year: null }, +]; + +describe('level2CareCertificate Property', () => { + describe('restoreFromJSON', async () => { + it("shouldn't return anything if undefined", async () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + const document = {}; + await level2CareCertificateProperty.restoreFromJson(document); + expect(level2CareCertificateProperty.property).to.deep.equal(null); + }); + + await Promise.all( + level2CareCertificateValues.map(async (level2CareCertificate, index) => { + it( + 'should return with correct value for ' + + level2CareCertificate.value + + ' and year ' + + level2CareCertificate?.year, + async () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + + const document = { + level2CareCertificate, + }; + await level2CareCertificateProperty.restoreFromJson(document); + expect(level2CareCertificateProperty.property).to.deep.equal(level2CareCertificateReturnedValues[index]); + }, + ); + }), + ); + }); + + describe('restorePropertyFromSequelize()', async () => { + it("shouldn't return anything if undefined", async () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + const document = {}; + const level2CareCertificate = await level2CareCertificateProperty.restorePropertyFromSequelize(document); + expect(level2CareCertificate).to.deep.equal({ value: undefined, year: undefined }); + }); + + await Promise.all( + level2CareCertificateValues.map(async (level2CareCertificate, index) => { + it( + 'should return with correct value for ' + + level2CareCertificate.value + + ' and year ' + + level2CareCertificate?.year, + async () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + + const document = { + Level2CareCertificateValue: level2CareCertificate.value, + Level2CareCertificateYear: level2CareCertificate.year ? level2CareCertificate.year : null, + }; + const level2CareCertificateProps = await level2CareCertificateProperty.restorePropertyFromSequelize( + document, + ); + expect(level2CareCertificateProps).to.deep.equal(level2CareCertificateReturnedValues[index]); + }, + ); + }), + ); + }); + + describe('savePropertyToSequelize', async () => { + await Promise.all( + level2CareCertificateValues.map(async (level2CareCertificate, index) => { + it( + 'should save in correct format as if saving into database for ' + + level2CareCertificate.value + + ' and year ' + + level2CareCertificate?.year, + async () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + + const document = { + Level2CareCertificateValue: level2CareCertificate.value, + Level2CareCertificateYear: level2CareCertificate.year ? level2CareCertificate.year : null, + }; + const level2CareCertificateProps = await level2CareCertificateProperty.restorePropertyFromSequelize( + document, + ); + expect(level2CareCertificateProps).to.deep.equal(level2CareCertificateReturnedValues[index]); + }, + ); + }), + ); + }); + + describe('isEqual()', () => { + it('should return true if the values are equal', () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + + const equal = level2CareCertificateProperty.isEqual( + level2CareCertificateValues[1], + level2CareCertificateReturnedValues[1], + ); + expect(equal).to.deep.equal(true); + }); + + it('should return false when there is a current year is but the new year sent is null', () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + const equal = level2CareCertificateProperty.isEqual( + level2CareCertificateValues[1], + level2CareCertificateReturnedValues[0], + ); + expect(equal).to.deep.equal(false); + }); + + it('should return false when there is no current year is but there is a new year sent', () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + const equal = level2CareCertificateProperty.isEqual( + level2CareCertificateValues[0], + level2CareCertificateValues[1], + ); + expect(equal).to.deep.equal(false); + }); + }); + + describe('toJSON()', () => { + level2CareCertificateValues.map((level2CCValue, index) => { + it( + 'should return correctly formatted JSON for ' + level2CCValue.value + ' and year ' + level2CCValue?.year, + () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + + const level2CareCertificate = { + year: level2CCValue.value, + value: level2CCValue.year ? level2CCValue.year : null, + }; + level2CareCertificateProperty.property = level2CareCertificate; + const json = level2CareCertificateProperty.toJSON(); + expect(json.level2CareCertificate).to.deep.equal(level2CareCertificate); + }, + ); + }); + }); +}); From b7545a024d407564183182aa4632b541ce7139ed Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Fri, 30 Aug 2024 14:13:17 +0100 Subject: [PATCH 43/53] finish the logic for handling year at _validateLevel2CareCert --- .../bulkUpload/classes/workerCSVValidator.js | 59 +++++++++---------- .../unit/classes/workerCSVValidator.spec.js | 36 +++++++++-- 2 files changed, 59 insertions(+), 36 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index e79439aaf9..ae6f20c250 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -1232,7 +1232,6 @@ class WorkerCsvValidator { _validateLevel2CareCert() { const allowedLevel2CareCertValues = [1, 2, 3]; - const yearLevel2CareCertificateIntroduced = 2024; const inputIsEmpty = !(this._currentLine.L2CARECERT && this._currentLine.L2CARECERT.length > 0); @@ -1252,46 +1251,19 @@ class WorkerCsvValidator { return false; } - const parseAndValidateYear = (yearString) => { - const parsedYear = parseInt(yearString, 10); - - if (yearString === '') { - return { - myLevel2CareCertYear: null, - }; - } - - if (parsedYear < yearLevel2CareCertificateIntroduced) { - return { - myLevel2CareCertYear: null, - warningMessage: 'The year achieved for L2CARECERT cannot be before 2024. The year value will be ignored', - }; - } - return { myLevel2CareCertYear: parsedYear }; - }; - - const { myLevel2CareCertYear, warningMessage } = parseAndValidateYear(yearString); - if (myLevel2CareCertValue === 1) { - if (myLevel2CareCertYear === null) { - // value is correct but year is invalid + if (yearString === '' || !yearString) { this._level2CareCert = { value: 'Yes, completed', year: null }; - if (warningMessage) { - const warning = this._generateWarning(warningMessage, 'L2CARECERT'); - this._validationErrors.push(warning); - return false; - } return true; } else { - this._level2CareCert = { value: 'Yes, completed', year: myLevel2CareCertYear }; - return true; + return this._handleLevel2CareCertCompleteWithAchievedYear(yearString); } } if ([2, 3].includes(myLevel2CareCertValue)) { if (yearString) { const warning = this._generateWarning( - 'Dummy msg: Option 2 or 3 for L2CARECERT cannot have achieved year. Your input will be ignored', + 'Option 2 or 3 for L2CARECERT cannot have achieved year. Your input will be ignored', 'L2CARECERT', ); this._validationErrors.push(warning); @@ -1310,6 +1282,31 @@ class WorkerCsvValidator { } } + _handleLevel2CareCertCompleteWithAchievedYear(yearString) { + const yearLevel2CareCertificateIntroduced = 2024; + const thisYear = new Date().getFullYear(); + const parsedYear = parseInt(yearString, 10); + let warningMessage; + + if (isNaN(parsedYear)) { + warningMessage = 'The year achieved for L2CARECERT is invalid. The year value will be ignored'; + } else if (parsedYear < yearLevel2CareCertificateIntroduced) { + warningMessage = 'The year achieved for L2CARECERT cannot be before 2024. The year value will be ignored'; + } else if (parsedYear > thisYear) { + warningMessage = 'The year achieved for L2CARECERT cannot be in the future. The year value will be ignored'; + } + + if (warningMessage) { + this._level2CareCert = { value: 'Yes, completed', year: null }; + const warning = this._generateWarning(warningMessage, 'L2CARECERT'); + this._validationErrors.push(warning); + return false; + } else { + this._level2CareCert = { value: 'Yes, completed', year: parsedYear }; + return true; + } + } + _validateRecSource() { const myRecSource = parseInt(this._currentLine.RECSOURCE, 10); diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index 3ef18d3fb5..963d2a45c2 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -1,5 +1,7 @@ const expect = require('chai').expect; +const { before, after } = require('mocha'); const moment = require('moment'); +const sinon = require('sinon'); const WorkerCsvValidator = require('../../../classes/workerCSVValidator').WorkerCsvValidator; const { build } = require('@jackfranklin/test-data-bot'); const mappings = require('../../../../../backend/reference/BUDIMappings').mappings; @@ -1225,12 +1227,25 @@ describe.only('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { }); describe.only('_validateLevel2CareCert()', () => { + let clock; + before(() => { + // stub current year as 2025 to test behavior related to year in future + clock = sinon.useFakeTimers(new Date(2025, 1, 1)); + }); + after(() => { + clock.restore(); + }); + describe('Valid inputs', () => { [ { l2CareCert: '1;', mapping: { value: 'Yes, completed', year: null } }, { l2CareCert: '1;2024', mapping: { value: 'Yes, completed', year: 2024 } }, + { l2CareCert: '1;2025', mapping: { value: 'Yes, completed', year: 2025 } }, { l2CareCert: '2;', mapping: { value: 'Yes, started', year: null } }, { l2CareCert: '3;', mapping: { value: 'No', year: null } }, + { l2CareCert: '1', mapping: { value: 'Yes, completed', year: null } }, + { l2CareCert: '2', mapping: { value: 'Yes, started', year: null } }, + { l2CareCert: '3', mapping: { value: 'No', year: null } }, ].forEach((answer) => { it(`should not add warning when valid (${answer.l2CareCert}) level 2 care certificate value provided`, async () => { const worker = buildWorkerCsv({ @@ -1268,9 +1283,20 @@ describe.only('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { }); describe('Partially accepted inputs', () => { - // TODO: warning message about ignoring the year input - const testCasesWithInvalidYears = ['1;2000', '1;2023']; - testCasesWithInvalidYears.forEach((l2CareCertInput) => { + const warningMessages = { + yearBefore2024: 'The year achieved for L2CARECERT cannot be before 2024. The year value will be ignored', + yearInFuture: 'The year achieved for L2CARECERT cannot be in the future. The year value will be ignored', + otherCase: 'The year achieved for L2CARECERT is invalid. The year value will be ignored', + }; + + const testCasesWithInvalidYears = [ + { l2CareCertInput: '1;2000', expectedWarningMessage: warningMessages.yearBefore2024 }, + { l2CareCertInput: '1;2023', expectedWarningMessage: warningMessages.yearBefore2024 }, + { l2CareCertInput: '1;2099', expectedWarningMessage: warningMessages.yearInFuture }, + { l2CareCertInput: '1;2026', expectedWarningMessage: warningMessages.yearInFuture }, + { l2CareCertInput: '1;abc', expectedWarningMessage: warningMessages.otherCase }, + ]; + testCasesWithInvalidYears.forEach(({ l2CareCertInput, expectedWarningMessage }) => { it(`given a valid value but incorrect year: (${l2CareCertInput}), ignore the year`, () => { const expected = { value: 'Yes, completed', year: null }; @@ -1306,7 +1332,7 @@ describe.only('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { source: l2CareCertInput, warnCode: WorkerCsvValidator.L2CARECERT_WARNING, warnType: 'L2CARECERT_WARNING', - warning: 'The year achieved for L2CARECERT cannot be before 2024. The year value will be ignored', + warning: expectedWarningMessage, worker: '3', }; @@ -1371,7 +1397,7 @@ describe.only('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { source: invalidLevel2CareCertInput, warnCode: WorkerCsvValidator.L2CARECERT_WARNING, warnType: 'L2CARECERT_WARNING', - warning: 'Dummy msg: Option 2 or 3 for L2CARECERT cannot have achieved year. Your input will be ignored', + warning: 'Option 2 or 3 for L2CARECERT cannot have achieved year. Your input will be ignored', worker: '3', }; From d0228c9777bf1e5d0c61e01934f958e7cee78236 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Fri, 30 Aug 2024 14:16:59 +0100 Subject: [PATCH 44/53] amend toAPI() and toJSON() to handle this._level2CareCert as an object --- lambdas/bulkUpload/classes/workerCSVValidator.js | 4 ++-- .../bulkUpload/test/unit/classes/workerCSVValidator.spec.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index ae6f20c250..f0b164ea6c 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -2945,7 +2945,7 @@ class WorkerCsvValidator { value: this._careCert, } : undefined, - level2CareCertificate: this._level2CareCert ? { value: this._level2CareCert } : undefined, + level2CareCertificate: this._level2CareCert?.value ? this._level2CareCert : undefined, recruitmentSource: this._recSource ? this._recSource : undefined, startDate: this._startDate ? this._startDate.format('DD/MM/YYYY') : undefined, startedInSector: this._startInsect ? this._startInsect : undefined, @@ -3028,7 +3028,7 @@ class WorkerCsvValidator { employedFromOutsideUk: this._employedFromOutsideUk ? this._employedFromOutsideUk : undefined, disability: this._disabled ? this._disabled : undefined, careCertificate: this._careCert ? this._careCert : undefined, - level2CareCertificate: this._level2CareCert ? { value: this._level2CareCert } : undefined, + level2CareCertificate: this._level2CareCert?.value ? this._level2CareCert : undefined, apprenticeshipTraining: this._apprentice ? this._apprentice : undefined, zeroHoursContract: this._zeroHourContract ? this._zeroHourContract : undefined, registeredNurse: this._registeredNurse ? this._registeredNurse : undefined, diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index 963d2a45c2..49da8bbf66 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -68,7 +68,7 @@ const buildWorkerRecord = build('WorkerRecord', { }, }); -describe.only('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { +describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { describe('validations', () => { describe('days sick', () => { it('should emit a warning when days sick not already changed today', async () => { @@ -1226,7 +1226,7 @@ describe.only('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { }); }); - describe.only('_validateLevel2CareCert()', () => { + describe('_validateLevel2CareCert()', () => { let clock; before(() => { // stub current year as 2025 to test behavior related to year in future From 5499fdc9e569482c6fb93516c5aa54d51e331330 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Fri, 30 Aug 2024 14:37:13 +0100 Subject: [PATCH 45/53] refactor _validateLevel2CareCert() --- .../bulkUpload/classes/workerCSVValidator.js | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index f0b164ea6c..5a2abc6c8b 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -1255,9 +1255,9 @@ class WorkerCsvValidator { if (yearString === '' || !yearString) { this._level2CareCert = { value: 'Yes, completed', year: null }; return true; - } else { - return this._handleLevel2CareCertCompleteWithAchievedYear(yearString); } + + return this._handleLevel2CareCertCompleteWithAchievedYear(yearString); } if ([2, 3].includes(myLevel2CareCertValue)) { @@ -1268,17 +1268,10 @@ class WorkerCsvValidator { ); this._validationErrors.push(warning); return false; - } else { - switch (myLevel2CareCertValue) { - case 2: - this._level2CareCert = { value: 'Yes, started', year: null }; - break; - case 3: - this._level2CareCert = { value: 'No', year: null }; - break; - } - return true; } + + this._level2CareCert = { value: myLevel2CareCertValue === 2 ? 'Yes, started' : 'No', year: null }; + return true; } } From de1562887d4beea938c9650ba1f2ceacfba2993a Mon Sep 17 00:00:00 2001 From: Sabrina Date: Fri, 30 Aug 2024 15:34:42 +0100 Subject: [PATCH 46/53] Refactor level2CareCertifcateProperty Co-authored-by: duncanc19 Co-authored-by: Joe Fong --- .../level2CareCertificateProperty.js | 9 ++-- .../level2CareCertificateProperty.spec.js | 52 ++++++++++++++++++- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js index 2707bc6b4a..222a81cb58 100644 --- a/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js +++ b/backend/server/models/classes/worker/properties/level2CareCertificateProperty.js @@ -78,14 +78,11 @@ exports.WorkerLevel2CareCertificateProperty = class WorkerLevel2CareCertificateP isEqual(currentValue, newValue) { // not a simple (enum'd) string compare; if "Yes, completed", also need to compare the year (just an integer) - let yearEqual = false; if (currentValue && newValue && currentValue.value === 'Yes, completed') { - if (currentValue.year && newValue.year && currentValue.year === newValue.year) { - yearEqual = true; - return currentValue && newValue && currentValue.value === newValue.value && yearEqual; + if (currentValue.year === newValue.year) { + return currentValue.value === newValue.value; } - yearEqual = false; - return currentValue && newValue && currentValue.value === newValue.value && yearEqual; + return false; } return currentValue && newValue && currentValue.value === newValue.value; diff --git a/backend/server/test/unit/models/classes/worker/properties/level2CareCertificateProperty.spec.js b/backend/server/test/unit/models/classes/worker/properties/level2CareCertificateProperty.spec.js index c56b37b824..3814abc5cb 100644 --- a/backend/server/test/unit/models/classes/worker/properties/level2CareCertificateProperty.spec.js +++ b/backend/server/test/unit/models/classes/worker/properties/level2CareCertificateProperty.spec.js @@ -104,7 +104,7 @@ describe('level2CareCertificate Property', () => { }); describe('isEqual()', () => { - it('should return true if the values are equal', () => { + it('should return true if the values are equal and the year is the same', () => { const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); const equal = level2CareCertificateProperty.isEqual( @@ -114,6 +114,56 @@ describe('level2CareCertificate Property', () => { expect(equal).to.deep.equal(true); }); + it('should return true if the values are equal and there is no year', () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + + const equal = level2CareCertificateProperty.isEqual( + level2CareCertificateValues[0], + level2CareCertificateReturnedValues[0], + ); + expect(equal).to.deep.equal(true); + }); + + it(`should return true if the values are the same when ${level2CareCertificateValues[2].value}`, () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + + const equal = level2CareCertificateProperty.isEqual( + level2CareCertificateValues[2], + level2CareCertificateReturnedValues[2], + ); + expect(equal).to.deep.equal(true); + }); + + it(`should return true if the values are the same when ${level2CareCertificateValues[3].value}`, () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + + const equal = level2CareCertificateProperty.isEqual( + level2CareCertificateValues[3], + level2CareCertificateReturnedValues[3], + ); + expect(equal).to.deep.equal(true); + }); + + it(`should return false if the values different (from ${level2CareCertificateValues[0].value} to ${level2CareCertificateReturnedValues[2].value})`, () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + + const equal = level2CareCertificateProperty.isEqual( + level2CareCertificateValues[0], + level2CareCertificateReturnedValues[2], + ); + expect(equal).to.deep.equal(false); + }); + + it(`should return false if the values different (from ${level2CareCertificateValues[0].value} to ${level2CareCertificateReturnedValues[3].value})`, () => { + const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); + + const equal = level2CareCertificateProperty.isEqual( + level2CareCertificateValues[0], + level2CareCertificateReturnedValues[3], + ); + expect(equal).to.deep.equal(false); + }); + it('should return false when there is a current year is but the new year sent is null', () => { const level2CareCertificateProperty = new level2CareCertificatePropertyClass(); const equal = level2CareCertificateProperty.isEqual( From 881087a02e27131173cae52cc26d88bf3a615c7a Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Fri, 30 Aug 2024 16:43:53 +0100 Subject: [PATCH 47/53] use different warn code for each warning case in L2CARECERT --- .../bulkUpload/classes/workerCSVValidator.js | 38 ++++++++++++++++++- .../unit/classes/workerCSVValidator.spec.js | 35 +++++++++++------ 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index 5a2abc6c8b..f0732078f2 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -363,6 +363,22 @@ class WorkerCsvValidator { return 5590; } + static get L2CARECERT_WARNING_IGNORE_YEAR() { + return 5600; + } + + static get L2CARECERT_WARNING_YEAR_BEFORE_2024() { + return 5610; + } + + static get L2CARECERT_WARNING_YEAR_IN_FUTURE() { + return 5620; + } + + static get L2CARECERT_WARNING_YEAR_INVALID() { + return 5630; + } + get lineNumber() { return this._lineNumber; } @@ -535,6 +551,19 @@ class WorkerCsvValidator { }; } + _generateWarningWithType(warning, columnName, warnType) { + return { + worker: this._currentLine.UNIQUEWORKERID, + name: this._currentLine.LOCALESTID, + lineNumber: this._lineNumber, + warnCode: WorkerCsvValidator[warnType], + warnType: warnType, + warning, + source: this._currentLine[columnName], + column: columnName, + }; + } + _validateContractType() { const myContractType = parseInt(this._currentLine.EMPLSTATUS, 10); @@ -1262,9 +1291,10 @@ class WorkerCsvValidator { if ([2, 3].includes(myLevel2CareCertValue)) { if (yearString) { - const warning = this._generateWarning( + const warning = this._generateWarningWithType( 'Option 2 or 3 for L2CARECERT cannot have achieved year. Your input will be ignored', 'L2CARECERT', + 'L2CARECERT_WARNING_IGNORE_YEAR', ); this._validationErrors.push(warning); return false; @@ -1280,18 +1310,22 @@ class WorkerCsvValidator { const thisYear = new Date().getFullYear(); const parsedYear = parseInt(yearString, 10); let warningMessage; + let warnType; if (isNaN(parsedYear)) { warningMessage = 'The year achieved for L2CARECERT is invalid. The year value will be ignored'; + warnType = 'L2CARECERT_WARNING_YEAR_INVALID'; } else if (parsedYear < yearLevel2CareCertificateIntroduced) { warningMessage = 'The year achieved for L2CARECERT cannot be before 2024. The year value will be ignored'; + warnType = 'L2CARECERT_WARNING_YEAR_BEFORE_2024'; } else if (parsedYear > thisYear) { warningMessage = 'The year achieved for L2CARECERT cannot be in the future. The year value will be ignored'; + warnType = 'L2CARECERT_WARNING_YEAR_IN_FUTURE'; } if (warningMessage) { this._level2CareCert = { value: 'Yes, completed', year: null }; - const warning = this._generateWarning(warningMessage, 'L2CARECERT'); + const warning = this._generateWarningWithType(warningMessage, 'L2CARECERT', warnType); this._validationErrors.push(warning); return false; } else { diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index 49da8bbf66..43fb720612 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -1288,15 +1288,28 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { yearInFuture: 'The year achieved for L2CARECERT cannot be in the future. The year value will be ignored', otherCase: 'The year achieved for L2CARECERT is invalid. The year value will be ignored', }; + const warnTypes = { + yearBefore2024: 'L2CARECERT_WARNING_YEAR_BEFORE_2024', + yearInFuture: 'L2CARECERT_WARNING_YEAR_IN_FUTURE', + otherCase: 'L2CARECERT_WARNING_YEAR_INVALID', + }; const testCasesWithInvalidYears = [ - { l2CareCertInput: '1;2000', expectedWarningMessage: warningMessages.yearBefore2024 }, - { l2CareCertInput: '1;2023', expectedWarningMessage: warningMessages.yearBefore2024 }, - { l2CareCertInput: '1;2099', expectedWarningMessage: warningMessages.yearInFuture }, - { l2CareCertInput: '1;2026', expectedWarningMessage: warningMessages.yearInFuture }, - { l2CareCertInput: '1;abc', expectedWarningMessage: warningMessages.otherCase }, + { + l2CareCertInput: '1;2000', + warningMessage: warningMessages.yearBefore2024, + warnType: warnTypes.yearBefore2024, + }, + { + l2CareCertInput: '1;2023', + warningMessage: warningMessages.yearBefore2024, + warnType: warnTypes.yearBefore2024, + }, + { l2CareCertInput: '1;2099', warningMessage: warningMessages.yearInFuture, warnType: warnTypes.yearInFuture }, + { l2CareCertInput: '1;2026', warningMessage: warningMessages.yearInFuture, warnType: warnTypes.yearInFuture }, + { l2CareCertInput: '1;abc', warningMessage: warningMessages.otherCase, warnType: warnTypes.otherCase }, ]; - testCasesWithInvalidYears.forEach(({ l2CareCertInput, expectedWarningMessage }) => { + testCasesWithInvalidYears.forEach(({ l2CareCertInput, warningMessage, warnType }) => { it(`given a valid value but incorrect year: (${l2CareCertInput}), ignore the year`, () => { const expected = { value: 'Yes, completed', year: null }; @@ -1330,9 +1343,9 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { lineNumber: 2, name: 'MARMA', source: l2CareCertInput, - warnCode: WorkerCsvValidator.L2CARECERT_WARNING, - warnType: 'L2CARECERT_WARNING', - warning: expectedWarningMessage, + warnCode: WorkerCsvValidator[warnType], + warnType: warnType, + warning: warningMessage, worker: '3', }; @@ -1395,8 +1408,8 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { lineNumber: 2, name: 'MARMA', source: invalidLevel2CareCertInput, - warnCode: WorkerCsvValidator.L2CARECERT_WARNING, - warnType: 'L2CARECERT_WARNING', + warnCode: WorkerCsvValidator.L2CARECERT_WARNING_IGNORE_YEAR, + warnType: 'L2CARECERT_WARNING_IGNORE_YEAR', warning: 'Option 2 or 3 for L2CARECERT cannot have achieved year. Your input will be ignored', worker: '3', }; From 17f9866d09580ea027f3bd41016805ebe0075654 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Mon, 2 Sep 2024 09:45:44 +0100 Subject: [PATCH 48/53] update workerCSV download to show semicolon and year in L2CARECERT --- .../bulkUpload/download/workerCSV.js | 10 +++++++--- .../bulkUpload/download/workerCSV.spec.js | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/backend/server/routes/establishments/bulkUpload/download/workerCSV.js b/backend/server/routes/establishments/bulkUpload/download/workerCSV.js index e1075b7b26..8fec43585c 100644 --- a/backend/server/routes/establishments/bulkUpload/download/workerCSV.js +++ b/backend/server/routes/establishments/bulkUpload/download/workerCSV.js @@ -179,13 +179,17 @@ const toCSV = (establishmentId, entity, MAX_QUALIFICATIONS, downloadType) => { let l2CareCert = ''; switch (entity.Level2CareCertificateValue) { case 'Yes, completed': - l2CareCert = 1; + if (entity.Level2CareCertificateYear) { + l2CareCert = `1;${entity.Level2CareCertificateYear}`; + } else { + l2CareCert = '1;'; + } break; case 'Yes, started': - l2CareCert = 2; + l2CareCert = '2;'; break; case 'No': - l2CareCert = 3; + l2CareCert = '3;'; break; } columns.push(l2CareCert); diff --git a/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js b/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js index 8bb0ad2faa..12dbdadb3a 100644 --- a/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js +++ b/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js @@ -310,12 +310,21 @@ describe('workerCSV', () => { }); [ - { name: 'Yes, completed', code: '1' }, - { name: 'Yes, started', code: '2' }, - { name: 'No', code: '3' }, + { name: 'Yes, completed', code: '1;' }, + { name: 'Yes, completed', year: 2024, code: '1;2024' }, + { name: 'Yes, started', code: '2;' }, + { name: 'No', code: '3;' }, ].forEach((level2CareCert) => { - it('should return the correct code for level 2 care certificate ' + level2CareCert.name, async () => { + let testName = 'should return the correct code for level 2 care certificate ' + level2CareCert.name; + if (level2CareCert.year) { + testName += ` with year: ${level2CareCert.year}`; + } + + it(testName, async () => { worker.Level2CareCertificateValue = level2CareCert.name; + if (level2CareCert.year) { + worker.Level2CareCertificateYear = level2CareCert.year; + } const csv = toCSV(establishment.LocalIdentifierValue, worker, 3); const csvAsArray = csv.split(','); From aa4fe061b46abd4c9561228caa495da00ef496b9 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Mon, 2 Sep 2024 09:47:17 +0100 Subject: [PATCH 49/53] amend warning message text --- lambdas/bulkUpload/classes/workerCSVValidator.js | 2 +- lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index f0732078f2..ca19d7bc49 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -1292,7 +1292,7 @@ class WorkerCsvValidator { if ([2, 3].includes(myLevel2CareCertValue)) { if (yearString) { const warning = this._generateWarningWithType( - 'Option 2 or 3 for L2CARECERT cannot have achieved year. Your input will be ignored', + 'Option 2 or 3 for L2CARECERT cannot have achieved year and will be ignored', 'L2CARECERT', 'L2CARECERT_WARNING_IGNORE_YEAR', ); diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index 43fb720612..6f28fc1f71 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -1410,7 +1410,7 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { source: invalidLevel2CareCertInput, warnCode: WorkerCsvValidator.L2CARECERT_WARNING_IGNORE_YEAR, warnType: 'L2CARECERT_WARNING_IGNORE_YEAR', - warning: 'Option 2 or 3 for L2CARECERT cannot have achieved year. Your input will be ignored', + warning: 'Option 2 or 3 for L2CARECERT cannot have achieved year and will be ignored', worker: '3', }; From 4bcda31dd2acdb983eca625f2fcff6519dfbfce5 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Mon, 2 Sep 2024 09:54:04 +0100 Subject: [PATCH 50/53] remove duplicated function _generateWarningWithType --- .../bulkUpload/classes/workerCSVValidator.js | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index ca19d7bc49..cb83229a69 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -537,21 +537,10 @@ class WorkerCsvValidator { return mappings[value] || ''; } - _generateWarning(warning, columnName) { - const warningType = `${columnName}_WARNING`; - return { - worker: this._currentLine.UNIQUEWORKERID, - name: this._currentLine.LOCALESTID, - lineNumber: this._lineNumber, - warnCode: WorkerCsvValidator[warningType], - warnType: warningType, - warning, - source: this._currentLine[columnName], - column: columnName, - }; - } - - _generateWarningWithType(warning, columnName, warnType) { + _generateWarning(warning, columnName, warnType = null) { + if (!warnType) { + warnType = `${columnName}_WARNING`; + } return { worker: this._currentLine.UNIQUEWORKERID, name: this._currentLine.LOCALESTID, @@ -1291,7 +1280,7 @@ class WorkerCsvValidator { if ([2, 3].includes(myLevel2CareCertValue)) { if (yearString) { - const warning = this._generateWarningWithType( + const warning = this._generateWarning( 'Option 2 or 3 for L2CARECERT cannot have achieved year and will be ignored', 'L2CARECERT', 'L2CARECERT_WARNING_IGNORE_YEAR', @@ -1325,7 +1314,7 @@ class WorkerCsvValidator { if (warningMessage) { this._level2CareCert = { value: 'Yes, completed', year: null }; - const warning = this._generateWarningWithType(warningMessage, 'L2CARECERT', warnType); + const warning = this._generateWarning(warningMessage, 'L2CARECERT', warnType); this._validationErrors.push(warning); return false; } else { From eec11951db321c7b7ab8ed6e16a76a94338a2e3e Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Mon, 2 Sep 2024 11:11:37 +0100 Subject: [PATCH 51/53] remove semicolon for L2CARECERT option 2 or 3 in downloading bulk upload file --- .../routes/establishments/bulkUpload/download/workerCSV.js | 4 ++-- .../establishments/bulkUpload/download/workerCSV.spec.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/server/routes/establishments/bulkUpload/download/workerCSV.js b/backend/server/routes/establishments/bulkUpload/download/workerCSV.js index 8fec43585c..6b76276803 100644 --- a/backend/server/routes/establishments/bulkUpload/download/workerCSV.js +++ b/backend/server/routes/establishments/bulkUpload/download/workerCSV.js @@ -186,10 +186,10 @@ const toCSV = (establishmentId, entity, MAX_QUALIFICATIONS, downloadType) => { } break; case 'Yes, started': - l2CareCert = '2;'; + l2CareCert = '2'; break; case 'No': - l2CareCert = '3;'; + l2CareCert = '3'; break; } columns.push(l2CareCert); diff --git a/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js b/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js index 12dbdadb3a..cee32ac01f 100644 --- a/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js +++ b/backend/server/test/unit/routes/establishments/bulkUpload/download/workerCSV.spec.js @@ -312,8 +312,8 @@ describe('workerCSV', () => { [ { name: 'Yes, completed', code: '1;' }, { name: 'Yes, completed', year: 2024, code: '1;2024' }, - { name: 'Yes, started', code: '2;' }, - { name: 'No', code: '3;' }, + { name: 'Yes, started', code: '2' }, + { name: 'No', code: '3' }, ].forEach((level2CareCert) => { let testName = 'should return the correct code for level 2 care certificate ' + level2CareCert.name; if (level2CareCert.year) { From df27baaa4131229e0f0143f6f82821ad6d504ec5 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Mon, 2 Sep 2024 11:20:55 +0100 Subject: [PATCH 52/53] separate the warning message for option 2 and option 3 with a year, text change achieved year --> year achieved --- lambdas/bulkUpload/classes/workerCSVValidator.js | 16 ++++++++++------ .../test/unit/classes/workerCSVValidator.spec.js | 11 +++++++---- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/lambdas/bulkUpload/classes/workerCSVValidator.js b/lambdas/bulkUpload/classes/workerCSVValidator.js index cb83229a69..2ed2063714 100644 --- a/lambdas/bulkUpload/classes/workerCSVValidator.js +++ b/lambdas/bulkUpload/classes/workerCSVValidator.js @@ -363,22 +363,26 @@ class WorkerCsvValidator { return 5590; } - static get L2CARECERT_WARNING_IGNORE_YEAR() { + static get L2CARECERT_WARNING_IGNORE_YEAR_FOR_OPTION_2() { return 5600; } - static get L2CARECERT_WARNING_YEAR_BEFORE_2024() { + static get L2CARECERT_WARNING_IGNORE_YEAR_FOR_OPTION_3() { return 5610; } - static get L2CARECERT_WARNING_YEAR_IN_FUTURE() { + static get L2CARECERT_WARNING_YEAR_BEFORE_2024() { return 5620; } - static get L2CARECERT_WARNING_YEAR_INVALID() { + static get L2CARECERT_WARNING_YEAR_IN_FUTURE() { return 5630; } + static get L2CARECERT_WARNING_YEAR_INVALID() { + return 5640; + } + get lineNumber() { return this._lineNumber; } @@ -1281,9 +1285,9 @@ class WorkerCsvValidator { if ([2, 3].includes(myLevel2CareCertValue)) { if (yearString) { const warning = this._generateWarning( - 'Option 2 or 3 for L2CARECERT cannot have achieved year and will be ignored', + `Option ${myLevel2CareCertValue} for L2CARECERT cannot have year achieved and will be ignored`, 'L2CARECERT', - 'L2CARECERT_WARNING_IGNORE_YEAR', + `L2CARECERT_WARNING_IGNORE_YEAR_FOR_OPTION_${myLevel2CareCertValue}`, ); this._validationErrors.push(warning); return false; diff --git a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js index 6f28fc1f71..5909071af8 100644 --- a/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js +++ b/lambdas/bulkUpload/test/unit/classes/workerCSVValidator.spec.js @@ -1396,21 +1396,24 @@ describe('/lambdas/bulkUpload/classes/workerCSVValidator', async () => { const invalidInputsWithYear = ['2;2024', '3;2024', '2;2000', '3;2000']; invalidInputsWithYear.forEach((invalidLevel2CareCertInput) => { - it(`should add warning and ignore the whole input when option 2 or 3 are given with achieved year: (${invalidLevel2CareCertInput})`, () => { + it(`should add warning and ignore the whole input when option 2 or 3 are given with year achieved: (${invalidLevel2CareCertInput})`, () => { + const optionChosen = invalidLevel2CareCertInput[0]; + const worker = buildWorkerCsv({ overrides: { STATUS: 'NEW', L2CARECERT: invalidLevel2CareCertInput, }, }); + const expectedWarnType = `L2CARECERT_WARNING_IGNORE_YEAR_FOR_OPTION_${optionChosen}`; const expectedWarning = { column: 'L2CARECERT', lineNumber: 2, name: 'MARMA', source: invalidLevel2CareCertInput, - warnCode: WorkerCsvValidator.L2CARECERT_WARNING_IGNORE_YEAR, - warnType: 'L2CARECERT_WARNING_IGNORE_YEAR', - warning: 'Option 2 or 3 for L2CARECERT cannot have achieved year and will be ignored', + warnCode: WorkerCsvValidator[expectedWarnType], + warnType: expectedWarnType, + warning: `Option ${optionChosen} for L2CARECERT cannot have year achieved and will be ignored`, worker: '3', }; From 29b7f35b553b03c60e5625db0a2056ba9734c070 Mon Sep 17 00:00:00 2001 From: Joe Fong Date: Mon, 2 Sep 2024 11:53:51 +0100 Subject: [PATCH 53/53] add unit tests for wdf version, add unit test for when canEditWorker is false --- ...lifications-and-training.component.spec.ts | 48 +++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts index 6c0944902c..62ffe6b2f5 100644 --- a/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts +++ b/frontend/src/app/shared/components/staff-record-summary/qualifications-and-training/qualifications-and-training.component.spec.ts @@ -16,7 +16,7 @@ import { QualificationsAndTrainingComponent } from './qualifications-and-trainin import { InternationalRecruitmentService } from '@core/services/international-recruitment.service'; describe('QualificationsAndTrainingComponent', () => { - async function setup() { + async function setup(isWdf = false, canEditWorker = true) { const { fixture, getByText } = await render(QualificationsAndTrainingComponent, { imports: [SharedModule, RouterModule, RouterTestingModule, HttpClientTestingModule], declarations: [SummaryRecordChangeComponent], @@ -24,15 +24,15 @@ describe('QualificationsAndTrainingComponent', () => { InternationalRecruitmentService, { provide: PermissionsService, - useFactory: MockPermissionsService.factory(['canEditWorker']), + useFactory: MockPermissionsService.factory(canEditWorker ? ['canEditWorker'] : []), deps: [HttpClient], }, ], componentProperties: { - canEditWorker: true, + canEditWorker: canEditWorker, workplace: establishmentBuilder() as Establishment, worker: workerWithWdf() as Worker, - wdfView: false, + wdfView: isWdf, }, }); @@ -112,5 +112,45 @@ describe('QualificationsAndTrainingComponent', () => { `/workplace/${component.workplace.uid}/staff-record/${component.worker.uid}/staff-record-summary/level-2-care-certificate`, ); }); + + it('should not render Add or Change link when canEditWorker is false', async () => { + const { fixture, component, getByText } = await setup(false, false); + + component.worker.level2CareCertificate.value = 'Yes, started'; + fixture.detectChanges(); + + const level2CareCertificateSection = getByText('Level 2 Adult Social Care Certificate').parentElement; + const addLink = within(level2CareCertificateSection).queryByText('Add'); + const changeLink = within(level2CareCertificateSection).queryByText('Change'); + + expect(addLink).toBeFalsy(); + expect(changeLink).toBeFalsy(); + }); + + describe('wdf version', () => { + it('should render Add link to the wdf question page in wdf version of summary page when level 2 care certificate is not answered', async () => { + const { fixture, component, getByText } = await setup(true); + + component.worker.level2CareCertificate = null; + fixture.detectChanges(); + + const level2CareCertificateSection = getByText('Level 2 Adult Social Care Certificate').parentElement; + const addLink = within(level2CareCertificateSection).getByText('Add'); + + expect(addLink.getAttribute('href')).toBe(`/wdf/staff-record/${component.worker.uid}/level-2-care-certificate`); + }); + + it('should render Change link to the wdf question page in wdf version of summary page when level 2 care certificate is answered', async () => { + const { fixture, component, getByText } = await setup(true); + + component.worker.level2CareCertificate.value = 'Yes, started'; + fixture.detectChanges(); + + const level2CareCertificateSection = getByText('Level 2 Adult Social Care Certificate').parentElement; + const addLink = within(level2CareCertificateSection).getByText('Change'); + + expect(addLink.getAttribute('href')).toBe(`/wdf/staff-record/${component.worker.uid}/level-2-care-certificate`); + }); + }); }); });