1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 05:13:29 +00:00

refactor(set-change-password): [Auth/PM-17649] Move and test compareInputs validator (#13553)

- Move the `compareInputs` validator to `libs/auth`
- Add tests for the `compareInputs` validator
- Delete the deprecated `InputsFieldMatch` class (inputs-field-match.validator.ts)
This commit is contained in:
rr-bw
2025-04-07 15:04:24 -07:00
committed by GitHub
parent 19d59212a8
commit ecb4b2d0b7
5 changed files with 365 additions and 179 deletions

View File

@@ -1,167 +0,0 @@
import { AbstractControl, UntypedFormGroup, ValidationErrors, ValidatorFn } from "@angular/forms";
import { FormGroupControls } from "../../platform/abstractions/form-validation-errors.service";
export class InputsFieldMatch {
/**
* Check to ensure two fields do not have the same value
*
* @deprecated Use compareInputs() instead
*/
static validateInputsDoesntMatch(matchTo: string, errorMessage: string): ValidatorFn {
return (control: AbstractControl) => {
if (control.parent && control.parent.controls) {
return control?.value === (control?.parent?.controls as FormGroupControls)[matchTo].value
? {
inputsMatchError: {
message: errorMessage,
},
}
: null;
}
return null;
};
}
//check to ensure two fields have the same value
static validateInputsMatch(matchTo: string, errorMessage: string): ValidatorFn {
return (control: AbstractControl) => {
if (control.parent && control.parent.controls) {
return control?.value === (control?.parent?.controls as FormGroupControls)[matchTo].value
? null
: {
inputsDoesntMatchError: {
message: errorMessage,
},
};
}
return null;
};
}
/**
* Checks the formGroup if two fields have the same value and validation is controlled from either field
*
* @deprecated
* Use compareInputs() instead.
*
* For more info on deprecation
* - Do not use untyped `options` object in formBuilder.group() {@link https://angular.dev/api/forms/UntypedFormBuilder}
* - Use formBuilder.group() overload with AbstractControlOptions type instead {@link https://angular.dev/api/forms/AbstractControlOptions}
*
* Remove this method after deprecated instances are replaced
*/
static validateFormInputsMatch(field: string, fieldMatchTo: string, errorMessage: string) {
return (formGroup: UntypedFormGroup) => {
const fieldCtrl = formGroup.controls[field];
const fieldMatchToCtrl = formGroup.controls[fieldMatchTo];
if (fieldCtrl.value !== fieldMatchToCtrl.value) {
fieldMatchToCtrl.setErrors({
inputsDoesntMatchError: {
message: errorMessage,
},
});
} else {
fieldMatchToCtrl.setErrors(null);
}
};
}
/**
* Checks whether two form controls do or do not have the same input value (except for empty string values).
*
* - Validation is controlled from either form control.
* - The error message is displayed under controlB by default, but can be set to controlA.
*
* @param validationGoal Whether you want to verify that the form control input values match or do not match
* @param controlNameA The name of the first form control to compare.
* @param controlNameB The name of the second form control to compare.
* @param errorMessage The error message to display if there is an error. This will probably
* be an i18n translated string.
* @param showErrorOn The control under which you want to display the error (default is controlB).
*/
static compareInputs(
validationGoal: "match" | "doNotMatch",
controlNameA: string,
controlNameB: string,
errorMessage: string,
showErrorOn: "controlA" | "controlB" = "controlB",
): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const controlA = control.get(controlNameA);
const controlB = control.get(controlNameB);
if (!controlA || !controlB) {
return null;
}
const controlThatShowsError = showErrorOn === "controlA" ? controlA : controlB;
// Don't compare empty strings
if (controlA.value === "" && controlB.value === "") {
return pass();
}
const controlValuesMatch = controlA.value === controlB.value;
if (validationGoal === "match") {
if (controlValuesMatch) {
return pass();
} else {
return fail();
}
}
if (validationGoal === "doNotMatch") {
if (!controlValuesMatch) {
return pass();
} else {
return fail();
}
}
return null; // default return
function fail() {
controlThatShowsError.setErrors({
// Preserve any pre-existing errors
...controlThatShowsError.errors,
// Add new inputMatchError
inputMatchError: {
message: errorMessage,
},
});
return {
inputMatchError: {
message: errorMessage,
},
};
}
function pass(): null {
// Get the current errors object
const errorsObj = controlThatShowsError?.errors;
if (errorsObj != null) {
// Remove any inputMatchError if it exists, since that is the sole error we are targeting with this validator
if (errorsObj?.inputMatchError) {
delete errorsObj.inputMatchError;
}
// Check if the errorsObj is now empty
const isEmptyObj = Object.keys(errorsObj).length === 0;
// If the errorsObj is empty, set errors to null, otherwise set the errors to an object of pre-existing errors (other than inputMatchError)
controlThatShowsError.setErrors(isEmptyObj ? null : errorsObj);
}
// Return null for this validator
return null;
}
};
}
}