WellNuo/utils/__tests__/wifiValidation.test.ts
Sergei 5a6c80533e Add comprehensive WiFi credentials validation
Implement WiFi SSID and password validation following IEEE 802.11 standards:

Features:
- SSID validation: length (max 32 bytes), control characters, whitespace warnings
- Password validation for WPA/WPA2/WPA3 (8-63 chars), WEP, and Open networks
- Weak password detection with warnings
- Non-ASCII character warnings
- Input sanitization (trim SSID, preserve password spaces)
- User-friendly error messages

Integration:
- Added validation to wifi-setup.tsx (ESP provisioning flow)
- Added validation to setup-wifi.tsx (batch sensor setup flow)
- Pre-provisioning validation with error/warning alerts
- Password requirements hints in UI

Tests:
- Comprehensive test suite with 42 test cases
- 100% coverage of validation logic
- Tests for all auth types (WPA, WEP, Open)
- Edge cases and warning scenarios

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-31 16:55:27 -08:00

356 lines
12 KiB
TypeScript

/**
* Tests for WiFi Credentials Validation
*/
import {
validateSSID,
validatePassword,
validateWiFiCredentials,
isStrongPassword,
sanitizeWiFiCredentials,
getValidationErrorMessage,
getValidationMessage,
} from '../wifiValidation';
describe('WiFi Validation', () => {
describe('validateSSID', () => {
it('should accept valid SSIDs', () => {
const validSSIDs = [
'MyHomeWiFi',
'Guest Network',
'Office-5G',
'Café WiFi',
'Network_2.4GHz',
'a',
'1234567890123456789012345678901', // 31 chars
'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456', // 32 chars
];
validSSIDs.forEach((ssid) => {
const result = validateSSID(ssid);
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
});
it('should reject empty SSID', () => {
const result = validateSSID('');
expect(result.valid).toBe(false);
expect(result.errors).toContain('Network name (SSID) cannot be empty');
});
it('should reject whitespace-only SSID', () => {
const result = validateSSID(' ');
expect(result.valid).toBe(false);
expect(result.errors).toContain('Network name (SSID) cannot be empty');
});
it('should reject SSID longer than 32 bytes', () => {
const longSSID = 'A'.repeat(33);
const result = validateSSID(longSSID);
expect(result.valid).toBe(false);
expect(result.errors).toContain('Network name is too long (max 32 bytes)');
});
it('should reject SSID with control characters', () => {
const result = validateSSID('Network\x00Name');
expect(result.valid).toBe(false);
expect(result.errors).toContain('Network name contains invalid control characters');
});
it('should warn about leading/trailing spaces', () => {
const result1 = validateSSID(' MyWiFi');
expect(result1.valid).toBe(true);
expect(result1.warnings).toContain(
'Network name has leading or trailing spaces - this may cause connection issues'
);
const result2 = validateSSID('MyWiFi ');
expect(result2.valid).toBe(true);
expect(result2.warnings).toContain(
'Network name has leading or trailing spaces - this may cause connection issues'
);
});
it('should warn about multiple consecutive spaces', () => {
const result = validateSSID('My WiFi');
expect(result.valid).toBe(true);
expect(result.warnings).toContain('Network name has multiple consecutive spaces');
});
});
describe('validatePassword', () => {
describe('WPA/WPA2/WPA3 networks', () => {
it('should accept valid WPA passwords', () => {
const validPasswords = [
'MySecurePass123',
'abcdefgh', // 8 chars minimum
'A'.repeat(63), // 63 chars maximum
'Pass with spaces!@#',
'ComplexP@ssw0rd!',
];
validPasswords.forEach((password) => {
const result = validatePassword(password, 'WPA2 PSK');
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
});
it('should reject passwords shorter than 8 characters', () => {
const result = validatePassword('1234567', 'WPA2 PSK');
expect(result.valid).toBe(false);
expect(result.errors).toContain(
'Password must be at least 8 characters for WPA/WPA2/WPA3 networks'
);
});
it('should reject passwords longer than 63 characters', () => {
const longPassword = 'A'.repeat(64);
const result = validatePassword(longPassword, 'WPA2 PSK');
expect(result.valid).toBe(false);
expect(result.errors).toContain(
'Password cannot exceed 63 characters for WPA/WPA2/WPA3 networks'
);
});
it('should warn about weak passwords', () => {
const result = validatePassword('12345678', 'WPA2 PSK');
expect(result.valid).toBe(true);
expect(result.warnings).toContain('Password is weak - consider using at least 12 characters');
});
it('should warn about commonly used weak passwords', () => {
const weakPasswords = ['password', '12345678', 'qwerty123'];
weakPasswords.forEach((password) => {
const result = validatePassword(password, 'WPA2 PSK');
expect(result.warnings).toContain('This is a commonly used weak password');
});
});
it('should warn about numeric-only passwords', () => {
const result = validatePassword('12345678', 'WPA2 PSK');
expect(result.warnings).toContain(
'Password contains only numbers - consider adding letters and symbols'
);
});
it('should warn about non-ASCII characters', () => {
const result = validatePassword('Password™123', 'WPA2 PSK');
expect(result.valid).toBe(true);
expect(result.warnings).toContain(
'Password contains non-ASCII characters - this may cause issues on some devices'
);
});
});
describe('Open networks', () => {
it('should accept empty password for open networks', () => {
const result = validatePassword('', 'Open');
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
it('should accept any password for open networks (will be ignored)', () => {
const result = validatePassword('any password', 'Open');
expect(result.valid).toBe(true);
});
});
describe('WEP networks', () => {
it('should accept valid 5-character WEP password', () => {
const result = validatePassword('abcde', 'WEP');
expect(result.valid).toBe(true);
expect(result.warnings).toContain(
'WEP is deprecated and insecure - consider upgrading your router to WPA2/WPA3'
);
});
it('should accept valid 13-character WEP password', () => {
const result = validatePassword('abcdefghijklm', 'WEP');
expect(result.valid).toBe(true);
});
it('should accept valid 10-digit hex WEP password', () => {
const result = validatePassword('1234567890', 'WEP');
expect(result.valid).toBe(true);
});
it('should accept valid 26-digit hex WEP password', () => {
const result = validatePassword('12345678901234567890123456', 'WEP');
expect(result.valid).toBe(true);
});
it('should reject invalid WEP password length', () => {
const result = validatePassword('abc', 'WEP');
expect(result.valid).toBe(false);
expect(result.errors).toContain(
'WEP password must be 5 or 13 ASCII characters, or 10/26 hexadecimal digits'
);
});
});
describe('Secured networks without auth type', () => {
it('should require password', () => {
const result = validatePassword('');
expect(result.valid).toBe(false);
expect(result.errors).toContain('Password is required for secured networks');
});
it('should apply WPA rules by default', () => {
const result = validatePassword('1234567'); // 7 chars
expect(result.valid).toBe(false);
expect(result.errors).toContain(
'Password must be at least 8 characters for WPA/WPA2/WPA3 networks'
);
});
});
it('should reject passwords with control characters', () => {
const result = validatePassword('Pass\x00word123', 'WPA2 PSK');
expect(result.valid).toBe(false);
expect(result.errors).toContain('Password contains invalid control characters');
});
});
describe('validateWiFiCredentials', () => {
it('should validate both SSID and password', () => {
const result = validateWiFiCredentials('MyWiFi', 'SecurePass123', 'WPA2 PSK');
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
it('should combine errors from both validations', () => {
const result = validateWiFiCredentials('', '123', 'WPA2 PSK');
expect(result.valid).toBe(false);
expect(result.errors).toContain('Network name (SSID) cannot be empty');
expect(result.errors).toContain(
'Password must be at least 8 characters for WPA/WPA2/WPA3 networks'
);
});
it('should combine warnings from both validations', () => {
const result = validateWiFiCredentials(' MyWiFi ', 'password123', 'WPA2 PSK');
expect(result.valid).toBe(true);
expect(result.warnings.length).toBeGreaterThan(0);
});
it('should validate open network correctly', () => {
const result = validateWiFiCredentials('GuestNetwork', '', 'Open');
expect(result.valid).toBe(true);
});
});
describe('isStrongPassword', () => {
it('should accept strong passwords', () => {
const strongPasswords = [
'MyP@ssw0rd123!',
'Secure_Password_2024',
'Compl3x!P@ssw0rd',
'abCD1234!@#$',
];
strongPasswords.forEach((password) => {
expect(isStrongPassword(password)).toBe(true);
});
});
it('should reject passwords shorter than 12 characters', () => {
expect(isStrongPassword('P@ssw0rd')).toBe(false);
});
it('should reject passwords with less than 3 character types', () => {
expect(isStrongPassword('onlylowercase')).toBe(false);
expect(isStrongPassword('12345678901234')).toBe(false);
expect(isStrongPassword('ONLYUPPERCASE')).toBe(false);
});
it('should accept passwords with 3 or 4 character types', () => {
// 3 types: lowercase, uppercase, numbers
expect(isStrongPassword('Password1234')).toBe(true);
// 4 types: lowercase, uppercase, numbers, special
expect(isStrongPassword('P@ssword1234')).toBe(true);
});
});
describe('sanitizeWiFiCredentials', () => {
it('should trim SSID whitespace', () => {
const result = sanitizeWiFiCredentials({
ssid: ' MyWiFi ',
password: 'password',
});
expect(result.ssid).toBe('MyWiFi');
});
it('should preserve password whitespace', () => {
const result = sanitizeWiFiCredentials({
ssid: 'MyWiFi',
password: ' password with spaces ',
});
expect(result.password).toBe(' password with spaces ');
});
it('should not modify valid credentials', () => {
const result = sanitizeWiFiCredentials({
ssid: 'MyWiFi',
password: 'SecurePass123',
});
expect(result.ssid).toBe('MyWiFi');
expect(result.password).toBe('SecurePass123');
});
});
describe('getValidationErrorMessage', () => {
it('should return empty string for valid credentials', () => {
const result = validateWiFiCredentials('MyWiFi', 'SecurePass123', 'WPA2 PSK');
expect(getValidationErrorMessage(result)).toBe('');
});
it('should return first error message', () => {
const result = validateWiFiCredentials('', '123', 'WPA2 PSK');
expect(getValidationErrorMessage(result)).toBe('Network name (SSID) cannot be empty');
});
it('should return default message if no specific error', () => {
const result = { valid: false, errors: [], warnings: [] };
expect(getValidationErrorMessage(result)).toBe('Invalid WiFi credentials');
});
});
describe('getValidationMessage', () => {
it('should return empty string for valid credentials with no warnings', () => {
const result = { valid: true, errors: [], warnings: [] };
expect(getValidationMessage(result)).toBe('');
});
it('should return errors only', () => {
const result = {
valid: false,
errors: ['Error 1', 'Error 2'],
warnings: [],
};
expect(getValidationMessage(result)).toBe('Error 1\nError 2');
});
it('should return warnings only', () => {
const result = {
valid: true,
errors: [],
warnings: ['Warning 1', 'Warning 2'],
};
expect(getValidationMessage(result)).toBe('Warning 1\nWarning 2');
});
it('should return both errors and warnings', () => {
const result = {
valid: false,
errors: ['Error 1'],
warnings: ['Warning 1'],
};
expect(getValidationMessage(result)).toBe('Error 1\nWarning 1');
});
});
});