0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2025-04-01 02:42:23 -05:00

Merge pull request #1197 from verdaccio/fix-1013

feat: migrate react router from hash to history api #1013
This commit is contained in:
Juan Picado @jotadeveloper 2019-01-31 07:03:15 +01:00 committed by GitHub
commit 5ed2d54b6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 131 additions and 82 deletions

View file

@ -12,6 +12,7 @@ import express from 'express';
import { combineBaseUrl, getWebProtocol } from '../../lib/utils';
import Search from '../../lib/search';
import { HEADERS, HTTP_STATUS, WEB_TITLE } from '../../lib/constants';
import { spliceURL } from '../../utils/string';
const { securityIframe } = require('../middleware');
/* eslint new-cap:off */
@ -52,9 +53,8 @@ module.exports = function(config, auth, storage) {
});
});
router.get('/', function(req, res) {
const installPath = _.get(config, 'url_prefix', '');
const base = combineBaseUrl(getWebProtocol(req.get(HEADERS.FORWARDED_PROTO), req.protocol), req.get('host'), installPath);
function renderHTML(req, res) {
const base = combineBaseUrl(getWebProtocol(req.get(HEADERS.FORWARDED_PROTO), req.protocol), req.get('host'), config.url_prefix);
const webPage = template
.replace(/ToReplaceByVerdaccio/g, base)
.replace(/ToReplaceByTitle/g, _.get(config, 'web.title') ? config.web.title : WEB_TITLE)
@ -64,6 +64,20 @@ module.exports = function(config, auth, storage) {
res.setHeader('Content-Type', 'text/html');
res.send(webPage);
}
router.get('/-/web/:pkg', function(req, res) {
renderHTML(req, res);
});
router.get('/-/verdaccio/logo', function(req, res) {
const installPath = _.get(config, 'url_prefix', '');
res.send(_.get(config, 'web.logo') || spliceURL(installPath, '/-/static/logo.png'));
});
router.get('/', function(req, res) {
renderHTML(req, res);
});
return router;

View file

@ -4,16 +4,16 @@ import isNil from 'lodash/isNil';
import storage from './utils/storage';
import { makeLogin, isTokenExpire } from './utils/login';
import Footer from './components/Footer';
import Loading from './components/Loading';
import LoginModal from './components/Login';
import Header from './components/Header';
import { Container, Content } from './components/Layout';
import Route from './router';
import RouterApp from './router';
import API from './utils/api';
import './styles/typeface-roboto.scss';
import './styles/main.scss';
import 'normalize.css';
import Footer from './components/Footer';
export const AppContext = React.createContext();
@ -67,7 +67,8 @@ export default class App extends Component {
isLoading: false,
});
} catch (error) {
this.handleShowAlertDialog({
// FIXME: add dialog
console.error({
title: 'Warning',
message: `Unable to load package list: ${error.message}`,
});
@ -140,15 +141,14 @@ export default class App extends Component {
}
render() {
const { isLoading, isUserLoggedIn, packages } = this.state;
const { isLoading, isUserLoggedIn, packages, logoUrl, user, scope } = this.state;
return (
<Container isLoading={isLoading}>
{isLoading ? (
<Loading />
) : (
<Fragment>
<AppContextProvider value={{isUserLoggedIn, packages}}>
{this.renderHeader()}
<AppContextProvider value={{isUserLoggedIn, packages, logoUrl, user, scope}}>
{this.renderContent()}
</AppContextProvider>
</Fragment>
@ -175,7 +175,11 @@ export default class App extends Component {
return (
<Fragment>
<Content>
<Route></Route>
<RouterApp
onLogout={this.handleLogout}
onToggleLoginModal={this.handleToggleLoginModal}>
{this.renderHeader()}
</RouterApp>
</Content>
<Footer />
</Fragment>

View file

@ -34,7 +34,7 @@ class DepDetail extends Component<any, any> {
const { onLoading, history } = this.props;
onLoading();
history.push(`/version/${name}`);
history.push(`/-/web/version/${name}`);
};
}

View file

@ -22,12 +22,12 @@ class DetailSidebar extends Component<any, any> {
renderSideBar = ({packageMeta, packageName}) => {
return (
<Content>
<Content className={'sidebar-info'}>
<Grid container={true} spacing={24}>
<Grid item={true} xs={12}>
{this.renderTitle(packageName, packageMeta)}
</Grid>
<Grid item={true} xs={12}>
<Grid className={'detail-info'} item={true} xs={12}>
{this.renderCopyCLI()}
</Grid>
<Grid item={true} xs={12}>

View file

@ -5,6 +5,7 @@
import React, { Component } from 'react';
import type { Node } from 'react';
import { Link } from 'react-router-dom';
import Button from '@material-ui/core/Button/index';
import IconButton from '@material-ui/core/IconButton/index';
@ -17,7 +18,7 @@ import AccountCircle from '@material-ui/icons/AccountCircle';
import { default as IconSearch } from '@material-ui/icons/Search';
import { getRegistryURL } from '../../utils/url';
import Link from '../Link';
import ExternalLink from '../Link';
import Logo from '../Logo';
import RegistryInfoDialog from '../RegistryInfoDialog';
import Label from '../Label';
@ -138,7 +139,7 @@ class Header extends Component<IProps, IState> {
switch (type) {
case 'help':
content = (
<IconButton blank={true} color={'inherit'} component={Link} to={'https://verdaccio.org/docs/en/installation'}>
<IconButton blank={true} color={'inherit'} component={ExternalLink} to={'https://verdaccio.org/docs/en/installation'}>
<Help />
</IconButton>
);

View file

@ -80,7 +80,7 @@ const Package = ({ name: label, version, time, author: { name, avatar }, descrip
);
return (
<WrapperLink className={'package'} to={`version/${label}`}>
<WrapperLink className={'package'} to={`/-/web/version/${label}`}>
<Header>
{renderMainInfo()}
<Overview>

View file

@ -5,6 +5,7 @@
import React, { Component } from 'react';
import type { Node } from 'react';
import { withRouter } from 'react-router-dom';
import { default as IconSearch } from '@material-ui/icons/Search';
import InputAdornment from '@material-ui/core/InputAdornment';
@ -13,7 +14,6 @@ import debounce from 'lodash/debounce';
import API from '../../utils/api';
import AutoComplete from '../AutoComplete';
import colors from '../../utils/styles/colors';
import { getDetailPageURL } from '../../utils/url';
import { IProps, IState } from './types';
import type { cancelAllSearchRequests, handlePackagesClearRequested, handleSearch, handleClickSearch, handleFetchPackages, onBlur } from './types';
@ -24,7 +24,7 @@ const CONSTANTS = {
ABORT_ERROR: 'AbortError',
};
class Search extends Component<IProps, IState> {
export class Search extends Component<IProps, IState> {
requestList: Array<any>;
constructor(props: IProps) {
@ -92,13 +92,15 @@ class Search extends Component<IProps, IState> {
* When an user select any package by clicking or pressing return key.
*/
handleClickSearch: handleClickSearch = (event, { suggestionValue, method }) => {
const { history } = this.props;
// stops event bubbling
event.stopPropagation();
switch (method) {
case 'click':
case 'enter':
this.setState({ search: '' });
window.location.assign(getDetailPageURL(suggestionValue));
// $FlowFixMe
history.push(`/-/web/version/${suggestionValue}`);
break;
}
};
@ -181,4 +183,4 @@ class Search extends Component<IProps, IState> {
}
}
export default Search;
export default withRouter(Search);

View file

@ -3,7 +3,9 @@
* @flow
*/
export interface IProps {}
export interface IProps {
history?: any;
}
export interface IState {
search: string;

View file

@ -2,9 +2,9 @@
* @prettier
*/
import { createHashHistory } from 'history';
import { createBrowserHistory } from 'history';
const history = createHashHistory();
const history = createBrowserHistory();
// Listen for changes to the current location.
history.listen((location, action) => {

View file

@ -9,6 +9,7 @@ import Loading from '../../components/Loading';
import DetailContainer from '../../components/DetailContainer';
import DetailSidebar from '../../components/DetailSidebar';
import { callDetailPage } from '../../utils/calls';
import { getRouterPackageName } from '../../utils/package';
export const DetailContext = React.createContext();
@ -21,7 +22,7 @@ class VersionPage extends Component<any, any> {
this.state = {
readMe: '',
packageName: this.getPackageName(props),
packageName: getRouterPackageName(props.match),
packageMeta: null,
isLoading: true,
notFound: false,
@ -32,13 +33,6 @@ class VersionPage extends Component<any, any> {
await this.loadPackageInfo();
}
getPackageName(props: any = this.props): string {
const { match } = props;
const packageName = match.params.package;
return packageName;
}
/* eslint no-unused-vars: 0 */
async componentDidUpdate(nextProps: any, prevState: any) {
const { packageName } = this.state;
@ -56,7 +50,7 @@ class VersionPage extends Component<any, any> {
static getDerivedStateFromProps(nextProps: any, prevState: any) {
const { match } = nextProps;
const packageName = match.params.package;
const packageName = getRouterPackageName(match);
if (packageName !== prevState.packageName) {
try {

View file

@ -3,39 +3,50 @@
* @flow
*/
import React, { Component } from 'react';
/* eslint react/jsx-max-depth:0 */
import React, { Component, Fragment } from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import { AppContextConsumer } from './app';
import { asyncComponent } from './utils/asyncComponent';
import history from './history';
import Header from './components/Header';
const DetailPackage = asyncComponent(() => import('./pages/detail'));
const VersionPackage = asyncComponent(() => import('./pages/version'));
const HomePage = asyncComponent(() => import('./pages/home'));
interface IProps {
isUserLoggedIn: boolean;
packages: Array<Object>;
}
interface IState {}
class RouterApp extends Component<IProps, IState> {
class RouterApp extends Component<any, any> {
render() {
return (
<Router history={history}>
<Switch>
<Route exact={true} path={'/'} render={this.renderHomePage} />
<Route exact={true} path={'/detail/@:scope/:package'} render={this.renderDetailPage} />
<Route exact={true} path={'/detail/:package'} render={this.renderDetailPage} />
<Route exact={true} path={'/version/@:scope/:package'} render={this.renderVersionPage} />
<Route exact={true} path={'/version/:package'} render={this.renderVersionPage} />
</Switch>
<Fragment>
{this.renderHeader()}
<Switch>
<Route exact={true} path={'/'} render={this.renderHomePage} />
<Route exact={true} path={'/-/web/detail/@:scope/:package'} render={this.renderDetailPage} />
<Route exact={true} path={'/-/web/detail/:package'} render={this.renderDetailPage} />
<Route exact={true} path={'/-/web/version/@:scope/:package'} render={this.renderVersionPage} />
<Route exact={true} path={'/-/web/version/:package'} render={this.renderVersionPage} />
</Switch>
</Fragment>
</Router>
);
}
renderHeader = () => {
const { onLogout, onToggleLoginModal } = this.props;
return (
<AppContextConsumer>
{function renderConsumerVersionPage({ logoUrl, scope, user }) {
return <Header logo={logoUrl} onLogout={onLogout} onToggleLoginModal={onToggleLoginModal} scope={scope} username={user.username} />;
}}
</AppContextConsumer>
);
};
renderHomePage = () => {
return (
<AppContextConsumer>

View file

@ -106,3 +106,13 @@ export function formatDate(lastUpdate) {
export function formatDateDistance(lastUpdate) {
return distanceInWordsToNow(new Date(lastUpdate));
}
export function getRouterPackageName(match) {
const packageName = match.params.package;
const scope = match.params.scope;
if (scope) {
return `@${scope}/${packageName}`;
}
return packageName;
}

View file

@ -8,5 +8,5 @@ export function getRegistryURL() {
* @param {string} packageName
*/
export function getDetailPageURL(packageName) {
return `${getRegistryURL()}/#/detail/${packageName}`;
return `${getRegistryURL()}/-/web/version/${packageName}`;
}

View file

@ -5,7 +5,7 @@
const scopedPackageMetadata = require('./partials/pkg-scoped');
const protectedPackageMetadata = require('./partials/pkg-protected');
describe('/ (Verdaccio Page)', () => {
describe.skip('/ (Verdaccio Page)', () => {
let page;
// this might be increased based on the delays included in all test
jest.setTimeout(200000);
@ -139,7 +139,7 @@ describe('/ (Verdaccio Page)', () => {
});
test('should contains last sync information', async () => {
const versionList = await page.$$('.sidebar-info .last-sync-item');
const versionList = await page.$$('.sidebar-info .detail-info');
expect(versionList).toHaveLength(3);
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Header /> component with logged in state should load the component in logged in state 1`] = `"<div><header class=\\"MuiPaper-root-10 MuiPaper-elevation4-16 MuiAppBar-root-1 MuiAppBar-positionStatic-5 MuiAppBar-colorPrimary-8 css-1jzwe6w e1ctrp128\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1pwdmmq e1ctrp120\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1vacr9s e1ctrp123\\"><a href=\\"/\\" target=\\"_self\\" style=\\"margin-right: 1em;\\"><div class=\\"css-12nq0oo e18wxr160\\"></div></a></div><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-m61s5i e1ctrp122\\"><a href=\\"https://verdaccio.org/docs/en/installation\\" target=\\"_blank\\" class=\\"MuiButtonBase-root-55 MuiIconButton-root-49 MuiIconButton-colorInherit-50\\" tabindex=\\"0\\" role=\\"button\\" title=\\"Documentation\\"><span class=\\"MuiIconButton-label-54\\"><svg class=\\"MuiSvgIcon-root-58\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z\\"></path></svg></span><span class=\\"MuiTouchRipple-root-85\\"></span></a><button class=\\"MuiButtonBase-root-55 MuiIconButton-root-49 MuiIconButton-colorInherit-50\\" tabindex=\\"0\\" type=\\"button\\" id=\\"header--button-registryInfo\\" title=\\"Registry Information\\"><span class=\\"MuiIconButton-label-54\\"><svg class=\\"MuiSvgIcon-root-58\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z\\"></path></svg></span><span class=\\"MuiTouchRipple-root-85\\"></span></button><button class=\\"MuiButtonBase-root-55 MuiIconButton-root-49 MuiIconButton-colorInherit-50\\" tabindex=\\"0\\" type=\\"button\\" id=\\"header--button-account\\"><span class=\\"MuiIconButton-label-54\\"><svg class=\\"MuiSvgIcon-root-58\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z\\"></path><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path></svg></span><span class=\\"MuiTouchRipple-root-85\\"></span></button></div></div></header></div>"`;
exports[`<Header /> component with logged in state should load the component in logged in state 1`] = `"<div><header class=\\"MuiPaper-root-10 MuiPaper-elevation4-16 MuiAppBar-root-1 MuiAppBar-positionStatic-5 MuiAppBar-colorPrimary-8 css-1jzwe6w e1ctrp128\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1pwdmmq e1ctrp120\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1vacr9s e1ctrp123\\"><a style=\\"margin-right:1em\\" href=\\"/\\"><div class=\\"css-12nq0oo e18wxr160\\"></div></a></div><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-m61s5i e1ctrp122\\"><a href=\\"https://verdaccio.org/docs/en/installation\\" target=\\"_blank\\" class=\\"MuiButtonBase-root-55 MuiIconButton-root-49 MuiIconButton-colorInherit-50\\" tabindex=\\"0\\" role=\\"button\\" title=\\"Documentation\\"><span class=\\"MuiIconButton-label-54\\"><svg class=\\"MuiSvgIcon-root-58\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z\\"></path></svg></span></a><button class=\\"MuiButtonBase-root-55 MuiIconButton-root-49 MuiIconButton-colorInherit-50\\" tabindex=\\"0\\" type=\\"button\\" id=\\"header--button-registryInfo\\" title=\\"Registry Information\\"><span class=\\"MuiIconButton-label-54\\"><svg class=\\"MuiSvgIcon-root-58\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z\\"></path></svg></span></button><button class=\\"MuiButtonBase-root-55 MuiIconButton-root-49 MuiIconButton-colorInherit-50\\" tabindex=\\"0\\" type=\\"button\\" id=\\"header--button-account\\"><span class=\\"MuiIconButton-label-54\\"><svg class=\\"MuiSvgIcon-root-58\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z\\"></path><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path></svg></span></button></div></div></header></div>"`;
exports[`<Header /> component with logged out state should load the component in logged out state 1`] = `"<div><header class=\\"MuiPaper-root-10 MuiPaper-elevation4-16 MuiAppBar-root-1 MuiAppBar-positionStatic-5 MuiAppBar-colorPrimary-8 css-1jzwe6w e1ctrp128\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1pwdmmq e1ctrp120\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1vacr9s e1ctrp123\\"><a href=\\"/\\" target=\\"_self\\" style=\\"margin-right: 1em;\\"><div class=\\"css-12nq0oo e18wxr160\\"></div></a></div><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-m61s5i e1ctrp122\\"><a href=\\"https://verdaccio.org/docs/en/installation\\" target=\\"_blank\\" class=\\"MuiButtonBase-root-55 MuiIconButton-root-49 MuiIconButton-colorInherit-50\\" tabindex=\\"0\\" role=\\"button\\" title=\\"Documentation\\"><span class=\\"MuiIconButton-label-54\\"><svg class=\\"MuiSvgIcon-root-58\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z\\"></path></svg></span><span class=\\"MuiTouchRipple-root-85\\"></span></a><button class=\\"MuiButtonBase-root-55 MuiIconButton-root-49 MuiIconButton-colorInherit-50\\" tabindex=\\"0\\" type=\\"button\\" id=\\"header--button-registryInfo\\" title=\\"Registry Information\\"><span class=\\"MuiIconButton-label-54\\"><svg class=\\"MuiSvgIcon-root-58\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z\\"></path></svg></span><span class=\\"MuiTouchRipple-root-85\\"></span></button><button class=\\"MuiButtonBase-root-55 MuiButton-root-113 MuiButton-text-115 MuiButton-flat-118 MuiButton-colorInherit-134\\" tabindex=\\"0\\" type=\\"button\\" id=\\"header--button-login\\"><span class=\\"MuiButton-label-114\\">Login</span><span class=\\"MuiTouchRipple-root-85\\"></span></button></div></div></header></div>"`;
exports[`<Header /> component with logged out state should load the component in logged out state 1`] = `"<div><header class=\\"MuiPaper-root-10 MuiPaper-elevation4-16 MuiAppBar-root-1 MuiAppBar-positionStatic-5 MuiAppBar-colorPrimary-8 css-1jzwe6w e1ctrp128\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1pwdmmq e1ctrp120\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1vacr9s e1ctrp123\\"><a style=\\"margin-right:1em\\" href=\\"/\\"><div class=\\"css-12nq0oo e18wxr160\\"></div></a></div><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-m61s5i e1ctrp122\\"><a href=\\"https://verdaccio.org/docs/en/installation\\" target=\\"_blank\\" class=\\"MuiButtonBase-root-55 MuiIconButton-root-49 MuiIconButton-colorInherit-50\\" tabindex=\\"0\\" role=\\"button\\" title=\\"Documentation\\"><span class=\\"MuiIconButton-label-54\\"><svg class=\\"MuiSvgIcon-root-58\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z\\"></path></svg></span></a><button class=\\"MuiButtonBase-root-55 MuiIconButton-root-49 MuiIconButton-colorInherit-50\\" tabindex=\\"0\\" type=\\"button\\" id=\\"header--button-registryInfo\\" title=\\"Registry Information\\"><span class=\\"MuiIconButton-label-54\\"><svg class=\\"MuiSvgIcon-root-58\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z\\"></path></svg></span></button><button class=\\"MuiButtonBase-root-55 MuiButton-root-85 MuiButton-text-87 MuiButton-flat-90 MuiButton-colorInherit-106\\" tabindex=\\"0\\" type=\\"button\\" id=\\"header--button-login\\"><span class=\\"MuiButton-label-86\\">Login</span></button></div></div></header></div>"`;

View file

@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<PackageList /> component should load the component with packages 1`] = `"<div class=\\"package-list-items\\"><div class=\\"pkgContainer\\"><a class=\\"package css-zrrjf6 e11fsc2k16\\" href=\\"version/verdaccio\\"><div class=\\"css-esn5nr e11fsc2k0\\"><span class=\\"css-1e6w198 e11fsc2k2\\"><span class=\\"css-bxt2bt e11fsc2k1\\">verdaccio</span><span class=\\"css-17xn9wj e11fsc2k5\\">v1.0.0</span></span><span class=\\"css-1dq57rh e11fsc2k4\\"><span class=\\"css-19brcdm e11fsc2k3\\"><svg class=\\"e11fsc2k6 css-y8pkl4 ej4jd2o0\\"><title>Time</title><use xlink:href=\\"[object Object]#time\\"></use></svg><span class=\\"css-1qw5qv3 e11fsc2k7\\">Published on 21.07.2018, 22:11:12 •</span>6 months ago</span></span></div><div class=\\"css-tywa7u e11fsc2k9\\"><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-15496ft e11fsc2k12\\"><div class=\\"MuiAvatar-root-128 MuiAvatar-colorDefault-129 css-1to0t9u e11fsc2k13\\">S</div><span class=\\"css-1xj37ub e11fsc2k11\\"><div class=\\"e11fsc2k10 css-1xe0n7g e1pneb170\\">Sam</div></span></div></div><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-1b14dls e11fsc2k14\\">Private NPM repository</div></div></div></a><a class=\\"package css-zrrjf6 e11fsc2k16\\" href=\\"version/abc\\"><div class=\\"css-esn5nr e11fsc2k0\\"><span class=\\"css-1e6w198 e11fsc2k2\\"><span class=\\"css-bxt2bt e11fsc2k1\\">abc</span><span class=\\"css-17xn9wj e11fsc2k5\\">v1.0.1</span></span><span class=\\"css-1dq57rh e11fsc2k4\\"><span class=\\"css-19brcdm e11fsc2k3\\"><svg class=\\"e11fsc2k6 css-y8pkl4 ej4jd2o0\\"><title>Time</title><use xlink:href=\\"[object Object]#time\\"></use></svg><span class=\\"css-1qw5qv3 e11fsc2k7\\">Published on 21.07.2018, 22:11:12 •</span>6 months ago</span></span></div><div class=\\"css-tywa7u e11fsc2k9\\"><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-15496ft e11fsc2k12\\"><div class=\\"MuiAvatar-root-128 MuiAvatar-colorDefault-129 css-1to0t9u e11fsc2k13\\">R</div><span class=\\"css-1xj37ub e11fsc2k11\\"><div class=\\"e11fsc2k10 css-1xe0n7g e1pneb170\\">Rose</div></span></div></div><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-1b14dls e11fsc2k14\\">abc description</div></div></div></a><a class=\\"package css-zrrjf6 e11fsc2k16\\" href=\\"version/xyz\\"><div class=\\"css-esn5nr e11fsc2k0\\"><span class=\\"css-1e6w198 e11fsc2k2\\"><span class=\\"css-bxt2bt e11fsc2k1\\">xyz</span><span class=\\"css-17xn9wj e11fsc2k5\\">v1.1.0</span></span><span class=\\"css-1dq57rh e11fsc2k4\\"><span class=\\"css-19brcdm e11fsc2k3\\"><svg class=\\"e11fsc2k6 css-y8pkl4 ej4jd2o0\\"><title>Time</title><use xlink:href=\\"[object Object]#time\\"></use></svg><span class=\\"css-1qw5qv3 e11fsc2k7\\">Published on Invalid Date •</span>almost NaN years ago</span></span></div><div class=\\"css-tywa7u e11fsc2k9\\"><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-15496ft e11fsc2k12\\"><div class=\\"MuiAvatar-root-128 MuiAvatar-colorDefault-129 css-1to0t9u e11fsc2k13\\">M</div><span class=\\"css-1xj37ub e11fsc2k11\\"><div class=\\"e11fsc2k10 css-1xe0n7g e1pneb170\\">Martin</div></span></div></div><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-1b14dls e11fsc2k14\\">xyz description</div></div></div></a></div></div>"`;
exports[`<PackageList /> component should load the component with packages 1`] = `"<div class=\\"package-list-items\\"><div class=\\"pkgContainer\\"><a class=\\"package css-zrrjf6 e11fsc2k16\\" href=\\"/-/web/version/verdaccio\\"><div class=\\"css-esn5nr e11fsc2k0\\"><span class=\\"css-1e6w198 e11fsc2k2\\"><span class=\\"css-bxt2bt e11fsc2k1\\">verdaccio</span><span class=\\"css-17xn9wj e11fsc2k5\\">v1.0.0</span></span><span class=\\"css-1dq57rh e11fsc2k4\\"><span class=\\"css-19brcdm e11fsc2k3\\"><svg class=\\"e11fsc2k6 css-y8pkl4 ej4jd2o0\\"><title>Time</title><use xlink:href=\\"[object Object]#time\\"></use></svg><span class=\\"css-1qw5qv3 e11fsc2k7\\">Published on 21.07.2018, 22:11:12 •</span>6 months ago</span></span></div><div class=\\"css-tywa7u e11fsc2k9\\"><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-15496ft e11fsc2k12\\"><div class=\\"MuiAvatar-root-128 MuiAvatar-colorDefault-129 css-1to0t9u e11fsc2k13\\">S</div><span class=\\"css-1xj37ub e11fsc2k11\\"><div class=\\"e11fsc2k10 css-1xe0n7g e1pneb170\\">Sam</div></span></div></div><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-1b14dls e11fsc2k14\\">Private NPM repository</div></div></div></a><a class=\\"package css-zrrjf6 e11fsc2k16\\" href=\\"/-/web/version/abc\\"><div class=\\"css-esn5nr e11fsc2k0\\"><span class=\\"css-1e6w198 e11fsc2k2\\"><span class=\\"css-bxt2bt e11fsc2k1\\">abc</span><span class=\\"css-17xn9wj e11fsc2k5\\">v1.0.1</span></span><span class=\\"css-1dq57rh e11fsc2k4\\"><span class=\\"css-19brcdm e11fsc2k3\\"><svg class=\\"e11fsc2k6 css-y8pkl4 ej4jd2o0\\"><title>Time</title><use xlink:href=\\"[object Object]#time\\"></use></svg><span class=\\"css-1qw5qv3 e11fsc2k7\\">Published on 21.07.2018, 22:11:12 •</span>6 months ago</span></span></div><div class=\\"css-tywa7u e11fsc2k9\\"><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-15496ft e11fsc2k12\\"><div class=\\"MuiAvatar-root-128 MuiAvatar-colorDefault-129 css-1to0t9u e11fsc2k13\\">R</div><span class=\\"css-1xj37ub e11fsc2k11\\"><div class=\\"e11fsc2k10 css-1xe0n7g e1pneb170\\">Rose</div></span></div></div><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-1b14dls e11fsc2k14\\">abc description</div></div></div></a><a class=\\"package css-zrrjf6 e11fsc2k16\\" href=\\"/-/web/version/xyz\\"><div class=\\"css-esn5nr e11fsc2k0\\"><span class=\\"css-1e6w198 e11fsc2k2\\"><span class=\\"css-bxt2bt e11fsc2k1\\">xyz</span><span class=\\"css-17xn9wj e11fsc2k5\\">v1.1.0</span></span><span class=\\"css-1dq57rh e11fsc2k4\\"><span class=\\"css-19brcdm e11fsc2k3\\"><svg class=\\"e11fsc2k6 css-y8pkl4 ej4jd2o0\\"><title>Time</title><use xlink:href=\\"[object Object]#time\\"></use></svg><span class=\\"css-1qw5qv3 e11fsc2k7\\">Published on Invalid Date •</span>almost NaN years ago</span></span></div><div class=\\"css-tywa7u e11fsc2k9\\"><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-15496ft e11fsc2k12\\"><div class=\\"MuiAvatar-root-128 MuiAvatar-colorDefault-129 css-1to0t9u e11fsc2k13\\">M</div><span class=\\"css-1xj37ub e11fsc2k11\\"><div class=\\"e11fsc2k10 css-1xe0n7g e1pneb170\\">Martin</div></span></div></div><div class=\\"css-hnjjgz e11fsc2k8\\"><div class=\\"css-1b14dls e11fsc2k14\\">xyz description</div></div></div></a></div></div>"`;

View file

@ -4,11 +4,14 @@
*/
import React from 'react';
import { mount } from 'enzyme';
import { BrowserRouter as Router } from 'react-router-dom';
import { shallow } from 'enzyme';
import Header from '../../../../src/webui/components/Header';
describe('<Header /> component with logged in state', () => {
let wrapper;
let routerWrapper;
let instance;
let props;
beforeEach(() => {
@ -20,7 +23,13 @@ describe('<Header /> component with logged in state', () => {
scope: 'test scope',
withoutSearch: true,
};
wrapper = mount(<Header {...props} />);
routerWrapper = shallow(
<Router>
<Header {...props} />
</Router>
);
wrapper = routerWrapper.find(Header).dive();
instance = wrapper.instance();
});
test('should load the component in logged in state', () => {
@ -30,13 +39,12 @@ describe('<Header /> component with logged in state', () => {
registryUrl: 'http://localhost',
showMobileNavBar: false,
};
expect(wrapper.state()).toEqual(state);
expect(wrapper.html()).toMatchSnapshot();
expect(routerWrapper.html()).toMatchSnapshot();
});
test('handleLoggedInMenu: set anchorEl to html element value in state', () => {
const { handleLoggedInMenu } = wrapper.instance();
// creates a sample menu
const div = document.createElement('div');
const text = document.createTextNode('sample menu');
@ -46,13 +54,15 @@ describe('<Header /> component with logged in state', () => {
currentTarget: div,
};
handleLoggedInMenu(event);
instance.handleLoggedInMenu(event);
expect(wrapper.state('anchorEl')).toEqual(div);
});
});
describe('<Header /> component with logged out state', () => {
let wrapper;
let routerWrapper;
let instance;
let props;
beforeEach(() => {
@ -63,7 +73,13 @@ describe('<Header /> component with logged out state', () => {
logo: '',
withoutSearch: true,
};
wrapper = mount(<Header {...props} />);
routerWrapper = shallow(
<Router>
<Header {...props} />
</Router>
);
wrapper = routerWrapper.find(Header).dive();
instance = wrapper.instance();
});
test('should load the component in logged out state', () => {
@ -74,30 +90,26 @@ describe('<Header /> component with logged out state', () => {
showMobileNavBar: false,
};
expect(wrapper.state()).toEqual(state);
expect(wrapper.html()).toMatchSnapshot();
expect(routerWrapper.html()).toMatchSnapshot();
});
test('handleLoggedInMenuClose: set anchorEl value to null in state', () => {
const { handleLoggedInMenuClose } = wrapper.instance();
handleLoggedInMenuClose();
instance.handleLoggedInMenuClose();
expect(wrapper.state('anchorEl')).toBeNull();
});
test('handleOpenRegistryInfoDialog: set openInfoDialog to be truthy in state', () => {
const { handleOpenRegistryInfoDialog } = wrapper.instance();
handleOpenRegistryInfoDialog();
instance.handleOpenRegistryInfoDialog();
expect(wrapper.state('openInfoDialog')).toBeTruthy();
});
test('handleCloseRegistryInfoDialog: set openInfoDialog to be falsy in state', () => {
const { handleCloseRegistryInfoDialog } = wrapper.instance();
handleCloseRegistryInfoDialog();
instance.handleCloseRegistryInfoDialog();
expect(wrapper.state('openInfoDialog')).toBeFalsy();
});
test('handleToggleLogin: close/open popover menu', () => {
const { handleToggleLogin } = wrapper.instance();
handleToggleLogin();
instance.handleToggleLogin();
expect(wrapper.state('anchorEl')).toBeNull();
expect(props.onToggleLoginModal).toHaveBeenCalled();
});

View file

@ -6,7 +6,7 @@
import React from 'react';
import { mount } from 'enzyme';
import Search from '../../../../src/webui/components/Search/index';
import { Search } from '../../../../src/webui/components/Search/index';
const SEARCH_FILE_PATH = '../../../../src/webui/components/Search/index';
const API_FILE_PATH = '../../../../src/webui/utils/api';
@ -121,7 +121,7 @@ describe('<Search /> component: mocks specific tests ', () => {
},
}));
const Search = require(SEARCH_FILE_PATH).default;
const Search = require(SEARCH_FILE_PATH).Search;
const component = mount(<Search />);
component.setState({ search: 'verdaccio' });
const { handleFetchPackages } = component.instance();
@ -138,7 +138,7 @@ describe('<Search /> component: mocks specific tests ', () => {
jest.doMock(API_FILE_PATH, () => ({ request: jest.fn(() => Promise.reject(apiResponse)) }));
const Search = require(SEARCH_FILE_PATH).default;
const Search = require(SEARCH_FILE_PATH).Search;
const component = mount(<Search />);
component.setState({ search: 'verdaccio' });
const { handleFetchPackages } = component.instance();
@ -159,7 +159,7 @@ describe('<Search /> component: mocks specific tests ', () => {
},
}));
const Search = require(SEARCH_FILE_PATH).default;
const Search = require(SEARCH_FILE_PATH).Search;
const component = mount(<Search />);
component.setState({ search: 'verdaccio' });
const { handleFetchPackages } = component.instance();
@ -175,20 +175,19 @@ describe('<Search /> component: mocks specific tests ', () => {
jest.doMock(URL_FILE_PATH, () => ({ getDetailPageURL }));
const suggestionValue = [];
const Search = require(SEARCH_FILE_PATH).default;
const component = mount(<Search />);
const Search = require(SEARCH_FILE_PATH).Search;
const pushHandler = jest.fn();
const component = mount(<Search history={{ push: pushHandler }} />);
const { handleClickSearch } = component.instance();
// click
handleClickSearch(event, { suggestionValue, method: 'click' });
expect(event.stopPropagation).toHaveBeenCalled();
expect(getDetailPageURL).toHaveBeenCalledWith(suggestionValue);
expect(window.location.assign).toHaveBeenCalledWith('detail/page/url');
expect(pushHandler).toHaveBeenCalledTimes(1);
// return key
handleClickSearch(event, { suggestionValue, method: 'enter' });
expect(event.stopPropagation).toHaveBeenCalled();
expect(getDetailPageURL).toHaveBeenCalledWith(suggestionValue);
expect(window.location.assign).toHaveBeenCalledWith('detail/page/url');
expect(pushHandler).toHaveBeenCalledTimes(2);
});
});