diff --git a/shlink-web-client.d.ts b/shlink-web-client.d.ts index bbe9db86..52526860 100644 --- a/shlink-web-client.d.ts +++ b/shlink-web-client.d.ts @@ -1,4 +1,6 @@ export declare global { + declare module '*.png' + interface Window { __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: Function; } diff --git a/src/common/AsideMenu.js b/src/common/AsideMenu.js deleted file mode 100644 index dca91132..00000000 --- a/src/common/AsideMenu.js +++ /dev/null @@ -1,81 +0,0 @@ -import { - faList as listIcon, - faLink as createIcon, - faTags as tagsIcon, - faPen as editIcon, -} from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import React from 'react'; -import { NavLink } from 'react-router-dom'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import { serverType } from '../servers/prop-types'; -import './AsideMenu.scss'; - -const AsideMenuItem = ({ children, to, className, ...rest }) => ( - - {children} - -); - -AsideMenuItem.propTypes = { - children: PropTypes.node.isRequired, - to: PropTypes.string.isRequired, - className: PropTypes.string, -}; - -const propTypes = { - selectedServer: serverType, - className: PropTypes.string, - showOnMobile: PropTypes.bool, -}; - -const AsideMenu = (DeleteServerButton) => { - const AsideMenu = ({ selectedServer, className, showOnMobile }) => { - const serverId = selectedServer ? selectedServer.id : ''; - const asideClass = classNames('aside-menu', className, { - 'aside-menu--hidden': !showOnMobile, - }); - const shortUrlsIsActive = (match, location) => location.pathname.match('/list-short-urls'); - const buildPath = (suffix) => `/server/${serverId}${suffix}`; - - return ( - - ); - }; - - AsideMenu.propTypes = propTypes; - - return AsideMenu; -}; - -export default AsideMenu; diff --git a/src/common/AsideMenu.tsx b/src/common/AsideMenu.tsx new file mode 100644 index 00000000..75647382 --- /dev/null +++ b/src/common/AsideMenu.tsx @@ -0,0 +1,77 @@ +import { + faList as listIcon, + faLink as createIcon, + faTags as tagsIcon, + faPen as editIcon, +} from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import React, { FC } from 'react'; +import { NavLink, NavLinkProps } from 'react-router-dom'; +import classNames from 'classnames'; +import { Location } from 'history'; +import { DeleteServerButtonProps } from '../servers/DeleteServerButton'; +import { ServerWithId } from '../servers/data'; +import './AsideMenu.scss'; + +interface AsideMenuProps { + selectedServer: ServerWithId; + className?: string; + showOnMobile?: boolean; +} + +interface AsideMenuItemItemProps extends NavLinkProps { + to: string; + className?: string; +} + +const AsideMenuItem: FC = ({ children, to, className, ...rest }) => ( + + {children} + +); + +const AsideMenu = (DeleteServerButton: FC) => ( + { selectedServer, className, showOnMobile = false }: AsideMenuProps, +) => { + const serverId = selectedServer ? selectedServer.id : ''; + const asideClass = classNames('aside-menu', className, { + 'aside-menu--hidden': !showOnMobile, + }); + const shortUrlsIsActive = (_: null, location: Location) => location.pathname.match('/list-short-urls') !== null; + const buildPath = (suffix: string) => `/server/${serverId}${suffix}`; + + return ( + + ); +}; + +export default AsideMenu; diff --git a/src/common/Home.js b/src/common/Home.tsx similarity index 77% rename from src/common/Home.js rename to src/common/Home.tsx index 63fbc80a..4c5623f3 100644 --- a/src/common/Home.js +++ b/src/common/Home.tsx @@ -1,16 +1,16 @@ import React, { useEffect } from 'react'; import { isEmpty, values } from 'ramda'; import { Link } from 'react-router-dom'; -import PropTypes from 'prop-types'; -import './Home.scss'; import ServersListGroup from '../servers/ServersListGroup'; +import { ServersMap } from '../servers/reducers/servers'; +import './Home.scss'; -const propTypes = { - resetSelectedServer: PropTypes.func, - servers: PropTypes.object, -}; +export interface HomeProps { + resetSelectedServer: Function; + servers: ServersMap; +} -const Home = ({ resetSelectedServer, servers }) => { +const Home = ({ resetSelectedServer, servers }: HomeProps) => { const serversList = values(servers); const hasServers = !isEmpty(serversList); @@ -29,6 +29,4 @@ const Home = ({ resetSelectedServer, servers }) => { ); }; -Home.propTypes = propTypes; - export default Home; diff --git a/src/common/MainHeader.js b/src/common/MainHeader.js deleted file mode 100644 index eecaf464..00000000 --- a/src/common/MainHeader.js +++ /dev/null @@ -1,61 +0,0 @@ -import { faPlus as plusIcon, faChevronDown as arrowIcon, faCogs as cogsIcon } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import React, { useEffect } from 'react'; -import { Link } from 'react-router-dom'; -import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap'; -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import { useToggle } from '../utils/helpers/hooks'; -import shlinkLogo from './shlink-logo-white.png'; -import './MainHeader.scss'; - -const propTypes = { - location: PropTypes.object, -}; - -const MainHeader = (ServersDropdown) => { - const MainHeaderComp = ({ location }) => { - const [ isOpen, toggleOpen, , close ] = useToggle(); - const { pathname } = location; - - useEffect(close, [ location ]); - - const createServerPath = '/server/create'; - const settingsPath = '/settings'; - const toggleClass = classNames('main-header__toggle-icon', { 'main-header__toggle-icon--opened': isOpen }); - - return ( - - - Shlink - - - - - - - - - - - Settings - - - - - Add server - - - - - - - ); - }; - - MainHeaderComp.propTypes = propTypes; - - return MainHeaderComp; -}; - -export default MainHeader; diff --git a/src/common/MainHeader.tsx b/src/common/MainHeader.tsx new file mode 100644 index 00000000..e4a8c163 --- /dev/null +++ b/src/common/MainHeader.tsx @@ -0,0 +1,51 @@ +import { faPlus as plusIcon, faChevronDown as arrowIcon, faCogs as cogsIcon } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import React, { FC, useEffect } from 'react'; +import { Link } from 'react-router-dom'; +import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap'; +import classNames from 'classnames'; +import { RouteChildrenProps } from 'react-router'; +import { useToggle } from '../utils/helpers/hooks'; +import shlinkLogo from './shlink-logo-white.png'; +import './MainHeader.scss'; + +const MainHeader = (ServersDropdown: FC) => ({ location }: RouteChildrenProps) => { + const [ isOpen, toggleOpen, , close ] = useToggle(); + const { pathname } = location; + + useEffect(close, [ location ]); + + const createServerPath = '/server/create'; + const settingsPath = '/settings'; + const toggleClass = classNames('main-header__toggle-icon', { 'main-header__toggle-icon--opened': isOpen }); + + return ( + + + Shlink + + + + + + + + + + + Settings + + + + + Add server + + + + + + + ); +}; + +export default MainHeader; diff --git a/src/common/NoMenuLayout.js b/src/common/NoMenuLayout.js deleted file mode 100644 index f63ca0cd..00000000 --- a/src/common/NoMenuLayout.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import './NoMenuLayout.scss'; - -const propTypes = { - children: PropTypes.node, -}; - -const NoMenuLayout = ({ children }) => {children}; - -NoMenuLayout.propTypes = propTypes; - -export default NoMenuLayout; diff --git a/src/common/NoMenuLayout.tsx b/src/common/NoMenuLayout.tsx new file mode 100644 index 00000000..1cbe2533 --- /dev/null +++ b/src/common/NoMenuLayout.tsx @@ -0,0 +1,6 @@ +import React, { FC } from 'react'; +import './NoMenuLayout.scss'; + +const NoMenuLayout: FC = ({ children }) => {children}; + +export default NoMenuLayout; diff --git a/src/common/NotFound.js b/src/common/NotFound.tsx similarity index 63% rename from src/common/NotFound.js rename to src/common/NotFound.tsx index 7a2355e9..4ec67f71 100644 --- a/src/common/NotFound.js +++ b/src/common/NotFound.tsx @@ -1,13 +1,11 @@ -import React from 'react'; +import React, { FC } from 'react'; import { Link } from 'react-router-dom'; -import * as PropTypes from 'prop-types'; -const propTypes = { - to: PropTypes.string, - children: PropTypes.node, -}; +interface NotFoundProps { + to?: string; +} -const NotFound = ({ to = '/', children = 'Home' }) => ( +const NotFound: FC = ({ to = '/', children = 'Home' }) => ( Oops! We could not find requested route. @@ -19,6 +17,4 @@ const NotFound = ({ to = '/', children = 'Home' }) => ( ); -NotFound.propTypes = propTypes; - export default NotFound; diff --git a/src/common/ScrollToTop.js b/src/common/ScrollToTop.js deleted file mode 100644 index 7de10d6d..00000000 --- a/src/common/ScrollToTop.js +++ /dev/null @@ -1,23 +0,0 @@ -import { useEffect } from 'react'; -import PropTypes from 'prop-types'; - -const propTypes = { - location: PropTypes.object, - children: PropTypes.node, -}; - -const ScrollToTop = () => { - const ScrollToTopComp = ({ location, children }) => { - useEffect(() => { - scrollTo(0, 0); - }, [ location ]); - - return children; - }; - - ScrollToTopComp.propTypes = propTypes; - - return ScrollToTopComp; -}; - -export default ScrollToTop; diff --git a/src/common/ScrollToTop.tsx b/src/common/ScrollToTop.tsx new file mode 100644 index 00000000..48bf2a04 --- /dev/null +++ b/src/common/ScrollToTop.tsx @@ -0,0 +1,12 @@ +import React, { PropsWithChildren, useEffect } from 'react'; +import { RouteChildrenProps } from 'react-router'; + +const ScrollToTop = () => ({ location, children }: PropsWithChildren) => { + useEffect(() => { + scrollTo(0, 0); + }, [ location ]); + + return {children}; +}; + +export default ScrollToTop; diff --git a/src/common/services/provideServices.ts b/src/common/services/provideServices.ts index ad3f1bb3..68d978af 100644 --- a/src/common/services/provideServices.ts +++ b/src/common/services/provideServices.ts @@ -12,7 +12,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator, withRouter: bottle.constant('window', (global as any).window); bottle.constant('console', global.console); - bottle.serviceFactory('ScrollToTop', ScrollToTop, 'window'); + bottle.serviceFactory('ScrollToTop', ScrollToTop); bottle.decorator('ScrollToTop', withRouter); bottle.serviceFactory('MainHeader', MainHeader, 'ServersDropdown'); diff --git a/src/servers/DeleteServerButton.js b/src/servers/DeleteServerButton.js deleted file mode 100644 index 23cab6e4..00000000 --- a/src/servers/DeleteServerButton.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { faMinusCircle as deleteIcon } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import PropTypes from 'prop-types'; -import { useToggle } from '../utils/helpers/hooks'; -import { serverType } from './prop-types'; - -const propTypes = { - server: serverType, - className: PropTypes.string, - textClassName: PropTypes.string, - children: PropTypes.node, -}; - -const DeleteServerButton = (DeleteServerModal) => { - const DeleteServerButtonComp = ({ server, className, children, textClassName }) => { - const [ isModalOpen, , showModal, hideModal ] = useToggle(); - - return ( - - - {!children && } - {children || 'Remove this server'} - - - - - ); - }; - - DeleteServerButtonComp.propTypes = propTypes; - - return DeleteServerButtonComp; -}; - -export default DeleteServerButton; diff --git a/src/servers/DeleteServerButton.tsx b/src/servers/DeleteServerButton.tsx new file mode 100644 index 00000000..152434a4 --- /dev/null +++ b/src/servers/DeleteServerButton.tsx @@ -0,0 +1,31 @@ +import React, { FC } from 'react'; +import { faMinusCircle as deleteIcon } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useToggle } from '../utils/helpers/hooks'; +import { DeleteServerModalProps } from './DeleteServerModal'; +import { ServerWithId } from './data'; + +export interface DeleteServerButtonProps { + server: ServerWithId; + className?: string; + textClassName?: string; +} + +const DeleteServerButton = (DeleteServerModal: FC): FC => ( + { server, className, children, textClassName }, +) => { + const [ isModalOpen, , showModal, hideModal ] = useToggle(); + + return ( + + + {!children && } + {children ?? 'Remove this server'} + + + + + ); +}; + +export default DeleteServerButton; diff --git a/src/servers/DeleteServerModal.js b/src/servers/DeleteServerModal.tsx similarity index 72% rename from src/servers/DeleteServerModal.js rename to src/servers/DeleteServerModal.tsx index 756c9c8e..bc757859 100644 --- a/src/servers/DeleteServerModal.js +++ b/src/servers/DeleteServerModal.tsx @@ -1,19 +1,19 @@ -import PropTypes from 'prop-types'; import React from 'react'; import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; -import { serverType } from './prop-types'; +import { RouterProps } from 'react-router'; +import { ServerWithId } from './data'; -const propTypes = { - toggle: PropTypes.func.isRequired, - isOpen: PropTypes.bool.isRequired, - server: serverType, - deleteServer: PropTypes.func, - history: PropTypes.shape({ - push: PropTypes.func, - }), -}; +export interface DeleteServerModalProps { + server: ServerWithId; + toggle: () => void; + isOpen: boolean; +} -const DeleteServerModal = ({ server, toggle, isOpen, deleteServer, history }) => { +interface DeleteServerModalConnectProps extends DeleteServerModalProps, RouterProps { + deleteServer: (server: ServerWithId) => void; +} + +const DeleteServerModal = ({ server, toggle, isOpen, deleteServer, history }: DeleteServerModalConnectProps) => { const closeModal = () => { deleteServer(server); toggle(); @@ -40,6 +40,4 @@ const DeleteServerModal = ({ server, toggle, isOpen, deleteServer, history }) => ); }; -DeleteServerModal.propTypes = propTypes; - export default DeleteServerModal; diff --git a/src/servers/ServersListGroup.js b/src/servers/ServersListGroup.tsx similarity index 66% rename from src/servers/ServersListGroup.js rename to src/servers/ServersListGroup.tsx index 55f8784a..133a95ca 100644 --- a/src/servers/ServersListGroup.js +++ b/src/servers/ServersListGroup.tsx @@ -1,30 +1,23 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React, { FC } from 'react'; import { ListGroup, ListGroupItem } from 'reactstrap'; import { Link } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faChevronRight as chevronIcon } from '@fortawesome/free-solid-svg-icons'; -import { serverType } from './prop-types'; import './ServersListGroup.scss'; +import { ServerWithId } from './data'; -const propTypes = { - servers: PropTypes.arrayOf(serverType).isRequired, - children: PropTypes.node.isRequired, -}; +interface ServersListGroup { + servers: ServerWithId[]; +} -const ServerListItem = ({ id, name }) => ( +const ServerListItem = ({ id, name }: { id: string; name: string }) => ( {name} ); -ServerListItem.propTypes = { - id: PropTypes.string, - name: PropTypes.string, -}; - -const ServersListGroup = ({ servers, children }) => ( +const ServersListGroup: FC = ({ servers, children }) => ( {children} @@ -37,6 +30,4 @@ const ServersListGroup = ({ servers, children }) => ( ); -ServersListGroup.propTypes = propTypes; - export default ServersListGroup; diff --git a/src/utils/helpers/hooks.ts b/src/utils/helpers/hooks.ts index 6e2c986c..3eadd866 100644 --- a/src/utils/helpers/hooks.ts +++ b/src/utils/helpers/hooks.ts @@ -23,7 +23,7 @@ export const useStateFlagTimeout = ( return [ flag, callback ]; }; -type ToggleResult = [ boolean, (flag: boolean) => void, () => void, () => void ]; +type ToggleResult = [ boolean, () => void, () => void, () => void ]; export const useToggle = (initialValue = false): ToggleResult => { const [ flag, setFlag ] = useState(initialValue); diff --git a/test/common/AsideMenu.test.js b/test/common/AsideMenu.test.tsx similarity index 65% rename from test/common/AsideMenu.test.js rename to test/common/AsideMenu.test.tsx index 03ab5097..c1145bca 100644 --- a/test/common/AsideMenu.test.js +++ b/test/common/AsideMenu.test.tsx @@ -1,15 +1,17 @@ -import { shallow } from 'enzyme'; +import { shallow, ShallowWrapper } from 'enzyme'; import React from 'react'; +import { Mock } from 'ts-mockery'; import asideMenuCreator from '../../src/common/AsideMenu'; +import { ServerWithId } from '../../src/servers/data'; describe('', () => { - let wrapped; - const DeleteServerButton = () => ''; + let wrapped: ShallowWrapper; + const DeleteServerButton = () => null; beforeEach(() => { const AsideMenu = asideMenuCreator(DeleteServerButton); - wrapped = shallow(); + wrapped = shallow(({ id: 'abc123' })} />); }); afterEach(() => wrapped.unmount()); diff --git a/test/common/Home.test.js b/test/common/Home.test.tsx similarity index 61% rename from test/common/Home.test.js rename to test/common/Home.test.tsx index 0af589b2..99eb3be8 100644 --- a/test/common/Home.test.js +++ b/test/common/Home.test.tsx @@ -1,14 +1,16 @@ -import { shallow } from 'enzyme'; +import { shallow, ShallowWrapper } from 'enzyme'; import React from 'react'; -import Home from '../../src/common/Home'; +import { Mock } from 'ts-mockery'; +import Home, { HomeProps } from '../../src/common/Home'; +import { ServerWithId } from '../../src/servers/data'; describe('', () => { - let wrapped; + let wrapped: ShallowWrapper; const defaultProps = { resetSelectedServer: jest.fn(), servers: {}, }; - const createComponent = (props) => { + const createComponent = (props: Partial = {}) => { const actualProps = { ...defaultProps, ...props }; wrapped = shallow(); @@ -16,7 +18,7 @@ describe('', () => { return wrapped; }; - afterEach(() => wrapped && wrapped.unmount()); + afterEach(() => wrapped?.unmount()); it('shows link to create server when no servers exist', () => { const wrapped = createComponent(); @@ -26,8 +28,8 @@ describe('', () => { it('asks to select a server when servers exist', () => { const servers = { - 1: { name: 'foo', id: '1' }, - 2: { name: 'bar', id: '2' }, + '1a': Mock.of({ name: 'foo', id: '1' }), + '2b': Mock.of({ name: 'bar', id: '2' }), }; const wrapped = createComponent({ servers }); const span = wrapped.find('span'); diff --git a/test/common/NotFound.test.js b/test/common/NotFound.test.tsx similarity index 92% rename from test/common/NotFound.test.js rename to test/common/NotFound.test.tsx index 036db8a6..a194711c 100644 --- a/test/common/NotFound.test.js +++ b/test/common/NotFound.test.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { shallow, ShallowWrapper } from 'enzyme'; import { Link } from 'react-router-dom'; import NotFound from '../../src/common/NotFound'; describe('', () => { - let wrapper; + let wrapper: ShallowWrapper; const createWrapper = (props = {}) => { wrapper = shallow(); const content = wrapper.text(); @@ -12,7 +12,7 @@ describe('', () => { return { wrapper, content }; }; - afterEach(() => wrapper && wrapper.unmount()); + afterEach(() => wrapper?.unmount()); it('shows expected error title', () => { const { content } = createWrapper(); diff --git a/test/common/ScrollToTop.test.js b/test/common/ScrollToTop.test.js deleted file mode 100644 index a0264182..00000000 --- a/test/common/ScrollToTop.test.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; -import createScrollToTop from '../../src/common/ScrollToTop'; - -describe('', () => { - let wrapper; - const window = { - scrollTo: jest.fn(), - }; - - beforeEach(() => { - const ScrollToTop = createScrollToTop(window); - - wrapper = shallow(Foobar); - }); - - afterEach(() => { - wrapper.unmount(); - window.scrollTo.mockReset(); - }); - - it('just renders children', () => expect(wrapper.text()).toEqual('Foobar')); -}); diff --git a/test/common/ScrollToTop.test.tsx b/test/common/ScrollToTop.test.tsx new file mode 100644 index 00000000..ff925292 --- /dev/null +++ b/test/common/ScrollToTop.test.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { shallow, ShallowWrapper } from 'enzyme'; +import { Mock } from 'ts-mockery'; +import { RouteChildrenProps } from 'react-router'; +import createScrollToTop from '../../src/common/ScrollToTop'; + +describe('', () => { + let wrapper: ShallowWrapper; + + beforeEach(() => { + const ScrollToTop = createScrollToTop(); + + wrapper = shallow(()}>Foobar); + }); + + afterEach(() => wrapper.unmount()); + + it('just renders children', () => expect(wrapper.text()).toEqual('Foobar')); +}); diff --git a/test/servers/DeleteServerButton.test.js b/test/servers/DeleteServerButton.test.tsx similarity index 70% rename from test/servers/DeleteServerButton.test.js rename to test/servers/DeleteServerButton.test.tsx index a377cf83..d5541662 100644 --- a/test/servers/DeleteServerButton.test.js +++ b/test/servers/DeleteServerButton.test.tsx @@ -1,15 +1,17 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { shallow, ShallowWrapper } from 'enzyme'; +import { Mock } from 'ts-mockery'; import deleteServerButtonConstruct from '../../src/servers/DeleteServerButton'; -import DeleteServerModal from '../../src/servers/DeleteServerModal'; +import { ServerWithId } from '../../src/servers/data'; describe('', () => { - let wrapper; + let wrapper: ShallowWrapper; + const DeleteServerModal = () => null; beforeEach(() => { const DeleteServerButton = deleteServerButtonConstruct(DeleteServerModal); - wrapper = shallow(); + wrapper = shallow(()} className="button" />); }); afterEach(() => wrapper.unmount()); diff --git a/test/servers/DeleteServerModal.test.js b/test/servers/DeleteServerModal.test.tsx similarity index 77% rename from test/servers/DeleteServerModal.test.js rename to test/servers/DeleteServerModal.test.tsx index 1114fd8f..cc5d881f 100644 --- a/test/servers/DeleteServerModal.test.js +++ b/test/servers/DeleteServerModal.test.tsx @@ -1,31 +1,31 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { shallow, ShallowWrapper } from 'enzyme'; import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; +import { History } from 'history'; +import { Mock } from 'ts-mockery'; import DeleteServerModal from '../../src/servers/DeleteServerModal'; +import { ServerWithId } from '../../src/servers/data'; describe('', () => { - let wrapper; + let wrapper: ShallowWrapper; const deleteServerMock = jest.fn(); - const historyMock = { push: jest.fn() }; + const push = jest.fn(); const toggleMock = jest.fn(); const serverName = 'the_server_name'; beforeEach(() => { - deleteServerMock.mockReset(); - toggleMock.mockReset(); - historyMock.push.mockReset(); - wrapper = shallow( ({ name: serverName })} toggle={toggleMock} isOpen={true} deleteServer={deleteServerMock} - history={historyMock} + history={Mock.of({ push })} />, ); }); afterEach(() => wrapper.unmount()); + afterEach(jest.clearAllMocks); it('renders a modal window', () => { expect(wrapper.find(Modal)).toHaveLength(1); @@ -49,7 +49,7 @@ describe('', () => { expect(toggleMock).toHaveBeenCalledTimes(1); expect(deleteServerMock).not.toHaveBeenCalled(); - expect(historyMock.push).not.toHaveBeenCalled(); + expect(push).not.toHaveBeenCalled(); }); it('deletes server when clicking accept button', () => { @@ -59,6 +59,6 @@ describe('', () => { expect(toggleMock).toHaveBeenCalledTimes(1); expect(deleteServerMock).toHaveBeenCalledTimes(1); - expect(historyMock.push).toHaveBeenCalledTimes(1); + expect(push).toHaveBeenCalledTimes(1); }); }); diff --git a/test/servers/ServersListGroup.test.js b/test/servers/ServersListGroup.test.tsx similarity index 66% rename from test/servers/ServersListGroup.test.js rename to test/servers/ServersListGroup.test.tsx index b2871bbe..2f6ba24b 100644 --- a/test/servers/ServersListGroup.test.js +++ b/test/servers/ServersListGroup.test.tsx @@ -1,17 +1,19 @@ -import { shallow } from 'enzyme'; +import { shallow, ShallowWrapper } from 'enzyme'; import React from 'react'; import { ListGroup } from 'reactstrap'; +import { Mock } from 'ts-mockery'; import ServersListGroup from '../../src/servers/ServersListGroup'; +import { ServerWithId } from '../../src/servers/data'; describe('', () => { - let wrapped; - const createComponent = (servers) => { + let wrapped: ShallowWrapper; + const createComponent = (servers: ServerWithId[]) => { wrapped = shallow(The list of servers); return wrapped; }; - afterEach(() => wrapped && wrapped.unmount()); + afterEach(() => wrapped?.unmount()); it('Renders title', () => { const wrapped = createComponent([]); @@ -23,8 +25,8 @@ describe('', () => { it('shows servers list', () => { const servers = [ - { name: 'foo', id: '123' }, - { name: 'bar', id: '456' }, + Mock.of({ name: 'foo', id: '123' }), + Mock.of({ name: 'bar', id: '456' }), ]; const wrapped = createComponent(servers);
@@ -19,6 +17,4 @@ const NotFound = ({ to = '/', children = 'Home' }) => (