mirror of
https://github.com/SomboChea/ui
synced 2026-01-19 01:25:51 +07:00
* chore: refactoring version page * refactor: migrate version page to hooks * refactor: Version page better imports * fix: #100 render not found on click item * test: add test for version page * chore: update mocks * test: add scenario for not found package * chore: fix wrong mock path * chore: update mock * chore: add todo list
This commit is contained in:
committed by
GitHub
parent
e7d3c461cd
commit
97e8448098
27
src/pages/Version/Layout.tsx
Normal file
27
src/pages/Version/Layout.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React, { FC, ReactElement } from 'react';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import DetailContainer from '../../components/DetailContainer';
|
||||
import DetailSidebar from '../../components/DetailSidebar';
|
||||
|
||||
function renderDetail(): ReactElement<HTMLElement> {
|
||||
return <DetailContainer />;
|
||||
}
|
||||
|
||||
function renderSidebar(): ReactElement<HTMLElement> {
|
||||
return <DetailSidebar />;
|
||||
}
|
||||
|
||||
const Layout: FC<{}> = () => {
|
||||
return (
|
||||
<Grid className={'container content'} container={true} data-testid="version-layout" spacing={0}>
|
||||
<Grid item={true} xs={8}>
|
||||
{renderDetail()}
|
||||
</Grid>
|
||||
<Grid item={true} xs={4}>
|
||||
{renderSidebar()}
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export { Layout };
|
||||
96
src/pages/Version/Version.test.tsx
Normal file
96
src/pages/Version/Version.test.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import React from 'react';
|
||||
import { render, cleanup } from '@testing-library/react';
|
||||
|
||||
import { MemoryRouter } from 'react-router';
|
||||
|
||||
import vueMetadata from '../../../test/fixtures/metadata/vue.json';
|
||||
|
||||
import Version from './Version';
|
||||
import { waitForElement } from '@testing-library/dom';
|
||||
import ErrorBoundary from '../../App/AppError';
|
||||
import { LABEL_NOT_FOUND } from '../../components/NotFound/NotFound';
|
||||
// import { NOT_FOUND_TEXT } from '../../components/NotFound/NotFound';
|
||||
|
||||
// :-) we mock this otherways fails on render, some weird issue on material-ui
|
||||
jest.mock('@material-ui/core/Avatar');
|
||||
|
||||
describe('test Version page', () => {
|
||||
beforeAll(() => {
|
||||
// FIXME: a better way to mock this
|
||||
// @ts-ignore
|
||||
global.window.VERDACCIO_API_URL = 'http://test';
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
test('should render the version page', async () => {
|
||||
const readmeText = 'test';
|
||||
// @ts-ignore
|
||||
fetch.mockResponses(
|
||||
[[JSON.stringify(vueMetadata)], { status: 200, headers: { 'content-type': 'application/json' } }],
|
||||
[[`<p align="center">${readmeText}</p>`], { status: 200, headers: { 'content-type': 'text/html' } }]
|
||||
);
|
||||
|
||||
const { getByTestId, getByText } = render(
|
||||
<ErrorBoundary>
|
||||
<MemoryRouter>
|
||||
<Version match={{ params: { ['package']: 'vue' } }}></Version>
|
||||
</MemoryRouter>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
||||
// first it display loading
|
||||
const hasLoading = getByTestId('loading');
|
||||
expect(hasLoading).toBeTruthy();
|
||||
|
||||
// we wait fetch response (mocked above)
|
||||
await waitForElement(() => getByTestId('version-layout'));
|
||||
|
||||
// check whether readme was loaded
|
||||
const hasReadme = getByText(readmeText);
|
||||
|
||||
expect(hasReadme).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should render 404 page if the resources are not found', async () => {
|
||||
// @ts-ignore
|
||||
fetch.mockResponses(
|
||||
[[JSON.stringify({})], { status: 404, headers: { 'content-type': 'application/json' } }],
|
||||
[[``], { status: 404, headers: { 'content-type': 'text/html' } }]
|
||||
);
|
||||
|
||||
const { getByTestId, getByText } = render(
|
||||
<ErrorBoundary>
|
||||
<MemoryRouter>
|
||||
<Version match={{ params: { ['package']: 'vue' } }}></Version>
|
||||
</MemoryRouter>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
||||
// first it display loading
|
||||
const hasLoading = getByTestId('loading');
|
||||
expect(hasLoading).toBeTruthy();
|
||||
|
||||
// we wait fetch response (mocked above)
|
||||
await waitForElement(() => getByTestId('404'));
|
||||
|
||||
// check whether readme was loaded
|
||||
const hasReadme = getByText(LABEL_NOT_FOUND);
|
||||
|
||||
expect(hasReadme).toBeTruthy();
|
||||
});
|
||||
|
||||
// Wanna contribute? Here we some scenarios we need to test
|
||||
|
||||
test.todo('should test click on tabs');
|
||||
test.todo('should check what is rendered int he sidebar is correct');
|
||||
test.todo('should test click back home on 404');
|
||||
test.todo('should test click on elements in the sidebar');
|
||||
test.todo('should test other not consider scenarios');
|
||||
});
|
||||
69
src/pages/Version/Version.tsx
Normal file
69
src/pages/Version/Version.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { callDetailPage, callReadme } from '../../utils/calls';
|
||||
import { buildScopePackage } from '../../utils/package';
|
||||
import Loading from '../../components/Loading/Loading';
|
||||
import NotFound from '../../components/NotFound';
|
||||
|
||||
import { Layout } from './Layout';
|
||||
import { DetailContextProvider } from './context';
|
||||
import { StateInterface } from './types';
|
||||
|
||||
export function getRouterPackageName(params): string {
|
||||
const packageName = params.package;
|
||||
const { scope } = params;
|
||||
if (scope) {
|
||||
return buildScopePackage(scope, packageName);
|
||||
}
|
||||
|
||||
return packageName;
|
||||
}
|
||||
|
||||
const Version = ({ match: { params } }) => {
|
||||
const pkgName = getRouterPackageName(params);
|
||||
const [readMe, setReadme] = useState();
|
||||
const [packageName, setPackageName] = useState(pkgName);
|
||||
const [packageMeta, setPackageMeta] = useState();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [notFound, setNotFound] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const packageMeta = (await callDetailPage(packageName)) as Partial<StateInterface>;
|
||||
const readMe = (await callReadme(packageName)) as Partial<StateInterface>;
|
||||
setReadme(readMe);
|
||||
setPackageMeta(packageMeta);
|
||||
setIsLoading(false);
|
||||
} catch (error) {
|
||||
setNotFound(true);
|
||||
setIsLoading(false);
|
||||
}
|
||||
})();
|
||||
}, [packageName]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = `Verdaccio - ${packageName}`;
|
||||
}, [packageName]);
|
||||
|
||||
useEffect(() => {
|
||||
const pkgName = getRouterPackageName(params);
|
||||
|
||||
setPackageName(pkgName);
|
||||
}, [params]);
|
||||
|
||||
const isNotFound = notFound || typeof packageMeta === 'undefined' || typeof packageName === 'undefined' || typeof readMe === 'undefined';
|
||||
const renderContent = (): React.ReactElement<HTMLElement> => {
|
||||
if (isLoading) {
|
||||
return <Loading />;
|
||||
} else if (isNotFound) {
|
||||
return <NotFound />;
|
||||
} else {
|
||||
return <Layout />;
|
||||
}
|
||||
};
|
||||
|
||||
return <DetailContextProvider value={{ packageMeta, readMe, packageName, enableLoading: setIsLoading }}>{renderContent()}</DetailContextProvider>;
|
||||
};
|
||||
|
||||
export default Version;
|
||||
7
src/pages/Version/context.ts
Normal file
7
src/pages/Version/context.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import React, { Consumer, Provider } from 'react';
|
||||
import { DetailContextProps, VersionPageConsumerProps } from './types';
|
||||
|
||||
export const DetailContext = React.createContext<Partial<DetailContextProps>>({});
|
||||
|
||||
export const DetailContextProvider: Provider<Partial<VersionPageConsumerProps>> = DetailContext.Provider;
|
||||
export const DetailContextConsumer: Consumer<Partial<VersionPageConsumerProps>> = DetailContext.Consumer;
|
||||
3
src/pages/Version/index.ts
Normal file
3
src/pages/Version/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export { DetailContextProps, VersionPageConsumerProps } from './types';
|
||||
export { DetailContext, DetailContextConsumer, DetailContextProvider } from './context';
|
||||
export { default } from './Version';
|
||||
12
src/pages/Version/styles.ts
Normal file
12
src/pages/Version/styles.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import styled from 'react-emotion';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import colors from '../../utils/styles/colors';
|
||||
import { fontSize } from '../../utils/styles/sizes';
|
||||
|
||||
export const Title = styled(DialogTitle)({
|
||||
'&&': {
|
||||
backgroundColor: colors.primary,
|
||||
color: colors.white,
|
||||
fontSize: fontSize.lg,
|
||||
},
|
||||
});
|
||||
28
src/pages/Version/types.ts
Normal file
28
src/pages/Version/types.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { PackageMetaInterface } from '../../../types/packageMeta';
|
||||
|
||||
export interface DetailContextProps {
|
||||
packageMeta: PackageMetaInterface;
|
||||
readMe: string;
|
||||
packageName: string;
|
||||
enableLoading: () => void;
|
||||
}
|
||||
|
||||
export interface VersionPageConsumerProps {
|
||||
packageMeta: PackageMetaInterface;
|
||||
readMe: string;
|
||||
packageName: string;
|
||||
// FIXME: looking for the appropiated type here
|
||||
enableLoading: any;
|
||||
}
|
||||
|
||||
export interface PropsInterface {
|
||||
match: boolean;
|
||||
}
|
||||
|
||||
export interface StateInterface {
|
||||
readMe: string;
|
||||
packageName: string;
|
||||
packageMeta?: PackageMetaInterface;
|
||||
isLoading: boolean;
|
||||
notFound: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user