const { loginSchema, registerSchema, errorsToString } = require('./validators'); describe('Zod Schemas', () => { describe('loginSchema', () => { it('should validate a correct login object', () => { const result = loginSchema.safeParse({ email: 'test@example.com', password: 'password123', }); expect(result.success).toBe(true); }); it('should invalidate an incorrect email', () => { const result = loginSchema.safeParse({ email: 'testexample.com', password: 'password123', }); expect(result.success).toBe(false); }); it('should invalidate a short password', () => { const result = loginSchema.safeParse({ email: 'test@example.com', password: 'pass', }); expect(result.success).toBe(false); }); it('should handle email with unusual characters', () => { const emails = ['test+alias@example.com', 'test@subdomain.example.co.uk']; emails.forEach((email) => { const result = loginSchema.safeParse({ email, password: 'password123', }); expect(result.success).toBe(true); }); }); it('should invalidate email without a domain', () => { const result = loginSchema.safeParse({ email: 'test@.com', password: 'password123', }); expect(result.success).toBe(false); }); it('should invalidate password with only spaces', () => { const result = loginSchema.safeParse({ email: 'test@example.com', password: ' ', }); expect(result.success).toBe(false); }); it('should invalidate password that is too long', () => { const result = loginSchema.safeParse({ email: 'test@example.com', password: 'a'.repeat(129), }); expect(result.success).toBe(false); }); it('should invalidate empty email or password', () => { const result = loginSchema.safeParse({ email: '', password: '', }); expect(result.success).toBe(false); }); }); describe('registerSchema', () => { it('should validate a correct register object', () => { const result = registerSchema.safeParse({ name: 'John Doe', username: 'john_doe', email: 'john@example.com', password: 'password123', confirm_password: 'password123', }); expect(result.success).toBe(true); }); it('should allow the username to be omitted', () => { const result = registerSchema.safeParse({ name: 'John Doe', email: 'john@example.com', password: 'password123', confirm_password: 'password123', }); expect(result.success).toBe(true); }); it('should invalidate a short name', () => { const result = registerSchema.safeParse({ name: 'Jo', username: 'john_doe', email: 'john@example.com', password: 'password123', confirm_password: 'password123', }); expect(result.success).toBe(false); }); it('should handle empty username by transforming to null', () => { const result = registerSchema.safeParse({ name: 'John Doe', username: '', email: 'john@example.com', password: 'password123', confirm_password: 'password123', }); expect(result.success).toBe(true); expect(result.data.username).toBe(null); }); it('should handle name with special characters', () => { const names = ['Jöhn Dœ', 'John ']; names.forEach((name) => { const result = registerSchema.safeParse({ name, username: 'john_doe', email: 'john@example.com', password: 'password123', confirm_password: 'password123', }); expect(result.success).toBe(true); }); }); it('should handle username with special characters', () => { const usernames = ['john.doe@', 'john..doe']; usernames.forEach((username) => { const result = registerSchema.safeParse({ name: 'John Doe', username, email: 'john@example.com', password: 'password123', confirm_password: 'password123', }); expect(result.success).toBe(true); }); }); it('should invalidate mismatched password and confirm_password', () => { const result = registerSchema.safeParse({ name: 'John Doe', username: 'john_doe', email: 'john@example.com', password: 'password123', confirm_password: 'password124', }); expect(result.success).toBe(false); }); it('should handle email without a TLD', () => { const result = registerSchema.safeParse({ name: 'John Doe', username: 'john_doe', email: 'john@domain', password: 'password123', confirm_password: 'password123', }); expect(result.success).toBe(false); }); it('should handle email with multiple @ symbols', () => { const result = registerSchema.safeParse({ name: 'John Doe', username: 'john_doe', email: 'john@domain@com', password: 'password123', confirm_password: 'password123', }); expect(result.success).toBe(false); }); it('should handle name that is too long', () => { const result = registerSchema.safeParse({ name: 'a'.repeat(81), username: 'john_doe', email: 'john@example.com', password: 'password123', confirm_password: 'password123', }); expect(result.success).toBe(false); }); it('should handle username that is too long', () => { const result = registerSchema.safeParse({ name: 'John Doe', username: 'a'.repeat(81), email: 'john@example.com', password: 'password123', confirm_password: 'password123', }); expect(result.success).toBe(false); }); it('should handle password or confirm_password that is too long', () => { const result = registerSchema.safeParse({ name: 'John Doe', username: 'john_doe', email: 'john@example.com', password: 'a'.repeat(129), confirm_password: 'a'.repeat(129), }); expect(result.success).toBe(false); }); it('should handle password or confirm_password that is just spaces', () => { const result = registerSchema.safeParse({ name: 'John Doe', username: 'john_doe', email: 'john@example.com', password: ' ', confirm_password: ' ', }); expect(result.success).toBe(false); }); it('should handle null values for fields', () => { const result = registerSchema.safeParse({ name: null, username: null, email: null, password: null, confirm_password: null, }); expect(result.success).toBe(false); }); it('should handle undefined values for fields', () => { const result = registerSchema.safeParse({ name: undefined, username: undefined, email: undefined, password: undefined, confirm_password: undefined, }); expect(result.success).toBe(false); }); it('should handle extra fields not defined in the schema', () => { const result = registerSchema.safeParse({ name: 'John Doe', username: 'john_doe', email: 'john@example.com', password: 'password123', confirm_password: 'password123', extraField: 'I shouldn\'t be here', }); expect(result.success).toBe(true); }); it('should handle username with special characters from various languages', () => { const usernames = [ // General 'éèäöü', // German 'Jöhn.Döe@', 'Jöhn_Ü', 'Jöhnß', // French 'Jéan-Piérre', 'Élève', 'Fiançée', 'Mère', // Spanish 'Niño', 'Señor', 'Muñoz', // Portuguese 'João', 'Coração', 'Pão', // Italian 'Pietro', 'Bambino', 'Forlì', // Romanian 'Mâncare', 'Școală', 'Țară', // Catalan 'Niç', 'Màquina', 'Çap', // Swedish 'Fjärran', 'Skål', 'Öland', // Norwegian 'Blåbær', 'Fjord', 'Årstid', // Danish 'Flød', 'Søster', 'Århus', // Icelandic 'Þór', 'Ætt', 'Öx', // Turkish 'Şehir', 'Çocuk', 'Gözlük', // Polish 'Łódź', 'Część', 'Świat', // Czech 'Čaj', 'Řeka', 'Život', // Slovak 'Kočka', 'Ľudia', 'Žaba', // Croatian 'Čovjek', 'Šuma', 'Žaba', // Hungarian 'Tűz', 'Ősz', 'Ünnep', // Finnish 'Mäki', 'Yö', 'Äiti', // Estonian 'Tänav', 'Öö', 'Ülikool', // Latvian 'Ēka', 'Ūdens', 'Čempions', // Lithuanian 'Ūsas', 'Ąžuolas', 'Čia', // Dutch 'Maïs', 'Geërfd', 'Coördinatie', ]; const failingUsernames = usernames.reduce((acc, username) => { const result = registerSchema.safeParse({ name: 'John Doe', username, email: 'john@example.com', password: 'password123', confirm_password: 'password123', }); if (!result.success) { acc.push({ username, error: result.error }); } return acc; }, []); if (failingUsernames.length > 0) { console.log('Failing Usernames:', failingUsernames); } expect(failingUsernames).toEqual([]); }); it('should reject invalid usernames', () => { const invalidUsernames = [ 'Дмитрий', // Cyrillic characters 'محمد', // Arabic characters '张伟', // Chinese characters 'john{doe}', // Contains `{` and `}` 'j', // Only one character 'a'.repeat(81), // More than 80 characters '\' OR \'1\'=\'1\'; --', // SQL Injection '{$ne: null}', // MongoDB Injection '', // Basic XSS '">', // XSS breaking out of an attribute '">', // XSS using an image tag ]; const passingUsernames = []; const failingUsernames = invalidUsernames.reduce((acc, username) => { const result = registerSchema.safeParse({ name: 'John Doe', username, email: 'john@example.com', password: 'password123', confirm_password: 'password123', }); if (!result.success) { acc.push({ username, error: result.error }); } if (result.success) { passingUsernames.push({ username }); } return acc; }, []); expect(failingUsernames.length).toEqual(invalidUsernames.length); // They should match since all invalidUsernames should fail. }); }); describe('errorsToString', () => { it('should convert errors to string', () => { const { error } = registerSchema.safeParse({ name: 'Jo', username: 'john_doe', email: 'john@example.com', password: 'password123', confirm_password: 'password123', }); const result = errorsToString(error.errors); expect(result).toBe('name: String must contain at least 3 character(s)'); }); }); });