Skip to content

Commit

Permalink
Merge pull request #219 from uh-dcm/tests
Browse files Browse the repository at this point in the history
test: add more tests
  • Loading branch information
armijuha authored Aug 24, 2024
2 parents 8c4e46f + 3643221 commit 86360f6
Show file tree
Hide file tree
Showing 12 changed files with 752 additions and 0 deletions.
91 changes: 91 additions & 0 deletions client/tests/internal/Errors.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import Errors from '@/features/errors/Errors';
import * as logRecords from '@/features/errors/log-records';
import { toast } from 'sonner';

vi.mock('@/features/errors/log-records', () => ({
getLogRecords: vi.fn(),
clearLogRecords: vi.fn(),
}));

vi.mock('sonner', () => ({
toast: {
success: vi.fn(),
error: vi.fn(),
},
}));

vi.mock('@/components/page-layout', () => ({
PageLayout: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}));

describe('Errors Component', () => {
beforeEach(() => {
vi.clearAllMocks();
});

it('renders error log correctly', async () => {
vi.mocked(logRecords.getLogRecords).mockResolvedValue(['Error 1', 'Error 2']);
render(<Errors />);

await waitFor(() => {
expect(screen.getByText('Error log')).toBeInTheDocument();
expect(screen.getByText('Error 1')).toBeInTheDocument();
expect(screen.getByText('Error 2')).toBeInTheDocument();
});
});

it('handles empty error log', async () => {
vi.mocked(logRecords.getLogRecords).mockResolvedValue([]);
render(<Errors />);

await waitFor(() => {
expect(screen.getByText('No error log.')).toBeInTheDocument();
});
});

it('clears error log', async () => {
vi.mocked(logRecords.getLogRecords).mockResolvedValue(['Error 1']);
vi.mocked(logRecords.clearLogRecords).mockResolvedValue();

render(<Errors />);

await waitFor(() => {
expect(screen.getByText('Error 1')).toBeInTheDocument();
});

fireEvent.click(screen.getByRole('button', { name: 'Clear Log' }));

const confirmButtons = screen.getAllByRole('button', { name: 'Clear Log' });
fireEvent.click(confirmButtons[confirmButtons.length - 1]);

await waitFor(() => {
expect(logRecords.clearLogRecords).toHaveBeenCalled();
expect(toast.success).toHaveBeenCalledWith('Log cleared successfully');
});
});

it('handles clear log error', async () => {
vi.mocked(logRecords.getLogRecords).mockResolvedValue(['Error 1']);
vi.mocked(logRecords.clearLogRecords).mockRejectedValue(new Error('Clear failed'));

render(<Errors />);

await waitFor(() => {
expect(screen.getByText('Error 1')).toBeInTheDocument();
});

fireEvent.click(screen.getByRole('button', { name: 'Clear Log' }));

const confirmButtons = screen.getAllByRole('button', { name: 'Clear Log' });
fireEvent.click(confirmButtons[confirmButtons.length - 1]);

await waitFor(() => {
expect(logRecords.clearLogRecords).toHaveBeenCalled();
expect(toast.error).toHaveBeenCalledWith('Failed to clear log');
});
});
});
89 changes: 89 additions & 0 deletions client/tests/internal/Login.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import Login from '@/features/user/Login';
import * as authFunctions from '@/services/authfunctions';
import { toast } from 'sonner';

vi.mock('@/services/authfunctions', () => ({
loginUser: vi.fn(),
}));

vi.mock('sonner', () => ({
toast: {
error: vi.fn(),
success: vi.fn(),
},
}));

