Skip to content

Commit

Permalink
Fixes date picker alignment and date value not showing up while editi…
Browse files Browse the repository at this point in the history
…ng on task details page (#1260)

* fix: date picker alignment and prefilled

* fix: test cases for dates and details

* update: test files

* refactor: detail content component

* fix: useEffect to be conditional

* Improved test coverage for taskDates

* revert back to original change

* fix: edge case of invalid date

* fix: redundancy in detailsContent

* added more restriction to date validation

* fix: test case for invalid-date

* fix: test case with await

* updated test case for failure onsave

* refactor: detailsContent

* update test case for isValidDate utils

* updated feature flag

* fix: test case name

---------

Co-authored-by: Achintya Chatterjee <55826451+Achintya-Chatterjee@users.noreply.github.com>
Co-authored-by: Yash Raj <56453897+yesyash@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 4, 2024
1 parent 4476ba9 commit b2743f2
Show file tree
Hide file tree
Showing 12 changed files with 500 additions and 118 deletions.
17 changes: 16 additions & 1 deletion __mocks__/handlers/task-details.handler.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TASKS_URL } from '@/constants/url';
import { rest } from 'msw';
const URL = process.env.NEXT_PUBLIC_BASE_URL;

Expand Down Expand Up @@ -135,4 +136,18 @@ const failedTaskDependencyDetails = rest.get(
}
);

export { taskDetailsHandler, failedTaskDependencyDetails };
const failedToUpdateTaskDetails = rest.patch(
`${TASKS_URL}/6KhcLU3yr45dzjQIVm0J`,
(req, res, ctx) => {
return res(
ctx.status(500),
ctx.json({ message: 'Failed to update the task details' })
);
}
);

export {
taskDetailsHandler,
failedTaskDependencyDetails,
failedToUpdateTaskDetails,
};
182 changes: 165 additions & 17 deletions __tests__/Unit/Components/Tasks/TaskDates.test.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,176 @@
import { render, screen, fireEvent } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { screen, fireEvent } from '@testing-library/react';
import { TaskDates } from '@/components/taskDetails/TaskDates';
import { store } from '@/app/store';
import { renderWithRouter } from '@/test_utils/createMockRouter';

const mockSetNewEndOnDate = jest.fn();
const mockHandleBlurOfEndsOn = jest.fn();
jest.mock('@/hooks/useUserData', () => {
return () => ({
data: {
roles: {
admin: true,
super_user: false,
},
},
isUserAuthorized: true,
isSuccess: true,
});
});

const mockHandleEditedTaskDetails = jest.fn();

describe('TaskDates Component', () => {
beforeEach(() => {
jest.clearAllMocks();
});

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"
/>
renderWithRouter(
<Provider store={store()}>
<TaskDates
isEditing={true}
startedOn="2024-03-30T11:20:00Z"
endsOn={1700000000}
setEditedTaskDetails={mockHandleEditedTaskDetails}
isExtensionRequestPending={false}
taskId="1"
/>
</Provider>
);

const input = screen.getByTestId(
'endsOnTaskDetails'
) as HTMLInputElement;
fireEvent.change(input, { target: { value: '2024-04-15' } });
fireEvent.blur(input);
expect(input.value).toBe('2024-04-15');
});

it('should not render input field for End On date when not in editing mode', () => {
renderWithRouter(
<Provider store={store()}>
<TaskDates
isEditing={false}
startedOn="2024-03-30T11:20:00Z"
endsOn={1700000000}
setEditedTaskDetails={mockHandleEditedTaskDetails}
isExtensionRequestPending={false}
taskId="1"
/>
</Provider>
);

const input = screen.queryByTestId('endsOnTaskDetails');
expect(input).toBeNull();
});

it('should display an extension icon, when isExtensionRequestPending is true', () => {
renderWithRouter(
<Provider store={store()}>
<TaskDates
isEditing={true}
startedOn="2024-03-30T11:20:00Z"
endsOn={1700000000}
setEditedTaskDetails={mockHandleEditedTaskDetails}
isExtensionRequestPending={true}
taskId="1"
/>
</Provider>
);

const extensionIcon = screen.getByTestId('extension-request-icon');
expect(extensionIcon).toBeInTheDocument();
});

it('should not update the input value if invalid date is entered', () => {
renderWithRouter(
<Provider store={store()}>
<TaskDates
isEditing={true}
startedOn="2024-03-30T11:20:00Z"
endsOn={null}
setEditedTaskDetails={mockHandleEditedTaskDetails}
isExtensionRequestPending={false}
taskId="1"
/>
</Provider>
);

const input = screen.getByTestId(
'endsOnTaskDetails'
) as HTMLInputElement;
fireEvent.change(input, { target: { value: 'invalid-date' } });
fireEvent.blur(input);
expect(input.value).toBe('');
});

it('should render input element correctly with admin role', () => {
renderWithRouter(
<Provider store={store()}>
<TaskDates
isEditing={true}
startedOn="2024-03-30T11:20:00Z"
endsOn={1700000000}
setEditedTaskDetails={mockHandleEditedTaskDetails}
isExtensionRequestPending={false}
taskId="1"
/>
</Provider>
);

const input = screen.getByTestId('endsOnTaskDetails');
expect(input).toBeInTheDocument();
fireEvent.blur(input);
expect(mockHandleBlurOfEndsOn).toHaveBeenCalled();
});

it('should render input element correctly with non-admin role', () => {
jest.mock('@/hooks/useUserData', () => {
return () => ({
data: {
roles: {
admin: false,
super_user: true,
},
},
isUserAuthorized: true,
isSuccess: true,
});
});

renderWithRouter(
<Provider store={store()}>
<TaskDates
isEditing={true}
startedOn="2024-03-30T11:20:00Z"
endsOn={1700000000}
setEditedTaskDetails={mockHandleEditedTaskDetails}
isExtensionRequestPending={false}
taskId="1"
/>
</Provider>
);

const input = screen.getByTestId('endsOnTaskDetails');
expect(input).toBeInTheDocument();
});

