mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 01:20:24 +03:00
Migrated first component and test to typescript
This commit is contained in:
parent
72de9d4ff8
commit
524b0a74c6
8 changed files with 91 additions and 56 deletions
|
@ -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
34
package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
44
src/App.js
44
src/App.js
|
@ -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
39
src/App.tsx
Normal 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;
|
|
@ -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, {}),
|
|
@ -1,4 +1,4 @@
|
|||
.open-map-modal-btn__btn {
|
||||
.open-map-modal-btn__btn.open-map-modal-btn__btn {
|
||||
padding: 0;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
Loading…
Reference in a new issue