Merge pull request #108 from acelaya/feature/not-found-page

Feature/not found page
This commit is contained in:
Alejandro Celaya 2019-03-03 11:24:56 +01:00 committed by GitHub
commit e9e808d339
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 89 additions and 6 deletions

View file

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { Route, Switch } from 'react-router-dom'; import { Route, Switch } from 'react-router-dom';
import './App.scss'; import './App.scss';
import NotFound from './common/NotFound';
const App = (MainHeader, Home, MenuLayout, CreateServer) => () => ( const App = (MainHeader, Home, MenuLayout, CreateServer) => () => (
<div className="container-fluid app-container"> <div className="container-fluid app-container">
@ -11,6 +12,7 @@ const App = (MainHeader, Home, MenuLayout, CreateServer) => () => (
<Route exact path="/server/create" component={CreateServer} /> <Route exact path="/server/create" component={CreateServer} />
<Route exact path="/" component={Home} /> <Route exact path="/" component={Home} />
<Route path="/server/:serverId" component={MenuLayout} /> <Route path="/server/:serverId" component={MenuLayout} />
<Route component={NotFound} />
</Switch> </Switch>
</div> </div>
</div> </div>

View file

@ -6,6 +6,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import classnames from 'classnames'; import classnames from 'classnames';
import * as PropTypes from 'prop-types'; import * as PropTypes from 'prop-types';
import { serverType } from '../servers/prop-types'; import { serverType } from '../servers/prop-types';
import NotFound from './NotFound';
import './MenuLayout.scss'; import './MenuLayout.scss';
const MenuLayout = (TagsList, ShortUrls, AsideMenu, CreateShortUrl, ShortUrlVisits) => const MenuLayout = (TagsList, ShortUrls, AsideMenu, CreateShortUrl, ShortUrlVisits) =>
@ -38,7 +39,8 @@ const MenuLayout = (TagsList, ShortUrls, AsideMenu, CreateShortUrl, ShortUrlVisi
} }
render() { render() {
const { selectedServer } = this.props; const { selectedServer, match } = this.props;
const { params: { serverId } } = match;
const burgerClasses = classnames('menu-layout__burger-icon', { const burgerClasses = classnames('menu-layout__burger-icon', {
'menu-layout__burger-icon--active': this.state.showSideBar, 'menu-layout__burger-icon--active': this.state.showSideBar,
}); });
@ -88,6 +90,9 @@ const MenuLayout = (TagsList, ShortUrls, AsideMenu, CreateShortUrl, ShortUrlVisi
path="/server/:serverId/manage-tags" path="/server/:serverId/manage-tags"
component={TagsList} component={TagsList}
/> />
<Route
render={() => <NotFound to={`/server/${serverId}/list-short-urls/1`} btnText="List short URLs" />}
/>
</Switch> </Switch>
</div> </div>
</div> </div>

23
src/common/NotFound.js Normal file
View file

@ -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' }) => (
<div className="home">
<h2>Oops! We could not find requested route.</h2>
<p>
Use your browser{'\''}s back button to navigate to the page you have previously come from, or just press this button.
</p>
<br />
<Link to={to} className="btn btn-outline-primary btn-lg">{btnText}</Link>
</div>
);
NotFound.propTypes = propTypes;
export default NotFound;

View file

@ -19,12 +19,17 @@ describe('<App />', () => {
it('renders app main routes', () => { it('renders app main routes', () => {
const routes = wrapper.find(Route); const routes = wrapper.find(Route);
const expectedRoutesCount = 3; const expectedRoutesCount = 4;
const second = 2; const expectedPaths = [
'/server/create',
'/',
'/server/:serverId',
];
expect.assertions(expectedPaths.length + 1);
expect(routes).toHaveLength(expectedRoutesCount); expect(routes).toHaveLength(expectedRoutesCount);
expect(routes.at(0).prop('path')).toEqual('/server/create'); expectedPaths.forEach((path, index) => {
expect(routes.at(1).prop('path')).toEqual('/'); expect(routes.at(index).prop('path')).toEqual(path);
expect(routes.at(second).prop('path')).toEqual('/server/:serverId'); });
}); });
}); });

View file

@ -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('<NotFound />', () => {
let wrapper;
const createWrapper = (props = {}) => {
wrapper = shallow(<NotFound {...props} />);
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');
});
});