feat(auth): add validatePassword function with requirements for min and max characters amount, presence of at least one uppercase letter, one lowercase letter, one digit and one special symbol; cover it with tests
This commit is contained in:
@@ -1 +1,2 @@
|
||||
export { validateEmail } from "./validateEmail/validateEmail";
|
||||
export { validatePassword } from "./validatePassword/validatePassword";
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import {
|
||||
MAX_PASSWORD_LENGTH,
|
||||
MIN_PASSWORD_LENGTH,
|
||||
validatePassword,
|
||||
} from "./validatePassword";
|
||||
|
||||
describe("validatePassword", () => {
|
||||
describe("Absence of necessary characters", () => {
|
||||
it("should return false when the password does not contain a lowercase letter", () => {
|
||||
expect(validatePassword("PASSWORD123!")).toBe(false);
|
||||
});
|
||||
it("should return false when the password does not contain an uppercase letter", () => {
|
||||
expect(validatePassword("password123!")).toBe(false);
|
||||
});
|
||||
it("should return false when the password does not contain a digit", () => {
|
||||
expect(validatePassword("Password!")).toBe(false);
|
||||
});
|
||||
it("should return false when the password does not contain a special character", () => {
|
||||
expect(validatePassword("Password123")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Length requirement", () => {
|
||||
const validChars = "aA1!";
|
||||
|
||||
it("should return false when the password is less than min length", () => {
|
||||
const shortPassword =
|
||||
validChars +
|
||||
"a".repeat(Math.max(0, MIN_PASSWORD_LENGTH - validChars.length - 1));
|
||||
|
||||
expect(validatePassword(shortPassword)).toBe(false);
|
||||
});
|
||||
it("should return true when the password is exactly min length", () => {
|
||||
const exactMinPassword =
|
||||
validChars +
|
||||
"a".repeat(Math.max(0, MIN_PASSWORD_LENGTH - validChars.length));
|
||||
|
||||
expect(validatePassword(exactMinPassword)).toBe(true);
|
||||
});
|
||||
it("should return false when the password is greater than max length", () => {
|
||||
const longPassword =
|
||||
validChars +
|
||||
"a".repeat(Math.max(0, MAX_PASSWORD_LENGTH - validChars.length + 1));
|
||||
|
||||
expect(validatePassword(longPassword)).toBe(false);
|
||||
});
|
||||
it("should return true when the password is exactly max length", () => {
|
||||
const exactMaxPassword =
|
||||
validChars +
|
||||
"a".repeat(Math.max(0, MAX_PASSWORD_LENGTH - validChars.length));
|
||||
|
||||
expect(validatePassword(exactMaxPassword)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Valid password", () => {
|
||||
it("should return true when the password is valid", () => {
|
||||
const validChars = "aA1!";
|
||||
const validPassword =
|
||||
validChars +
|
||||
"a".repeat(Math.max(0, MIN_PASSWORD_LENGTH - validChars.length));
|
||||
|
||||
expect(validatePassword(validPassword)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
export const MIN_PASSWORD_LENGTH = 11;
|
||||
export const MAX_PASSWORD_LENGTH = 63;
|
||||
|
||||
/**
|
||||
* The password regex used to validate passwords.
|
||||
* Uses a case-sensitive regex with at least one lowercase letter, one uppercase letter, one digit, and one special character.
|
||||
*/
|
||||
export const PASSWORD_REGEX = new RegExp(
|
||||
`^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{${MIN_PASSWORD_LENGTH},${MAX_PASSWORD_LENGTH}}$`,
|
||||
);
|
||||
|
||||
/**
|
||||
* Validates a password against the password regex.
|
||||
* @param password The password to validate.
|
||||
* @returns `true` if the password is valid, `false` otherwise.
|
||||
*/
|
||||
export function validatePassword(password: string): boolean {
|
||||
return PASSWORD_REGEX.test(password);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { login, logout, register } from "../../../api";
|
||||
import { callApi } from "shared/utils";
|
||||
import { UNEXPECTED_ERROR_MESSAGE } from "shared/api";
|
||||
import { selectAuthData, selectFormValid } from "../../selectors";
|
||||
import { validateEmail } from "../../../lib";
|
||||
import { validateEmail, validatePassword } from "../../../lib";
|
||||
|
||||
export const defaultStoreState: Readonly<AuthStoreState> = {
|
||||
formData: {
|
||||
@@ -16,10 +16,6 @@ export const defaultStoreState: Readonly<AuthStoreState> = {
|
||||
error: null,
|
||||
};
|
||||
|
||||
function validatePassword(password: string): boolean {
|
||||
return Boolean(password);
|
||||
}
|
||||
|
||||
export const useAuthStore = create<AuthStore>()((set, get) => ({
|
||||
...defaultStoreState,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user