2025-12-03 21:56:50 +00:00
|
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
|
|
|
import { render, screen, waitFor, fireEvent } from '@/test/helpers';
|
|
|
|
|
import { BrowserRouter } from 'react-router-dom';
|
|
|
|
|
import { LoginForm } from './LoginForm';
|
|
|
|
|
import * as emailVerificationService from '../services/emailVerificationService';
|
|
|
|
|
|
|
|
|
|
// Mock useAuthStore
|
|
|
|
|
const mockLogin = vi.fn();
|
|
|
|
|
const mockClearError = vi.fn();
|
|
|
|
|
const mockError = { message: '', code: '' };
|
|
|
|
|
|
|
|
|
|
vi.mock('@/stores/auth', () => ({
|
|
|
|
|
useAuthStore: () => ({
|
|
|
|
|
login: mockLogin,
|
|
|
|
|
isLoading: false,
|
|
|
|
|
error: mockError,
|
|
|
|
|
clearError: mockClearError,
|
|
|
|
|
}),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// Mock useTranslation
|
|
|
|
|
vi.mock('@/hooks/useTranslation', () => ({
|
|
|
|
|
useTranslation: () => ({
|
|
|
|
|
t: (key: string) => key,
|
|
|
|
|
}),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// Mock emailVerificationService
|
|
|
|
|
vi.mock('../services/emailVerificationService', () => ({
|
|
|
|
|
resendVerificationEmail: vi.fn(),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
describe('LoginForm - Resend Verification Email', () => {
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
vi.clearAllMocks();
|
|
|
|
|
mockError.message = '';
|
|
|
|
|
mockError.code = '';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('Resend verification email button', () => {
|
|
|
|
|
it('should display resend button when error indicates email not verified', async () => {
|
|
|
|
|
mockError.message = 'Email not verified';
|
|
|
|
|
|
|
|
|
|
render(
|
|
|
|
|
<BrowserRouter>
|
|
|
|
|
<LoginForm />
|
2025-12-13 02:34:34 +00:00
|
|
|
</BrowserRouter>,
|
2025-12-03 21:56:50 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(screen.getByText(/email not verified/i)).toBeInTheDocument();
|
2025-12-13 02:34:34 +00:00
|
|
|
expect(
|
|
|
|
|
screen.getByText(/resend verification email/i),
|
|
|
|
|
).toBeInTheDocument();
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not display resend button for other errors', async () => {
|
|
|
|
|
mockError.message = 'Invalid credentials';
|
|
|
|
|
|
|
|
|
|
render(
|
|
|
|
|
<BrowserRouter>
|
|
|
|
|
<LoginForm />
|
2025-12-13 02:34:34 +00:00
|
|
|
</BrowserRouter>,
|
2025-12-03 21:56:50 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(screen.getByText(/invalid credentials/i)).toBeInTheDocument();
|
2025-12-13 02:34:34 +00:00
|
|
|
expect(
|
|
|
|
|
screen.queryByText(/resend verification email/i),
|
|
|
|
|
).not.toBeInTheDocument();
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should call resendVerificationEmail when resend button is clicked', async () => {
|
|
|
|
|
mockError.message = 'Email not verified';
|
2025-12-13 02:34:34 +00:00
|
|
|
vi.mocked(
|
|
|
|
|
emailVerificationService.resendVerificationEmail,
|
|
|
|
|
).mockResolvedValue({
|
2025-12-03 21:56:50 +00:00
|
|
|
message: 'verification email sent',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
render(
|
|
|
|
|
<BrowserRouter>
|
|
|
|
|
<LoginForm />
|
2025-12-13 02:34:34 +00:00
|
|
|
</BrowserRouter>,
|
2025-12-03 21:56:50 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
2025-12-13 02:34:34 +00:00
|
|
|
expect(
|
|
|
|
|
screen.getByText(/resend verification email/i),
|
|
|
|
|
).toBeInTheDocument();
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const emailInput = screen.getByLabelText(/email/i);
|
|
|
|
|
fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
|
|
|
|
|
|
|
|
|
|
const resendButton = screen.getByText(/resend verification email/i);
|
|
|
|
|
fireEvent.click(resendButton);
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
2025-12-13 02:34:34 +00:00
|
|
|
expect(
|
|
|
|
|
emailVerificationService.resendVerificationEmail,
|
|
|
|
|
).toHaveBeenCalledWith('test@example.com');
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should display cooldown countdown after resending email', async () => {
|
|
|
|
|
mockError.message = 'Email not verified';
|
2025-12-13 02:34:34 +00:00
|
|
|
vi.mocked(
|
|
|
|
|
emailVerificationService.resendVerificationEmail,
|
|
|
|
|
).mockResolvedValue({
|
2025-12-03 21:56:50 +00:00
|
|
|
message: 'verification email sent',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
vi.useFakeTimers();
|
|
|
|
|
render(
|
|
|
|
|
<BrowserRouter>
|
|
|
|
|
<LoginForm />
|
2025-12-13 02:34:34 +00:00
|
|
|
</BrowserRouter>,
|
2025-12-03 21:56:50 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
2025-12-13 02:34:34 +00:00
|
|
|
expect(
|
|
|
|
|
screen.getByText(/resend verification email/i),
|
|
|
|
|
).toBeInTheDocument();
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const emailInput = screen.getByLabelText(/email/i);
|
|
|
|
|
fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
|
|
|
|
|
|
|
|
|
|
const resendButton = screen.getByText(/resend verification email/i);
|
|
|
|
|
fireEvent.click(resendButton);
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(screen.getByText(/resend in/i)).toBeInTheDocument();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
vi.useRealTimers();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should display confirmation message after successful resend', async () => {
|
|
|
|
|
mockError.message = 'Email not verified';
|
2025-12-13 02:34:34 +00:00
|
|
|
vi.mocked(
|
|
|
|
|
emailVerificationService.resendVerificationEmail,
|
|
|
|
|
).mockResolvedValue({
|
2025-12-03 21:56:50 +00:00
|
|
|
message: 'verification email sent',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
render(
|
|
|
|
|
<BrowserRouter>
|
|
|
|
|
<LoginForm />
|
2025-12-13 02:34:34 +00:00
|
|
|
</BrowserRouter>,
|
2025-12-03 21:56:50 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
2025-12-13 02:34:34 +00:00
|
|
|
expect(
|
|
|
|
|
screen.getByText(/resend verification email/i),
|
|
|
|
|
).toBeInTheDocument();
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const emailInput = screen.getByLabelText(/email/i);
|
|
|
|
|
fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
|
|
|
|
|
|
|
|
|
|
const resendButton = screen.getByText(/resend verification email/i);
|
|
|
|
|
fireEvent.click(resendButton);
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
2025-12-13 02:34:34 +00:00
|
|
|
expect(
|
|
|
|
|
screen.getByText(/verification email sent/i),
|
|
|
|
|
).toBeInTheDocument();
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should display error message when resend fails', async () => {
|
|
|
|
|
mockError.message = 'Email not verified';
|
2025-12-13 02:34:34 +00:00
|
|
|
vi.mocked(
|
|
|
|
|
emailVerificationService.resendVerificationEmail,
|
|
|
|
|
).mockRejectedValue({
|
2025-12-03 21:56:50 +00:00
|
|
|
message: 'Failed to resend email',
|
|
|
|
|
code: '500',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
render(
|
|
|
|
|
<BrowserRouter>
|
|
|
|
|
<LoginForm />
|
2025-12-13 02:34:34 +00:00
|
|
|
</BrowserRouter>,
|
2025-12-03 21:56:50 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
2025-12-13 02:34:34 +00:00
|
|
|
expect(
|
|
|
|
|
screen.getByText(/resend verification email/i),
|
|
|
|
|
).toBeInTheDocument();
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const emailInput = screen.getByLabelText(/email/i);
|
|
|
|
|
fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
|
|
|
|
|
|
|
|
|
|
const resendButton = screen.getByText(/resend verification email/i);
|
|
|
|
|
fireEvent.click(resendButton);
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(screen.getByText(/failed to resend email/i)).toBeInTheDocument();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|