it('should render the correct date when endsOn is null', () => {
renderWithRouter(
<Provider store={store()}>
<TaskDates
isEditing={true}
startedOn="2024-03-30T11:20:00Z"
endsOn={null}
setEditedTaskDetails={mockHandleEditedTaskDetails}
isExtensionRequestPending={false}
taskId="1"
/>
</Provider>
);

const input = screen.getByTestId(
'endsOnTaskDetails'
) as HTMLInputElement;
expect(input.value).toBe('');
});
});
107 changes: 99 additions & 8 deletions __tests__/Unit/Components/Tasks/TaskDetails.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import { ButtonProps, TextAreaProps } from '@/interfaces/taskDetails.type';
import { ToastContainer } from 'react-toastify';
import * as progressQueries from '@/app/services/progressesApi';
import Details from '@/components/taskDetails/Details';
import { taskDetailsHandler } from '../../../../__mocks__/handlers/task-details.handler';
import {
failedToUpdateTaskDetails,
taskDetailsHandler,
} from '../../../../__mocks__/handlers/task-details.handler';
import { superUserSelfHandler } from '../../../../__mocks__/handlers/self.handler';
import convertTimeStamp from '@/helperFunctions/convertTimeStamp';
import { STARTED_ON, ENDS_ON } from '@/constants/constants';
Expand Down Expand Up @@ -49,6 +52,8 @@ jest.mock('@/hooks/useUserData', () => {
});

const mockNavigateToUpdateProgressPage = jest.fn();
const mockHandleEditedTaskDetails = jest.fn();

describe('TaskDetails Page', () => {
it('Should render title', async () => {
const { getByText } = renderWithRouter(
Expand Down Expand Up @@ -323,13 +328,72 @@ test('should call onSave and reset state when clicked', async () => {
await waitFor(() => {
const editButton = screen.getByRole('button', { name: 'Edit' });
fireEvent.click(editButton);
const input = screen.getByTestId(
'endsOnTaskDetails'
) as HTMLInputElement;
fireEvent.change(input, { target: { value: '2024-04-15' } });
fireEvent.blur(input);
expect(input.value).toBe('2024-04-15');
const saveButton = screen.getByRole('button', { name: 'Save' });
fireEvent.click(saveButton);
});

await waitFor(() => {
const saveButton = screen.getByRole('button', { name: 'Save' });
fireEvent.click(saveButton);
expect(
screen.getByRole('button', { name: 'Saving...' })
).toBeInTheDocument();
});

await waitFor(() => {
const editButtonAfterSave = screen.getByRole('button', {
name: 'Edit',
});
expect(editButtonAfterSave).toBeInTheDocument();
});
});

test('should call onSave and show error toast when save fails', async () => {
server.use(failedToUpdateTaskDetails);

renderWithRouter(
<Provider store={store()}>
<TaskDetails taskID={details.taskID} />
<ToastContainer />
</Provider>,
{}
);

await waitFor(() => {
const editButton = screen.getByRole('button', { name: 'Edit' });
expect(editButton).toBeInTheDocument();
fireEvent.click(editButton);
});

const input = screen.getByTestId('endsOnTaskDetails') as HTMLInputElement;
fireEvent.change(input, { target: { value: '2024-04-15' } });
fireEvent.blur(input);

expect(input.value).toBe('2024-04-15');

const saveButton = screen.getByRole('button', { name: 'Save' });
fireEvent.click(saveButton);

await waitFor(() => {
expect(
screen.getByRole('button', { name: 'Saving...' })
).toBeInTheDocument();
});

await waitFor(() => {
expect(
screen.getByText(/Failed to update the task details/i)
).toBeInTheDocument();
});

await waitFor(() => {
const editButtonAfterSave = screen.getByRole('button', {
name: 'Edit',
});
expect(editButtonAfterSave).toBeInTheDocument();
});
});

Expand All @@ -351,11 +415,12 @@ test('should update the title and description with the new values', async () =>
fireEvent.change(textareaElement, {
target: { name: 'title', value: 'New Title' },
});
await waitFor(async () => {
const saveButton = screen.getByRole('button', { name: 'Save' });
fireEvent.click(saveButton);
expect(await screen.findByText(/Successfully saved/i)).not.toBeNull();

const saveButton = await screen.findByRole('button', {
name: 'Save',
});
fireEvent.click(saveButton);
expect(screen.findByText(/Successfully saved/i)).not.toBeNull();
});
test('should not update the title and description with the same values', async () => {
server.use(...taskDetailsHandler);
Expand Down Expand Up @@ -701,4 +766,30 @@ describe('Details component', () => {
throw error;
}
});

it('Renders an input with prefilled data provided, when isEditing is true', () => {
const task = {
id: 'L1SDW6O835o0EI8ZmvRc',
endedOn: 1700000000,
};
const formattedEndsOn = convertTimeStamp(task.endedOn);
const expectedDate = new Date(formattedEndsOn).toLocaleDateString(
'en-CA'
);

renderWithRouter(
<Details
detailType={ENDS_ON}
value={formattedEndsOn}
isEditing
setEditedTaskDetails={mockHandleEditedTaskDetails}
/>
);

const input = screen.getByTestId(
'endsOnTaskDetails'
) as HTMLInputElement;

expect(input.defaultValue).toBe(expectedDate);
});
});
Loading

0 comments on commit b2743f2

Please sign in to comment.