Skip to content

Password Reset Flow Testing Guide

This document provides comprehensive testing strategies and implementation details for the password reset flow in Bartendie, including unit tests, integration tests, and manual testing procedures.

The password reset flow testing covers:

  1. ForgotPasswordPage - Email submission and validation
  2. ResetPasswordPage - Password reset with token validation
  3. Integration Flow - Complete end-to-end password reset process
  4. Security Features - Email enumeration protection and token validation
  5. Accessibility - Screen reader support and keyboard navigation
frontend/src/components/auth/__tests__/
├── ForgotPasswordPage.test.tsx # Unit tests for forgot password
├── ResetPasswordPage.test.tsx # Unit tests for password reset
├── PasswordResetFlow.integration.test.tsx # Integration tests
└── setup.ts # Test configuration

File: frontend/src/components/auth/__tests__/setup.ts

import { vi } from 'vitest';
import '@testing-library/jest-dom';
// Mock browser APIs
global.IntersectionObserver = vi.fn().mockImplementation(() => ({
observe: vi.fn(),
unobserve: vi.fn(),
disconnect: vi.fn(),
}));
// Mock localStorage and sessionStorage
const localStorageMock = {
getItem: vi.fn(),
setItem: vi.fn(),
removeItem: vi.fn(),
clear: vi.fn(),
};
Object.defineProperty(window, 'localStorage', { value: localStorageMock });

Test Categories:

  1. Initial Render

    • Form structure and accessibility
    • Proper labels and input types
    • Navigation links
  2. Form Validation

    • Empty email validation
    • Invalid email format validation
    • Error clearing on input change
  3. Form Submission

    • Loading states during submission
    • Success state display
    • Error handling (with security considerations)
  4. Security Features

    • Email enumeration protection
    • Consistent success responses

Example Test:

test('shows success state even on API error (security feature)', async () => {
const mocks = [
{
request: {
query: REQUEST_PASSWORD_RESET_MUTATION,
variables: { email: 'nonexistent@example.com' },
},
error: new Error('User not found'),
},
];
render(
<TestWrapper mocks={mocks}>
<ForgotPasswordPage />
</TestWrapper>
);
// Submit form with non-existent email
const emailInput = screen.getByLabelText(/email address/i);
const submitButton = screen.getByRole('button', { name: /send reset link/i });
fireEvent.change(emailInput, { target: { value: 'nonexistent@example.com' } });
fireEvent.click(submitButton);
// Should still show success for security
await waitFor(() => {
expect(screen.getByText('Check your email')).toBeInTheDocument();
});
});

Test Categories:

  1. Token Validation

    • Redirect when no token provided
    • Token extraction from URL parameters
    • Invalid/expired token handling
  2. Password Requirements

    • Real-time requirement checking
    • Password strength indicator
    • Visual feedback for met/unmet requirements
  3. Password Matching

    • Confirm password validation
    • Real-time match indicators
    • Error states for mismatched passwords
  4. Form Submission

    • Loading states
    • Success state after reset
    • Error handling for various scenarios

Example Test:

test('shows password requirements when user starts typing', () => {
render(
<TestWrapper>
<ResetPasswordPage />
</TestWrapper>
);
const passwordInput = screen.getByLabelText(/new password/i);
// Requirements should not be visible initially
expect(screen.queryByText('Password must contain:')).not.toBeInTheDocument();
// Start typing to show requirements
fireEvent.change(passwordInput, { target: { value: 'a' } });
expect(screen.getByText('Password must contain:')).toBeInTheDocument();
expect(screen.getByText('At least 8 characters')).toBeInTheDocument();
expect(screen.getByText('Contains uppercase letter')).toBeInTheDocument();
});

Test Scenarios:

  1. Successful Password Reset

    • Request reset → Success state → Reset with token → Success
    • Validates entire user journey
  2. Expired Token Handling

    • Request reset → Try to reset with expired token → Error handling
  3. Network Error Handling

    • Network failures at various stages
    • Graceful degradation

Example Integration Test:

