Migrated first component and test to typescript

This commit is contained in:
Alejandro Celaya 2020-08-22 09:15:05 +02:00
parent 72de9d4ff8
commit 524b0a74c6
8 changed files with 91 additions and 56 deletions

View file

@ -17,9 +17,9 @@ module.exports = {
testEnvironment: 'jsdom',
testURL: 'http://localhost',
transform: {
'^.+\\.(js|jsx|mjs)$': '<rootDir>/node_modules/babel-jest',
'^.+\\.(ts|tsx|js|jsx|mjs)$': '<rootDir>/node_modules/babel-jest',
'^.+\\.css$': '<rootDir>/config/jest/cssTransform.js',
'^(?!.*\\.(js|jsx|mjs|css|json)$)': '<rootDir>/config/jest/fileTransform.js',
'^(?!.*\\.(ts|tsx|js|jsx|mjs|css|json)$)': '<rootDir>/config/jest/fileTransform.js',
},
transformIgnorePatterns: [
'[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$',

34
package-lock.json generated
View file

@ -2022,12 +2022,31 @@
"@babel/types": "^7.3.0"
}
},
"@types/cheerio": {
"version": "0.22.21",
"resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.21.tgz",
"integrity": "sha512-aGI3DfswwqgKPiEOTaiHV2ZPC9KEhprpgEbJnv0fZl3SGX0cGgEva1126dGrMC6AJM6v/aihlUgJn9M5DbDZ/Q==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
"dev": true
},
"@types/enzyme": {
"version": "3.10.5",
"resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.10.5.tgz",
"integrity": "sha512-R+phe509UuUYy9Tk0YlSbipRpfVtIzb/9BHn5pTEtjJTF5LXvUjrIQcZvNyANNEyFrd2YGs196PniNT1fgvOQA==",
"dev": true,
"requires": {
"@types/cheerio": "*",
"@types/react": "*"
}
},
"@types/eslint-visitor-keys": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
@ -2264,6 +2283,15 @@
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==",
"dev": true
},
"@types/ramda": {
"version": "0.27.14",
"resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.27.14.tgz",
"integrity": "sha512-vbw/VAtEJeSJ6Z61QT+epirlnBeJiJIO7ndK1BJ0fKswnfbiTNga/jBG6R3OnBaFYx+UJv6Iv7ZfWDFSsSzNqA==",
"dev": true,
"requires": {
"ts-toolbelt": "^6.3.3"
}
},
"@types/react": {
"version": "16.9.46",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.46.tgz",
@ -19465,6 +19493,12 @@
"integrity": "sha512-1J/vefLC+BWSo+qe8OnJQfWTYRS6ingxjwqmHMqaMxXMj7kFtKLgAaYW3JeX3mktjgUL+etlU8/B4VUAUI9QGw==",
"dev": true
},
"ts-toolbelt": {
"version": "6.15.5",
"resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz",
"integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==",
"dev": true
},
"tsconfig-paths": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",

View file

@ -73,6 +73,9 @@
"@stryker-mutator/javascript-mutator": "^3.2.4",
"@stryker-mutator/jest-runner": "^3.2.4",
"@svgr/webpack": "^4.3.3",
"@types/enzyme": "^3.10.5",
"@types/jest": "^26.0.10",
"@types/ramda": "^0.27.14",
"@types/react": "^16.9.46",
"@types/react-dom": "^16.9.8",
"@types/react-redux": "^7.1.9",

View file

