Skip to content

Commit

Permalink
DSEGOG-350 Delete favourite filter
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuadkitenge committed Nov 4, 2024
1 parent b6c2aa4 commit 4255f88
Show file tree
Hide file tree
Showing 9 changed files with 321 additions and 8 deletions.
34 changes: 34 additions & 0 deletions cypress/e2e/filtering.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -684,5 +684,39 @@ describe('Filtering Component', () => {
);
cy.findByRole('button', { name: 'Save' }).should('not.be.disabled');
});

it('delete favourite filter', () => {
cy.findByRole('button', {
name: 'Delete test 1 favourite filter',
}).click();

cy.startSnoopingBrowserMockedRequest();
cy.findByRole('button', { name: 'Continue' }).click();

cy.findBrowserMockedRequests({
method: 'DELETE',
url: '/users/filters/:id',
}).should((deleteRequests) => {
expect(deleteRequests.length).equal(1);
});
});

it('display api error message for delete', () => {
cy.findByRole('button', {
name: 'Delete test 3 favourite filter',
}).click();

cy.startSnoopingBrowserMockedRequest();
cy.findByRole('button', { name: 'Continue' }).click();

cy.findBrowserMockedRequests({
method: 'DELETE',
url: '/users/filters/:id',
}).should((deleteRequests) => {
expect(deleteRequests.length).equal(1);
});

cy.findByText('error').should('exist');
});
});
});
12 changes: 11 additions & 1 deletion e2e/real/filtering.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ test('should be able to add a multiple filters', async ({ page }) => {
await expect(page.getByText('1–7 of 7')).toBeVisible();
});

test('CRU favourite filter', async ({ page }) => {
test('CRUD favourite filter', async ({ page }) => {
await page.getByRole('button', { name: 'Filters' }).click();

await page.getByText('Favourite filters').click();
Expand Down Expand Up @@ -151,4 +151,14 @@ test('CRU favourite filter', async ({ page }) => {
// Assert the changes were successful (checking 'test 1' and updated filter value)
const updatedTextField = page.locator('input[value="test 1"]');
await expect(updatedTextField).toHaveValue('test 1');

await page
.getByRole('button', { name: 'Delete test 1 favourite filter' })
.click();

await page.getByRole('button', { name: 'Continue' }).click();

expect(
await page.getByRole('button', { name: 'Delete test 1 favourite filter' })
).not.toBeInViewport();
});
22 changes: 22 additions & 0 deletions src/api/favouriteFilters.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FavouriteFilterPatch, FavouriteFilterPost } from '../app.types';
import { hooksWrapperWithProviders } from '../testUtils';
import {
useAddFavouriteFilter,
useDeleteFavouriteFilter,
useEditFavouriteFilter,
} from './favouriteFilters';

Expand Down Expand Up @@ -65,4 +66,25 @@ describe('favourite filters api functions', () => {
'sends axios request to edit favourite filters for a user and throws an appropriate error on failure'
);
});

describe('useDeleteFavouriteFilter', () => {
it('delete request to delete user session and returns successful response', async () => {
const { result } = renderHook(() => useDeleteFavouriteFilter(), {
wrapper: hooksWrapperWithProviders(),
});
expect(result.current.isIdle).toBe(true);

result.current.mutate('1');

await waitFor(() => {
expect(result.current.isSuccess).toBeTruthy();
});

expect(result.current.data).toEqual('');
});

it.todo(
'sends axios request to delete user favourite Filter and throws an appropriate error on failure'
);
});
});
28 changes: 28 additions & 0 deletions src/api/favouriteFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,31 @@ export const useFavouriteFilters = (): UseQueryResult<
},
});
};

const deleteFavouriteFilter = (apiUrl: string, id: string): Promise<void> => {
return axios
.delete(`${apiUrl}/users/filters/${id}`, {
headers: {
Authorization: `Bearer ${readSciGatewayToken()}`,
},
})
.then((response) => response.data);
};

export const useDeleteFavouriteFilter = (): UseMutationResult<
void,
AxiosError,
string
> => {
const { apiUrl } = useAppSelector(selectUrls);
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => deleteFavouriteFilter(apiUrl, id),
onError: (error) => {
console.log('Got error ' + error.message);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['favouriteFilters'] });
},
});
};
86 changes: 86 additions & 0 deletions src/filtering/deleteFavouriteFilterDialogue.component.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { RenderResult, screen, waitFor } from '@testing-library/react';
import userEvent, { UserEvent } from '@testing-library/user-event';
import favouriteFiltersJson from '../mocks/favouriteFilters.json';
import { renderComponentWithProviders } from '../testUtils';
import DeleteFavouriteFilterDialogue, {
DeleteFavouriteFilterDialogueProps,
} from './deleteFavouriteFilterDialogue.component';

