Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sametaln committed Dec 20, 2024
1 parent 54289c7 commit 555e156
Show file tree
Hide file tree
Showing 4 changed files with 328 additions and 0 deletions.
21 changes: 21 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
"prettier-plugin-style-order": "^0.2.2",
"prettier-plugin-tailwindcss": "^0.1.13",
"react-test-renderer": "^18.2.0",
"redux-mock-store": "^1.5.5",
"stylelint": "^14.11.0",
"stylelint-config-idiomatic-order": "^8.1.0",
"stylelint-config-prettier-scss": "^0.0.1",
Expand Down
175 changes: 175 additions & 0 deletions frontend/src/components/CreatePostModal.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import { Provider } from 'react-redux';
import { ChakraProvider, useToast } from '@chakra-ui/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import configureStore from 'redux-mock-store';
import CreatePostModal from './CreatePostModal.component.jsx';
import { PhaseContextProvider } from '../context/PostContext';
import { UserContextProvider } from '../context/UserContext';

jest.mock('@tanstack/react-query', () => ({
...jest.requireActual('@tanstack/react-query'),
useMutation: jest.fn(),
useQueryClient: jest.fn(() => ({
invalidateQueries: jest.fn(),
})),
}));

jest.mock('react-redux', () => ({
useSelector: jest.fn(() => 'mockSessionToken'),
}));

jest.mock('@chakra-ui/react', () => ({
...jest.requireActual('@chakra-ui/react'),
useToast: jest.fn(() => jest.fn()),
}));

const mockStore = configureStore([]);
const queryClient = new QueryClient();
const mockToast = jest.fn();
useToast.mockReturnValue(mockToast);

describe('CreatePostModal Component', () => {
const mockPrograms = [
{ id: '1', title: 'Program 1' },
{ id: '2', title: 'Program 2' },
];

const mockTags = ['Tag1', 'Tag2', 'Tag3'];

const mockPostContext = {
programs: mockPrograms,
isLoadingPrograms: false,
tags: mockTags,
isLoadingTags: false,
};

const mockUserContext = {
user: { id: 'user1', name: 'Test User' },
};

let store;

beforeEach(() => {
store = mockStore({});
jest.clearAllMocks();
});

const renderComponent = (props = {}) => {
render(
<Provider store={store}>
<QueryClientProvider client={queryClient}>
<ChakraProvider>
<UserContextProvider value={mockUserContext}>
<PhaseContextProvider value={mockPostContext}>
<CreatePostModal isOpen={true} onClose={jest.fn()} {...props} />
</PhaseContextProvider>
</UserContextProvider>
</ChakraProvider>
</QueryClientProvider>
</Provider>
);
};

it('renders the modal with all fields', () => {
renderComponent();

expect(screen.getByText('Create a new post')).toBeInTheDocument();
expect(screen.getByLabelText('Content')).toBeInTheDocument();
expect(screen.getByLabelText('Image URL')).toBeInTheDocument();
expect(screen.getByText('Attach a training program')).toBeInTheDocument();
expect(screen.getByText('Tags')).toBeInTheDocument();
});

it('allows users to fill out the form fields', () => {
renderComponent();

const contentInput = screen.getByLabelText('Content');
const imageInput = screen.getByLabelText('Image URL');

fireEvent.change(contentInput, { target: { value: 'Test content' } });
fireEvent.change(imageInput, { target: { value: 'http://example.com/image.jpg' } });

expect(contentInput.value).toBe('Test content');
expect(imageInput.value).toBe('http://example.com/image.jpg');
});

it('displays the training programs in the dropdown', () => {
renderComponent();

fireEvent.mouseDown(screen.getByText('Attach a training program'));
expect(screen.getByText('Program 1')).toBeInTheDocument();
expect(screen.getByText('Program 2')).toBeInTheDocument();
});

it('displays the tags in the dropdown', () => {
renderComponent();

fireEvent.mouseDown(screen.getByText('Tags'));
expect(screen.getByText('Tag1')).toBeInTheDocument();
expect(screen.getByText('Tag2')).toBeInTheDocument();
expect(screen.getByText('Tag3')).toBeInTheDocument();
});

it('shows an error toast if no tags are selected', async () => {
const mockMutate = jest.fn((options) => options.mutationFn());
const { useMutation } = require('@tanstack/react-query');
useMutation.mockReturnValue({ mutate: mockMutate });

renderComponent();

fireEvent.change(screen.getByLabelText('Content'), { target: { value: 'Test content' } });
fireEvent.change(screen.getByLabelText('Image URL'), { target: { value: 'http://example.com/image.jpg' } });

fireEvent.click(screen.getByRole('button', { name: /Save/i }));

await waitFor(() => {
expect(mockToast).toHaveBeenCalledWith(
expect.objectContaining({
title: 'No tags selected.',
description: 'Please select at least one tag.',
status: 'error',
})
);
});
});

it('shows a success toast on successful post creation', async () => {
const mockMutate = jest.fn((options) => options.onSuccess());
const { useMutation } = require('@tanstack/react-query');
useMutation.mockReturnValue({ mutate: mockMutate });

renderComponent();

fireEvent.change(screen.getByLabelText('Content'), { target: { value: 'Test content' } });
fireEvent.change(screen.getByLabelText('Image URL'), { target: { value: 'http://example.com/image.jpg' } });
fireEvent.mouseDown(screen.getByText('Tags'));
fireEvent.click(screen.getByText('Tag1'));

fireEvent.click(screen.getByRole('button', { name: /Save/i }));

await waitFor(() => {
expect(mockMutate).toHaveBeenCalled();
expect(mockToast).toHaveBeenCalledWith(
expect.objectContaining({
title: 'Post created.',
description: 'Your post has been created successfully.',
status: 'success',
})
);
});
});

it('resets fields and closes the modal when cancel is clicked', () => {
const mockOnClose = jest.fn();
renderComponent({ onClose: mockOnClose });

fireEvent.change(screen.getByLabelText('Content'), { target: { value: 'Test content' } });
fireEvent.click(screen.getByRole('button', { name: /Cancel/i }));

expect(screen.queryByDisplayValue('Test content')).not.toBeInTheDocument();
expect(mockOnClose).toHaveBeenCalled();
});
});
131 changes: 131 additions & 0 deletions frontend/src/components/Login.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import LoginCard from './loginCard.component.jsx'
import { Provider } from 'react-redux';
import { ChakraProvider, useToast } from '@chakra-ui/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import configureStore from 'redux-mock-store';
import { userActions } from '../context/user';

