Add comprehensive tests for hooks, middleware, and routes
Some checks are pending
Deploy to Test Environment / deploy-to-test (push) Has started running
Some checks are pending
Deploy to Test Environment / deploy-to-test (push) Has started running
- Implement tests for `useFlyers`, `useMasterItems`, `useModal`, `useUserData` hooks to ensure correct functionality and error handling. - Create tests for `fileUpload.middleware` and `validation.middleware` to validate file uploads and request data. - Add tests for `AddressForm` and `AuthView` components to verify rendering, user interactions, and API calls. - Develop tests for `deals.routes` to check authentication and response for best prices on watched items.
This commit is contained in:
201
src/pages/admin/components/AuthView.test.tsx
Normal file
201
src/pages/admin/components/AuthView.test.tsx
Normal file
@@ -0,0 +1,201 @@
|
||||
// src/pages/admin/components/AuthView.test.tsx
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
||||
import { AuthView } from './AuthView';
|
||||
import * as apiClient from '../../../services/apiClient';
|
||||
import { notifySuccess, notifyError } from '../../../services/notificationService';
|
||||
|
||||
const mockedApiClient = vi.mocked(apiClient, true);
|
||||
|
||||
const mockOnClose = vi.fn();
|
||||
const mockOnLoginSuccess = vi.fn();
|
||||
|
||||
const defaultProps = {
|
||||
onClose: mockOnClose,
|
||||
onLoginSuccess: mockOnLoginSuccess,
|
||||
};
|
||||
|
||||
const setupSuccessMocks = () => {
|
||||
const mockAuthResponse = {
|
||||
user: { user_id: '123', email: 'test@example.com' },
|
||||
token: 'mock-token',
|
||||
};
|
||||
(mockedApiClient.loginUser as Mock).mockResolvedValue(new Response(JSON.stringify(mockAuthResponse)));
|
||||
(mockedApiClient.registerUser as Mock).mockResolvedValue(new Response(JSON.stringify(mockAuthResponse)));
|
||||
(mockedApiClient.requestPasswordReset as Mock).mockResolvedValue(
|
||||
new Response(JSON.stringify({ message: 'Password reset email sent.' }))
|
||||
);
|
||||
};
|
||||
|
||||
describe('AuthView', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
setupSuccessMocks();
|
||||
});
|
||||
|
||||
describe('Initial Render and Login', () => {
|
||||
it('should render the Sign In form by default', () => {
|
||||
render(<AuthView {...defaultProps} />);
|
||||
expect(screen.getByRole('heading', { name: /sign in/i })).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(/email address/i)).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(/^password$/i)).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: /sign in$/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should allow typing in email and password fields', () => {
|
||||
render(<AuthView {...defaultProps} />);
|
||||
const emailInput = screen.getByLabelText(/email address/i);
|
||||
const passwordInput = screen.getByLabelText(/^password$/i);
|
||||
|
||||
fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
|
||||
fireEvent.change(passwordInput, { target: { value: 'password123' } });
|
||||
|
||||
expect(emailInput).toHaveValue('test@example.com');
|
||||
expect(passwordInput).toHaveValue('password123');
|
||||
});
|
||||
|
||||
it('should call loginUser and onLoginSuccess on successful login', async () => {
|
||||
render(<AuthView {...defaultProps} />);
|
||||
fireEvent.change(screen.getByLabelText(/email address/i), { target: { value: 'test@example.com' } });
|
||||
fireEvent.change(screen.getByLabelText(/^password$/i), { target: { value: 'password123' } });
|
||||
fireEvent.click(screen.getByRole('checkbox', { name: /remember me/i }));
|
||||
fireEvent.submit(screen.getByTestId('auth-form'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockedApiClient.loginUser).toHaveBeenCalledWith('test@example.com', 'password123', true);
|
||||
expect(mockOnLoginSuccess).toHaveBeenCalledWith(
|
||||
{ user_id: '123', email: 'test@example.com' },
|
||||
'mock-token',
|
||||
true
|
||||
);
|
||||
expect(mockOnClose).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display an error on failed login', async () => {
|
||||
(mockedApiClient.loginUser as Mock).mockRejectedValueOnce(new Error('Invalid credentials'));
|
||||
render(<AuthView {...defaultProps} />);
|
||||
fireEvent.submit(screen.getByTestId('auth-form'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(notifyError).toHaveBeenCalledWith('Invalid credentials');
|
||||
});
|
||||
expect(mockOnLoginSuccess).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Registration', () => {
|
||||
it('should switch to the registration form', () => {
|
||||
render(<AuthView {...defaultProps} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /don't have an account\? register/i }));
|
||||
|
||||
expect(screen.getByRole('heading', { name: /create an account/i })).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(/full name/i)).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: /^register$/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call registerUser on successful registration', async () => {
|
||||
render(<AuthView {...defaultProps} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /don't have an account\? register/i }));
|
||||
|
||||
fireEvent.change(screen.getByLabelText(/full name/i), { target: { value: 'Test User' } });
|
||||
fireEvent.change(screen.getByLabelText(/email address/i), { target: { value: 'new@example.com' } });
|
||||
fireEvent.change(screen.getByLabelText(/^password$/i), { target: { value: 'newpassword' } });
|
||||
fireEvent.submit(screen.getByTestId('auth-form'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockedApiClient.registerUser).toHaveBeenCalledWith('new@example.com', 'newpassword', 'Test User', '');
|
||||
expect(mockOnLoginSuccess).toHaveBeenCalledWith(
|
||||
{ user_id: '123', email: 'test@example.com' },
|
||||
'mock-token',
|
||||
false // rememberMe is false for registration
|
||||
);
|
||||
expect(mockOnClose).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display an error on failed registration', async () => {
|
||||
(mockedApiClient.registerUser as Mock).mockRejectedValueOnce(new Error('Email already exists'));
|
||||
render(<AuthView {...defaultProps} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /don't have an account\? register/i }));
|
||||
fireEvent.submit(screen.getByTestId('auth-form'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(notifyError).toHaveBeenCalledWith('Email already exists');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Forgot Password', () => {
|
||||
it('should switch to the reset password form', () => {
|
||||
render(<AuthView {...defaultProps} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /forgot password\?/i }));
|
||||
|
||||
expect(screen.getByRole('heading', { name: /reset password/i })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: /send reset link/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call requestPasswordReset and show success message', async () => {
|
||||
render(<AuthView {...defaultProps} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /forgot password\?/i }));
|
||||
|
||||
fireEvent.change(screen.getByLabelText(/email address/i), { target: { value: 'forgot@example.com' } });
|
||||
fireEvent.submit(screen.getByTestId('reset-password-form'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockedApiClient.requestPasswordReset).toHaveBeenCalledWith('forgot@example.com');
|
||||
expect(notifySuccess).toHaveBeenCalledWith('Password reset email sent.');
|
||||
});
|
||||
});
|
||||
|
||||
it('should display an error on failed password reset request', async () => {
|
||||
(mockedApiClient.requestPasswordReset as Mock).mockRejectedValueOnce(new Error('User not found'));
|
||||
render(<AuthView {...defaultProps} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /forgot password\?/i }));
|
||||
fireEvent.submit(screen.getByTestId('reset-password-form'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(notifyError).toHaveBeenCalledWith('User not found');
|
||||
});
|
||||
});
|
||||
|
||||
it('should switch back to sign in from forgot password', () => {
|
||||
render(<AuthView {...defaultProps} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /forgot password\?/i }));
|
||||
fireEvent.click(screen.getByRole('button', { name: /back to sign in/i }));
|
||||
|
||||
expect(screen.getByRole('heading', { name: /sign in/i })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('OAuth', () => {
|
||||
const originalLocation = window.location;
|
||||
|
||||
beforeEach(() => {
|
||||
Object.defineProperty(window, 'location', {
|
||||
writable: true,
|
||||
value: { ...originalLocation, href: '' },
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Object.defineProperty(window, 'location', {
|
||||
writable: true,
|
||||
value: originalLocation,
|
||||
});
|
||||
});
|
||||
|
||||
it('should set window.location.href for Google OAuth', () => {
|
||||
render(<AuthView {...defaultProps} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /sign in with google/i }));
|
||||
expect(window.location.href).toBe('/api/auth/google');
|
||||
});
|
||||
|
||||
it('should set window.location.href for GitHub OAuth', () => {
|
||||
render(<AuthView {...defaultProps} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /sign in with github/i }));
|
||||
expect(window.location.href).toBe('/api/auth/github');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user