diff --git a/src/library-authoring/collections/LibraryCollectionPage.test.tsx b/src/library-authoring/collections/LibraryCollectionPage.test.tsx
index b242601474..aa90836316 100644
--- a/src/library-authoring/collections/LibraryCollectionPage.test.tsx
+++ b/src/library-authoring/collections/LibraryCollectionPage.test.tsx
@@ -1,5 +1,7 @@
import fetchMock from 'fetch-mock-jest';
import { cloneDeep } from 'lodash';
+import MockAdapter from 'axios-mock-adapter/types';
+
import {
fireEvent,
initializeMocks,
@@ -17,6 +19,10 @@ import {
import { mockContentSearchConfig, mockGetBlockTypes } from '../../search-manager/data/api.mock';
import { mockBroadcastChannel, mockClipboardEmpty } from '../../generic/data/api.mock';
import { LibraryLayout } from '..';
+import { getLibraryCollectionComponentApiUrl } from '../data/api';
+
+let axiosMock: MockAdapter;
+let mockShowToast;
mockClipboardEmpty.applyMock();
mockGetCollectionMetadata.applyMock();
@@ -40,7 +46,9 @@ const { title } = mockGetCollectionMetadata.collectionData;
describe('', () => {
beforeEach(() => {
- initializeMocks();
+ const mocks = initializeMocks();
+ axiosMock = mocks.axiosMock;
+ mockShowToast = mocks.mockShowToast;
fetchMock.mockReset();
// The Meilisearch client-side API uses fetch, not Axios.
@@ -301,7 +309,6 @@ describe('', () => {
expect(mockResult0.display_name).toStrictEqual(displayName);
await renderLibraryCollectionPage();
- // Click on the first component. It should appear twice, in both "Recently Modified" and "Components"
fireEvent.click((await screen.findAllByText(displayName))[0]);
const sidebar = screen.getByTestId('library-sidebar');
@@ -324,4 +331,30 @@ describe('', () => {
expect(screen.getByText(/no matching components/i)).toBeInTheDocument();
});
+
+ it('should remove component from collection and hides sidebar', async () => {
+ const url = getLibraryCollectionComponentApiUrl(
+ mockContentLibrary.libraryId,
+ mockCollection.collectionId,
+ );
+ axiosMock.onDelete(url).reply(204);
+ const displayName = 'Introduction to Testing';
+ await renderLibraryCollectionPage();
+
+ // open sidebar
+ fireEvent.click(await screen.findByText(displayName));
+ await waitFor(() => expect(screen.queryByTestId('library-sidebar')).toBeInTheDocument());
+
+ const menuBtns = await screen.findAllByRole('button', { name: 'Component actions menu' });
+ // open menu
+ fireEvent.click(menuBtns[0]);
+
+ fireEvent.click(await screen.findByText('Remove from collection'));
+ await waitFor(() => {
+ expect(axiosMock.history.delete.length).toEqual(1);
+ expect(mockShowToast).toHaveBeenCalledWith('Component successfully removed');
+ });
+ // Should close sidebar as component was removed
+ await waitFor(() => expect(screen.queryByTestId('library-sidebar')).not.toBeInTheDocument());
+ });
});
diff --git a/src/library-authoring/components/ComponentCard.tsx b/src/library-authoring/components/ComponentCard.tsx
index 25101d8287..662344247a 100644
--- a/src/library-authoring/components/ComponentCard.tsx
+++ b/src/library-authoring/components/ComponentCard.tsx
@@ -8,6 +8,7 @@ import {
} from '@openedx/paragon';
import { MoreVert } from '@openedx/paragon/icons';
+import { useParams } from 'react-router';
import { updateClipboard } from '../../generic/data/api';
import { ToastContext } from '../../generic/toast-context';
import { type ContentHit } from '../../search-manager';
@@ -16,7 +17,6 @@ import messages from './messages';
import { STUDIO_CLIPBOARD_CHANNEL } from '../../constants';
import BaseComponentCard from './BaseComponentCard';
import { canEditComponent } from './ComponentEditorModal';
-import { useParams } from 'react-router';
import { useRemoveComponentsFromCollection } from '../data/apiHooks';
type ComponentCardProps = {
@@ -55,7 +55,7 @@ export const ComponentMenu = ({ usageKey }: { usageKey: string }) => {
}).catch(() => {
showToast(intl.formatMessage(messages.removeComponentFailure));
});
- }
+ };
return (
e.stopPropagation()}>
@@ -75,9 +75,11 @@ export const ComponentMenu = ({ usageKey }: { usageKey: string }) => {
- {collectionId &&
+ {collectionId && (
+
- }
+
+ )}