Skip to content

Commit

Permalink
refactor: Improve LibraryContext, convert tests to testUtils (#1345)
Browse files Browse the repository at this point in the history
  • Loading branch information
bradenmacdonald authored Oct 4, 2024
1 parent dc6ede4 commit 652af9f
Show file tree
Hide file tree
Showing 20 changed files with 170 additions and 246 deletions.
4 changes: 2 additions & 2 deletions src/library-authoring/EmptyStates.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useParams } from 'react-router';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import type { MessageDescriptor } from 'react-intl';
import {
Expand All @@ -8,6 +7,7 @@ import { Add } from '@openedx/paragon/icons';
import { ClearFiltersButton } from '../search-manager';
import messages from './messages';
import { useContentLibrary } from './data/apiHooks';
import { useLibraryContext } from './common/context';

export const NoComponents = ({
infoText = messages.noComponents,
Expand All @@ -18,7 +18,7 @@ export const NoComponents = ({
addBtnText?: MessageDescriptor;
handleBtnClick: () => void;
}) => {
const { libraryId } = useParams();
const { libraryId } = useLibraryContext();
const { data: libraryData } = useContentLibrary(libraryId);
const canEditLibrary = libraryData?.canEditLibrary ?? false;

Expand Down
24 changes: 8 additions & 16 deletions src/library-authoring/LibraryAuthoringPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, useEffect } from 'react';
import React, { useEffect } from 'react';
import { Helmet } from 'react-helmet';
import classNames from 'classnames';
import { StudioFooter } from '@edx/frontend-component-footer';
Expand All @@ -13,7 +13,7 @@ import {
} from '@openedx/paragon';
import { Add, InfoOutline } from '@openedx/paragon/icons';
import {
Routes, Route, useLocation, useNavigate, useParams, useSearchParams,
Routes, Route, useLocation, useNavigate, useSearchParams,
} from 'react-router-dom';

import Loading from '../generic/Loading';
Expand All @@ -33,7 +33,7 @@ import LibraryCollections from './collections/LibraryCollections';
import LibraryHome from './LibraryHome';
import { useContentLibrary } from './data/apiHooks';
import { LibrarySidebar } from './library-sidebar';
import { LibraryContext, SidebarBodyComponentId } from './common/context';
import { SidebarBodyComponentId, useLibraryContext } from './common/context';
import messages from './messages';

enum TabList {
Expand All @@ -53,7 +53,7 @@ const HeaderActions = ({ canEditLibrary }: HeaderActionsProps) => {
openInfoSidebar,
closeLibrarySidebar,
sidebarBodyComponent,
} = useContext(LibraryContext);
} = useLibraryContext();

if (!canEditLibrary) {
return null;
Expand Down Expand Up @@ -119,19 +119,15 @@ const LibraryAuthoringPage = () => {
const location = useLocation();
const navigate = useNavigate();

const { libraryId } = useParams();
if (!libraryId) {
// istanbul ignore next - This shouldn't be possible; it's just here to satisfy the type checker.
throw new Error('Rendered without libraryId URL parameter');
}
const { libraryId } = useLibraryContext();
const { data: libraryData, isLoading } = useContentLibrary(libraryId);

const currentPath = location.pathname.split('/').pop();
const activeKey = (currentPath && currentPath in TabList) ? TabList[currentPath] : TabList.home;
const {
sidebarBodyComponent,
openInfoSidebar,
} = useContext(LibraryContext);
} = useLibraryContext();

useEffect(() => {
openInfoSidebar();
Expand Down Expand Up @@ -199,16 +195,12 @@ const LibraryAuthoringPage = () => {
<Route
path={TabList.home}
element={(
<LibraryHome
libraryId={libraryId}
tabList={TabList}
handleTabChange={handleTabChange}
/>
<LibraryHome tabList={TabList} handleTabChange={handleTabChange} />
)}
/>
<Route
path={TabList.components}
element={<LibraryComponents libraryId={libraryId} variant="full" />}
element={<LibraryComponents variant="full" />}
/>
<Route
path={TabList.collections}
Expand Down
12 changes: 5 additions & 7 deletions src/library-authoring/LibraryHome.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React, { useContext } from 'react';
import { Stack } from '@openedx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';

Expand All @@ -9,22 +8,21 @@ import { LibraryComponents } from './components';
import LibrarySection from './components/LibrarySection';
import LibraryRecentlyModified from './LibraryRecentlyModified';
import messages from './messages';
import { LibraryContext } from './common/context';
import { useLibraryContext } from './common/context';

type LibraryHomeProps = {
libraryId: string,
tabList: { home: string, components: string, collections: string },
handleTabChange: (key: string) => void,
};

const LibraryHome = ({ libraryId, tabList, handleTabChange } : LibraryHomeProps) => {
const LibraryHome = ({ tabList, handleTabChange } : LibraryHomeProps) => {
const intl = useIntl();
const {
totalHits: componentCount,
totalCollectionHits: collectionCount,
isFiltered,
} = useSearchContext();
const { openAddContentSidebar } = useContext(LibraryContext);
const { openAddContentSidebar } = useLibraryContext();

const renderEmptyState = () => {
if (componentCount === 0 && collectionCount === 0) {
Expand All @@ -35,7 +33,7 @@ const LibraryHome = ({ libraryId, tabList, handleTabChange } : LibraryHomeProps)

return (
<Stack gap={3}>
<LibraryRecentlyModified libraryId={libraryId} />
<LibraryRecentlyModified />
{
renderEmptyState()
|| (
Expand All @@ -52,7 +50,7 @@ const LibraryHome = ({ libraryId, tabList, handleTabChange } : LibraryHomeProps)
contentCount={componentCount}
viewAllAction={() => handleTabChange(tabList.components)}
>
<LibraryComponents libraryId={libraryId} variant="preview" />
<LibraryComponents variant="preview" />
</LibrarySection>
</>
)
Expand Down
2 changes: 1 addition & 1 deletion src/library-authoring/LibraryLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const LibraryLayout = () => {
}, [goBack]);

return (
<LibraryProvider>
<LibraryProvider libraryId={libraryId}>
<Routes>
{/*
TODO: we should be opening this editor as a modal, not making it a separate page/URL.
Expand Down
23 changes: 14 additions & 9 deletions src/library-authoring/LibraryRecentlyModified.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ import messages from './messages';
import ComponentCard from './components/ComponentCard';
import { useLibraryBlockTypes } from './data/apiHooks';
import CollectionCard from './components/CollectionCard';
import { useLibraryContext } from './common/context';

const RecentlyModified: React.FC<{ libraryId: string }> = ({ libraryId }) => {
const RecentlyModified: React.FC<Record<never, never>> = () => {
const intl = useIntl();
const {
hits,
collectionHits,
totalHits,
totalCollectionHits,
} = useSearchContext();
const { libraryId } = useLibraryContext();

const componentCount = totalHits + totalCollectionHits;
// Since we only display a fixed number of items in preview,
Expand Down Expand Up @@ -68,13 +70,16 @@ const RecentlyModified: React.FC<{ libraryId: string }> = ({ libraryId }) => {
: null;
};

const LibraryRecentlyModified: React.FC<{ libraryId: string }> = ({ libraryId }) => (
<SearchContextProvider
extraFilter={`context_key = "${libraryId}"`}
overrideSearchSortOrder={SearchSortOption.RECENTLY_MODIFIED}
>
<RecentlyModified libraryId={libraryId} />
</SearchContextProvider>
);
const LibraryRecentlyModified: React.FC<Record<never, never>> = () => {
const { libraryId } = useLibraryContext();
return (
<SearchContextProvider
extraFilter={`context_key = "${libraryId}"`}
overrideSearchSortOrder={SearchSortOption.RECENTLY_MODIFIED}
>
<RecentlyModified />
</SearchContextProvider>
);
};

export default LibraryRecentlyModified;
21 changes: 13 additions & 8 deletions src/library-authoring/add-content/AddContentContainer.test.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import {
fireEvent,
render,
render as baseRender,
screen,
waitFor,
initializeMocks,
} from '../../testUtils';
import { mockContentLibrary } from '../data/api.mocks';
import { getCreateLibraryBlockUrl, getLibraryPasteClipboardUrl } from '../data/api';
import { mockBroadcastChannel, mockClipboardEmpty, mockClipboardHtml } from '../../generic/data/api.mock';
import { LibraryProvider } from '../common/context';
import AddContentContainer from './AddContentContainer';

mockBroadcastChannel();

const { libraryId } = mockContentLibrary;
const renderOpts = { path: '/library/:libraryId/*', params: { libraryId } };
const render = () => baseRender(<AddContentContainer />, {
path: '/library/:libraryId/*',
params: { libraryId },
extraWrapper: ({ children }) => <LibraryProvider libraryId={libraryId}>{ children }</LibraryProvider>,
});

describe('<AddContentContainer />', () => {
it('should render content buttons', () => {
initializeMocks();
mockClipboardEmpty.applyMock();
render(<AddContentContainer />);
render();
expect(screen.getByRole('button', { name: /collection/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /text/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /problem/i })).toBeInTheDocument();
Expand All @@ -36,7 +41,7 @@ describe('<AddContentContainer />', () => {
const url = getCreateLibraryBlockUrl(libraryId);
axiosMock.onPost(url).reply(200);

render(<AddContentContainer />, renderOpts);
render();

const textButton = screen.getByRole('button', { name: /text/i });
fireEvent.click(textButton);
Expand All @@ -48,9 +53,9 @@ describe('<AddContentContainer />', () => {
initializeMocks();
// Simulate having an HTML block in the clipboard:
const getClipboardSpy = mockClipboardHtml.applyMock();
const doc = render(<AddContentContainer />, renderOpts);
render();
expect(getClipboardSpy).toHaveBeenCalled(); // Hmm, this is getting called three times! Refactor to use react-query.
await waitFor(() => expect(doc.queryByRole('button', { name: /paste from clipboard/i })).toBeInTheDocument());
await waitFor(() => expect(screen.queryByRole('button', { name: /paste from clipboard/i })).toBeInTheDocument());
});

it('should paste content', async () => {
Expand All @@ -61,7 +66,7 @@ describe('<AddContentContainer />', () => {
const pasteUrl = getLibraryPasteClipboardUrl(libraryId);
axiosMock.onPost(pasteUrl).reply(200);

render(<AddContentContainer />, renderOpts);
render();

expect(getClipboardSpy).toHaveBeenCalled(); // Hmm, this is getting called four times! Refactor to use react-query.

Expand All @@ -79,7 +84,7 @@ describe('<AddContentContainer />', () => {
const pasteUrl = getLibraryPasteClipboardUrl(libraryId);
axiosMock.onPost(pasteUrl).reply(400);

render(<AddContentContainer />, renderOpts);
render();

const pasteButton = await screen.findByRole('button', { name: /paste from clipboard/i });
fireEvent.click(pasteButton);
Expand Down
4 changes: 2 additions & 2 deletions src/library-authoring/add-content/AddContentContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import { useCopyToClipboard } from '../../generic/clipboard';
import { getCanEdit } from '../../course-unit/data/selectors';
import { useCreateLibraryBlock, useLibraryPasteClipboard, useUpdateCollectionComponents } from '../data/apiHooks';
import { getEditUrl } from '../components/utils';
import { useLibraryContext } from '../common/context';

import messages from './messages';
import { LibraryContext } from '../common/context';

type ContentType = {
name: string,
Expand Down Expand Up @@ -73,7 +73,7 @@ const AddContentContainer = () => {
const { showPasteXBlock } = useCopyToClipboard(canEdit);
const {
openCreateCollectionModal,
} = React.useContext(LibraryContext);
} = useLibraryContext();

const collectionButtonData = {
name: intl.formatMessage(messages.collectionButton),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { useContext } from 'react';
import { Stack } from '@openedx/paragon';
import { NoComponents, NoSearchResults } from '../EmptyStates';
import { useSearchContext } from '../../search-manager';
import { LibraryComponents } from '../components';
import messages from './messages';
import { LibraryContext } from '../common/context';
import { useLibraryContext } from '../common/context';

const LibraryCollectionComponents = ({ libraryId }: { libraryId: string }) => {
const LibraryCollectionComponents = () => {
const { totalHits: componentCount, isFiltered } = useSearchContext();
const { openAddContentSidebar } = useContext(LibraryContext);
const { openAddContentSidebar } = useLibraryContext();

if (componentCount === 0) {
return isFiltered
Expand All @@ -25,7 +24,7 @@ const LibraryCollectionComponents = ({ libraryId }: { libraryId: string }) => {
return (
<Stack direction="vertical" gap={3}>
<h3 className="text-gray">Content ({componentCount})</h3>
<LibraryComponents libraryId={libraryId} variant="full" />
<LibraryComponents variant="full" />
</Stack>
);
};
Expand Down
10 changes: 5 additions & 5 deletions src/library-authoring/collections/LibraryCollectionPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useContext, useEffect } from 'react';
import { useEffect } from 'react';
import { StudioFooter } from '@edx/frontend-component-footer';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
Expand Down Expand Up @@ -27,7 +27,7 @@ import {
SearchSortWidget,
} from '../../search-manager';
import { useCollection, useContentLibrary } from '../data/apiHooks';
import { LibraryContext } from '../common/context';
import { useLibraryContext } from '../common/context';
import messages from './messages';
import { LibrarySidebar } from '../library-sidebar';
import LibraryCollectionComponents from './LibraryCollectionComponents';
Expand All @@ -36,7 +36,7 @@ const HeaderActions = ({ canEditLibrary }: { canEditLibrary: boolean; }) => {
const intl = useIntl();
const {
openAddContentSidebar,
} = useContext(LibraryContext);
} = useLibraryContext();

if (!canEditLibrary) {
return null;
Expand Down Expand Up @@ -104,7 +104,7 @@ const LibraryCollectionPage = () => {
const {
sidebarBodyComponent,
openCollectionInfoSidebar,
} = useContext(LibraryContext);
} = useLibraryContext();

const {
data: collectionData,
Expand Down Expand Up @@ -189,7 +189,7 @@ const LibraryCollectionPage = () => {
<div className="flex-grow-1" />
<SearchSortWidget />
</div>
<LibraryCollectionComponents libraryId={libraryId} />
<LibraryCollectionComponents />
</SearchContextProvider>
</Container>
<StudioFooter />
Expand Down
6 changes: 2 additions & 4 deletions src/library-authoring/collections/LibraryCollections.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { useContext } from 'react';

import { useLoadOnScroll } from '../../hooks';
import { useSearchContext } from '../../search-manager';
import { NoComponents, NoSearchResults } from '../EmptyStates';
import CollectionCard from '../components/CollectionCard';
import { LIBRARY_SECTION_PREVIEW_LIMIT } from '../components/LibrarySection';
import messages from './messages';
import { LibraryContext } from '../common/context';
import { useLibraryContext } from '../common/context';

type LibraryCollectionsProps = {
variant: 'full' | 'preview',
Expand All @@ -29,7 +27,7 @@ const LibraryCollections = ({ variant }: LibraryCollectionsProps) => {
isFiltered,
} = useSearchContext();

const { openCreateCollectionModal } = useContext(LibraryContext);
const { openCreateCollectionModal } = useLibraryContext();

const collectionList = variant === 'preview' ? collectionHits.slice(0, LIBRARY_SECTION_PREVIEW_LIMIT) : collectionHits;

Expand Down
Loading

0 comments on commit 652af9f

Please sign in to comment.