Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Unit Tests for Refactored TaskDetails Subcomponents #1245

Merged
merged 42 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
b7ea2f5
refactor(TaskDetails): Modularize and optimize TaskDetails component …
Achintya-Chatterjee Aug 28, 2024
30de74c
fix(TaskDetails): Correct data type issues and ensure proper conditio…
Achintya-Chatterjee Aug 28, 2024
4a38c2b
fix(task-details): Correct the position of status and link fields
Achintya-Chatterjee Aug 29, 2024
978f2ee
chore: remove unnecessary comments from the code
Achintya-Chatterjee Aug 29, 2024
3029018
fix: restore original styling for TaskDates and TaskParticipants comp…
Achintya-Chatterjee Aug 29, 2024
5cc8eb4
test: Add unit tests for TaskHeader component of refactored TaskDetai…
Achintya-Chatterjee Aug 29, 2024
2e876bb
test: Add unit tests for TaskDescription component of refactored Task…
Achintya-Chatterjee Aug 29, 2024
3c357bf
test: Add unit tests for TaskProgress component of refactored TaskDet…
Achintya-Chatterjee Aug 29, 2024
c6b1f95
test: Add unit tests for TaskParticipants component of refactored Tas…
Achintya-Chatterjee Aug 29, 2024
ff837bb
test: Add unit tests for TaskDates component of refactored TaskDetail…
Achintya-Chatterjee Aug 29, 2024
beeaef9
test: Add unit tests for TaskDetailsSection component of refactored T…
Achintya-Chatterjee Aug 30, 2024
ba15678
test: Add unit tests for TaskDependencies component of refactored Tas…
Achintya-Chatterjee Aug 30, 2024
8b00a96
chore: remove react memo from every component as it was unnecessary
Achintya-Chatterjee Aug 31, 2024
f3daf06
chore: remove react memo from every component as it was unnecessary
Achintya-Chatterjee Aug 31, 2024
890ea61
refactor: TaskDates component to conditionally render Details based o…
Achintya-Chatterjee Aug 31, 2024
748bb14
refactor: switch to named exports for all of the sub-components
Achintya-Chatterjee Aug 31, 2024
39f2955
Merge branch 'feature/refactor-taskdetails-component' into test/refac…
Achintya-Chatterjee Aug 31, 2024
51bc91f
chore: remove any from TaskDetails component and replace them with ap…
Achintya-Chatterjee Aug 31, 2024
2e8d2e1
Merge branch 'feature/refactor-taskdetails-component' into test/refac…
Achintya-Chatterjee Aug 31, 2024
36fe5fb
chore
Achintya-Chatterjee Sep 1, 2024
dd73f5d
Delete src/components/taskDetails/TaskProgress.tsx
Achintya-Chatterjee Sep 1, 2024
5f6c476
Delete src/components/taskDetails/TaskParticipants.tsx
Achintya-Chatterjee Sep 1, 2024
836ef08
Delete src/components/taskDetails/TaskHeader.tsx
Achintya-Chatterjee Sep 1, 2024
9be5725
Delete src/components/taskDetails/TaskDetailsSection.tsx
Achintya-Chatterjee Sep 1, 2024
4720819
Delete src/components/taskDetails/TaskDescription.tsx
Achintya-Chatterjee Sep 1, 2024
6a9706f
Delete src/components/taskDetails/TaskDependencies.tsx
Achintya-Chatterjee Sep 1, 2024
bfb34fe
Delete src/components/taskDetails/TaskDates.tsx
Achintya-Chatterjee Sep 1, 2024
67d30d8
chore: removed default export from every sub-component as we are alr…
Achintya-Chatterjee Sep 1, 2024
f8c709b
chore: removed default export from every sub-component as we are alr…
Achintya-Chatterjee Sep 1, 2024
f75e31c
Merge branch 'feature/refactor-taskdetails-component' into test/refac…
Achintya-Chatterjee Sep 1, 2024
f416a65
refactor: refactor test codes to use named export instead of default …
Achintya-Chatterjee Sep 1, 2024
6b86410
refactor(TaskDetails): remove unnecessary TaskProgress and TaskDepend…
Achintya-Chatterjee Sep 1, 2024
ab73918
Merge branch 'feature/refactor-taskdetails-component' into test/refac…
Achintya-Chatterjee Sep 1, 2024
cc43c98
chore: remove test code of taskdependency and taskprogress as i have …
Achintya-Chatterjee Sep 1, 2024
607d553
chore: remove test code of taskdependency and taskprogress as i have …
Achintya-Chatterjee Sep 1, 2024
832e1dd
refactor: refactor code to simplyfy code reading used is else instead…
Achintya-Chatterjee Sep 2, 2024
76f9aaf
Merge branch 'feature/refactor-taskdetails-component' into test/refac…
Achintya-Chatterjee Sep 2, 2024
851f47b
chore: remove extra Taskcontainer wrap that was impacting styling of …
Achintya-Chatterjee Sep 2, 2024
36a70aa
Merge branch 'feature/refactor-taskdetails-component' into test/refac…
Achintya-Chatterjee Sep 2, 2024
67c90ed
Merge branch 'develop' into feature/refactor-taskdetails-component
ashifkhn Sep 3, 2024
c8642b8
Merge branch 'feature/refactor-taskdetails-component' into test/refac…
Achintya-Chatterjee Sep 3, 2024
bccc937
Merge branch 'develop' into test/refactor-taskdetails-component
iamitprakash Sep 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions __tests__/Unit/Components/Tasks/TaskDates.test.tsx
Original file line number Diff line number Diff line change
@@ -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(
<TaskDates
isEditing={true}
isUserAuthorized={true}
startedOn="2024-03-30T11:20:00Z"
endsOn={1700000000}
newEndOnDate="2024-03-30"
setNewEndOnDate={mockSetNewEndOnDate}
handleBlurOfEndsOn={mockHandleBlurOfEndsOn}
isExtensionRequestPending={false}
taskId="1"
/>
);

