Skip to content

Commit

Permalink
feat(cb2-13667): capitalise cert numbers for iva/msva (#1590)
Browse files Browse the repository at this point in the history
* feat(cb2-13667): capitalise all letters in iva/msva cert number

* feat(cb2-13667): reorder spec group 1 test type ids for better readability

* feat(cb2-13667): capitalise amend cert numb and handle legacy lowercase certs

---------

Co-authored-by: Thomas Crawley <[email protected]>
  • Loading branch information
BrandonT95 and tomcrawleyy authored Sep 13, 2024
1 parent d35ffd4 commit d86db95
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 41 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule, NgControl, Validators } from '@angular/forms';
import { CustomFormControl, FormNodeTypes } from '@services/dynamic-forms/dynamic-form.types';
import {
CustomFormControl,
FormNode,
FormNodeTypes,
FormNodeValueFormat,
} from '@services/dynamic-forms/dynamic-form.types';
import { BaseControlComponent } from '../base-control.component';

describe('BaseControlComponent', () => {
let component: BaseControlComponent;
let fixture: ComponentFixture<BaseControlComponent>;

const controlMetaData = { name: 'testControl', type: FormNodeTypes.CONTROL, children: [] };
const controlMetaData: FormNode = { name: 'testControl', type: FormNodeTypes.CONTROL, children: [] };

describe('has control binding', () => {
beforeEach(async () => {
controlMetaData.valueFormat = undefined;
const NG_CONTROL_PROVIDER = {
provide: NgControl,
useClass: class extends NgControl {
Expand Down Expand Up @@ -84,6 +90,19 @@ describe('BaseControlComponent', () => {
expect(state).toBeNull();
});

describe('formatString', () => {
it('should return the value if it has no valueFormat property', () => {
const newValue = component.formatString('string');
expect(newValue).toBe('string');
});

it('should uppercase the value if it has valueFormat as uppercase', () => {
controlMetaData.valueFormat = FormNodeValueFormat.UPPERCASE;
const newValue = component.formatString('string');
expect(newValue).toBe('STRING');
});
});

describe('interacting with the value', () => {
it('writeValue should set the value', () => {
component.writeValue('anything');
Expand All @@ -94,6 +113,12 @@ describe('BaseControlComponent', () => {
component.value = 'anything';
expect(component.value).toBe('anything');
});

it('should set and uppercase the value', () => {
controlMetaData.valueFormat = FormNodeValueFormat.UPPERCASE;
component.value = 'anything';
expect(component.value).toBe('ANYTHING');
});
});

describe('validation', () => {
Expand Down
25 changes: 21 additions & 4 deletions src/app/forms/components/base-control/base-control.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ import { ControlValueAccessor, NgControl } from '@angular/forms';
import { PrefixDirective } from '@directives/prefix/prefix.directive';
import { SuffixDirective } from '@directives/suffix/suffix.directive';
import { ValidatorNames } from '@models/validators.enum';
// eslint-disable-next-line import/no-cycle
import { CustomControl, FormNodeViewTypes, FormNodeWidth } from '@services/dynamic-forms/dynamic-form.types';
import {
CustomControl,
FormNodeValueFormat,
FormNodeViewTypes,
FormNodeWidth,
} from '@services/dynamic-forms/dynamic-form.types';
import { ErrorMessageMap } from '../../utils/error-message-map';

@Component({
Expand Down Expand Up @@ -55,7 +59,7 @@ export class BaseControlComponent implements ControlValueAccessor, AfterContentI
const ngControl: NgControl | null = this.injector.get(NgControl, null);
if (ngControl) {
this.control = ngControl.control as CustomControl;
if (this.control && this.control.meta) {
if (this.control?.meta) {
this.control.meta.changeDetection = this.cdr;
}
} else {
Expand All @@ -80,7 +84,11 @@ export class BaseControlComponent implements ControlValueAccessor, AfterContentI
}

set value(value) {
this.control_value = value;
if (typeof value === 'string') {
this.control_value = this.formatString(value);
} else {
this.control_value = value;
}
}

get disabled() {
Expand Down Expand Up @@ -119,4 +127,13 @@ export class BaseControlComponent implements ControlValueAccessor, AfterContentI
trackBy(i: number) {
return i;
}

formatString(value: string) {
switch (this.control?.meta.valueFormat) {
case FormNodeValueFormat.UPPERCASE:
return value.toUpperCase();
default:
return value;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,52 @@
import { Component } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormGroup } from '@angular/forms';
import { CustomFormControl, FormNodeTypes } from '@services/dynamic-forms/dynamic-form.types';
import { FormsModule, NgControl, Validators } from '@angular/forms';
import { FieldErrorMessageComponent } from '@forms/components/field-error-message/field-error-message.component';
import { CustomFormControl, FormNodeTypes, FormNodeValueFormat } from '@services/dynamic-forms/dynamic-form.types';
import { TextInputComponent } from '../text-input.component';

@Component({
selector: 'app-host-component',
template: `<form [formGroup]="form">
<app-text-input name="foo" formControlName="foo"></app-text-input>
</form> `,
styles: [],
})
class HostComponent {
form = new FormGroup({
foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, ''),
});
}

describe('TextInputComponent', () => {
let component: HostComponent;
let fixture: ComponentFixture<HostComponent>;
let component: TextInputComponent;
let fixture: ComponentFixture<TextInputComponent>;
const metadata = {
name: 'foo',
type: FormNodeTypes.CONTROL,
children: [],
valueFormat: FormNodeValueFormat.UPPERCASE,
};

beforeEach(async () => {
const NG_CONTROL_PROVIDER = {
provide: NgControl,
useClass: class extends NgControl {
control = new CustomFormControl(metadata, '', [Validators.required]);
viewToModelUpdate() {}
},
};

await TestBed.configureTestingModule({
declarations: [TextInputComponent],
}).compileComponents();
});
declarations: [TextInputComponent, FieldErrorMessageComponent],
imports: [FormsModule],
})
.overrideComponent(TextInputComponent, { add: { providers: [NG_CONTROL_PROVIDER] } })
.compileComponents();

beforeEach(() => {
fixture = TestBed.createComponent(HostComponent);
fixture = TestBed.createComponent(TextInputComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

describe('handleChange', () => {
it('should call the formatString method if the value is a string', () => {
const formatString = jest.spyOn(component, 'formatString');
const onChange = jest.spyOn(component, 'onChange');
component.handleChange('string');
expect(formatString).toHaveBeenCalled();
expect(onChange).toHaveBeenCalledWith('STRING');
expect(component.value).toBe('STRING');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
[class]="style"
[(ngModel)]="value"
[disabled]="disabled"
(ngModelChange)="onChange($event)"
(ngModelChange)="handleChange($event)"
(blur)="onTouched(); handleEvent($event); blur.emit($event)"
(focus)="handleEvent($event)"
/>
Expand Down
7 changes: 7 additions & 0 deletions src/app/forms/components/text-input/text-input.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,11 @@ export class TextInputComponent extends BaseControlComponent {
get style(): string {
return `govuk-input ${this.width ? `govuk-input--width-${this.width}` : ''}`;
}

handleChange(event: unknown) {
if (typeof event === 'string') {
this.value = this.formatString(event);
}
this.onChange(this.value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
FormNode,
FormNodeEditTypes,
FormNodeTypes,
FormNodeValueFormat,
FormNodeViewTypes,
FormNodeWidth,
} from '@services/dynamic-forms/dynamic-form.types';
Expand Down Expand Up @@ -137,6 +138,7 @@ export const ContingencyTestSectionSpecialistGroup1: FormNode = {
type: FormNodeTypes.CONTROL,
viewType: FormNodeViewTypes.STRING,
editType: FormNodeEditTypes.TEXT,
valueFormat: FormNodeValueFormat.UPPERCASE,
validators: [
{ name: ValidatorNames.Alphanumeric },
// Make required if test result is pass/prs, but issue documents centrally is false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
FormNode,
FormNodeEditTypes,
FormNodeTypes,
FormNodeValueFormat,
FormNodeViewTypes,
FormNodeWidth,
} from '@services/dynamic-forms/dynamic-form.types';
Expand Down Expand Up @@ -154,6 +155,7 @@ export const SpecialistTestSectionGroup1: FormNode = {
label: 'Certificate number',
type: FormNodeTypes.CONTROL,
editType: FormNodeEditTypes.TEXT,
valueFormat: FormNodeValueFormat.UPPERCASE,
validators: [
{ name: ValidatorNames.Alphanumeric },
// Make required if test result is pass/prs, but issue documents centrally is false
Expand Down
16 changes: 8 additions & 8 deletions src/app/models/testTypeId.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,7 @@ export const TEST_TYPES_GROUP15_16: string[] = ['39', '201', '45', '44'];
export const TEST_TYPES_GROUP1_SPEC_TEST: string[] = [
'125',
'126',
'186',
'187',
'128',
'188',
'189',
'129',
'130',
'133',
Expand All @@ -110,18 +106,22 @@ export const TEST_TYPES_GROUP1_SPEC_TEST: string[] = [
'158',
'159',
'161',
'192',
'193',
'162',
'194',
'195',
'163',
'166',
'167',
'169',
'170',
'172',
'173',
'186',
'187',
'188',
'189',
'192',
'193',
'194',
'195',
];

// Test/Retest COIF with annual test, Seatbelt installation check COIF with annual test
Expand Down
6 changes: 6 additions & 0 deletions src/app/services/dynamic-forms/dynamic-form.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export interface FormNode {
link?: string;
delimited?: { regex?: string; separator: string };
value?: unknown;
valueFormat?: FormNodeValueFormat;
path?: string;
options?: FormNodeOption<string | number | boolean | null>[] | FormNodeCombinationOptions;
validators?: FormNodeValidator[];
Expand All @@ -131,6 +132,11 @@ export interface FormNode {
viewComponent?: typeof BaseControlComponent;
editComponent?: typeof BaseControlComponent;
}

export enum FormNodeValueFormat {
UPPERCASE = 'uppercase',
}

export interface CustomTag {
label: TagTypeLabels;
colour: TagTypes;
Expand Down
3 changes: 0 additions & 3 deletions src/app/store/test-records/test-records.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,6 @@ function cleanTestResultPayload(testResult: TestResultModel | undefined) {
}

const testTypes = testResult.testTypes.map((testType, index) => {
// Always remove testCode
delete testType.testCode;

// Remove empty requiredStandards from pass/prs non-voluntary IVA/MVSA tests
if (index === 0) {
const { testTypeId, requiredStandards } = testType;
Expand Down

0 comments on commit d86db95

Please sign in to comment.