diff --git a/src/app/pages/waiting-room-to-car/cat-a-mod1/waiting-room-to-car.cat-a-mod1.page.html b/src/app/pages/waiting-room-to-car/cat-a-mod1/waiting-room-to-car.cat-a-mod1.page.html
index 6cf24f556..55883c5b7 100644
--- a/src/app/pages/waiting-room-to-car/cat-a-mod1/waiting-room-to-car.cat-a-mod1.page.html
+++ b/src/app/pages/waiting-room-to-car/cat-a-mod1/waiting-room-to-car.cat-a-mod1.page.html
@@ -7,6 +7,7 @@
[category]="pageState.category$ | async"
[isPracticeMode]="isPracticeMode"
[shouldAuthenticate]="false"
+ (endTestLinkClicked)="abortMOTCall()"
>
@@ -47,6 +48,7 @@
[isPracticeMode]="isEndToEndPracticeMode"
[vehicleRegistration]="pageState.registrationNumber$ | async"
[isRekeyMode]="pageState.isRekeyMode$ | async"
+ [abortSubject]="abortSubject"
>
diff --git a/src/app/pages/waiting-room-to-car/cat-a-mod2/waiting-room-to-car.cat-a-mod2.page.html b/src/app/pages/waiting-room-to-car/cat-a-mod2/waiting-room-to-car.cat-a-mod2.page.html
index 20c81a370..7c32e0f70 100644
--- a/src/app/pages/waiting-room-to-car/cat-a-mod2/waiting-room-to-car.cat-a-mod2.page.html
+++ b/src/app/pages/waiting-room-to-car/cat-a-mod2/waiting-room-to-car.cat-a-mod2.page.html
@@ -7,6 +7,7 @@
[category]="pageState.category$ | async"
[isPracticeMode]="isPracticeMode"
[shouldAuthenticate]="false"
+ (endTestLinkClicked)="abortMOTCall()"
>
@@ -67,6 +68,7 @@
[isPracticeMode]="isEndToEndPracticeMode"
[vehicleRegistration]="pageState.registrationNumber$ | async"
[isRekeyMode]="pageState.isRekeyMode$ | async"
+ [abortSubject]="abortSubject"
>
diff --git a/src/app/pages/waiting-room-to-car/cat-adi-part2/waiting-room-to-car.cat-adi-part2.page.html b/src/app/pages/waiting-room-to-car/cat-adi-part2/waiting-room-to-car.cat-adi-part2.page.html
index 0664f8fee..68fb95392 100644
--- a/src/app/pages/waiting-room-to-car/cat-adi-part2/waiting-room-to-car.cat-adi-part2.page.html
+++ b/src/app/pages/waiting-room-to-car/cat-adi-part2/waiting-room-to-car.cat-adi-part2.page.html
@@ -10,6 +10,7 @@
[category]="pageState.category$ | async"
[isPracticeMode]="isPracticeMode"
[shouldAuthenticate]="false"
+ (endTestLinkClicked)="abortMOTCall()"
>
@@ -63,6 +64,7 @@
[isPracticeMode]="isEndToEndPracticeMode"
[vehicleRegistration]="pageState.registrationNumber$ | async"
[isRekeyMode]="pageState.isRekeyMode$ | async"
+ [abortSubject]="abortSubject"
>
diff --git a/src/app/pages/waiting-room-to-car/cat-adi-part3/waiting-room-to-car.cat-adi-part3.page.html b/src/app/pages/waiting-room-to-car/cat-adi-part3/waiting-room-to-car.cat-adi-part3.page.html
index 5319e2d04..a730a87c5 100644
--- a/src/app/pages/waiting-room-to-car/cat-adi-part3/waiting-room-to-car.cat-adi-part3.page.html
+++ b/src/app/pages/waiting-room-to-car/cat-adi-part3/waiting-room-to-car.cat-adi-part3.page.html
@@ -10,6 +10,7 @@
[category]="pageState.category$ | async"
[isPracticeMode]="isPracticeMode"
[shouldAuthenticate]="false"
+ (endTestLinkClicked)="abortMOTCall()"
>
@@ -33,6 +34,7 @@
[isPracticeMode]="isEndToEndPracticeMode"
[vehicleRegistration]="pageState.registrationNumber$ | async"
[isRekeyMode]="pageState.isRekeyMode$ | async"
+ [abortSubject]="abortSubject"
>
diff --git a/src/app/pages/waiting-room-to-car/cat-b/waiting-room-to-car.cat-b.page.html b/src/app/pages/waiting-room-to-car/cat-b/waiting-room-to-car.cat-b.page.html
index 5e9ee906b..4f21f71e4 100644
--- a/src/app/pages/waiting-room-to-car/cat-b/waiting-room-to-car.cat-b.page.html
+++ b/src/app/pages/waiting-room-to-car/cat-b/waiting-room-to-car.cat-b.page.html
@@ -12,6 +12,7 @@
[category]="pageState.category$ | async"
[isPracticeMode]="isPracticeMode"
[shouldAuthenticate]="false"
+ (endTestLinkClicked)="abortMOTCall()"
>
@@ -53,6 +54,7 @@
[isPracticeMode]="isEndToEndPracticeMode"
[vehicleRegistration]="pageState.registrationNumber$ | async"
[isRekeyMode]="pageState.isRekeyMode$ | async"
+ [abortSubject]="abortSubject"
>
diff --git a/src/app/pages/waiting-room-to-car/cat-c/waiting-room-to-car.cat-c.page.html b/src/app/pages/waiting-room-to-car/cat-c/waiting-room-to-car.cat-c.page.html
index 1190fd55c..18a671d20 100644
--- a/src/app/pages/waiting-room-to-car/cat-c/waiting-room-to-car.cat-c.page.html
+++ b/src/app/pages/waiting-room-to-car/cat-c/waiting-room-to-car.cat-c.page.html
@@ -11,6 +11,7 @@
[isDelegated]="pageState.delegatedTest$ | async"
[isPracticeMode]="isPracticeMode"
[shouldAuthenticate]="false"
+ (endTestLinkClicked)="abortMOTCall()"
>
@@ -43,6 +44,7 @@
[isPracticeMode]="isEndToEndPracticeMode"
[vehicleRegistration]="pageState.registrationNumber$ | async"
[isRekeyMode]="pageState.isRekeyMode$ | async"
+ [abortSubject]="abortSubject"
>
diff --git a/src/app/pages/waiting-room-to-car/cat-cpc/waiting-room-to-car.cat-cpc.page.html b/src/app/pages/waiting-room-to-car/cat-cpc/waiting-room-to-car.cat-cpc.page.html
index 6d307a03a..9116da909 100644
--- a/src/app/pages/waiting-room-to-car/cat-cpc/waiting-room-to-car.cat-cpc.page.html
+++ b/src/app/pages/waiting-room-to-car/cat-cpc/waiting-room-to-car.cat-cpc.page.html
@@ -11,6 +11,7 @@
[isDelegated]="pageState.delegatedTest$ | async"
[isPracticeMode]="isPracticeMode"
[shouldAuthenticate]="false"
+ (endTestLinkClicked)="abortMOTCall()"
>
@@ -43,6 +44,7 @@
[isPracticeMode]="isEndToEndPracticeMode"
[vehicleRegistration]="pageState.registrationNumber$ | async"
[isRekeyMode]="pageState.isRekeyMode$ | async"
+ [abortSubject]="abortSubject"
>
diff --git a/src/app/pages/waiting-room-to-car/cat-d/waiting-room-to-car.cat-d.page.html b/src/app/pages/waiting-room-to-car/cat-d/waiting-room-to-car.cat-d.page.html
index 255eb722f..a22c4809b 100644
--- a/src/app/pages/waiting-room-to-car/cat-d/waiting-room-to-car.cat-d.page.html
+++ b/src/app/pages/waiting-room-to-car/cat-d/waiting-room-to-car.cat-d.page.html
@@ -11,6 +11,7 @@
[isDelegated]="pageState.delegatedTest$ | async"
[isPracticeMode]="isPracticeMode"
[shouldAuthenticate]="false"
+ (endTestLinkClicked)="abortMOTCall()"
>
@@ -43,6 +44,7 @@
[isPracticeMode]="isEndToEndPracticeMode"
[vehicleRegistration]="pageState.registrationNumber$ | async"
[isRekeyMode]="pageState.isRekeyMode$ | async"
+ [abortSubject]="abortSubject"
>
diff --git a/src/app/pages/waiting-room-to-car/cat-home-test/waiting-room-to-car.cat-home-test.page.html b/src/app/pages/waiting-room-to-car/cat-home-test/waiting-room-to-car.cat-home-test.page.html
index 75e530628..890c8b7ed 100644
--- a/src/app/pages/waiting-room-to-car/cat-home-test/waiting-room-to-car.cat-home-test.page.html
+++ b/src/app/pages/waiting-room-to-car/cat-home-test/waiting-room-to-car.cat-home-test.page.html
@@ -10,6 +10,7 @@
[category]="pageState.category$ | async"
[isPracticeMode]="isPracticeMode"
[shouldAuthenticate]="false"
+ (endTestLinkClicked)="abortMOTCall()"
>
@@ -56,6 +57,7 @@
[isPracticeMode]="isEndToEndPracticeMode"
[vehicleRegistration]="pageState.registrationNumber$ | async"
[isRekeyMode]="pageState.isRekeyMode$ | async"
+ [abortSubject]="abortSubject"
>
diff --git a/src/app/pages/waiting-room-to-car/cat-manoeuvre/waiting-room-to-car.cat-manoeuvre.page.html b/src/app/pages/waiting-room-to-car/cat-manoeuvre/waiting-room-to-car.cat-manoeuvre.page.html
index 33f988fda..7f6c380fe 100644
--- a/src/app/pages/waiting-room-to-car/cat-manoeuvre/waiting-room-to-car.cat-manoeuvre.page.html
+++ b/src/app/pages/waiting-room-to-car/cat-manoeuvre/waiting-room-to-car.cat-manoeuvre.page.html
@@ -11,6 +11,7 @@
[isDelegated]="pageState.delegatedTest$ | async"
[isPracticeMode]="isPracticeMode"
[shouldAuthenticate]="false"
+ (endTestLinkClicked)="abortMOTCall()"
>
@@ -34,6 +35,7 @@
[isPracticeMode]="isEndToEndPracticeMode"
[vehicleRegistration]="pageState.registrationNumber$ | async"
[isRekeyMode]="pageState.isRekeyMode$ | async"
+ [abortSubject]="abortSubject"
>
diff --git a/src/app/pages/waiting-room-to-car/components/vehicle-registration/__tests__/vehicle-registration.spec.ts b/src/app/pages/waiting-room-to-car/components/vehicle-registration/__tests__/vehicle-registration.spec.ts
index 82336461f..f00ecfdcf 100644
--- a/src/app/pages/waiting-room-to-car/components/vehicle-registration/__tests__/vehicle-registration.spec.ts
+++ b/src/app/pages/waiting-room-to-car/components/vehicle-registration/__tests__/vehicle-registration.spec.ts
@@ -64,6 +64,14 @@ describe('VehicleRegistrationComponent', () => {
});
});
+ describe('abortMOTCall', () => {
+ it('should emit a value from abortSubject', () => {
+ spyOn(component.abortSubject, 'next');
+ component.abortMOTCall();
+ expect(component.abortSubject.next).toHaveBeenCalled();
+ });
+ });
+
describe('invalid', () => {
it('should return true if the formControl is invalid and dirty', () => {
component.formControl.setValue(null);
@@ -117,7 +125,7 @@ describe('VehicleRegistrationComponent', () => {
});
describe('shouldDisableMOTButton', () => {
it('should return true if the search spinner is shown', () => {
- component.showSearchSpinner = true;
+ component.isSearchingForMOT = true;
component.formControl.setValue('valid');
spyOn(component['networkState'], 'getNetworkState').and.returnValue(ConnectionStatus.ONLINE);
@@ -125,7 +133,7 @@ describe('VehicleRegistrationComponent', () => {
});
it('should return true if the form control is not valid', () => {
- component.showSearchSpinner = false;
+ component.isSearchingForMOT = false;
component.formControl.setValue(null);
spyOn(component['networkState'], 'getNetworkState').and.returnValue(ConnectionStatus.ONLINE);
@@ -133,7 +141,7 @@ describe('VehicleRegistrationComponent', () => {
});
it('should return true if the network state is offline and not in practice mode', () => {
- component.showSearchSpinner = false;
+ component.isSearchingForMOT = false;
component.formControl.setValue('valid');
component.isPracticeMode = false;
spyOn(component['networkState'], 'getNetworkState').and.returnValue(ConnectionStatus.OFFLINE);
@@ -142,7 +150,7 @@ describe('VehicleRegistrationComponent', () => {
});
it('should return false if the search spinner is not shown, form control is valid, and network state is online', () => {
- component.showSearchSpinner = false;
+ component.isSearchingForMOT = false;
component.formControl.setValue('valid');
spyOn(component['networkState'], 'getNetworkState').and.returnValue(ConnectionStatus.ONLINE);
@@ -150,7 +158,7 @@ describe('VehicleRegistrationComponent', () => {
});
it('should return false if the search spinner is not shown, form control is valid, and in practice mode', () => {
- component.showSearchSpinner = false;
+ component.isSearchingForMOT = false;
component.formControl.setValue('valid');
component.isPracticeMode = true;
spyOn(component['networkState'], 'getNetworkState').and.returnValue(ConnectionStatus.OFFLINE);
diff --git a/src/app/pages/waiting-room-to-car/components/vehicle-registration/vehicle-registration.html b/src/app/pages/waiting-room-to-car/components/vehicle-registration/vehicle-registration.html
index 4e3256144..5e75762a7 100644
--- a/src/app/pages/waiting-room-to-car/components/vehicle-registration/vehicle-registration.html
+++ b/src/app/pages/waiting-room-to-car/components/vehicle-registration/vehicle-registration.html
@@ -39,7 +39,7 @@
-
+
diff --git a/src/app/pages/waiting-room-to-car/components/vehicle-registration/vehicle-registration.ts b/src/app/pages/waiting-room-to-car/components/vehicle-registration/vehicle-registration.ts
index e692011b1..b3a3f0b21 100644
--- a/src/app/pages/waiting-room-to-car/components/vehicle-registration/vehicle-registration.ts
+++ b/src/app/pages/waiting-room-to-car/components/vehicle-registration/vehicle-registration.ts
@@ -17,6 +17,8 @@ import {
nonAlphaNumericValues,
} from '@shared/constants/field-validators/field-validators';
import { isEmpty } from 'lodash-es';
+import { Subject } from 'rxjs';
+import { finalize, takeUntil } from 'rxjs/operators';
@Component({
selector: 'vehicle-registration',
@@ -32,6 +34,8 @@ export class VehicleRegistrationComponent implements OnChanges {
isPracticeMode: boolean;
@Input()
isRekeyMode: boolean;
+ @Input()
+ abortSubject: Subject = new Subject();
@Output()
vehicleRegistrationChange = new EventEmitter();
@@ -48,7 +52,7 @@ export class VehicleRegistrationComponent implements OnChanges {
motData: MotHistoryWithStatus = null;
modalData: string = null;
hasCalledMOT = false;
- showSearchSpinner = false;
+ isSearchingForMOT = false;
readonly registrationNumberValidator: FieldValidators = getRegistrationNumberValidator();
@@ -73,36 +77,44 @@ export class VehicleRegistrationComponent implements OnChanges {
async getMOT(value: string) {
this.clearData();
this.hasCalledMOT = false;
- this.showSearchSpinner = true;
+ this.isSearchingForMOT = true;
if (!this.isPracticeMode) {
const apiCall$ = this.motApiService.getMotHistoryByIdentifier(value);
- apiCall$.subscribe(async (val) => {
- // Assign the API response to the motData property
- this.motData = val;
- // Emit the vehicle registration number to update the search list
- this.vrnSearchListUpdate.emit(value);
-
- // If the MOT status is not valid, open the reconfirm modal
- if (this.motData?.data?.status === MotStatusCodes.NOT_VALID) {
- await this.loadFailedMOTModal();
- // If the modal was cancelled, stop the spinner and return
- if (this.modalData === ModalEvent.CANCEL) {
- this.showSearchSpinner = false;
- return;
+ apiCall$
+ .pipe(
+ takeUntil(this.abortSubject),
+ finalize(() => {
+ // Stop the search spinner
+ this.isSearchingForMOT = false;
+ })
+ )
+ .subscribe(async (val) => {
+ // Assign the API response to the motData property
+ this.motData = val;
+ // Emit the vehicle registration number to update the search list
+ this.vrnSearchListUpdate.emit(value);
+
+ // If the MOT status is not valid, open the reconfirm modal
+ if (this.motData?.data?.status === MotStatusCodes.NOT_VALID) {
+ await this.loadFailedMOTModal();
+ // If the modal was cancelled, stop the spinner and return
+ if (this.modalData === ModalEvent.CANCEL) {
+ this.isSearchingForMOT = false;
+ return;
+ }
+ }
+
+ // Set the flag indicating that the MOT call has been made
+ this.hasCalledMOT = true;
+ // Stop the search spinner
+ this.isSearchingForMOT = false;
+ // If motData is not null, emit the vehicle details
+ if (this.motData) {
+ this.motDetailsUpdate.emit(this.motData?.data);
}
- }
-
- // Set the flag indicating that the MOT call has been made
- this.hasCalledMOT = true;
- // Stop the search spinner
- this.showSearchSpinner = false;
- // If motData is not null, emit the vehicle details
- if (this.motData) {
- this.motDetailsUpdate.emit(this.motData?.data);
- }
- });
+ });
} else {
// Load the practice mode modal and wait for the user's response
const fakeModalReturn = await this.loadPracticeModeModal();
@@ -110,24 +122,16 @@ export class VehicleRegistrationComponent implements OnChanges {
// If the user indicates that the MOT failed, load the failed MOT modal
if (fakeModalReturn === PracticeModeMOTType.FAILED) {
await this.loadFailedMOTModal();
- // If the modal was cancelled, stop the spinner and return
- if (this.modalData === ModalEvent.CANCEL) {
- this.showSearchSpinner = false;
- return;
- }
}
// If the user cancelled the practice mode modal, reset motData and stop the spinner
if (fakeModalReturn === ModalEvent.CANCEL) {
this.motData = null;
- this.showSearchSpinner = false;
return;
}
// Set the flag indicating that the MOT call has been made
this.hasCalledMOT = true;
- // Stop the search spinner
- this.showSearchSpinner = false;
// Make a mock API call to get the MOT result based on the practice mode response
this.motApiService
@@ -179,6 +183,9 @@ export class VehicleRegistrationComponent implements OnChanges {
vehicleRegistrationChanged(event: any): void {
this.clearData();
+ if (this.isSearchingForMOT) {
+ this.abortMOTCall();
+ }
this.hasCalledMOT = false;
if (typeof event.target.value === 'string' && !this.registrationNumberValidator.pattern.test(event.target.value)) {
event.target.value = event.target.value?.replace(nonAlphaNumericValues, '');
@@ -220,9 +227,19 @@ export class VehicleRegistrationComponent implements OnChanges {
*/
shouldDisableMOTButton(): boolean {
return !(
- !this.showSearchSpinner &&
+ !this.isSearchingForMOT &&
this.formControl.valid &&
(this.networkState.getNetworkState() == ConnectionStatus.ONLINE || this.isPracticeMode)
);
}
+
+ /**
+ * Aborts the ongoing MOT call.
+ *
+ * This method emits a value from the `abortSubject`,
+ * which is used to signal the abortion of the ongoing HTTP request.
+ */
+ abortMOTCall() {
+ this.abortSubject.next();
+ }
}
diff --git a/src/app/shared/classes/test-flow-base-pages/waiting-room-to-car/__tests__/waiting-room-to-car-base-page.spec.ts b/src/app/shared/classes/test-flow-base-pages/waiting-room-to-car/__tests__/waiting-room-to-car-base-page.spec.ts
index 809af2305..a773ee6db 100644
--- a/src/app/shared/classes/test-flow-base-pages/waiting-room-to-car/__tests__/waiting-room-to-car-base-page.spec.ts
+++ b/src/app/shared/classes/test-flow-base-pages/waiting-room-to-car/__tests__/waiting-room-to-car-base-page.spec.ts
@@ -380,4 +380,12 @@ describe('WaitingRoomToCarBasePageComponent', () => {
] as QuestionResult[]);
});
});
+
+ describe('abortMOTCall', () => {
+ it('should emit a value from abortSubject', () => {
+ spyOn(basePageComponent.abortSubject, 'next');
+ basePageComponent.abortMOTCall();
+ expect(basePageComponent.abortSubject.next).toHaveBeenCalled();
+ });
+ });
});
diff --git a/src/app/shared/classes/test-flow-base-pages/waiting-room-to-car/waiting-room-to-car-base-page.ts b/src/app/shared/classes/test-flow-base-pages/waiting-room-to-car/waiting-room-to-car-base-page.ts
index 6a6bd4cf4..b2e9bfb58 100644
--- a/src/app/shared/classes/test-flow-base-pages/waiting-room-to-car/waiting-room-to-car-base-page.ts
+++ b/src/app/shared/classes/test-flow-base-pages/waiting-room-to-car/waiting-room-to-car-base-page.ts
@@ -122,6 +122,7 @@ export abstract class WaitingRoomToCarBasePageComponent extends PracticeableBase
testCategory: TestCategory;
trainerNumberProvided = false;
failedMOTModalCurrentlyOpen = false;
+ abortSubject: Subject = new Subject();
private categoriesRequiringEyesightTest: TestCategory[] = [
TestCategory.B,
@@ -192,6 +193,7 @@ export abstract class WaitingRoomToCarBasePageComponent extends PracticeableBase
}
ionViewWillLeave(): void {
+ this.abortMOTCall();
this.store$.dispatch(PersistTests());
}
@@ -331,4 +333,14 @@ export abstract class WaitingRoomToCarBasePageComponent extends PracticeableBase
await alert.present();
}
+
+ /**
+ * Aborts the ongoing MOT call.
+ *
+ * This method emits a value from the `abortSubject`,
+ * which is used to signal the abortion of the ongoing HTTP request.
+ */
+ abortMOTCall() {
+ this.abortSubject.next();
+ }
}
diff --git a/src/components/common/end-test-link/end-test-link.ts b/src/components/common/end-test-link/end-test-link.ts
index f1d3444e5..fea4bbf46 100644
--- a/src/components/common/end-test-link/end-test-link.ts
+++ b/src/components/common/end-test-link/end-test-link.ts
@@ -1,4 +1,4 @@
-import { Component, Input } from '@angular/core';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Router } from '@angular/router';
import { TerminateTestModal } from '@components/common/terminate-test-modal/terminate-test-modal';
import { TestCategory } from '@dvsa/mes-test-schema/category-definitions/common/test-category';
@@ -29,6 +29,9 @@ export class EndTestLinkComponent {
@Input()
isPracticeMode = false;
+ @Output()
+ endTestLinkClicked = new EventEmitter();
+
constructor(
public modalController: ModalController,
public router: Router,
@@ -37,6 +40,7 @@ export class EndTestLinkComponent {
) {}
openEndTestModal = async (): Promise => {
+ this.endTestLinkClicked.emit();
this.terminateTestModal = await this.modalController.create({
id: 'TerminateTestModal',
component: TerminateTestModal,