diff --git a/src/components/Versions/Versions.test.tsx b/src/components/Versions/Versions.test.tsx index c3015b7..96c4a2a 100644 --- a/src/components/Versions/Versions.test.tsx +++ b/src/components/Versions/Versions.test.tsx @@ -1,48 +1,39 @@ import React from 'react'; import { mount } from 'enzyme'; import { MemoryRouter } from 'react-router'; +import { DetailContext, DetailContextProps } from '../../pages/Version'; import Versions, { LABEL_CURRENT_TAGS, LABEL_VERSION_HISTORY } from './Versions'; import data from './__partials__/data.json'; import { render, cleanup } from '@testing-library/react'; -const mockPackageMeta = jest.fn(() => ({ +const detailContextValue: Partial = { packageName: 'foo', packageMeta: data, -})); +}; -jest.mock('../../pages/Version', () => ({ - DetailContextConsumer: component => { - return component.children({ ...mockPackageMeta() }); - }, -})); +const ComponentToBeRendered: React.FC<{ contextValue: Partial }> = ({ contextValue }) => ( + + + + + +); describe(' component', () => { - beforeEach(() => { - jest.resetModules(); - }); - afterEach(() => { cleanup(); }); // FIXME: this test is not deterministic (writes `N days ago` in the snapshot, where N is random number) test.skip('should render the component in default state', () => { - const wrapper = mount( - - - - ); + const wrapper = mount(); expect(wrapper.html()).toMatchSnapshot(); }); test('should render versions', () => { - const { getByText } = render( - - - - ); + const { getByText } = render(); expect(getByText(LABEL_VERSION_HISTORY)).toBeTruthy(); expect(getByText(LABEL_CURRENT_TAGS)).toBeTruthy(); @@ -53,18 +44,7 @@ describe(' component', () => { }); test('should not render versions', () => { - const request = { - packageName: 'foo', - }; - - // @ts-ignore - mockPackageMeta.mockImplementation(() => request); - - const { queryByText } = render( - - - - ); + const { queryByText } = render(); expect(queryByText(LABEL_VERSION_HISTORY)).toBeFalsy(); expect(queryByText(LABEL_CURRENT_TAGS)).toBeFalsy(); diff --git a/src/components/Versions/Versions.tsx b/src/components/Versions/Versions.tsx index f8d250c..5f6863e 100644 --- a/src/components/Versions/Versions.tsx +++ b/src/components/Versions/Versions.tsx @@ -1,90 +1,46 @@ -import React, { ReactElement } from 'react'; -import List from '@material-ui/core/List'; -import { Link as RouterLink } from 'react-router-dom'; -import Link from '@material-ui/core/Link'; -import ListItem from '@material-ui/core/ListItem'; +import React, { useContext } from 'react'; + +import { DetailContext } from '../../pages/Version'; + +import { Heading } from './styles'; + +import VersionsTagList from './VersionsTagList'; +import VersionsHistoryList from './VersionsHistoryList'; -import { DetailContextConsumer } from '../../pages/Version'; -import { formatDateDistance } from '../../utils/package'; import { DIST_TAGS } from '../../../lib/constants'; -import { Heading, Spacer, ListItemText } from './styles'; - export const NOT_AVAILABLE = 'Not available'; export const LABEL_CURRENT_TAGS = 'Current Tags'; export const LABEL_VERSION_HISTORY = 'Version History'; -class Versions extends React.PureComponent { - public render(): ReactElement { - return ( - - {context => { - const { packageMeta, packageName } = context; +const Versions: React.FC = () => { + const detailContext = useContext(DetailContext); - if (!packageMeta) { - return null; - } + const { packageMeta, packageName } = detailContext; - return this.renderContent(packageMeta, packageName); - }} - - ); + if (!packageMeta) { + return null; } - public renderPackageList = (packages: {}, timeMap: Record, packageName): ReactElement => { - return ( - - {Object.keys(packages) - .reverse() - .map(version => ( - - - {version} - - - {timeMap[version] ? `${formatDateDistance(timeMap[version])} ago` : NOT_AVAILABLE} - - ))} - - ); - }; + // @ts-ignore - Property 'dist-tags' does not exist on type 'PackageMetaInterface' + const { versions = {}, time = {}, [DIST_TAGS]: distTags = {} } = packageMeta; - public renderTagList = (packages: {}): ReactElement => { - return ( - - {Object.keys(packages) - .reverse() - .map(tag => ( - - {tag} - - {packages[tag]} - - ))} - - ); - }; - - public renderContent(packageMeta, packageName): ReactElement { - const { versions = {}, time: timeMap = {}, [DIST_TAGS]: distTags = {} } = packageMeta; - - return ( - <> - {distTags && ( - <> - {LABEL_CURRENT_TAGS} - {this.renderTagList(distTags)} - - )} - {versions && ( - <> - {LABEL_VERSION_HISTORY} - {this.renderPackageList(versions, timeMap, packageName)} - - )} - - ); - } -} + return ( + <> + {distTags && Object.keys(distTags).length > 0 && ( + <> + {LABEL_CURRENT_TAGS} + + + )} + {versions && Object.keys(versions).length > 0 && packageName && ( + <> + {LABEL_VERSION_HISTORY} + + + )} + + ); +}; export default Versions; diff --git a/src/components/Versions/VersionsHistoryList.tsx b/src/components/Versions/VersionsHistoryList.tsx new file mode 100644 index 0000000..b64bed8 --- /dev/null +++ b/src/components/Versions/VersionsHistoryList.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import List from '@material-ui/core/List'; +import Link from '@material-ui/core/Link'; +import ListItem from '@material-ui/core/ListItem'; +import { Link as RouterLink } from 'react-router-dom'; +import { Spacer, ListItemText } from './styles'; + +import { Versions, Time } from '../../../types/packageMeta'; +import { formatDateDistance } from '../../utils/package'; + +export const NOT_AVAILABLE = 'Not available'; + +interface Props { + versions: Versions; + packageName: string; + time: Time; +} + +const VersionsHistoryList: React.FC = ({ versions, packageName, time }) => ( + + {Object.keys(versions) + .reverse() + .map(version => ( + + + {version} + + + {time[version] ? `${formatDateDistance(time[version])} ago` : NOT_AVAILABLE} + + ))} + +); + +export default VersionsHistoryList; diff --git a/src/components/Versions/VersionsTagList.tsx b/src/components/Versions/VersionsTagList.tsx new file mode 100644 index 0000000..0ec44aa --- /dev/null +++ b/src/components/Versions/VersionsTagList.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; +import { Spacer, ListItemText } from './styles'; + +import { DistTags } from '../../../types/packageMeta'; + +interface Props { + tags: DistTags; +} + +const VersionsTagList: React.FC = ({ tags }) => ( + + {Object.keys(tags) + .reverse() + .map(tag => ( + + {tag} + + {tags[tag]} + + ))} + +); + +export default VersionsTagList; diff --git a/src/components/Versions/__snapshots__/Versions.test.tsx.snap b/src/components/Versions/__snapshots__/Versions.test.tsx.snap index 4139876..12e19fe 100644 --- a/src/components/Versions/__snapshots__/Versions.test.tsx.snap +++ b/src/components/Versions/__snapshots__/Versions.test.tsx.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` component should render the component in default state 1`] = `"
Current Tags
  • canary
    8.0.1-master.1
  • token
    2.2.1-pr-token-3
  • next
    8.0.1-next.1
  • beta
    2.0.0-beta.3
  • latest
    8.0.0
Version History
"`; +exports[` component should render the component in default state 1`] = `"
Current Tags
  • canary
    8.0.1-master.1
  • token
    2.2.1-pr-token-3
  • next
    8.0.1-next.1
  • beta
    2.0.0-beta.3
  • latest
    8.0.0
Version History
"`; diff --git a/src/components/Versions/styles.ts b/src/components/Versions/styles.ts index 01909fe..b6cba42 100644 --- a/src/components/Versions/styles.ts +++ b/src/components/Versions/styles.ts @@ -14,6 +14,7 @@ export const Spacer = styled('div')({ borderBottom: '1px dotted rgba(0, 0, 0, 0.2)', whiteSpace: 'nowrap', height: '0.5em', + margin: '0 16px', }); export const ListItemText = styled(MuiListItemText)({ diff --git a/types/packageMeta.ts b/types/packageMeta.ts index 171095d..9ca70cb 100644 --- a/types/packageMeta.ts +++ b/types/packageMeta.ts @@ -1,4 +1,7 @@ export interface PackageMetaInterface { + versions?: Versions; + distTags?: DistTags; + time?: Time; latest: { name: string; dist: { @@ -14,3 +17,37 @@ interface LicenseInterface { type: string; url: string; } + +export interface DistTags { + [key: string]: string; +} + +export interface Time { + [key: string]: string; +} + +export interface Versions { + [key: string]: Version; +} + +export interface Version { + name: string; + version: string; + author?: string | Author; + maintainers?: Maintainer[]; + description?: string; + license?: string; + main?: string; + keywords?: string[]; +} + +interface Author { + name?: string; + email?: string; + url?: string; +} + +interface Maintainer { + email?: string; + name?: string; +}