Skip to content

Commit

Permalink
feat: fixing merge issues and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rpenido committed Jul 2, 2024
1 parent 1af4fbe commit 99b9b31
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 34 deletions.
91 changes: 64 additions & 27 deletions src/library-authoring/components/LibraryComponents.test.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,60 @@
import React from 'react';
import { AppProvider } from '@edx/frontend-platform/react';
import { initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { render, screen, fireEvent } from '@testing-library/react';
import LibraryComponents from './LibraryComponents';
import MockAdapter from 'axios-mock-adapter';
import fetchMock from 'fetch-mock-jest';
import type { Store } from 'redux';

import { getContentSearchConfigUrl } from '../../search-modal/data/api';
import mockEmptyResult from '../../search-modal/__mocks__/empty-search-result.json';
import { SearchContextProvider } from '../../search-modal/manager/SearchManager';
import initializeStore from '../../store';
import { libraryComponentsMock } from '../__mocks__';
import LibraryComponents from './LibraryComponents';

const searchEndpoint = 'http://mock.meilisearch.local/multi-search';

const mockUseLibraryComponents = jest.fn();
const mockUseLibraryComponentCount = jest.fn();
const mockUseLibraryBlockTypes = jest.fn();
const mockFetchNextPage = jest.fn();
let store;
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const mockUseSearchContext = jest.fn();

const data = {
totalHits: 1,
hits: [],
isFetching: true,
isFetchingNextPage: false,
hasNextPage: false,
fetchNextPage: mockFetchNextPage,
searchKeywords: '',
};
const countData = {
componentCount: 1,
collectionCount: 0,

let store: Store;
let axiosMock: MockAdapter;

const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});

const returnEmptyResult = (_url: string, req) => {
const requestData = JSON.parse(req.body?.toString() ?? '');
const query = requestData?.queries[0]?.q ?? '';
// We have to replace the query (search keywords) in the mock results with the actual query,
// because otherwise we may have an inconsistent state that causes more queries and unexpected results.
mockEmptyResult.results[0].query = query;
// And fake the required '_formatted' fields; it contains the highlighting <mark>...</mark> around matched words
// eslint-disable-next-line no-underscore-dangle, no-param-reassign
mockEmptyResult.results[0]?.hits.forEach((hit: any) => { hit._formatted = { ...hit }; });
return mockEmptyResult;
};

const blockTypeData = {
data: [
{
Expand All @@ -51,16 +73,21 @@ const blockTypeData = {
};

jest.mock('../data/apiHook', () => ({
useLibraryComponents: () => mockUseLibraryComponents(),
useLibraryComponentCount: () => mockUseLibraryComponentCount(),
useLibraryBlockTypes: () => mockUseLibraryBlockTypes(),
}));

jest.mock('../../search-modal/manager/SearchManager', () => ({
...jest.requireActual('../../search-modal/manager/SearchManager'),
useSearchContext: () => mockUseSearchContext(),
}));

const RootWrapper = (props) => (
<AppProvider store={store}>
<IntlProvider locale="en" messages={{}}>
<QueryClientProvider client={queryClient}>
<LibraryComponents libraryId="1" filter={{ searchKeywords: '' }} {...props} />
<SearchContextProvider>
<LibraryComponents libraryId="1" {...props} />
</SearchContextProvider>
</QueryClientProvider>
</IntlProvider>
</AppProvider>
Expand All @@ -77,20 +104,30 @@ describe('<LibraryComponents />', () => {
},
});
store = initializeStore();
mockUseLibraryComponents.mockReturnValue(data);
mockUseLibraryComponentCount.mockReturnValue(countData);
mockUseLibraryBlockTypes.mockReturnValue(blockTypeData);
mockUseSearchContext.mockReturnValue(data);

fetchMock.post(searchEndpoint, returnEmptyResult, { overwriteRoutes: true });

// The API method to get the Meilisearch connection details uses Axios:
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(getContentSearchConfigUrl()).reply(200, {
url: 'http://mock.meilisearch.local',
index_name: 'studio',
api_key: 'test-key',
});
});

afterEach(() => {
jest.resetAllMocks();
});

it('should render empty state', async () => {
mockUseLibraryComponentCount.mockReturnValueOnce({
...countData,
componentCount: 0,
mockUseSearchContext.mockReturnValue({
...data,
totalHits: 0,
});

render(<RootWrapper />);
expect(await screen.findByText(/you have not added any content to this library yet\./i));
});
Expand All @@ -101,7 +138,7 @@ describe('<LibraryComponents />', () => {
});

it('should render components in full variant', async () => {
mockUseLibraryComponents.mockReturnValue({
mockUseSearchContext.mockReturnValue({
...data,
hits: libraryComponentsMock,
isFetching: false,
Expand All @@ -117,7 +154,7 @@ describe('<LibraryComponents />', () => {
});

it('should render components in preview variant', async () => {
mockUseLibraryComponents.mockReturnValue({
mockUseSearchContext.mockReturnValue({
...data,
hits: libraryComponentsMock,
isFetching: false,
Expand All @@ -133,7 +170,7 @@ describe('<LibraryComponents />', () => {
});

it('should call `fetchNextPage` on scroll to bottom in full variant', async () => {
mockUseLibraryComponents.mockReturnValue({
mockUseSearchContext.mockReturnValue({
...data,
hits: libraryComponentsMock,
isFetching: false,
Expand All @@ -151,7 +188,7 @@ describe('<LibraryComponents />', () => {
});

it('should not call `fetchNextPage` on croll to bottom in preview variant', async () => {
mockUseLibraryComponents.mockReturnValue({
mockUseSearchContext.mockReturnValue({
...data,
hits: libraryComponentsMock,
isFetching: false,
Expand All @@ -169,7 +206,7 @@ describe('<LibraryComponents />', () => {
});

it('should render content and loading when fetching next page', async () => {
mockUseLibraryComponents.mockReturnValue({
mockUseSearchContext.mockReturnValue({
...data,
hits: libraryComponentsMock,
isFetching: true,
Expand Down
5 changes: 1 addition & 4 deletions src/library-authoring/components/LibraryComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import { ComponentCard, ComponentCardLoading } from './ComponentCard';

type LibraryComponentsProps = {
libraryId: string,
filter: {
searchKeywords: string,
},
variant: string,
variant: 'full' | 'preview',
};

/**
Expand Down
1 change: 0 additions & 1 deletion src/library-authoring/data/apiHook.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import { useQuery } from '@tanstack/react-query';

import { getContentLibrary, getLibraryBlockTypes } from './api';
Expand Down
4 changes: 2 additions & 2 deletions src/search-modal/manager/SearchManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ export const SearchContextProvider: React.FC<{
closeSearchModal?: () => void,
}> = ({ extraFilter, ...props }) => {
const [searchKeywords, setSearchKeywords] = React.useState('');
const [blockTypesFilter, setBlockTypesFilter] = React.useState(/** type {string[]} */([]));
const [tagsFilter, setTagsFilter] = React.useState(/** type {string[]} */([]));
const [blockTypesFilter, setBlockTypesFilter] = React.useState<string[]>([]);
const [tagsFilter, setTagsFilter] = React.useState<string[]>([]);

const canClearFilters = blockTypesFilter.length > 0 || tagsFilter.length > 0;
const clearFilters = React.useCallback(() => {
Expand Down

0 comments on commit 99b9b31

Please sign in to comment.