diff --git a/src/App.js b/src/App.js index b351422c..ba40b7e8 100644 --- a/src/App.js +++ b/src/App.js @@ -1,6 +1,7 @@ import React from 'react'; import { Route, Switch } from 'react-router-dom'; import './App.scss'; +import NotFound from './common/NotFound'; const App = (MainHeader, Home, MenuLayout, CreateServer) => () => (
@@ -11,6 +12,7 @@ const App = (MainHeader, Home, MenuLayout, CreateServer) => () => ( +
diff --git a/src/common/MenuLayout.js b/src/common/MenuLayout.js index 62c9c256..93662271 100644 --- a/src/common/MenuLayout.js +++ b/src/common/MenuLayout.js @@ -6,6 +6,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import classnames from 'classnames'; import * as PropTypes from 'prop-types'; import { serverType } from '../servers/prop-types'; +import NotFound from './NotFound'; import './MenuLayout.scss'; const MenuLayout = (TagsList, ShortUrls, AsideMenu, CreateShortUrl, ShortUrlVisits) => @@ -38,7 +39,8 @@ const MenuLayout = (TagsList, ShortUrls, AsideMenu, CreateShortUrl, ShortUrlVisi } render() { - const { selectedServer } = this.props; + const { selectedServer, match } = this.props; + const { params: { serverId } } = match; const burgerClasses = classnames('menu-layout__burger-icon', { 'menu-layout__burger-icon--active': this.state.showSideBar, }); @@ -88,6 +90,9 @@ const MenuLayout = (TagsList, ShortUrls, AsideMenu, CreateShortUrl, ShortUrlVisi path="/server/:serverId/manage-tags" component={TagsList} /> + } + /> diff --git a/src/common/NotFound.js b/src/common/NotFound.js new file mode 100644 index 00000000..d34e0143 --- /dev/null +++ b/src/common/NotFound.js @@ -0,0 +1,23 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import * as PropTypes from 'prop-types'; + +const propTypes = { + to: PropTypes.string, + btnText: PropTypes.string, +}; + +const NotFound = ({ to = '/', btnText = 'Home' }) => ( +
+

Oops! We could not find requested route.

+

+ Use your browser{'\''}s back button to navigate to the page you have previously come from, or just press this button. +

+
+ {btnText} +
+); + +NotFound.propTypes = propTypes; + +export default NotFound; diff --git a/test/App.test.js b/test/App.test.js index 1a112ae7..c9df2d9c 100644 --- a/test/App.test.js +++ b/test/App.test.js @@ -19,12 +19,17 @@ describe('', () => { it('renders app main routes', () => { const routes = wrapper.find(Route); - const expectedRoutesCount = 3; - const second = 2; + const expectedRoutesCount = 4; + const expectedPaths = [ + '/server/create', + '/', + '/server/:serverId', + ]; + expect.assertions(expectedPaths.length + 1); expect(routes).toHaveLength(expectedRoutesCount); - expect(routes.at(0).prop('path')).toEqual('/server/create'); - expect(routes.at(1).prop('path')).toEqual('/'); - expect(routes.at(second).prop('path')).toEqual('/server/:serverId'); + expectedPaths.forEach((path, index) => { + expect(routes.at(index).prop('path')).toEqual(path); + }); }); }); diff --git a/test/common/NotFound.test.js b/test/common/NotFound.test.js new file mode 100644 index 00000000..a230cc56 --- /dev/null +++ b/test/common/NotFound.test.js @@ -0,0 +1,48 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { Link } from 'react-router-dom'; +import NotFound from '../../src/common/NotFound'; + +describe('', () => { + let wrapper; + const createWrapper = (props = {}) => { + wrapper = shallow(); + const content = wrapper.text(); + + return { wrapper, content }; + }; + + afterEach(() => wrapper && wrapper.unmount()); + + it('shows expected error title', () => { + const { content } = createWrapper(); + + expect(content).toContain('Oops! We could not find requested route.'); + }); + + it('shows expected error message', () => { + const { content } = createWrapper(); + + expect(content).toContain( + 'Use your browser\'s back button to navigate to the page you have previously come from, or just press this button.' + ); + }); + + it('shows a link to the home', () => { + const { wrapper } = createWrapper(); + const link = wrapper.find(Link); + + expect(link.prop('to')).toEqual('/'); + expect(link.prop('className')).toEqual('btn btn-outline-primary btn-lg'); + expect(link.prop('children')).toEqual('Home'); + }); + + it('shows a link with provided props', () => { + const { wrapper } = createWrapper({ to: '/foo/bar', btnText: 'Hello' }); + const link = wrapper.find(Link); + + expect(link.prop('to')).toEqual('/foo/bar'); + expect(link.prop('className')).toEqual('btn btn-outline-primary btn-lg'); + expect(link.prop('children')).toEqual('Hello'); + }); +});