const input = screen.getByTestId('endsOnTaskDetails');
expect(input).toBeInTheDocument();
fireEvent.blur(input);
expect(mockHandleBlurOfEndsOn).toHaveBeenCalled();
});
});
126 changes: 126 additions & 0 deletions __tests__/Unit/Components/Tasks/TaskDependencies.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { Provider } from 'react-redux';
import { configureStore } from '@reduxjs/toolkit';
import TaskDependencies from '@/components/taskDetails/TaskDependencies';
import '@testing-library/jest-dom/extend-expect';
import {
taskDetailsApi,
useGetTasksDependencyDetailsQuery,
} from '@/app/services/taskDetailsApi';
import { useRouter } from 'next/router';

jest.mock('next/router', () => ({
useRouter: jest.fn(),
}));

const createMockStore = () => {
return configureStore({
reducer: {
[taskDetailsApi.reducerPath]: taskDetailsApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(taskDetailsApi.middleware),
});
};

jest.mock('@/app/services/taskDetailsApi', () => {
const actualApi = jest.requireActual('@/app/services/taskDetailsApi');
return {
...actualApi,
useGetTasksDependencyDetailsQuery: jest.fn(),
};
});

describe('TaskDependencies Component', () => {
const mockSetEditedTaskDetails = jest.fn();
const mockPush = jest.fn();

beforeEach(() => {
(useRouter as jest.Mock).mockReturnValue({
push: mockPush,
});

jest.clearAllMocks();

(useGetTasksDependencyDetailsQuery as jest.Mock).mockReturnValue({
data: [
{
status: 'fulfilled',
value: { id: '6KhcLU3yr45dzjQIVm0J', title: 'Task 1' },
},
{
status: 'fulfilled',
value: { id: 'taskid-2', title: 'Task 2' },
},
],
isLoading: false,
isError: false,
});
});

const defaultProps = {
isEditing: false,
taskDependencyIds: ['6KhcLU3yr45dzjQIVm0J', 'taskid-2'],
setEditedTaskDetails: mockSetEditedTaskDetails,
};

it('should render task dependencies correctly when API returns data', async () => {
render(
<Provider store={createMockStore()}>
<TaskDependencies {...defaultProps} />
</Provider>
);

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

it('should render an error message when API fails to fetch a dependency', async () => {
(useGetTasksDependencyDetailsQuery as jest.Mock).mockReturnValue({
data: [
{
status: 'rejected',
reason: 'Failed to fetch',
id: '6KhcLU3yr45dzjQIVm0J',
},
{
status: 'rejected',
reason: 'Failed to fetch',
id: 'taskid-2',
},
],
isLoading: false,
isError: true,
});

render(
<Provider store={createMockStore()}>
<TaskDependencies {...defaultProps} />
</Provider>
);

await waitFor(() => {
expect(
screen.getByText('Unable to fetch dependency tasks')
).toBeInTheDocument();
});
});

it('should show a loading state while API is fetching data', () => {
(useGetTasksDependencyDetailsQuery as jest.Mock).mockReturnValue({
data: null,
isLoading: true,
isError: false,
});

render(
<Provider store={createMockStore()}>
<TaskDependencies {...defaultProps} />
</Provider>
);

expect(screen.getByText('Loading...')).toBeInTheDocument();
});
});
55 changes: 55 additions & 0 deletions __tests__/Unit/Components/Tasks/TaskDescription.test.tsx
Original file line number Diff line number Diff line change
@@ -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(
<TaskDescription
isEditing={false}
purpose="Test Purpose"
handleChange={mockHandleChange}
/>
);
expect(screen.getByText('Test Purpose')).toBeInTheDocument();
});

it('should renders "No description available" when purpose is empty', () => {
render(
<TaskDescription
isEditing={false}
purpose=""
handleChange={mockHandleChange}
/>
);
expect(
screen.getByText('No description available')
).toBeInTheDocument();
});

it('should renders textarea when in editing mode', () => {
render(
<TaskDescription
isEditing={true}
purpose="Test Purpose"
handleChange={mockHandleChange}
/>
);
expect(screen.getByTestId('purpose-textarea')).toBeInTheDocument();
});

it('should calls handleChange when textarea value changes', () => {
render(
<TaskDescription
isEditing={true}
purpose="Test Purpose"
handleChange={mockHandleChange}
/>
);
fireEvent.change(screen.getByTestId('purpose-textarea'), {
target: { value: 'New Purpose' },
});
expect(mockHandleChange).toHaveBeenCalled();
});
});
97 changes: 97 additions & 0 deletions __tests__/Unit/Components/Tasks/TaskDetailsSection.test.tsx
Original file line number Diff line number Diff line change
@@ -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(
<Provider store={createMockStore()}>
<TaskDetailsSection {...defaultProps} />
</Provider>
);

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(
<Provider store={createMockStore()}>
<TaskDetailsSection {...defaultProps} isEditing={true} />
</Provider>
);
expect(screen.getByRole('combobox')).toBeInTheDocument();
expect(screen.queryByText(TASK.status)).toBeNull();
});

it('should call handleTaskStatusUpdate when task status is changed', () => {
render(
<Provider store={createMockStore()}>
<TaskDetailsSection {...defaultProps} isEditing={true} />
</Provider>
);
const dropdown = screen.getByRole('combobox');
fireEvent.change(dropdown, { target: { value: 'DONE' } });

expect(mockHandleTaskStatusUpdate).toHaveBeenCalledWith({
newStatus: 'DONE',
});
});

it('should render progress container correctly', () => {
render(
<Provider store={createMockStore()}>
<TaskDetailsSection {...defaultProps} />
</Provider>
);
expect(
screen.getByText(`${TASK.percentCompleted}%`)
).toBeInTheDocument();
});
});
61 changes: 61 additions & 0 deletions __tests__/Unit/Components/Tasks/TaskHeader.test.tsx
Original file line number Diff line number Diff line change
@@ -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(
<TaskHeader
isEditing={isEditing}
setIsEditing={mockSetIsEditing}
onSave={mockOnSave}
onCancel={mockOnCancel}
title="Test Title"
handleChange={mockHandleChange}
isUserAuthorized={true}
/>
);
};

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();
});
});
Loading
Loading