@ -1,44 +0,0 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { Route, Switch } from 'react-router-dom';
import NotFound from './common/NotFound';
import './App.scss';
const propTypes = {
fetchServers: PropTypes.func,
servers: PropTypes.object,
};
const App = (MainHeader, Home, MenuLayout, CreateServer, EditServer, Settings) => {
const AppComp = ({ fetchServers, servers }) => {
// On first load, try to fetch the remote servers if the list is empty
useEffect(() => {
if (Object.keys(servers).length === 0) {
fetchServers();
}
}, []);
return (
<div className="container-fluid app-container">
<MainHeader />
<div className="app">
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/settings" component={Settings} />
<Route exact path="/server/create" component={CreateServer} />
<Route exact path="/server/:serverId/edit" component={EditServer} />
<Route path="/server/:serverId" component={MenuLayout} />
<Route component={NotFound} />
</Switch>
</div>
</div>
);
};
AppComp.propTypes = propTypes;
return AppComp;
};
export default App;

39
src/App.tsx Normal file
View file

@ -0,0 +1,39 @@
import React, { useEffect, FC } from 'react';
import { Route, Switch } from 'react-router-dom';
import NotFound from './common/NotFound';
import './App.scss';
interface AppProps {
fetchServers: Function;
servers: Record<string, object>;
}
const App = (MainHeader: FC, Home: FC, MenuLayout: FC, CreateServer: FC, EditServer: FC, Settings: FC) => (
{ fetchServers, servers }: AppProps,
) => {
// On first load, try to fetch the remote servers if the list is empty
useEffect(() => {
if (Object.keys(servers).length === 0) {
fetchServers();
}
}, []);
return (
<div className="container-fluid app-container">
<MainHeader />
<div className="app">
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/settings" component={Settings} />
<Route exact path="/server/create" component={CreateServer} />
<Route exact path="/server/:serverId/edit" component={EditServer} />
<Route path="/server/:serverId" component={MenuLayout} />
<Route component={NotFound} />
</Switch>
</div>
</div>
);
};
export default App;

View file

@ -1,4 +1,4 @@
import Bottle from 'bottlejs';
import Bottle, { IContainer } from 'bottlejs';
import { withRouter } from 'react-router-dom';
import { connect as reduxConnect } from 'react-redux';
import { pick } from 'ramda';
@ -12,17 +12,19 @@ import provideUtilsServices from '../utils/services/provideServices';
import provideMercureServices from '../mercure/services/provideServices';
import provideSettingsServices from '../settings/services/provideServices';
type ActionMap = Record<string, any>;
const bottle = new Bottle();
const { container } = bottle;
const lazyService = (container, serviceName) => (...args) => container[serviceName](...args);
const mapActionService = (map, actionName) => ({
const lazyService = (container: IContainer, serviceName: string) => (...args: any[]) => container[serviceName](...args);
const mapActionService = (map: ActionMap, actionName: string): ActionMap => ({
...map,
// Wrap actual action service in a function so that it is lazily created the first time it is called
[actionName]: lazyService(container, actionName),
});
const connect = (propsFromState, actionServiceNames = []) =>
const connect = (propsFromState: string[], actionServiceNames: string[] = []) =>
reduxConnect(
propsFromState ? pick(propsFromState) : null,
actionServiceNames.reduce(mapActionService, {}),

View file

@ -1,4 +1,4 @@
.open-map-modal-btn__btn {
.open-map-modal-btn__btn.open-map-modal-btn__btn {
padding: 0;
margin-right: 1rem;
}

View file

@ -1,17 +1,18 @@
import React from 'react';
import { shallow } from 'enzyme';
import { shallow, ShallowWrapper } from 'enzyme';
import { Route } from 'react-router-dom';
import { identity } from 'ramda';
import appFactory from '../src/App';
describe('<App />', () => {
let wrapper;
const MainHeader = () => '';
let wrapper: ShallowWrapper;
const MainHeader = () => null;
const DummyComponent = () => null;
beforeEach(() => {
const App = appFactory(MainHeader, identity, identity, identity, identity);
const App = appFactory(MainHeader, DummyComponent, DummyComponent, DummyComponent, DummyComponent, DummyComponent);
wrapper = shallow(<App />);
wrapper = shallow(<App fetchServers={identity} servers={{}} />);
});
afterEach(() => wrapper.unmount());