veza/apps/web/src/components/forms/PasswordStrengthIndicator.test.tsx
2025-12-12 21:34:34 -05:00

116 lines
4.7 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { PasswordStrengthIndicator } from './PasswordStrengthIndicator';
describe('PasswordStrengthIndicator', () => {
it('should not render when password is empty', () => {
const { container } = render(<PasswordStrengthIndicator password="" />);
expect(container.firstChild).toBeNull();
});
it('should show "Very Weak" for very weak password', () => {
render(<PasswordStrengthIndicator password="a" />);
expect(screen.getByText('Very Weak')).toBeInTheDocument();
});
it('should show "Weak" for weak password with only length', () => {
render(<PasswordStrengthIndicator password="abcdefghijkl" />);
expect(screen.getByText('Weak')).toBeInTheDocument();
});
it('should show "Fair" for password with length, uppercase, and lowercase', () => {
render(<PasswordStrengthIndicator password="PasswordTest" />);
expect(screen.getByText('Fair')).toBeInTheDocument();
});
it('should show "Good" for password with length, uppercase, lowercase, and number', () => {
render(<PasswordStrengthIndicator password="Password1234" />);
expect(screen.getByText('Good')).toBeInTheDocument();
});
it('should show "Strong" for password with all requirements', () => {
render(<PasswordStrengthIndicator password="SecurePass123!" />);
expect(screen.getByText('Strong')).toBeInTheDocument();
});
it('should display all validation rules', () => {
render(<PasswordStrengthIndicator password="test" />);
expect(screen.getByText(/at least 12 characters/i)).toBeInTheDocument();
expect(screen.getByText(/one uppercase letter/i)).toBeInTheDocument();
expect(screen.getByText(/one lowercase letter/i)).toBeInTheDocument();
expect(screen.getByText(/one number/i)).toBeInTheDocument();
expect(screen.getByText(/one special character/i)).toBeInTheDocument();
});
it('should show checkmarks for fulfilled requirements', () => {
render(<PasswordStrengthIndicator password="SecurePass123!" />);
const checks = screen.getAllByText('✓');
expect(checks.length).toBe(5); // All 5 requirements met
});
it('should show circles for unfulfilled requirements', () => {
render(<PasswordStrengthIndicator password="a" />);
const circles = screen.getAllByText('○');
expect(circles.length).toBeGreaterThan(0);
});
it('should have correct progress bar width for score', () => {
const { container } = render(
<PasswordStrengthIndicator password="SecurePass123!" />,
);
const progressBar = container.querySelector(
'[role="progressbar"]',
) as HTMLElement;
expect(progressBar).toBeInTheDocument();
expect(progressBar.style.width).toBe('100%'); // 5/5 = 100%
expect(progressBar.getAttribute('aria-valuenow')).toBe('5');
});
it('should have correct progress bar width for partial score', () => {
// Password1234 has 12 characters, upper, lower, number = 4 points = 80%
const { container } = render(
<PasswordStrengthIndicator password="Password1234" />,
);
const progressBar = container.querySelector(
'[role="progressbar"]',
) as HTMLElement;
expect(progressBar).toBeInTheDocument();
expect(progressBar.getAttribute('aria-valuenow')).toBe('4');
expect(progressBar.style.width).toContain('%'); // Should have percentage width
});
it('should correctly identify special characters', () => {
// Test with a single special character
const { container } = render(
<PasswordStrengthIndicator password="Password1234!" />,
);
expect(container.firstChild).not.toBeNull();
// Should show "Strong" for password with all requirements including special char
expect(screen.getByText('Strong')).toBeInTheDocument();
});
it('should have accessible progress bar attributes', () => {
const { container } = render(
<PasswordStrengthIndicator password="SecurePass123!" />,
);
const progressBar = container.querySelector(
'[role="progressbar"]',
) as HTMLElement;
expect(progressBar.getAttribute('role')).toBe('progressbar');
expect(progressBar.getAttribute('aria-valuenow')).toBe('5');
expect(progressBar.getAttribute('aria-valuemin')).toBe('0');
expect(progressBar.getAttribute('aria-valuemax')).toBe('5');
expect(progressBar.getAttribute('aria-label')).toContain(
'Password strength',
);
});
it('should update score when password changes', () => {
const { rerender } = render(<PasswordStrengthIndicator password="a" />);
expect(screen.getByText('Very Weak')).toBeInTheDocument();
rerender(<PasswordStrengthIndicator password="SecurePass123!" />);
expect(screen.getByText('Strong')).toBeInTheDocument();
});
});