Spaces:
Sleeping
Sleeping
File size: 4,656 Bytes
1f5ea39 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | import { describe, it, expect } from 'vitest';
import { validatePassword } from '../../../src/services/passwordPolicy';
describe('validatePassword', () => {
// AUTH-006 β Registration with weak password
describe('length requirement', () => {
it('AUTH-006: rejects passwords shorter than 8 characters', () => {
expect(validatePassword('Ab1!')).toEqual({ ok: false, reason: expect.stringContaining('8 characters') });
expect(validatePassword('Ab1!456')).toEqual({ ok: false, reason: expect.stringContaining('8 characters') });
});
it('accepts passwords of exactly 8 characters that meet all requirements', () => {
expect(validatePassword('Ab1!abcd')).toEqual({ ok: true });
});
});
describe('complexity requirements', () => {
it('AUTH-006: rejects password missing uppercase letter', () => {
const result = validatePassword('abcd1234!');
expect(result.ok).toBe(false);
expect(result.reason).toContain('uppercase');
});
it('AUTH-006: rejects password missing lowercase letter', () => {
const result = validatePassword('ABCD1234!');
expect(result.ok).toBe(false);
expect(result.reason).toContain('lowercase');
});
it('AUTH-006: rejects password missing a number', () => {
const result = validatePassword('Abcdefg!');
expect(result.ok).toBe(false);
expect(result.reason).toContain('number');
});
it('AUTH-006: rejects password missing a special character', () => {
// 'TrekApp1' β has upper, lower, number, NO special char, NOT in blocklist
const result = validatePassword('TrekApp1');
expect(result.ok).toBe(false);
expect(result.reason).toContain('special character');
});
});
// AUTH-007 β Registration with common password
describe('common password blocklist', () => {
it('AUTH-007: rejects password matching exact blocklist entry (case-insensitive)', () => {
// 'password1' is in the blocklist. A capitalised+special variant still matches
// because the check is COMMON_PASSWORDS.has(password.toLowerCase()).
// However, 'Password1!' lowercased is 'password1!' which is NOT in the set.
// We must use a password whose lowercase is exactly in the set:
// 'Iloveyou1!' β lowercased: 'iloveyou1!' β NOT in set.
// Use a password whose *lowercase* IS in set: 'changeme' β 'Changeme' is 8 chars
// but lacks uppercase/number/special β test blocklist with full complex variants:
// 'ILoveyou1!' lowercased = 'iloveyou1!' β not in set.
// Just test exact matches that satisfy complexity: use blocklist entry itself.
// 'Iloveyou' is 8 chars, no number/special β fails complexity, not blocklist.
// Better: pick a blocklist entry that, when capitalised + special added, still matches.
// The check is: COMMON_PASSWORDS.has(password.toLowerCase())
// So 'FOOTBALL!' lowercased = 'football!' β not in set ('football' is in set).
// We need password.toLowerCase() to equal a set entry exactly:
// 'football' β add uppercase β 'Football' is still 8 chars, no number, no special β fails complexity first
// The blocklist check happens BEFORE complexity checks, after length + repetitive checks.
// So any 8+ char string whose lowercase is in the blocklist gets caught first.
// 'Password1' lowercased = 'password1' β in blocklist! β (length ok, not repetitive)
expect(validatePassword('Password1')).toEqual({
ok: false,
reason: expect.stringContaining('common'),
});
});
it('AUTH-007: rejects "Changeme" whose lowercase is in the blocklist', () => {
// 'changeme' is in the set; 'Changeme'.toLowerCase() === 'changeme' β
expect(validatePassword('Changeme')).toEqual({
ok: false,
reason: expect.stringContaining('common'),
});
});
it('accepts a strong password that is not in the blocklist', () => {
expect(validatePassword('MyUniq!1Trek')).toEqual({ ok: true });
});
});
describe('repetitive password', () => {
it('rejects passwords made of a single repeated character', () => {
const result = validatePassword('AAAAAAAA');
expect(result.ok).toBe(false);
expect(result.reason).toContain('repetitive');
});
});
describe('valid passwords', () => {
it('accepts a strong unique password', () => {
expect(validatePassword('Tr3k!SecurePass')).toEqual({ ok: true });
});
it('accepts a strong password with special characters', () => {
expect(validatePassword('MyP@ss#2024')).toEqual({ ok: true });
});
});
});
|