import { describe, expect, test } from "vitest" import { passwordValidator } from "./passwordValidator" // Test cases to find differences between Curity and Zod validation const testCases = [ // Valid passwords { password: "Password123!", description: "standard valid password" }, { password: "ValidPass1@", description: "valid with @" }, { password: "TestPass9#", description: "valid with #" }, // Edge cases for length { password: "Pass123!", description: "8 characters (too short for both)" }, { password: "ValidPass1!", description: "10 characters (minimum)" }, { password: "A".repeat(40) + "1!", description: "40 characters (maximum)" }, { password: "A".repeat(41) + "1!", description: "41 characters (too long)" }, // Special character differences { password: "Password123*", description: "with asterisk" }, { password: "Password123-", description: "with hyphen" }, { password: "Password123=", description: "with equals" }, { password: "Password123+", description: "with plus" }, { password: "Password123_", description: "with underscore" }, { password: "Password123&", description: "with ampersand" }, { password: "Password123?", description: "with question mark" }, { password: "Password123(", description: "with opening parenthesis" }, { password: "Password123)", description: "with closing parenthesis" }, // International characters (Curity supports these, Zod might not) { password: "Påssword123!", description: "with å" }, { password: "Pässword123!", description: "with ä" }, { password: "Pöössword123!", description: "with ö" }, { password: "Pæssword123!", description: "with æ" }, { password: "Pøssword123!", description: "with ø" }, { password: "Püssword123!", description: "with ü" }, { password: "Paßsword123!", description: "with ß" }, // Mixed case international { password: "PÅSSWORD123!", description: "with uppercase Å" }, { password: "PÄSSWORD123!", description: "with uppercase Ä" }, { password: "PÖÖSSWORD123!", description: "with uppercase Ö" }, // Special characters not in Curity regex { password: "Password123~", description: "with tilde (not in Curity)" }, { password: "Password123`", description: "with backtick (not in Curity)" }, { password: "Password123|", description: "with pipe (not in Curity)" }, { password: "Password123\\", description: "with backslash (not in Curity)" }, { password: "Password123/", description: "with forward slash (not in Curity)", }, { password: "Password123<", description: "with less than (not in Curity)" }, { password: "Password123>", description: "with greater than (not in Curity)", }, { password: "Password123.", description: "with period (not in Curity)" }, { password: "Password123,", description: "with comma (not in Curity)" }, { password: "Password123;", description: "with semicolon (not in Curity)" }, { password: "Password123:", description: "with colon (not in Curity)" }, { password: "Password123'", description: "with apostrophe (not in Curity)" }, { password: 'Password123"', description: "with quote (not in Curity)" }, { password: "Password123[", description: "with opening bracket (not in Curity)", }, { password: "Password123]", description: "with closing bracket (not in Curity)", }, { password: "Password123{", description: "with opening brace (not in Curity)", }, { password: "Password123}", description: "with closing brace (not in Curity)", }, ] const curityPasswordRegex = new RegExp( "^(?!^.{41})(?=.{10,})(?=.*[0-9])(?=.*[a-zåäöæøüß])(?=.*[A-ZÅÄÖÆØÜ])(?=.*[&!?()@#$%^+=_\*\-])[A-Za-zåäöæøüßÅÄÖÆØÜ0-9&!?()@#$%^+=_\*\-]+$", "g" ) describe("Should validate password the same way as Curity", () => { beforeEach(() => { // reset regex state before test curityPasswordRegex.lastIndex = 0 }) test.each(testCases)("$description", ({ password }) => { console.log(password) const curityResult = curityPasswordRegex.test(password) const zodResult = passwordValidator().safeParse(password) expect(zodResult.success).toBe(curityResult) }) })