forked from openedx/frontend-app-authoring
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
29 changed files
with
962 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { StudioFooter } from '@edx/frontend-component-footer'; | ||
import { Outlet } from 'react-router-dom'; | ||
|
||
import Header from '../header'; | ||
|
||
const TaxonomyLayout = () => ( | ||
<div className="bg-light-400"> | ||
<Header isHiddenMainMenu /> | ||
<Outlet /> | ||
<StudioFooter /> | ||
</div> | ||
); | ||
|
||
export default TaxonomyLayout; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import React from 'react'; | ||
import { IntlProvider } from '@edx/frontend-platform/i18n'; | ||
import { initializeMockApp } from '@edx/frontend-platform'; | ||
import { AppProvider } from '@edx/frontend-platform/react'; | ||
import { render } from '@testing-library/react'; | ||
|
||
import initializeStore from '../store'; | ||
import TaxonomyLayout from './TaxonomyLayout'; | ||
|
||
let store; | ||
|
||
jest.mock('../header', () => jest.fn(() => <div data-testid="mock-header" />)); | ||
jest.mock('@edx/frontend-component-footer', () => ({ | ||
StudioFooter: jest.fn(() => <div data-testid="mock-footer" />), | ||
})); | ||
jest.mock('react-router-dom', () => ({ | ||
...jest.requireActual('react-router-dom'), | ||
Outlet: jest.fn(() => <div data-testid="mock-content" />), | ||
})); | ||
|
||
const RootWrapper = () => ( | ||
<AppProvider store={store}> | ||
<IntlProvider locale="en" messages={{}}> | ||
<TaxonomyLayout /> | ||
</IntlProvider> | ||
</AppProvider> | ||
); | ||
|
||
describe('<TaxonomyLayout />', async () => { | ||
beforeEach(async () => { | ||
initializeMockApp({ | ||
authenticatedUser: { | ||
userId: 3, | ||
username: 'abc123', | ||
administrator: true, | ||
roles: [], | ||
}, | ||
}); | ||
store = initializeStore(); | ||
}); | ||
|
||
it('should render page correctly', async () => { | ||
const { getByTestId } = render(<RootWrapper />); | ||
expect(getByTestId('mock-header')).toBeInTheDocument(); | ||
expect(getByTestId('mock-content')).toBeInTheDocument(); | ||
expect(getByTestId('mock-footer')).toBeInTheDocument(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
// eslint-disable-next-line import/prefer-default-export | ||
export { default as TaxonomyListPage } from './TaxonomyListPage'; | ||
export { default as TaxonomyLayout } from './TaxonomyLayout'; | ||
export { TaxonomyDetailPage } from './taxonomy-detail'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// ts-check | ||
import { useIntl } from '@edx/frontend-platform/i18n'; | ||
import { | ||
DataTable, | ||
} from '@edx/paragon'; | ||
import _ from 'lodash'; | ||
import Proptypes from 'prop-types'; | ||
import { useState } from 'react'; | ||
|
||
import messages from './messages'; | ||
import { useTagListDataResponse, useTagListDataStatus } from './data/selectors'; | ||
|
||
const TagListTable = ({ taxonomyId }) => { | ||
const intl = useIntl(); | ||
|
||
const [options, setOptions] = useState({ | ||
pageIndex: 0, | ||
}); | ||
|
||
const useTagListData = () => { | ||
const { isError, isFetched, isLoading } = useTagListDataStatus(taxonomyId, options); | ||
const tagList = useTagListDataResponse(taxonomyId, options); | ||
return { | ||
isError, | ||
isFetched, | ||
isLoading, | ||
tagList, | ||
}; | ||
}; | ||
|
||
const { tagList, isLoading } = useTagListData(); | ||
|
||
const fetchData = (args) => { | ||
if (!_.isEqual(args, options)) { | ||
setOptions({ ...args }); | ||
} | ||
}; | ||
|
||
return ( | ||
<DataTable | ||
isLoading={isLoading} | ||
isPaginated | ||
manualPagination | ||
fetchData={fetchData} | ||
data={tagList?.results || []} | ||
itemCount={tagList?.count || 0} | ||
pageCount={tagList?.numPages || 0} | ||
initialState={options} | ||
columns={[ | ||
{ | ||
Header: intl.formatMessage(messages.tagListColumnValueHeader), | ||
accessor: 'value', | ||
}, | ||
]} | ||
> | ||
<DataTable.TableControlBar /> | ||
<DataTable.Table /> | ||
<DataTable.EmptyTable content={intl.formatMessage(messages.noResultsFoundMessage)} /> | ||
<DataTable.TableFooter /> | ||
</DataTable> | ||
); | ||
}; | ||
|
||
TagListTable.propTypes = { | ||
taxonomyId: Proptypes.string.isRequired, | ||
}; | ||
|
||
export default TagListTable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import React from 'react'; | ||
import { IntlProvider } from '@edx/frontend-platform/i18n'; | ||
import { initializeMockApp } from '@edx/frontend-platform'; | ||
import { AppProvider } from '@edx/frontend-platform/react'; | ||
import { render } from '@testing-library/react'; | ||
|
||
import { useTagListData } from './data/api'; | ||
import initializeStore from '../../store'; | ||
import TagListTable from './TagListTable'; | ||
|
||
let store; | ||
|
||
jest.mock('./data/api', () => ({ | ||
useTagListData: jest.fn(), | ||
})); | ||
|
||
const RootWrapper = () => ( | ||
<AppProvider store={store}> | ||
<IntlProvider locale="en" messages={{}}> | ||
<TagListTable taxonomyId="1" /> | ||
</IntlProvider> | ||
</AppProvider> | ||
); | ||
|
||
describe('<TagListPage />', async () => { | ||
beforeEach(async () => { | ||
initializeMockApp({ | ||
authenticatedUser: { | ||
userId: 3, | ||
username: 'abc123', | ||
administrator: true, | ||
roles: [], | ||
}, | ||
}); | ||
store = initializeStore(); | ||
}); | ||
|
||
it('shows the spinner before the query is complete', async () => { | ||
useTagListData.mockReturnValue({ | ||
isLoading: true, | ||
isFetched: false, | ||
}); | ||
const { getByRole } = render(<RootWrapper />); | ||
const spinner = getByRole('status'); | ||
expect(spinner.textContent).toEqual('loading'); | ||
}); | ||
|
||
it('should render page correctly', async () => { | ||
useTagListData.mockReturnValue({ | ||
isSuccess: true, | ||
isFetched: true, | ||
isError: false, | ||
data: { | ||
count: 3, | ||
numPages: 1, | ||
results: [ | ||
{ value: 'Tag 1' }, | ||
{ value: 'Tag 2' }, | ||
{ value: 'Tag 3' }, | ||
], | ||
}, | ||
}); | ||
const { getAllByRole } = render(<RootWrapper />); | ||
const rows = getAllByRole('row'); | ||
expect(rows.length).toBe(3 + 1); // 3 items plus header | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// @ts-check | ||
import { useQuery } from '@tanstack/react-query'; | ||
import { camelCaseObject, getConfig } from '@edx/frontend-platform'; | ||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; | ||
|
||
const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL; | ||
const getTagListApiUrl = (taxonomyId, page) => new URL( | ||
`api/content_tagging/v1/taxonomies/${taxonomyId}/tags/?page=${page + 1}`, | ||
getApiBaseUrl(), | ||
).href; | ||
|
||
// ToDo: fix types | ||
/** | ||
* @param {number} taxonomyId | ||
* @param {import('./types.mjs').QueryOptions} options | ||
* @returns {import('@tanstack/react-query').UseQueryResult<import('./types.mjs').TagListData>} | ||
*/ // eslint-disable-next-line import/prefer-default-export | ||
export const useTagListData = (taxonomyId, options) => { | ||
const { pageIndex } = options; | ||
return useQuery({ | ||
queryKey: ['tagList', taxonomyId, pageIndex], | ||
queryFn: () => getAuthenticatedHttpClient().get(getTagListApiUrl(taxonomyId, pageIndex)) | ||
.then((response) => response.data) | ||
.then(camelCaseObject), | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { useQuery } from '@tanstack/react-query'; | ||
import { | ||
useTagListData, | ||
} from './api'; | ||
|
||
const mockHttpClient = { | ||
get: jest.fn(), | ||
}; | ||
|
||
jest.mock('@tanstack/react-query', () => ({ | ||
useQuery: jest.fn(), | ||
})); | ||
|
||
jest.mock('@edx/frontend-platform/auth', () => ({ | ||
getAuthenticatedHttpClient: jest.fn(() => mockHttpClient), | ||
})); | ||
|
||
describe('useTagListData', () => { | ||
it('should call useQuery with the correct parameters', () => { | ||
useTagListData('1', { pageIndex: 3 }); | ||
|
||
expect(useQuery).toHaveBeenCalledWith({ | ||
queryKey: ['tagList', '1', 3], | ||
queryFn: expect.any(Function), | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// @ts-check | ||
import { | ||
useTagListData, | ||
} from './api'; | ||
|
||
/* eslint-disable max-len */ | ||
/** | ||
* @param {number} taxonomyId | ||
* @param {import("./types.mjs").QueryOptions} options | ||
* @returns {Pick<import('@tanstack/react-query').UseQueryResult, "error" | "isError" | "isFetched" | "isLoading" | "isSuccess" >} | ||
*/ /* eslint-enable max-len */ | ||
export const useTagListDataStatus = (taxonomyId, options) => { | ||
const { | ||
error, | ||
isError, | ||
isFetched, | ||
isLoading, | ||
isSuccess, | ||
} = useTagListData(taxonomyId, options); | ||
return { | ||
error, | ||
isError, | ||
isFetched, | ||
isLoading, | ||
isSuccess, | ||
}; | ||
}; | ||
|
||
// ToDo: fix types | ||
/** | ||
* @param {number} taxonomyId | ||
* @param {import("./types.mjs").QueryOptions} options | ||
* @returns {import("./types.mjs").TagListData | undefined} | ||
*/ | ||
export const useTagListDataResponse = (taxonomyId, options) => { | ||
const { isSuccess, data } = useTagListData(taxonomyId, options); | ||
if (isSuccess) { | ||
return data; | ||
} | ||
|
||
return undefined; | ||
}; |
Oops, something went wrong.