// Mock dependencies
jest.mock('../instance/apiInstance.js', () => jest.fn(() => ({
post: jest.fn(() =>
Promise.resolve({
status: 200,
data: { sessionToken: 'mockToken' },
})
),
})));

const mockNavigate = jest.fn();
jest.mock('@tanstack/react-router', () => ({
useNavigate: () => mockNavigate,
}));

jest.mock('@chakra-ui/react', () => ({
...jest.requireActual('@chakra-ui/react'),
useToast: jest.fn(() => jest.fn()),
}));

const mockStore = configureStore([]);
const queryClient = new QueryClient();
const mockToast = jest.fn();
useToast.mockReturnValue(mockToast);

describe('LoginCard Component', () => {
let store;

beforeEach(() => {
store = mockStore({});
jest.clearAllMocks();
});

const renderComponent = () => {
render(
<Provider store={store}>
<QueryClientProvider client={queryClient}>
<ChakraProvider>
<LoginCard />
</ChakraProvider>
</QueryClientProvider>
</Provider>
);
};

it('should render the component correctly', () => {
renderComponent();

expect(screen.getByText('Sign in to your account')).toBeInTheDocument();
expect(screen.getByLabelText('Username')).toBeInTheDocument();
expect(screen.getByLabelText('Password')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /sign in/i })).toBeInTheDocument();
});

it('should handle username and password input', () => {
renderComponent();

const usernameInput = screen.getByLabelText('Username');
const passwordInput = screen.getByLabelText('Password');

fireEvent.change(usernameInput, { target: { value: 'testUser' } });
fireEvent.change(passwordInput, { target: { value: 'testPassword123' } });

expect(usernameInput.value).toBe('testUser');
expect(passwordInput.value).toBe('testPassword123');
});

it('should call login API and dispatch actions on successful login', async () => {
renderComponent();

const usernameInput = screen.getByLabelText('Username');
const passwordInput = screen.getByLabelText('Password');
const loginButton = screen.getByRole('button', { name: /sign in/i });

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

await waitFor(() => {
const actions = store.getActions();
expect(actions).toContainEqual(
userActions.login({
userName: 'testUser',
password: 'testPassword123',
sessionToken: 'mockToken',
})
);
});
});

it('should show an error toast on failed login', async () => {
const apiInstance = require('../instance/apiInstance.js');
apiInstance.mockReturnValue({
post: jest.fn(() =>
Promise.reject({
response: { status: 401, data: { message: 'Invalid credentials' } },
})
),
});

renderComponent();

const usernameInput = screen.getByLabelText('Username');
const passwordInput = screen.getByLabelText('Password');
const loginButton = screen.getByRole('button', { name: /sign in/i });

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

await waitFor(() => {
expect(mockToast).toHaveBeenCalledWith(
expect.objectContaining({
title: 'There was an error while logging in. Please try again.',
status: 'error',
isClosable: true,
})
);
});
});
});

0 comments on commit 555e156

Please sign in to comment.