Skip to content
This repository was archived by the owner on Jan 16, 2022. It is now read-only.

Commit 5cb47ed

Browse files
Andrew Hughsonjuanpicado
authored andcommitted
fix: convert Engine component to hooks (#233)
* refactor: convert Engine component to hooks * inline engine test data only used by one test * remove from engines tests * remove confusing test abstraction * change tests to not use mutations
1 parent b56e438 commit 5cb47ed

File tree

3 files changed

+77
-105
lines changed

3 files changed

+77
-105
lines changed
Lines changed: 37 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,61 @@
11
import React from 'react';
22
import { mount } from 'enzyme';
33

4+
import { DetailContext } from '../../pages/Version';
5+
import { PackageMetaInterface } from '../../../types/packageMeta';
6+
47
import Engine from './Engines';
58

69
jest.mock('./img/node.png', () => '');
710
jest.mock('../Install/img/npm.svg', () => '');
811

9-
const mockPackageMeta: jest.Mock = jest.fn(() => ({
12+
const mockPackageMeta = (engines?: PackageMetaInterface['latest']['engines']): PackageMetaInterface => ({
1013
latest: {
11-
homepage: 'https://verdaccio.tld',
12-
bugs: {
13-
url: 'https://verdaccio.tld/bugs',
14-
},
14+
name: 'verdaccio',
15+
version: '0.0.0',
1516
dist: {
16-
tarball: 'https://verdaccio.tld/download',
17+
fileCount: 1,
18+
unpackedSize: 1,
1719
},
20+
...(engines && { engines }),
1821
},
19-
}));
20-
21-
jest.mock('../../pages/Version', () => ({
22-
DetailContextConsumer: component => {
23-
return component.children({ packageMeta: mockPackageMeta() });
24-
},
25-
}));
22+
_uplinks: {},
23+
});
2624

2725
describe('<Engines /> component', () => {
28-
beforeEach(() => {
29-
jest.resetAllMocks();
30-
});
31-
3226
test('should render the component in default state', () => {
33-
const packageMeta = {
34-
latest: {
35-
engines: {
36-
node: '>= 0.1.98',
37-
npm: '>3',
38-
},
39-
},
40-
};
41-
42-
mockPackageMeta.mockImplementation(() => packageMeta);
43-
44-
const wrapper = mount(<Engine />);
27+
const packageMeta = mockPackageMeta({
28+
node: '>= 0.1.98',
29+
npm: '>3',
30+
});
31+
32+
const wrapper = mount(
33+
<DetailContext.Provider value={{ packageMeta }}>
34+
<Engine />
35+
</DetailContext.Provider>
36+
);
4537
expect(wrapper.html()).toMatchSnapshot();
4638
});
4739

4840
test('should render the component when there is no engine key in package meta', () => {
49-
const packageMeta = {
50-
latest: {},
51-
};
52-
53-
mockPackageMeta.mockImplementation(() => packageMeta);
54-
55-
const wrapper = mount(<Engine />);
56-
expect(wrapper.html()).toEqual('');
41+
const packageMeta = mockPackageMeta();
42+
43+
const wrapper = mount(
44+
<DetailContext.Provider value={{ packageMeta }}>
45+
<Engine />
46+
</DetailContext.Provider>
47+
);
48+
expect(wrapper.html()).toBeNull();
5749
});
5850

5951
test('should render the component when there is no keys in engine in package meta', () => {
60-
const packageMeta = {
61-
latest: {
62-
engines: {},
63-
},
64-
};
65-
66-
mockPackageMeta.mockImplementation(() => packageMeta);
67-
68-
const wrapper = mount(<Engine />);
69-
expect(wrapper.html()).toEqual('');
52+
const packageMeta = mockPackageMeta({});
53+
54+
const wrapper = mount(
55+
<DetailContext.Provider value={{ packageMeta }}>
56+
<Engine />
57+
</DetailContext.Provider>
58+
);
59+
expect(wrapper.html()).toBeNull();
7060
});
7161
});

src/components/Engines/Engines.tsx

Lines changed: 36 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,51 @@
1-
import React, { Component, ReactElement } from 'react';
1+
import React, { useContext } from 'react';
22

3-
import { VersionPageConsumerProps, DetailContextConsumer } from '../../pages/Version';
3+
import { DetailContext } from '../../pages/Version';
44
import Avatar from '../../muiComponents/Avatar';
55
import List from '../../muiComponents/List';
66
import npm from '../Install/img/npm.svg';
77
import ListItemText from '../../muiComponents/ListItemText';
88
import Grid from '../../muiComponents/Grid';
99

1010
import { StyledText, EngineListItem } from './styles';
11-
// @ts-ignore
1211
import node from './img/node.png';
1312

14-
const ICONS = {
15-
'node-JS': <Avatar src={node} />,
16-
'NPM-version': <Avatar src={npm} />,
17-
};
18-
19-
class Engine extends Component {
20-
public render(): ReactElement<HTMLElement> {
21-
return (
22-
<DetailContextConsumer>
23-
{context => {
24-
return this.renderEngine(context as VersionPageConsumerProps);
25-
}}
26-
</DetailContextConsumer>
27-
);
28-
}
29-
30-
private renderEngine = ({ packageMeta }): ReactElement<HTMLElement> | null => {
31-
const { engines } = packageMeta.latest;
32-
if (!engines) {
33-
return null;
34-
}
13+
const Engine: React.FC = () => {
14+
const { packageMeta } = useContext(DetailContext);
3515

36-
const engineDict = {
37-
'node-JS': engines.node,
38-
'NPM-version': engines.npm,
39-
};
16+
const engines = packageMeta && packageMeta.latest && packageMeta.latest.engines;
4017

41-
const accumulator: React.ReactNode[] = [];
42-
const items = Object.keys(engineDict).reduce((markup, text, key) => {
43-
const heading = engineDict[text];
44-
if (heading) {
45-
markup.push(
46-
<Grid item={true} key={key} xs={6}>
47-
{this.renderListItems(heading, text)}
48-
</Grid>
49-
);
50-
}
51-
return markup;
52-
}, accumulator);
53-
54-
if (items.length < 1) {
55-
return null;
56-
}
57-
58-
return <Grid container={true}>{items}</Grid>;
59-
};
18+
if (!engines || (!engines.node && !engines.npm)) {
19+
return null;
20+
}
6021

61-
private renderListItems = (heading: string, text: string) => {
62-
return (
63-
<List subheader={<StyledText variant={'subtitle1'}>{text.split('-').join(' ')}</StyledText>}>
64-
<EngineListItem button={true}>
65-
{ICONS[text]}
66-
<ListItemText primary={heading} />
67-
</EngineListItem>
68-
</List>
69-
);
70-
};
71-
}
22+
/* eslint-disable react/jsx-max-depth */
23+
return (
24+
<Grid container={true}>
25+
{engines.node && (
26+
<Grid item={true} xs={6}>
27+
<List subheader={<StyledText variant={'subtitle1'}>{'node JS'}</StyledText>}>
28+
<EngineListItem button={true}>
29+
<Avatar src={node} />
30+
<ListItemText primary={engines.node} />
31+
</EngineListItem>
32+
</List>
33+
</Grid>
34+
)}
35+
36+
{engines.npm && (
37+
<Grid item={true} xs={6}>
38+
<List subheader={<StyledText variant={'subtitle1'}>{'NPM version'}</StyledText>}>
39+
<EngineListItem button={true}>
40+
<Avatar src={npm} />
41+
<ListItemText primary={engines.npm} />
42+
</EngineListItem>
43+
</List>
44+
</Grid>
45+
)}
46+
</Grid>
47+
);
48+
/* eslint-enable react/jsx-max-depth */
49+
};
7250

7351
export default Engine;

types/packageMeta.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export interface PackageMetaInterface {
99
fileCount: number;
1010
unpackedSize: number;
1111
};
12+
engines?: {
13+
node?: string;
14+
npm?: string;
15+
};
1216
license?: Partial<LicenseInterface> | string;
1317
version: string;
1418
};

0 commit comments

Comments
 (0)