diff --git a/__tests__/Unit/Components/Tasks/TaskDates.test.tsx b/__tests__/Unit/Components/Tasks/TaskDates.test.tsx new file mode 100644 index 000000000..2c507b7c6 --- /dev/null +++ b/__tests__/Unit/Components/Tasks/TaskDates.test.tsx @@ -0,0 +1,28 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import { TaskDates } from '@/components/taskDetails/TaskDates'; + +const mockSetNewEndOnDate = jest.fn(); +const mockHandleBlurOfEndsOn = jest.fn(); + +describe('TaskDates Component', () => { + it('should render input field for End On date when in editing mode', () => { + render( + + ); + + const input = screen.getByTestId('endsOnTaskDetails'); + expect(input).toBeInTheDocument(); + fireEvent.blur(input); + expect(mockHandleBlurOfEndsOn).toHaveBeenCalled(); + }); +}); diff --git a/__tests__/Unit/Components/Tasks/TaskDependency.test.tsx b/__tests__/Unit/Components/Tasks/TaskDependency.test.tsx deleted file mode 100644 index a1a300776..000000000 --- a/__tests__/Unit/Components/Tasks/TaskDependency.test.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import React from 'react'; -import { fireEvent, waitFor } from '@testing-library/react'; -import { renderWithRouter } from '@/test_utils/createMockRouter'; -import TaskDependency from '@/components/taskDetails/taskDependency'; -import { taskDetailsHandler } from '../../../../__mocks__/handlers/task-details.handler'; -import { filterTaskHandler } from '../../../../__mocks__/handlers/tasks.handler'; -import { setupServer } from 'msw/node'; -import { Provider } from 'react-redux'; -import { store } from '@/app/store'; -import { TaskDependencyIds } from '../../../../__mocks__/db/tasks'; -import { useGetAllTasksQuery } from '@/app/services/tasksApi'; - -const setEditedTaskDetails = jest.fn(); -const mockNavigateToTask = jest.fn(); - -jest.mock('@/app/services/tasksApi'); -const mockedUseGetAllTasksQuery = useGetAllTasksQuery as jest.MockedFunction< - typeof useGetAllTasksQuery ->; - -describe('TaskDependency', () => { - const server = setupServer(...taskDetailsHandler); - beforeAll(() => server.listen()); - afterEach(() => server.resetHandlers()); - afterAll(() => server.close()); - - it('should select/unselect a task when checkbox is clicked', async () => { - mockedUseGetAllTasksQuery.mockReturnValue({ - data: { - tasks: [ - { id: 'task1', title: 'Test Task 1' }, - { id: 'task2', title: 'Test Task 2' }, - ], - }, - isLoading: false, - isError: false, - refetch: jest.fn(), - }); - const { container } = renderWithRouter( - - - - ); - const checkboxes = container.querySelectorAll('input[type="checkbox"]'); - const firstCheckbox = checkboxes[0] as HTMLInputElement; - expect(firstCheckbox.checked).toBe(false); - fireEvent.click(firstCheckbox); - await waitFor(() => { - expect(firstCheckbox.checked).toBe(true); - }); - fireEvent.click(firstCheckbox); - await waitFor(() => { - expect(firstCheckbox.checked).toBe(false); - }); - }); - - it('should render loading state when searching for tasks', async () => { - server.use(filterTaskHandler); - const { getByText } = renderWithRouter( - - - - ); - const loadingText = await waitFor(() => getByText('Loading...')); - expect(loadingText).toBeInTheDocument(); - }); - - it('should render DependencyList when isEditing is false', async () => { - const { queryByRole, getByTestId } = renderWithRouter( - - - , - { push: mockNavigateToTask } - ); - - const textarea = queryByRole('textbox'); - expect(textarea).toBeNull(); - - await waitFor(() => { - const dependencyList = getByTestId('dependency-list'); - expect(dependencyList).toBeInTheDocument(); - }); - }); -}); diff --git a/__tests__/Unit/Components/Tasks/TaskDescription.test.tsx b/__tests__/Unit/Components/Tasks/TaskDescription.test.tsx new file mode 100644 index 000000000..c2b8363a3 --- /dev/null +++ b/__tests__/Unit/Components/Tasks/TaskDescription.test.tsx @@ -0,0 +1,55 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import { TaskDescription } from '@/components/taskDetails/TaskDescription'; + +const mockHandleChange = jest.fn(); + +describe('TaskDescription Component', () => { + it('should renders the task description when not editing', () => { + render( + + ); + expect(screen.getByText('Test Purpose')).toBeInTheDocument(); + }); + + it('should renders "No description available" when purpose is empty', () => { + render( + + ); + expect( + screen.getByText('No description available') + ).toBeInTheDocument(); + }); + + it('should renders textarea when in editing mode', () => { + render( + + ); + expect(screen.getByTestId('purpose-textarea')).toBeInTheDocument(); + }); + + it('should calls handleChange when textarea value changes', () => { + render( + + ); + fireEvent.change(screen.getByTestId('purpose-textarea'), { + target: { value: 'New Purpose' }, + }); + expect(mockHandleChange).toHaveBeenCalled(); + }); +}); diff --git a/__tests__/Unit/Components/Tasks/TaskDetailsSection.test.tsx b/__tests__/Unit/Components/Tasks/TaskDetailsSection.test.tsx new file mode 100644 index 000000000..fb79a3caa --- /dev/null +++ b/__tests__/Unit/Components/Tasks/TaskDetailsSection.test.tsx @@ -0,0 +1,97 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { configureStore } from '@reduxjs/toolkit'; +import { TaskDetailsSection } from '@/components/taskDetails/TaskDetailsSection'; +import '@testing-library/jest-dom/extend-expect'; +import { TASK } from '../../../../__mocks__/db/tasks'; +import { useRouter } from 'next/router'; +import { api } from '@/app/services/api'; + +jest.mock('next/router', () => ({ + useRouter: jest.fn(), +})); + +const createMockStore = () => { + return configureStore({ + reducer: { + user: (state = { roles: {} }) => state, + [api.reducerPath]: api.reducer, + }, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware().concat(api.middleware), + }); +}; + +describe('TaskDetailsSection Component', () => { + const mockHandleTaskStatusUpdate = jest.fn(); + const mockRouter = { + query: { dev: true }, + }; + + beforeEach(() => { + (useRouter as jest.Mock).mockReturnValue(mockRouter); + }); + + const defaultProps = { + isEditing: false, + type: TASK.type, + priority: TASK.priority, + status: TASK.status, + link: TASK.featureUrl, + percentCompleted: TASK.percentCompleted, + handleTaskStatusUpdate: mockHandleTaskStatusUpdate, + taskDetailsData: TASK, + }; + + it('should render task details correctly when not in editing mode', () => { + render( + + + + ); + + expect(screen.getByText(TASK.type)).toBeInTheDocument(); + expect(screen.getByText(TASK.priority)).toBeInTheDocument(); + expect(screen.getByText(TASK.status)).toBeInTheDocument(); + + const linkElement = screen.getByRole('link', { + name: /open github issue/i, + }); + expect(linkElement).toHaveAttribute('href', TASK.featureUrl); + }); + + it('should render task status dropdown when in editing mode', () => { + render( + + + + ); + expect(screen.getByRole('combobox')).toBeInTheDocument(); + expect(screen.queryByText(TASK.status)).toBeNull(); + }); + + it('should call handleTaskStatusUpdate when task status is changed', () => { + render( + + + + ); + const dropdown = screen.getByRole('combobox'); + fireEvent.change(dropdown, { target: { value: 'DONE' } }); + + expect(mockHandleTaskStatusUpdate).toHaveBeenCalledWith({ + newStatus: 'DONE', + }); + }); + + it('should render progress container correctly', () => { + render( + + + + ); + expect( + screen.getByText(`${TASK.percentCompleted}%`) + ).toBeInTheDocument(); + }); +}); diff --git a/__tests__/Unit/Components/Tasks/TaskHeader.test.tsx b/__tests__/Unit/Components/Tasks/TaskHeader.test.tsx new file mode 100644 index 000000000..bda23da68 --- /dev/null +++ b/__tests__/Unit/Components/Tasks/TaskHeader.test.tsx @@ -0,0 +1,61 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import { TaskHeader } from '@/components/taskDetails/TaskHeader'; +import { ButtonProps } from '@/interfaces/taskDetails.type'; + +const mockSetIsEditing = jest.fn(); +const mockOnSave = jest.fn(); +const mockOnCancel = jest.fn(); +const mockHandleChange = jest.fn(); + +const renderTaskHeader = (isEditing = false) => { + return render( + + ); +}; + +describe('TaskHeader Component', () => { + it('should renders the task title correctly when not editing', () => { + renderTaskHeader(false); + expect(screen.getByText('Test Title')).toBeInTheDocument(); + expect( + screen.getByRole('button', { name: 'Edit' }) + ).toBeInTheDocument(); + }); + + it('should renders textarea for title when in editing mode', () => { + renderTaskHeader(true); + expect(screen.getByTestId('title-textarea')).toBeInTheDocument(); + expect( + screen.getByRole('button', { name: 'Save' }) + ).toBeInTheDocument(); + expect( + screen.getByRole('button', { name: 'Cancel' }) + ).toBeInTheDocument(); + }); + + it('should calls setIsEditing with true when Edit button is clicked', () => { + renderTaskHeader(false); + fireEvent.click(screen.getByRole('button', { name: 'Edit' })); + expect(mockSetIsEditing).toHaveBeenCalledWith(true); + }); + + it('should calls onSave when Save button is clicked', () => { + renderTaskHeader(true); + fireEvent.click(screen.getByRole('button', { name: 'Save' })); + expect(mockOnSave).toHaveBeenCalled(); + }); + + it('should calls onCancel when Cancel button is clicked', () => { + renderTaskHeader(true); + fireEvent.click(screen.getByRole('button', { name: 'Cancel' })); + expect(mockOnCancel).toHaveBeenCalled(); + }); +}); diff --git a/__tests__/Unit/Components/Tasks/TaskParticipants.test.tsx b/__tests__/Unit/Components/Tasks/TaskParticipants.test.tsx new file mode 100644 index 000000000..d0e9c6fc9 --- /dev/null +++ b/__tests__/Unit/Components/Tasks/TaskParticipants.test.tsx @@ -0,0 +1,49 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import { TaskParticipants } from '@/components/taskDetails/TaskParticipants'; +import { Provider } from 'react-redux'; +import { store } from '@/app/store'; + +const mockHandleAssignment = jest.fn(); +const mockHandleAssigneSelect = jest.fn(); +const mockSetShowSuggestion = jest.fn(); + +const renderWithProvider = (ui: React.ReactElement) => { + return render({ui}); +}; + +describe('TaskParticipants Component', () => { + it('should render the assignee name correctly when not editing', () => { + renderWithProvider( + + ); + + expect(screen.getByText('John Doe')).toBeInTheDocument(); + }); + + it('should render the Suggestions component when editing', () => { + renderWithProvider( + + ); + + const input = screen.getByRole('textbox'); + expect(input).toBeInTheDocument(); + fireEvent.change(input, { target: { value: 'Jane Doe' } }); + expect(mockHandleAssignment).toHaveBeenCalled(); + }); +});