test('successfully completes entire password reset flow', async () => {
const testEmail = 'test@example.com';
const testToken = 'valid-reset-token';
const newPassword = 'NewStrongPassword123!';
const mocks = [
// Step 1: Request password reset
{
request: {
query: REQUEST_PASSWORD_RESET_MUTATION,
variables: { email: testEmail },
},
result: {
data: { requestPasswordReset: { success: true, message: 'Reset email sent' } },
},
},
// Step 2: Reset password with token
{
request: {
query: RESET_PASSWORD_MUTATION,
variables: { token: testToken, password: newPassword, confirmPassword: newPassword },
},
result: {
data: { resetPassword: { success: true, message: 'Password reset successful' } },
},
},
];
// Test complete flow...
});

Test Objective: Ensure the system doesn’t reveal whether an email exists

test('does not reveal whether email exists in system', async () => {
const nonExistentEmail = 'nonexistent@example.com';
const mocks = [
{
request: {
query: REQUEST_PASSWORD_RESET_MUTATION,
variables: { email: nonExistentEmail },
},
error: new Error('User not found'),
},
];
// Should show success even for non-existent email
await waitFor(() => {
expect(screen.getByText('Check your email')).toBeInTheDocument();
expect(screen.getByText(new RegExp(nonExistentEmail))).toBeInTheDocument();
});
});

Test Scenarios:

  • Invalid token format
  • Expired tokens
  • Already used tokens
  • Missing tokens

Test Areas:

  • Form labels and descriptions
  • Error announcements
  • Loading state announcements
  • Success state communication
test('announces errors to screen readers', async () => {
render(<ForgotPasswordPage />);
const submitButton = screen.getByRole('button', { name: /send reset link/i });
fireEvent.click(submitButton);
await waitFor(() => {
const errorMessage = screen.getByText('Email is required');
expect(errorMessage).toBeInTheDocument();
expect(errorMessage.closest('p')).toHaveClass('text-red-600');
});
});

Test Areas:

  • Tab order through form elements
  • Enter key form submission
  • Escape key handling
  • Focus management
  • Form renders correctly
  • Email validation works (empty, invalid format)
  • Submit button shows loading state
  • Success state displays correctly
  • “Try again” functionality works
  • Navigation links work correctly
  • Redirects when no token provided
  • Password requirements display correctly
  • Password strength indicator updates
  • Password matching validation works
  • Form submission handles all states
  • Success state provides login link
  • Complete flow from forgot password to reset
  • Email link navigation works
  • Token expiration handling
  • Multiple reset attempts

Supported Browsers:

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

Mobile Testing:

  • iOS Safari
  • Android Chrome
  • Responsive design validation

Tools:

  • axe-core automated testing
  • Screen reader testing (NVDA, VoiceOver)
  • Keyboard-only navigation
  • High contrast mode testing

Manual Checks:

  • All interactive elements are keyboard accessible
  • Focus indicators are visible
  • Error messages are announced
  • Form structure is semantic
  • Color contrast meets WCAG standards
  1. Form Submission Performance

    • Measure response times for password reset requests
    • Test with various network conditions
  2. Client-Side Performance

    • Password strength calculation performance
    • Real-time validation responsiveness
  • Form submission response time
  • Password validation calculation time
  • Bundle size impact of authentication components
  • Memory usage during form interactions
  1. Offline Handling

    • Test behavior when network is unavailable
    • Graceful error messages
  2. Slow Network

    • Loading states remain visible
    • Timeout handling
  3. Server Errors

    • 500 errors
    • Rate limiting responses
    • Malformed responses
  1. Malicious Input

    • XSS attempt in email field
    • SQL injection attempts
    • Extremely long inputs
  2. Browser Edge Cases

    • Disabled JavaScript
    • Cookies disabled
    • Local storage unavailable
Terminal window
# Run all authentication tests
npm test -- src/components/auth/__tests__/
# Run with coverage
npm run test:coverage -- src/components/auth/
# Run integration tests only
npm test -- src/components/auth/__tests__/PasswordResetFlow.integration.test.tsx
  • Coverage reports for authentication components
  • Accessibility audit results
  • Performance benchmark results
  • Cross-browser test results
  1. Visual Regression Testing

    • Screenshot comparison for UI consistency
    • Cross-browser visual testing
  2. End-to-End Testing

    • Playwright/Cypress integration
    • Real email service testing
  3. Load Testing

    • Stress testing password reset endpoints
    • Concurrent user simulation
  4. Security Testing

    • Penetration testing scenarios
    • OWASP compliance validation

This comprehensive testing strategy ensures the password reset flow is robust, secure, and accessible across all supported platforms and user scenarios.