describe('delete favourite filter dialogue', () => {
let props: DeleteFavouriteFilterDialogueProps;
let user: UserEvent;
const onClose = vi.fn();

const createView = (): RenderResult => {
return renderComponentWithProviders(
<DeleteFavouriteFilterDialogue {...props} />
);
};

beforeEach(() => {
props = {
open: true,
onClose: onClose,
favouriteFilter: favouriteFiltersJson[0],
};
user = userEvent.setup();
});
afterEach(() => {
vi.clearAllMocks();
});
it('renders correctly', async () => {
createView();
expect(screen.getByText('Delete Favourite filter')).toBeInTheDocument();
expect(
screen.getByTestId('delete-favourite-filter-name')
).toHaveTextContent('test');
});

it('calls onClose when Close button is clicked', async () => {
createView();
const closeButton = screen.getByRole('button', { name: 'Close' });
await user.click(closeButton);

await waitFor(() => {
expect(onClose).toHaveBeenCalled();
});
});

it('displays warning message when favourite filter data is not loaded', async () => {
props = {
...props,
favouriteFilter: undefined,
};
createView();
const continueButton = screen.getByRole('button', { name: 'Continue' });
await user.click(continueButton);
const helperTexts = screen.getByText(
'No data provided, Please refresh and try again'
);
expect(helperTexts).toBeInTheDocument();
expect(onClose).not.toHaveBeenCalled();
});

it('displays warning message when api errors', async () => {
props = {
...props,
favouriteFilter: favouriteFiltersJson[2],
};
createView();
const continueButton = screen.getByRole('button', { name: 'Continue' });
await user.click(continueButton);
const helperTexts = screen.getByText('error');
expect(helperTexts).toBeInTheDocument();
expect(onClose).not.toHaveBeenCalled();
});

it('calls handleDeleteFavouriteFilter when continue button is clicked with a valid favourite filter name', async () => {
createView();
const continueButton = screen.getByRole('button', { name: 'Continue' });
await user.click(continueButton);

await waitFor(() => {
expect(onClose).toHaveBeenCalled();
});
});
});
91 changes: 91 additions & 0 deletions src/filtering/deleteFavouriteFilterDialogue.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import {
Box,
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
FormHelperText,
} from '@mui/material';
import React, { useState } from 'react';

import { AxiosError } from 'axios';
import { useDeleteFavouriteFilter } from '../api/favouriteFilters';
import { FavouriteFilter } from '../app.types';

export interface DeleteFavouriteFilterDialogueProps {
open: boolean;
onClose: () => void;
favouriteFilter: FavouriteFilter | undefined;
}

const DeleteFavouriteFilterDialogue = (
props: DeleteFavouriteFilterDialogueProps
) => {
const { open, onClose, favouriteFilter } = props;

const [error, setError] = useState(false);
const [errorMessage, setErrorMessage] = React.useState<string | undefined>(
undefined
);

const handleClose = React.useCallback(() => {
onClose();
setError(false);
setErrorMessage(undefined);
}, [onClose]);

const { mutateAsync: deleteFavouriteFilter } = useDeleteFavouriteFilter();

const handleDeleteFavouriteFilter = React.useCallback(() => {
if (favouriteFilter) {
deleteFavouriteFilter(favouriteFilter._id)
.then(() => {
handleClose();
})
.catch((error: AxiosError) => {
setError(true);
setErrorMessage((error.response?.data as { detail: string }).detail);
});
} else {
setError(true);
setErrorMessage('No data provided, Please refresh and try again');
}
}, [deleteFavouriteFilter, handleClose, favouriteFilter]);

return (
<Dialog open={open} onClose={handleClose} maxWidth="lg">
<DialogTitle>Delete Favourite filter</DialogTitle>
<DialogContent>
Are you sure you want to delete{' '}
<strong data-testid="delete-favourite-filter-name">
{favouriteFilter?.name}
</strong>
?
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Close</Button>
<Button disabled={error} onClick={handleDeleteFavouriteFilter}>
Continue
</Button>
</DialogActions>
{error && (
<Box
sx={{
mx: 3,
marginBottom: 3,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<FormHelperText sx={{ textAlign: 'center' }} error>
{errorMessage}
</FormHelperText>
</Box>
)}
</Dialog>
);
};

export default DeleteFavouriteFilterDialogue;
20 changes: 19 additions & 1 deletion src/filtering/filterDialogue.component.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe('Filter dialogue component', () => {
expect(baseElement).toMatchSnapshot();
});

it('opens and closes Add new favourite filter dialogue', async () => {
it('opens and closes edit favourite filter dialogue', async () => {
createView();

await user.click(screen.getByText('Favourite filters'));
Expand All @@ -75,6 +75,24 @@ describe('Filter dialogue component', () => {
});
});

it('opens and closes delete favourite filter dialogue', async () => {
createView();

await user.click(screen.getByText('Favourite filters'));
await user.click(
await screen.findByRole('button', {
name: 'Delete test 1 favourite filter',
})
);

expect(screen.getAllByText('Close').length).toEqual(2);

await user.click(screen.getAllByText('Close')[1]);
await waitFor(() => {
expect(screen.getAllByText('Close').length).toEqual(1);
});
});

it('opens and closes edit new favourite filter dialogue', async () => {
createView();

Expand Down
Loading

0 comments on commit 4255f88

Please sign in to comment.