describe('Login Component', () => {
const mockOnLoginSuccess = vi.fn();

beforeEach(() => {
vi.clearAllMocks();
});

it('renders login form correctly', () => {
render(<Login onLoginSuccess={mockOnLoginSuccess} />);

expect(screen.getByAltText('News Article Collector Logo')).toBeInTheDocument();
expect(screen.getByText('News Article Collector')).toBeInTheDocument();
expect(screen.getByPlaceholderText('Enter your password')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Log in' })).toBeInTheDocument();
});

it('handles successful login', async () => {
const mockLoginResponse = { access_token: 'mock-token' };
vi.mocked(authFunctions.loginUser).mockResolvedValue(mockLoginResponse);

render(<Login onLoginSuccess={mockOnLoginSuccess} />);

const passwordInput = screen.getByPlaceholderText('Enter your password');
const loginButton = screen.getByRole('button', { name: 'Log in' });

fireEvent.change(passwordInput, { target: { value: 'testpassword' } });
fireEvent.click(loginButton);

await waitFor(() => {
expect(authFunctions.loginUser).toHaveBeenCalledWith('testpassword');
expect(toast.success).toHaveBeenCalledWith('Login successful!');
expect(mockOnLoginSuccess).toHaveBeenCalled();
});
});

it('handles login failure', async () => {
vi.mocked(authFunctions.loginUser).mockResolvedValue(null);

render(<Login onLoginSuccess={mockOnLoginSuccess} />);

const passwordInput = screen.getByPlaceholderText('Enter your password');
const loginButton = screen.getByRole('button', { name: 'Log in' });

fireEvent.change(passwordInput, { target: { value: 'wrongpassword' } });
fireEvent.click(loginButton);

await waitFor(() => {
expect(authFunctions.loginUser).toHaveBeenCalledWith('wrongpassword');
expect(toast.error).toHaveBeenCalledWith('Failed to login');
expect(mockOnLoginSuccess).not.toHaveBeenCalled();
});
});

it('handles login error', async () => {
vi.mocked(authFunctions.loginUser).mockRejectedValue(new Error('Network error'));

render(<Login onLoginSuccess={mockOnLoginSuccess} />);

const passwordInput = screen.getByPlaceholderText('Enter your password');
const loginButton = screen.getByRole('button', { name: 'Log in' });

fireEvent.change(passwordInput, { target: { value: 'testpassword' } });
fireEvent.click(loginButton);

await waitFor(() => {
expect(authFunctions.loginUser).toHaveBeenCalledWith('testpassword');
expect(toast.error).toHaveBeenCalledWith('Login failed: Network error');
expect(mockOnLoginSuccess).not.toHaveBeenCalled();
});
});
});
90 changes: 90 additions & 0 deletions client/tests/internal/Register.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { BrowserRouter } from 'react-router-dom';
import Register from '@/features/user/Register';
import * as authFunctions from '@/services/authfunctions';
import { toast } from 'sonner';

vi.mock('@/services/authfunctions', () => ({
registerUser: vi.fn(),
}));

vi.mock('sonner', () => ({
toast: {
error: vi.fn(),
success: vi.fn(),
warning: vi.fn(),
},
}));

describe('Register Component', () => {
const mockOnRegistrationSuccess = vi.fn();

beforeEach(() => {
vi.clearAllMocks();
});

const renderRegister = () => {
return render(
<BrowserRouter>
<Register onRegistrationSuccess={mockOnRegistrationSuccess} />
</BrowserRouter>
);
};

it('renders register form correctly', () => {
renderRegister();
expect(screen.getByAltText('News Article Collector Logo')).toBeInTheDocument();
expect(screen.getByText('News Article Collector')).toBeInTheDocument();
expect(screen.getByPlaceholderText('Enter your email')).toBeInTheDocument();
expect(screen.getByPlaceholderText('Enter your password')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Register' })).toBeInTheDocument();
});

it('handles successful registration', async () => {
vi.mocked(authFunctions.registerUser).mockResolvedValue({ success: true, data: {}, emailSent: true });
renderRegister();

fireEvent.change(screen.getByPlaceholderText('Enter your email'), { target: { value: 'test@example.com' } });
fireEvent.change(screen.getByPlaceholderText('Enter your password'), { target: { value: 'password123' } });
fireEvent.click(screen.getByRole('button', { name: 'Register' }));

await waitFor(() => {
expect(authFunctions.registerUser).toHaveBeenCalledWith('test@example.com', 'password123', false);
expect(toast.success).toHaveBeenCalledWith('Registration successful!');
expect(mockOnRegistrationSuccess).toHaveBeenCalled();
});
});

it('handles registration failure', async () => {
vi.mocked(authFunctions.registerUser).mockResolvedValue({ success: false, error: 'Registration failed' });
renderRegister();

fireEvent.change(screen.getByPlaceholderText('Enter your email'), { target: { value: 'test@example.com' } });
fireEvent.change(screen.getByPlaceholderText('Enter your password'), { target: { value: 'password123' } });
fireEvent.click(screen.getByRole('button', { name: 'Register' }));

await waitFor(() => {
expect(authFunctions.registerUser).toHaveBeenCalledWith('test@example.com', 'password123', false);
expect(toast.error).toHaveBeenCalledWith('Failed to register: Registration failed');
expect(mockOnRegistrationSuccess).not.toHaveBeenCalled();
});
});

it('handles registration with email sending issue', async () => {
vi.mocked(authFunctions.registerUser).mockResolvedValue({ success: true, data: {}, emailSent: false });
renderRegister();

fireEvent.change(screen.getByPlaceholderText('Enter your email'), { target: { value: 'test@example.com' } });
fireEvent.change(screen.getByPlaceholderText('Enter your password'), { target: { value: 'password123' } });
fireEvent.click(screen.getByRole('button', { name: 'Register' }));

await waitFor(() => {
expect(authFunctions.registerUser).toHaveBeenCalledWith('test@example.com', 'password123', false);
expect(toast.success).toHaveBeenCalledWith('Registration successful!');
expect(toast.warning).toHaveBeenCalledWith('Registration successful, but there was an issue sending the confirmation email. You can still use the app.', { duration: 10000 });
expect(mockOnRegistrationSuccess).toHaveBeenCalled();
});
});
});
74 changes: 74 additions & 0 deletions client/tests/internal/ReregisterValidator.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { render, screen, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import ReregisterValidator from '@/features/user/ReregisterValidator';
import * as authFunctions from '@/services/authfunctions';
import { toast } from 'sonner';

vi.mock('@/services/authfunctions', () => ({
validateReregisterToken: vi.fn(),
}));

vi.mock('sonner', () => ({
toast: {
error: vi.fn(),
custom: vi.fn(),
},
}));

describe('ReregisterValidator Component', () => {
const mockOnValidationComplete = vi.fn();

beforeEach(() => {
vi.clearAllMocks();
});

const renderReregisterValidator = (token: string) => {
return render(
<MemoryRouter initialEntries={[`/reregister/${token}`]}>
<Routes>
<Route path="/reregister/:token" element={<ReregisterValidator onValidationComplete={mockOnValidationComplete} />} />
</Routes>
</MemoryRouter>
);
};

it('displays loading message while validating', () => {
renderReregisterValidator('valid-token');
expect(screen.getByText('Validating reregistration token...')).toBeInTheDocument();
});

it('handles valid token', async () => {
vi.mocked(authFunctions.validateReregisterToken).mockResolvedValue({ valid: true });
renderReregisterValidator('valid-token');

await waitFor(() => {
expect(authFunctions.validateReregisterToken).toHaveBeenCalledWith('valid-token');
expect(toast.custom).toHaveBeenCalled();
expect(mockOnValidationComplete).toHaveBeenCalledWith(true);
});
});

it('handles invalid token', async () => {
vi.mocked(authFunctions.validateReregisterToken).mockResolvedValue({ valid: false });
renderReregisterValidator('invalid-token');

await waitFor(() => {
expect(authFunctions.validateReregisterToken).toHaveBeenCalledWith('invalid-token');
expect(toast.error).toHaveBeenCalledWith('Invalid or expired token');
expect(mockOnValidationComplete).toHaveBeenCalledWith(false);
});
});

it('handles validation error', async () => {
vi.mocked(authFunctions.validateReregisterToken).mockRejectedValue(new Error('Validation failed'));
renderReregisterValidator('error-token');

await waitFor(() => {
expect(authFunctions.validateReregisterToken).toHaveBeenCalledWith('error-token');
expect(toast.error).toHaveBeenCalledWith('An error occurred when validating the token. Did it expire already?');
expect(mockOnValidationComplete).toHaveBeenCalledWith(false);
});
});
});
Loading

0 comments on commit 86360f6

Please sign in to comment.