1
0
mirror of https://github.com/SomboChea/ui synced 2026-01-12 06:05:43 +07:00

Merge branch '4.x-master' into test/bdd-acceptance-testing-setup

This commit is contained in:
Juan Picado @jotadeveloper
2019-08-04 11:10:56 +02:00
committed by GitHub
409 changed files with 7735 additions and 60600 deletions

View File

@@ -1,29 +0,0 @@
{
"extends": [
"eslint:recommended"
],
"env": {
"node": true,
"mocha": true,
"es6": true
},
"globals": {
"jsdom": true
},
"rules": {
"valid-jsdoc": 0,
"no-redeclare": 1,
"jest/consistent-test-it": ["error", {"fn": "test"}],
"jest/no-jasmine-globals": 2,
"no-console": [
2,
{
"allow": [
"log",
"error"
]
}
],
"no-useless-escape": 0
}
}

View File

@@ -1,54 +0,0 @@
// @flow
export interface IVerdaccioConfig {
storagePath: string;
configPath: string;
domainPath: string;
port: number;
}
export interface IRequestPromise {
status(reason: any): any;
body_ok(reason: any): any;
body_error(reason: any): any;
request(reason: any): any;
response(reason: any): any;
send(reason: any): any;
}
export interface IServerProcess {
bridge: IServerBridge;
config: IVerdaccioConfig;
childFork: any;
isDebug: boolean;
silence: boolean;
init(): Promise<any>;
stop(): void;
}
declare class verdaccio$PromiseAssert<IRequestPromise> extends Promise<any> {
constructor(options: any): IRequestPromise;
}
export interface IServerBridge {
url: string;
userAgent: string;
authstr: string;
request(options: any): typeof verdaccio$PromiseAssert;
auth(name: string, password: string): IRequestPromise;
logout(token: string): Promise<any>;
auth(name: string, password: string): IRequestPromise;
getPackage(name: string): Promise<any>;
putPackage(name: string, data: any): Promise<any>;
putVersion(name: string, version: string, data: any): Promise<any>;
getTarball(name: string, filename: string): Promise<any>;
putTarball(name: string, filename: string, data: any): Promise<any>;
removeTarball(name: string): Promise<any>;
removeSingleTarball(name: string, filename: string): Promise<any>;
addTag(name: string, tag: string, version: string): Promise<any>;
putTarballIncomplete(name: string, filename: string, data: any, size: number, cb: Function): Promise<any>;
addPackage(name: string): Promise<any>;
whoami(): Promise<any>;
ping(): Promise<any>;
debug(): IRequestPromise;
}

5
test/unit/.eslintrc Normal file
View File

@@ -0,0 +1,5 @@
{
"rules": {
"no-console": 0
}
}

View File

@@ -1,94 +0,0 @@
import React from 'react';
import { mount } from 'enzyme';
import storage from '../../src/webui/utils/storage';
import App from '../../src/webui/app';
import { generateTokenWithTimeRange } from './components/__mocks__/token';
jest.mock('../../src/webui/utils/storage', () => {
class LocalStorageMock {
constructor() {
this.store = {};
}
clear() {
this.store = {};
}
getItem(key) {
return this.store[key] || null;
}
setItem(key, value) {
this.store[key] = value.toString();
}
removeItem(key) {
delete this.store[key];
}
}
return new LocalStorageMock();
});
jest.mock('../../src/webui/utils/api', () => ({
request: require('./components/__mocks__/api').default.request
}));
describe('App', () => {
let wrapper;
beforeEach(() => {
wrapper = mount(<App />);
});
test('toggleLoginModal: should toggle the value in state', () => {
const { handleToggleLoginModal } = wrapper.instance();
expect(wrapper.state().showLoginModal).toBeFalsy();
handleToggleLoginModal();
expect(wrapper.state('showLoginModal')).toBeTruthy();
expect(wrapper.state('error')).toEqual({});
});
test('isUserAlreadyLoggedIn: token already available in storage', async () => {
storage.setItem('username', 'verdaccio');
storage.setItem('token', generateTokenWithTimeRange(24));
const { isUserAlreadyLoggedIn } = wrapper.instance();
isUserAlreadyLoggedIn();
expect(wrapper.state('user').username).toEqual('verdaccio');
});
test('handleLogout - logouts the user and clear localstorage', async () => {
const { handleLogout } = wrapper.instance();
storage.setItem('username', 'verdaccio');
storage.setItem('token', 'xxxx.TOKEN.xxxx');
await handleLogout();
expect(wrapper.state('user')).toEqual({});
expect(wrapper.state('isUserLoggedIn')).toBeFalsy();
});
test('handleDoLogin - login the user successfully', async () => {
const { handleDoLogin } = wrapper.instance();
await handleDoLogin('sam', '1234');
const result = {
username: 'sam',
token: 'TEST_TOKEN'
};
expect(wrapper.state('isUserLoggedIn')).toBeTruthy();
expect(wrapper.state('showLoginModal')).toBeFalsy();
expect(storage.getItem('username')).toEqual('sam');
expect(storage.getItem('token')).toEqual('TEST_TOKEN');
expect(wrapper.state('user')).toEqual(result);
});
test('handleDoLogin - authentication failure', async () => {
const { handleDoLogin } = wrapper.instance();
await handleDoLogin('sam', '12345');
const result = {
description: 'bad username/password, access denied',
title: 'Unable to login',
type: 'error'
};
expect(wrapper.state('user')).toEqual({});
expect(wrapper.state('error')).toEqual(result);
});
});

View File

@@ -1,48 +0,0 @@
/**
* API Mocks for WebUI
*/
import logo from '../store/logo';
import login from '../store/login';
import { packageMeta } from '../store/packageMeta';
import { packageInformation } from '../store/package';
/**
* Register mock api endpoints
* @param {string} endpoint
* @returns {Promise}
*/
const register = (url, method = 'get', options = {}) => {
if (url === 'login' && method.toLocaleLowerCase() === 'post') {
return login(options);
}
if (url === 'logo' && method.toLocaleLowerCase() === 'get') {
return logo();
}
if (url === 'sidebar/verdaccio' && method.toLocaleLowerCase() === 'get') {
return new Promise(function(resolve) {
resolve(packageMeta);
});
}
if (url === 'packages' && method.toLocaleLowerCase() === 'get') {
return new Promise(function (resolve) {
resolve(packageInformation);
});
}
throw Error(`URL not found: ${url}`);
};
/**
* Bind API methods
*/
class API {
request() {
return register.call(null, ...arguments);
}
}
export default new API;

View File

@@ -1,26 +0,0 @@
/**
* Token Utility
*/
import { Base64 } from 'js-base64';
import addHours from 'date-fns/add_hours';
export function generateTokenWithTimeRange (limit = 0) {
const payload = {
username: 'verdaccio',
exp: Number.parseInt(addHours(new Date(), limit).getTime() / 1000, 10)
};
return `xxxxxx.${Base64.encode(JSON.stringify(payload))}.xxxxxx`;
}
export function generateTokenWithExpirationAsString () {
const payload = { username: 'verdaccio', exp: 'I am not a number' };
return `xxxxxx.${Base64.encode(payload)}.xxxxxx`;
}
export function generateTokenWithOutExpiration (){
const payload = {
username: 'verdaccio'
};
return `xxxxxx.${Base64.encode(JSON.stringify(payload))}.xxxxxx`;
}

View File

@@ -1,3 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<CopyToClipBoard /> component render the component 1`] = `"<div class=\\"css-1mta3t8 e1mfrkg70\\"><span class=\\"css-1m8aenu e1mfrkg71\\">copy text</span><button class=\\"MuiButtonBase-root-15 MuiIconButton-root-9 css-56v3u0 e1mfrkg72\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label-14\\"><svg class=\\"MuiSvgIcon-root-18\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span></button></div>"`;

View File

@@ -1,3 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Footer /> component should load the initial state of Footer component 1`] = `"<div class=\\"css-i0nj2g e19gp4r80\\"><div class=\\"css-hzfs9b e19gp4r81\\"><div class=\\"css-d8nsp7 e19gp4r82\\"> Made with<span class=\\"css-1so4oe0 e19gp4r87\\">♥</span>on<span class=\\"css-1ie354y e19gp4r84\\"><svg class=\\"e19gp4r85 css-1kgp95j e9byyw50\\"><title>Earth</title><use xlink:href=\\"[object Object]#earth\\"></use></svg><span class=\\"css-1v4n0q4 e19gp4r86\\"><svg class=\\"e19gp4r88 css-f1ndto e9byyw50\\"><title>Spain</title><use xlink:href=\\"[object Object]#spain\\"></use></svg><svg class=\\"e19gp4r88 css-f1ndto e9byyw50\\"><title>Nicaragua</title><use xlink:href=\\"[object Object]#nicaragua\\"></use></svg><svg class=\\"e19gp4r88 css-f1ndto e9byyw50\\"><title>India</title><use xlink:href=\\"[object Object]#india\\"></use></svg><svg class=\\"e19gp4r88 css-f1ndto e9byyw50\\"><title>Brazil</title><use xlink:href=\\"[object Object]#brazil\\"></use></svg><svg class=\\"e19gp4r88 css-f1ndto e9byyw50\\"><title>China</title><use xlink:href=\\"[object Object]#china\\"></use></svg><svg class=\\"e19gp4r88 css-f1ndto e9byyw50\\"><title>Austria</title><use xlink:href=\\"[object Object]#austria\\"></use></svg></span></span></div><div class=\\"css-1wbzdyy e19gp4r83\\">Powered by<span class=\\"e19gp4r88 css-i15wza e9byyw51\\" title=\\"Verdaccio\\"><img alt=\\"Verdaccio\\" src=\\"[object Object]\\" class=\\"css-1ncdhax e9byyw52\\"></span>/ v.1.0.0</div></div></div>"`;

View File

@@ -1,5 +0,0 @@
// 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-k4mg52 e1yrof0d8\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1pwdmmq e1yrof0d0\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1vacr9s e1yrof0d3\\"><a style=\\"margin-right:1em\\" href=\\"/\\"><div class=\\"css-12nq0oo e1nk49ti0\\"></div></a></div><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-m61s5i e1yrof0d2\\"><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-k4mg52 e1yrof0d8\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1pwdmmq e1yrof0d0\\"><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-1vacr9s e1yrof0d3\\"><a style=\\"margin-right:1em\\" href=\\"/\\"><div class=\\"css-12nq0oo e1nk49ti0\\"></div></a></div><div class=\\"MuiToolbar-root-37 MuiToolbar-regular-39 MuiToolbar-gutters-38 css-m61s5i e1yrof0d2\\"><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 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Help /> component should render the component in default state 1`] = `"<div class=\\"MuiPaper-root-2 MuiPaper-elevation1-5 MuiPaper-rounded-3 MuiCard-root-1 css-ryznli e1ail7510\\" id=\\"help-card\\"><div class=\\"MuiCardContent-root-29\\"><h2 class=\\"MuiTypography-root-30 MuiTypography-headline-35 MuiTypography-gutterBottom-57\\" id=\\"help-card__title\\">No Package Published Yet.</h2><p class=\\"MuiTypography-root-30 MuiTypography-body1-39 MuiTypography-colorTextSecondary-63 MuiTypography-gutterBottom-57 css-zg2fwz e1ail7511\\">To publish your first package just:</p><p class=\\"MuiTypography-root-30 MuiTypography-body2-38\\">1. Login</p><div class=\\"css-1mta3t8 e1mfrkg70\\"><span class=\\"css-1m8aenu e1mfrkg71\\">npm adduser --registry http://localhost</span><button class=\\"MuiButtonBase-root-80 MuiIconButton-root-74 css-56v3u0 e1mfrkg72\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label-79\\"><svg class=\\"MuiSvgIcon-root-83\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span></button></div><p class=\\"MuiTypography-root-30 MuiTypography-body2-38\\">2. Publish</p><div class=\\"css-1mta3t8 e1mfrkg70\\"><span class=\\"css-1m8aenu e1mfrkg71\\">npm publish --registry http://localhost</span><button class=\\"MuiButtonBase-root-80 MuiIconButton-root-74 css-56v3u0 e1mfrkg72\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label-79\\"><svg class=\\"MuiSvgIcon-root-83\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span></button></div><p class=\\"MuiTypography-root-30 MuiTypography-body2-38\\">3. Refresh this page.</p></div><div class=\\"MuiCardActions-root-92\\"><a class=\\"MuiButtonBase-root-80 MuiButton-root-95 MuiButton-text-97 MuiButton-textPrimary-98 MuiButton-flat-100 MuiButton-flatPrimary-101 MuiButton-sizeSmall-118 MuiCardActions-action-94\\" tabindex=\\"0\\" role=\\"button\\" href=\\"https://verdaccio.org/docs/en/installation\\" target=\\"_blank\\"><span class=\\"MuiButton-label-96\\">Learn More</span></a></div></div>"`;

View File

@@ -1,5 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<LoginModal /> should load the component in default state 1`] = `"<div role=\\"dialog\\" class=\\"mui-fixed MuiModal-root-15 MuiDialog-root-1\\" id=\\"login--form-container\\" style=\\"padding-right: 0px;\\"><div class=\\"MuiBackdrop-root-17\\" aria-hidden=\\"true\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\"></div><div class=\\"MuiDialog-container-4 MuiDialog-scrollPaper-2\\" role=\\"document\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\" tabindex=\\"-1\\"><div class=\\"MuiPaper-root-19 MuiPaper-elevation24-45 MuiPaper-rounded-20 MuiDialog-paper-5 MuiDialog-paperScrollPaper-6 MuiDialog-paperWidthXs-8 MuiDialog-paperFullWidth-13\\"><form novalidate=\\"\\"><div class=\\"MuiDialogTitle-root-46\\"><h2 class=\\"MuiTypography-root-47 MuiTypography-title-53\\">Login</h2></div><div class=\\"MuiDialogContent-root-83\\"><div class=\\"MuiFormControl-root-84 MuiFormControl-fullWidth-87\\"><label class=\\"MuiFormLabel-root-99 MuiFormLabel-required-104 MuiInputLabel-required-92 MuiInputLabel-root-88 MuiInputLabel-formControl-93 MuiInputLabel-animated-96\\" data-shrink=\\"false\\" for=\\"username\\">Username<span class=\\"MuiFormLabel-asterisk-105\\">*</span></label><div class=\\"MuiInputBase-root-119 MuiInput-root-106 MuiInput-underline-110 MuiInputBase-formControl-120 MuiInput-formControl-107\\"><input aria-invalid=\\"false\\" class=\\"MuiInputBase-input-129 MuiInput-input-114\\" id=\\"login--form-username\\" placeholder=\\"Your username\\" required=\\"\\" type=\\"text\\" value=\\"\\"></div></div><div class=\\"MuiFormControl-root-84 MuiFormControl-fullWidth-87\\" style=\\"margin-top: 8px;\\"><label class=\\"MuiFormLabel-root-99 MuiFormLabel-required-104 MuiInputLabel-required-92 MuiInputLabel-root-88 MuiInputLabel-formControl-93 MuiInputLabel-animated-96\\" data-shrink=\\"false\\" for=\\"password\\">Password<span class=\\"MuiFormLabel-asterisk-105\\">*</span></label><div class=\\"MuiInputBase-root-119 MuiInput-root-106 MuiInput-underline-110 MuiInputBase-formControl-120 MuiInput-formControl-107\\"><input aria-invalid=\\"false\\" class=\\"MuiInputBase-input-129 MuiInput-input-114 MuiInputBase-inputType-132 MuiInput-inputType-117\\" id=\\"login--form-password\\" placeholder=\\"Your strong password\\" required=\\"\\" type=\\"password\\" value=\\"\\"></div></div></div><div class=\\"MuiDialogActions-root-136 dialog-footer\\"><button class=\\"MuiButtonBase-root-164 MuiButton-root-138 MuiButton-text-140 MuiButton-flat-143 MuiButton-colorInherit-159 MuiDialogActions-action-137\\" tabindex=\\"0\\" type=\\"button\\" id=\\"login--form-cancel\\"><span class=\\"MuiButton-label-139\\">Cancel</span><span class=\\"MuiTouchRipple-root-167\\"></span></button><button class=\\"MuiButtonBase-root-164 MuiButtonBase-disabled-165 MuiButton-root-138 MuiButton-text-140 MuiButton-flat-143 MuiButton-disabled-158 MuiButton-colorInherit-159 MuiDialogActions-action-137\\" tabindex=\\"-1\\" type=\\"submit\\" disabled=\\"\\" id=\\"login--form-submit\\"><span class=\\"MuiButton-label-139\\">Login</span></button></div></form></div></div></div>"`;
exports[`<LoginModal /> should load the component with props 1`] = `"<div role=\\"dialog\\" class=\\"mui-fixed MuiModal-root-15 MuiDialog-root-1\\" id=\\"login--form-container\\"><div class=\\"MuiBackdrop-root-17\\" aria-hidden=\\"true\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\"></div><div class=\\"MuiDialog-container-4 MuiDialog-scrollPaper-2\\" role=\\"document\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\" tabindex=\\"-1\\"><div class=\\"MuiPaper-root-19 MuiPaper-elevation24-45 MuiPaper-rounded-20 MuiDialog-paper-5 MuiDialog-paperScrollPaper-6 MuiDialog-paperWidthXs-8 MuiDialog-paperFullWidth-13\\"><form novalidate=\\"\\"><div class=\\"MuiDialogTitle-root-46\\"><h2 class=\\"MuiTypography-root-47 MuiTypography-title-53\\">Login</h2></div><div class=\\"MuiDialogContent-root-83\\"><div class=\\"MuiTypography-root-47 MuiTypography-body1-56 MuiPaper-root-19 MuiPaper-elevation6-27 MuiSnackbarContent-root-174 loginError\\" role=\\"alertdialog\\"><div class=\\"MuiSnackbarContent-message-175\\"><div class=\\"loginErrorMsg\\" id=\\"client-snackbar\\"><svg class=\\"MuiSvgIcon-root-177 loginIcon\\" 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-2h2v2zm0-4h-2V7h2v6z\\"></path></svg><span><div><strong>Error Title</strong></div><div>Error Description</div></span></div></div></div><div class=\\"MuiFormControl-root-84 MuiFormControl-fullWidth-87\\"><label class=\\"MuiFormLabel-root-99 MuiFormLabel-required-104 MuiInputLabel-required-92 MuiInputLabel-root-88 MuiInputLabel-formControl-93 MuiInputLabel-animated-96\\" data-shrink=\\"false\\" for=\\"username\\">Username<span class=\\"MuiFormLabel-asterisk-105\\">*</span></label><div class=\\"MuiInputBase-root-119 MuiInput-root-106 MuiInput-underline-110 MuiInputBase-formControl-120 MuiInput-formControl-107\\"><input aria-invalid=\\"false\\" class=\\"MuiInputBase-input-129 MuiInput-input-114\\" id=\\"login--form-username\\" placeholder=\\"Your username\\" required=\\"\\" type=\\"text\\" value=\\"\\"></div></div><div class=\\"MuiFormControl-root-84 MuiFormControl-fullWidth-87\\" style=\\"margin-top: 8px;\\"><label class=\\"MuiFormLabel-root-99 MuiFormLabel-required-104 MuiInputLabel-required-92 MuiInputLabel-root-88 MuiInputLabel-formControl-93 MuiInputLabel-animated-96\\" data-shrink=\\"false\\" for=\\"password\\">Password<span class=\\"MuiFormLabel-asterisk-105\\">*</span></label><div class=\\"MuiInputBase-root-119 MuiInput-root-106 MuiInput-underline-110 MuiInputBase-formControl-120 MuiInput-formControl-107\\"><input aria-invalid=\\"false\\" class=\\"MuiInputBase-input-129 MuiInput-input-114 MuiInputBase-inputType-132 MuiInput-inputType-117\\" id=\\"login--form-password\\" placeholder=\\"Your strong password\\" required=\\"\\" type=\\"password\\" value=\\"\\"></div></div></div><div class=\\"MuiDialogActions-root-136 dialog-footer\\"><button class=\\"MuiButtonBase-root-164 MuiButton-root-138 MuiButton-text-140 MuiButton-flat-143 MuiButton-colorInherit-159 MuiDialogActions-action-137\\" tabindex=\\"0\\" type=\\"button\\" id=\\"login--form-cancel\\"><span class=\\"MuiButton-label-139\\">Cancel</span><span class=\\"MuiTouchRipple-root-167\\"></span></button><button class=\\"MuiButtonBase-root-164 MuiButtonBase-disabled-165 MuiButton-root-138 MuiButton-text-140 MuiButton-flat-143 MuiButton-disabled-158 MuiButton-colorInherit-159 MuiDialogActions-action-137\\" tabindex=\\"-1\\" type=\\"submit\\" disabled=\\"\\" id=\\"login--form-submit\\"><span class=\\"MuiButton-label-139\\">Login</span></button></div></form></div></div></div>"`;

View File

@@ -1,5 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<NoItem /> component should load the component in default state 1`] = `"<h6 class=\\"MuiTypography-root-1 MuiTypography-subtitle1-19 MuiTypography-gutterBottom-28\\"></h6>"`;
exports[`<NoItem /> component should set html from props 1`] = `"<h6 class=\\"MuiTypography-root-1 MuiTypography-subtitle1-19 MuiTypography-gutterBottom-28\\">This is a test string</h6>"`;

View File

@@ -1,3 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<NotFound /> component should load the component in default state 1`] = `<withRouter(WithTheme(WithWidth(NotFound))) />`;

View File

@@ -1,3 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Package /> component should load the component without author 1`] = `"<a class=\\"package css-scoisj e11fsc2k15\\" href=\\"detail/verdaccio\\"><div class=\\"css-esn5nr e11fsc2k0\\"><span class=\\"css-ilb586 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-1vtxmi9 e11fsc2k3\\"><svg class=\\"e11fsc2k6 css-19sh63r ej4jd2o0\\"><title>License</title><use xlink:href=\\"[object Object]#license\\"></use></svg>MIT</span><span class=\\"css-1vtxmi9 e11fsc2k3\\"><svg class=\\"e11fsc2k6 css-1iep4l8 ej4jd2o0\\"><title>Time</title><use xlink:href=\\"[object Object]#time\\"></use></svg><span class=\\"css-c3js4s e11fsc2k7\\">Published on 09.12.2018, 17:49:30 •</span>about 6 hours ago</span></span></div><div class=\\"css-tywa7u e11fsc2k9\\"><div class=\\"css-r6baau e11fsc2k8\\"><div class=\\"e11fsc2k10 css-1w35jfk e1pneb170\\">Author</div><div class=\\"css-15496ft e11fsc2k12\\"><div class=\\"MuiAvatar-root-1 MuiAvatar-colorDefault-2 css-1to0t9u e11fsc2k13\\">A</div><span class=\\"css-1xj37ub e11fsc2k11\\"><div class=\\"e11fsc2k10 css-1xe0n7g e1pneb170\\">Anonymous</div></span></div></div><div class=\\"css-r6baau e11fsc2k8\\"><div class=\\"e11fsc2k10 css-1w35jfk e1pneb170\\">Description</div><span>Private NPM repository</span></div></div></a>"`;

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Readme /> component should dangerously set html 1`] = `"<div class=\\"markdown-body\\"><h1>This is a test string</h1></div>"`;
exports[`<Readme /> component should load the component in default state 1`] = `"<div class=\\"markdown-body\\">test</div>"`;

View File

@@ -1,3 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Search /> component test should load the component in default state 1`] = `"<div class=\\"css-1crzyyo e18292mt0\\"><div role=\\"combobox\\" aria-haspopup=\\"listbox\\" aria-owns=\\"react-autowhatever-1\\" aria-expanded=\\"false\\" class=\\"react-autosuggest__container\\"><div class=\\"MuiFormControl-root-1 MuiFormControl-fullWidth-4 react-autosuggest__input\\" aria-autocomplete=\\"list\\" aria-controls=\\"react-autowhatever-1\\"><div class=\\"MuiInputBase-root-18 MuiInput-root-5 css-n9ojyg MuiInput-underline-9 MuiInputBase-fullWidth-27 MuiInput-fullWidth-12 MuiInputBase-formControl-19 MuiInput-formControl-6 MuiInputBase-adornedStart-22\\"><div class=\\"MuiInputAdornment-root-35 MuiInputAdornment-positionStart-37\\" style=\\"color: rgb(255, 255, 255);\\"><svg class=\\"MuiSvgIcon-root-40\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z\\"></path><path fill=\\"none\\" d=\\"M0 0h24v24H0z\\"></path></svg></div><input aria-invalid=\\"false\\" autocomplete=\\"off\\" class=\\"MuiInputBase-input-28 MuiInput-input-13 css-hodoyq MuiInputBase-inputAdornedStart-33\\" placeholder=\\"Search Packages\\" type=\\"text\\" value=\\"\\"></div></div><div class=\\"MuiPaper-root-49 MuiPaper-elevation2-53 react-autosuggest__suggestions-container\\" id=\\"react-autowhatever-1\\" role=\\"listbox\\"></div></div></div>"`;

View File

@@ -1,45 +0,0 @@
/**
* @prettier
* @flow
*/
import React from 'react';
import { shallow } from 'enzyme';
import CopyToClipBoard from '../../../src/webui/components/CopyToClipBoard/index';
import { CopyIcon } from '../../../src/webui/components/CopyToClipBoard/styles';
describe('<CopyToClipBoard /> component', () => {
let wrapper;
let props;
beforeEach(() => {
props = {
text: 'copy text',
};
wrapper = shallow(<CopyToClipBoard {...props} />);
});
test('render the component', () => {
expect(wrapper.html()).toMatchSnapshot();
});
test('should call the DOM APIs for copy to clipboard utility', () => {
const event = {
preventDefault: jest.fn(),
};
global.getSelection = jest.fn(() => ({
removeAllRanges: () => {},
addRange: () => {},
}));
const { document, getSelection } = global;
wrapper.find(CopyIcon).simulate('click', event);
expect(event.preventDefault).toHaveBeenCalled();
expect(document.createRange).toHaveBeenCalled();
expect(getSelection).toHaveBeenCalled();
expect(document.execCommand).toHaveBeenCalledWith('copy');
});
});

View File

@@ -1,22 +0,0 @@
import React from 'react';
import { mount } from 'enzyme';
import Footer from '../../../src/webui/components/Footer/index';
jest.mock('../../../package.json', () => ({
version: '4.0.0-alpha.3'
}));
describe('<Footer /> component', () => {
let wrapper;
beforeEach(() => {
window.VERDACCIO_VERSION = 'v.1.0.0';
wrapper = mount(<Footer />);
delete window.VERDACCIO_VERSION;
});
test('should load the initial state of Footer component', () => {
expect(wrapper.html()).toMatchSnapshot();
});
});

View File

@@ -1,116 +0,0 @@
/**
* @prettier
* @flow
*/
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { shallow } from 'enzyme';
import Header from '../../../src/webui/components/Header/index';
describe('<Header /> component with logged in state', () => {
let wrapper;
let routerWrapper;
let instance;
let props;
beforeEach(() => {
props = {
username: 'test user',
handleLogout: jest.fn(),
logo: '',
onToggleLoginModal: jest.fn(),
scope: 'test scope',
withoutSearch: true,
};
routerWrapper = shallow(
<Router>
<Header {...props} />
</Router>
);
wrapper = routerWrapper.find(Header).dive();
instance = wrapper.instance();
});
test('should load the component in logged in state', () => {
const state = {
openInfoDialog: false,
packages: undefined,
registryUrl: 'http://localhost',
showMobileNavBar: false,
};
expect(wrapper.state()).toEqual(state);
expect(routerWrapper.html()).toMatchSnapshot();
});
test('handleLoggedInMenu: set anchorEl to html element value in state', () => {
// creates a sample menu
const div = document.createElement('div');
const text = document.createTextNode('sample menu');
div.appendChild(text);
const event = {
currentTarget: div,
};
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(() => {
props = {
handleLogout: jest.fn(),
onToggleLoginModal: jest.fn(),
scope: 'test scope',
logo: '',
withoutSearch: true,
};
routerWrapper = shallow(
<Router>
<Header {...props} />
</Router>
);
wrapper = routerWrapper.find(Header).dive();
instance = wrapper.instance();
});
test('should load the component in logged out state', () => {
const state = {
openInfoDialog: false,
packages: undefined,
registryUrl: 'http://localhost',
showMobileNavBar: false,
};
expect(wrapper.state()).toEqual(state);
expect(routerWrapper.html()).toMatchSnapshot();
});
test('handleLoggedInMenuClose: set anchorEl value to null in state', () => {
instance.handleLoggedInMenuClose();
expect(wrapper.state('anchorEl')).toBeNull();
});
test('handleOpenRegistryInfoDialog: set openInfoDialog to be truthy in state', () => {
instance.handleOpenRegistryInfoDialog();
expect(wrapper.state('openInfoDialog')).toBeTruthy();
});
test('handleCloseRegistryInfoDialog: set openInfoDialog to be falsy in state', () => {
instance.handleCloseRegistryInfoDialog();
expect(wrapper.state('openInfoDialog')).toBeFalsy();
});
test('handleToggleLogin: close/open popover menu', () => {
instance.handleToggleLogin();
expect(wrapper.state('anchorEl')).toBeNull();
expect(props.onToggleLoginModal).toHaveBeenCalled();
});
});

View File

@@ -1,14 +0,0 @@
/**
* Help component
*/
import React from 'react';
import { shallow } from 'enzyme';
import Help from '../../../src/webui/components/Help/index';
describe('<Help /> component', () => {
test('should render the component in default state', () => {
const wrapper = shallow(<Help />);
expect(wrapper.html()).toMatchSnapshot();
});
});

View File

@@ -1,129 +0,0 @@
/**
* @prettier
* @flow
*/
import React from 'react';
import { mount } from 'enzyme';
import LoginModal from '../../../src/webui/components/Login/index';
const eventUsername = {
target: {
value: 'xyz',
},
};
const eventPassword = {
target: {
value: '1234',
},
};
const event = {
preventDefault: jest.fn(),
};
describe('<LoginModal />', () => {
test('should load the component in default state', () => {
const wrapper = mount(<LoginModal />);
expect(wrapper.html()).toMatchSnapshot();
});
test('should load the component with props', () => {
const props = {
visibility: true,
error: {
type: 'error',
title: 'Error Title',
description: 'Error Description',
},
onCancel: () => {},
onSubmit: () => {},
};
const wrapper = mount(<LoginModal {...props} />);
expect(wrapper.html()).toMatchSnapshot();
});
test('onCancel: should close the login modal', () => {
const props = {
visibility: true,
error: {
type: 'error',
title: 'Error Title',
description: 'Error Description',
},
onCancel: jest.fn(),
onSubmit: () => {},
};
const wrapper = mount(<LoginModal {...props} />);
wrapper.find('button[id="login--form-cancel"]').simulate('click');
expect(props.onCancel).toHaveBeenCalled();
});
test('setCredentials - should set username and password in state', () => {
const props = {
visibility: true,
error: {},
onCancel: () => {},
onSubmit: () => {},
};
const wrapper = mount(<LoginModal {...props} />);
const { setCredentials } = wrapper.instance();
expect(setCredentials('username', eventUsername)).toBeUndefined();
expect(wrapper.state('form').username.value).toEqual('xyz');
expect(setCredentials('password', eventPassword)).toBeUndefined();
expect(wrapper.state('form').password.value).toEqual('1234');
});
test('validateCredentials: should validate credentials', async () => {
const props = {
visibility: true,
error: {},
onCancel: () => {},
onSubmit: jest.fn(),
};
const wrapper = mount(<LoginModal {...props} />);
const instance = wrapper.instance();
instance.submitCredentials = jest.fn();
const { validateCredentials, setCredentials, submitCredentials } = instance;
expect(setCredentials('username', eventUsername)).toBeUndefined();
expect(wrapper.state('form').username.value).toEqual('xyz');
expect(setCredentials('password', eventPassword)).toBeUndefined();
expect(wrapper.state('form').password.value).toEqual('1234');
validateCredentials(event);
expect(event.preventDefault).toHaveBeenCalled();
expect(wrapper.state('form').username.pristine).toEqual(false);
expect(wrapper.state('form').password.pristine).toEqual(false);
expect(submitCredentials).toHaveBeenCalledTimes(1);
});
test('submitCredentials: should submit credentials', async () => {
const props = {
onSubmit: jest.fn(),
};
const wrapper = mount(<LoginModal {...props} />);
const { setCredentials, submitCredentials } = wrapper.instance();
expect(setCredentials('username', eventUsername)).toBeUndefined();
expect(wrapper.state('form').username.value).toEqual('xyz');
expect(setCredentials('password', eventPassword)).toBeUndefined();
expect(wrapper.state('form').password.value).toEqual('1234');
await submitCredentials();
expect(props.onSubmit).toHaveBeenCalledWith('xyz', '1234');
expect(wrapper.state('form').username.value).toEqual('');
expect(wrapper.state('form').username.pristine).toEqual(true);
expect(wrapper.state('form').password.value).toEqual('');
expect(wrapper.state('form').password.pristine).toEqual(true);
});
});

View File

@@ -1,24 +0,0 @@
/**
* NoItems component
*/
import React from 'react';
import { shallow, mount } from 'enzyme';
import NoItems from '../../../src/webui/components/NoItems/index';
console.error = jest.fn();
describe('<NoItem /> component', () => {
test('should load the component in default state', () => {
const wrapper = shallow(<NoItems />);
expect(wrapper.html()).toMatchSnapshot();
});
test('should set html from props', () => {
const props = {
text: 'This is a test string'
};
const wrapper = mount(<NoItems {...props} />);
expect(wrapper.html()).toMatchSnapshot();
});
});

View File

@@ -1,27 +0,0 @@
/**
* NotFound component
*/
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { shallow } from 'enzyme';
import NotFound from '../../../src/webui/components/NotFound/index';
console.error = jest.fn();
describe('<NotFound /> component', () => {
let routerWrapper;
beforeEach(() => {
routerWrapper = shallow(
<Router>
<NotFound />
</Router>
);
});
test('should load the component in default state', () => {
expect(routerWrapper.find(NotFound)).toMatchSnapshot();
});
});

View File

@@ -1,86 +0,0 @@
/**
* Package component
*/
import React from 'react';
import { shallow } from 'enzyme';
import Package from '../../../src/webui/components/Package/index';
import Tag from '../../../src/webui/components/Tag/index';
import { Version, WrapperLink, Field, OverviewItem } from '../../../src/webui/components/Package/styles';
/**
* Generates one month back date from current time
* @return {object} date object
*/
const dateOneMonthAgo = () => new Date(1544377770747)
describe('<Package /> component', () => {
test.skip('should load the component', () => {
const props = {
name: 'verdaccio',
version: '1.0.0',
time: dateOneMonthAgo(),
license: 'MIT',
description: 'Private NPM repository',
author: {
name: 'Sam'
},
keywords: [
"verdaccio"
]
};
const wrapper = shallow(
<Package {...props} />
);
// integration expectations
// check link
expect(wrapper.find(WrapperLink).prop('to')).toEqual(`detail/${props.name}`);
// check version
expect(wrapper.find(Version).prop('children')).toEqual(`v${props.version}`);
// TODO - REWRITE THE TEST
//expect(wrapper.find(Author).dive())
// check description
expect(wrapper.find(Field).someWhere(n => {
return (
n.children().first().get(0).props.children[0].props.text === 'Description' &&
n.children().childAt(1).containsMatchingElement(<span>{props.description}</span>)
)
})).toBe(true);
// check license
expect(wrapper.find(OverviewItem).someWhere(n => n.get(0).props.children[1] === props.license)).toBe(true);
// check keyword
expect(wrapper.find(Tag).prop('children')).toEqual(props.keywords[0]);
});
test.skip('should load the component without author', () => {
const props = {
name: 'verdaccio',
version: '1.0.0',
time: dateOneMonthAgo(),
license: 'MIT',
author: {
name: 'Anonymous',
email: '',
avatar: ''
},
description: 'Private NPM repository'
};
const wrapper = shallow(
<Package {...props} />
);
// integration expectations
expect(wrapper.html()).toMatchSnapshot();
});
});

View File

@@ -1,63 +0,0 @@
/**
* PackageList component
*/
import React from 'react';
import { mount } from 'enzyme';
import PackageList from '../../../src/webui/components/PackageList/index';
import Help from '../../../src/webui/components/Help/index';
import { BrowserRouter } from 'react-router-dom';
describe('<PackageList /> component', () => {
test('should load the component with no packages', () => {
const props = {
packages: [],
help: true
};
const wrapper = mount(
<PackageList help={props.help} packages={props.packages} />
);
expect(wrapper.find(Help).exists()).toBeTruthy();
});
test('should load the component with packages', () => {
const props = {
packages: [
{
name: 'verdaccio',
version: '1.0.0',
time: new Date(1532211072138).getTime(),
description: 'Private NPM repository',
author: { name: 'Sam', avatar: 'test avatar' }
},
{
name: 'abc',
version: '1.0.1',
time: new Date(1532211072138).getTime(),
description: 'abc description',
author: { name: 'Rose', avatar: 'test avatar' }
},
{
name: 'xyz',
version: '1.1.0',
description: 'xyz description',
author: { name: 'Martin', avatar: 'test avatar' }
}
],
help: false
};
const wrapper = mount(
<BrowserRouter>
<PackageList help={props.help} packages={props.packages} />
</BrowserRouter>
);
// package count
expect(wrapper.find('Package')).toHaveLength(3);
// match snapshot
expect(wrapper.html()).toMatchSnapshot();
});
});

View File

@@ -1,22 +0,0 @@
/**
* Readme component
*/
import React from 'react';
import { shallow, mount } from 'enzyme';
import Readme from '../../../src/webui/components/Readme/index';
describe('<Readme /> component', () => {
test('should load the component in default state', () => {
const wrapper = mount(<Readme description={"test"} />);
expect(wrapper.html()).toMatchSnapshot();
});
test('should dangerously set html', () => {
const wrapper = shallow(<Readme description={"<h1>This is a test string</h1>"} />);
expect(wrapper.html()).toEqual(
'<div class="markdown-body"><h1>This is a test string</h1></div>'
);
expect(wrapper.html()).toMatchSnapshot();
});
});

View File

@@ -1,193 +0,0 @@
/**
* @flow
* @prettier
*/
import React from 'react';
import { mount } from 'enzyme';
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';
const URL_FILE_PATH = '../../../src/webui/utils/url';
// Global mocks
const event = {
stopPropagation: jest.fn(),
};
window.location.assign = jest.fn();
describe('<Search /> component test', () => {
let wrapper;
beforeEach(() => {
wrapper = mount(<Search />);
});
test('should load the component in default state', () => {
expect(wrapper.html()).toMatchSnapshot();
});
test('onBlur: should cancel all search requests', async () => {
const { onBlur, requestList } = wrapper.instance();
const spy = jest.spyOn(wrapper.instance(), 'cancelAllSearchRequests');
const request = {
abort: jest.fn(),
};
// adds a request for AbortController
wrapper.instance().requestList = [request];
onBlur(event);
expect(request.abort).toHaveBeenCalled();
expect(event.stopPropagation).toHaveBeenCalled();
expect(wrapper.state('error')).toBeFalsy();
expect(wrapper.state('loaded')).toBeFalsy();
expect(wrapper.state('loading')).toBeFalsy();
expect(spy).toHaveBeenCalled();
expect(requestList).toEqual([]);
});
test('handleSearch: when user type package name in search component and set loading to true', () => {
const { handleSearch } = wrapper.instance();
const newValue = 'verdaccio';
handleSearch(event, { newValue, method: 'type' });
expect(event.stopPropagation).toHaveBeenCalled();
expect(wrapper.state('error')).toBeFalsy();
expect(wrapper.state('loaded')).toBeFalsy();
expect(wrapper.state('loading')).toBeTruthy();
expect(wrapper.state('search')).toEqual(newValue);
});
test('handleSearch: cancel all search requests when there is no value in search component with type method', () => {
const { handleSearch, requestList } = wrapper.instance();
const spy = jest.spyOn(wrapper.instance(), 'cancelAllSearchRequests');
const newValue = '';
handleSearch(event, { newValue, method: 'type' });
expect(event.stopPropagation).toHaveBeenCalled();
expect(wrapper.state('error')).toBeFalsy();
expect(wrapper.state('loaded')).toBeFalsy();
expect(wrapper.state('loading')).toBeTruthy();
expect(wrapper.state('search')).toEqual(newValue);
expect(spy).toHaveBeenCalled();
expect(requestList).toEqual([]);
});
test('handleSearch: when method is not type method', () => {
const { handleSearch } = wrapper.instance();
const newValue = '';
handleSearch(event, { newValue, method: 'click' });
expect(event.stopPropagation).toHaveBeenCalled();
expect(wrapper.state('error')).toBeFalsy();
expect(wrapper.state('loaded')).toBeFalsy();
expect(wrapper.state('loading')).toBeFalsy();
expect(wrapper.state('search')).toEqual(newValue);
});
test('handlePackagesClearRequested: should clear suggestions', () => {
const { handlePackagesClearRequested } = wrapper.instance();
handlePackagesClearRequested();
expect(wrapper.state('suggestions')).toEqual([]);
});
});
describe('<Search /> component: mocks specific tests ', () => {
beforeEach(() => {
jest.resetModules();
jest.doMock('lodash/debounce', () => {
return function debounceMock(fn, delay) {
return fn;
};
});
});
test('handleFetchPackages: should load the packages from API', async () => {
const apiResponse = [{ name: 'verdaccio' }, { name: 'verdaccio-htpasswd' }];
const suggestions = [{ name: 'verdaccio' }, { name: 'verdaccio-htpasswd' }];
jest.doMock(API_FILE_PATH, () => ({
request(url) {
expect(url).toEqual('search/verdaccio');
return Promise.resolve(apiResponse);
},
}));
const Search = require(SEARCH_FILE_PATH).Search;
const component = mount(<Search />);
component.setState({ search: 'verdaccio' });
const { handleFetchPackages } = component.instance();
await handleFetchPackages({ value: 'verdaccio' });
expect(component.state('suggestions')).toEqual(suggestions);
expect(component.state('error')).toBeFalsy();
expect(component.state('loaded')).toBeTruthy();
expect(component.state('loading')).toBeFalsy();
});
test('handleFetchPackages: when browser cancel a request', async () => {
const apiResponse = { name: 'AbortError' };
jest.doMock(API_FILE_PATH, () => ({ request: jest.fn(() => Promise.reject(apiResponse)) }));
const Search = require(SEARCH_FILE_PATH).Search;
const component = mount(<Search />);
component.setState({ search: 'verdaccio' });
const { handleFetchPackages } = component.instance();
await handleFetchPackages({ value: 'verdaccio' });
expect(component.state('error')).toBeFalsy();
expect(component.state('loaded')).toBeFalsy();
expect(component.state('loading')).toBeFalsy();
});
test('handleFetchPackages: when API server failed request', async () => {
const apiResponse = { name: 'BAD_REQUEST' };
jest.doMock(API_FILE_PATH, () => ({
request(url) {
expect(url).toEqual('search/verdaccio');
return Promise.reject(apiResponse);
},
}));
const Search = require(SEARCH_FILE_PATH).Search;
const component = mount(<Search />);
component.setState({ search: 'verdaccio' });
const { handleFetchPackages } = component.instance();
await handleFetchPackages({ value: 'verdaccio' });
expect(component.state('error')).toBeTruthy();
expect(component.state('loaded')).toBeFalsy();
expect(component.state('loading')).toBeFalsy();
});
test('handleClickSearch: should change the window location on click or return key', () => {
const getDetailPageURL = jest.fn(() => 'detail/page/url');
jest.doMock(URL_FILE_PATH, () => ({ getDetailPageURL }));
const suggestionValue = [];
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(pushHandler).toHaveBeenCalledTimes(1);
// return key
handleClickSearch(event, { suggestionValue, method: 'enter' });
expect(event.stopPropagation).toHaveBeenCalled();
expect(pushHandler).toHaveBeenCalledTimes(2);
});
});

View File

@@ -1,21 +0,0 @@
import {API_ERROR} from '../../../../src/lib/constants';
/**
* API mock for login endpoint
* @param {object} config configuration of api call
* @returns {promise}
*/
export default function(config) {
return new Promise((resolve, reject) => {
const body = JSON.parse(config.body);
if (body.username === 'sam' && body.password === '1234') {
resolve({
username: 'sam',
token: 'TEST_TOKEN'
});
} else {
reject({
error: API_ERROR.BAD_USERNAME_PASSWORD
});
}
});
}

View File

@@ -1,7 +0,0 @@
/**
* Mock response for logo api
* @returns {promise}
*/
export default function() {
return Promise.resolve('http://localhost/-/static/logo.png');
}

View File

@@ -1,174 +0,0 @@
export const packageInformation = [
{
name: 'jquery',
title: 'jQuery',
description: 'JavaScript library for DOM operations',
version: '3.3.2-pre',
main: 'dist/jquery.js',
homepage: 'https://jquery.com',
author: {
name: 'JS Foundation and other contributors',
url: 'https://github.com/jquery/jquery/blob/master/AUTHORS.txt',
avatar: '',
},
repository: {
type: 'git',
url: 'https://github.com/jquery/jquery.git'
},
keywords: ['jquery', 'javascript', 'browser', 'library'],
bugs: {
url: 'https://github.com/jquery/jquery/issues'
},
license: 'MIT',
dependencies: {},
devDependencies: {
'babel-core': '7.0.0-beta.0',
'babel-plugin-transform-es2015-for-of': '7.0.0-beta.0',
commitplease: '3.2.0',
'core-js': '2.5.7',
'eslint-config-jquery': '1.0.1',
grunt: '1.0.3',
'grunt-babel': '7.0.0',
'grunt-cli': '1.2.0',
'grunt-compare-size': '0.4.2',
'grunt-contrib-uglify': '3.3.0',
'grunt-contrib-watch': '1.1.0',
'grunt-eslint': '20.2.0',
'grunt-git-authors': '3.2.0',
'grunt-jsonlint': '1.1.0',
'grunt-karma': '2.0.0',
'grunt-newer': '1.3.0',
'grunt-npmcopy': '0.1.0',
'gzip-js': '0.3.2',
husky: '0.14.3',
insight: '0.10.1',
jsdom: '5.6.1',
karma: '2.0.3',
'karma-browserstack-launcher': '1.3.0',
'karma-chrome-launcher': '2.2.0',
'karma-firefox-launcher': '1.1.0',
'karma-qunit': '1.2.1',
'load-grunt-tasks': '4.0.0',
'native-promise-only': '0.8.1',
'promises-aplus-tests': '2.1.2',
q: '1.5.1',
'qunit-assert-step': '1.1.1',
qunitjs: '1.23.1',
'raw-body': '2.3.3',
requirejs: '2.3.5',
sinon: '2.3.7',
sizzle: '2.3.3',
'strip-json-comments': '2.0.1',
testswarm: '1.1.0',
'uglify-js': '3.4.0'
},
scripts: {
build: 'npm install && grunt',
start: 'grunt watch',
'test:browserless': 'grunt && grunt test:slow',
'test:browser': 'grunt && grunt karma:main',
test: 'grunt && grunt test:slow && grunt karma:main',
jenkins: 'npm run test:browserless',
precommit: 'grunt lint:newer qunit_fixture',
commitmsg: 'node node_modules/commitplease'
},
commitplease: {
nohook: true,
components: [
'Docs',
'Tests',
'Build',
'Support',
'Release',
'Core',
'Ajax',
'Attributes',
'Callbacks',
'CSS',
'Data',
'Deferred',
'Deprecated',
'Dimensions',
'Effects',
'Event',
'Manipulation',
'Offset',
'Queue',
'Selector',
'Serialize',
'Traversing',
'Wrap'
],
markerPattern: '^((clos|fix|resolv)(e[sd]|ing))|^(refs?)',
ticketPattern: '^((Closes|Fixes) ([a-zA-Z]{2,}-)[0-9]+)|^(Refs? [^#])'
}
},
{
name: 'lodash',
version: '4.17.4',
license: 'MIT',
private: true,
main: 'lodash.js',
author: {
name: 'John david dalton',
url: 'test url',
avatar: 'test avatar',
},
engines: {
node: '>=4.0.0'
},
sideEffects: false,
scripts: {
build: 'npm run build:main && npm run build:fp',
'build:fp': 'node lib/fp/build-dist.js',
'build:fp-modules': 'node lib/fp/build-modules.js',
'build:main': 'node lib/main/build-dist.js',
'build:main-modules': 'node lib/main/build-modules.js',
doc: 'node lib/main/build-doc github && npm run test:doc',
'doc:fp': 'node lib/fp/build-doc',
'doc:site': 'node lib/main/build-doc site',
'doc:sitehtml':
'optional-dev-dependency marky-markdown@^9.0.1 && npm run doc:site && node lib/main/build-site',
pretest: 'npm run build',
style: 'eslint *.js .internal/**/*.js',
test: 'npm run test:main && npm run test:fp',
'test:doc': 'markdown-doctest doc/*.md',
'test:fp': 'node test/test-fp',
'test:main': 'node test/test',
validate: 'npm run style && npm run test'
},
devDependencies: {
async: '^2.1.4',
benchmark: '^2.1.3',
chalk: '^1.1.3',
cheerio: '^0.22.0',
'codecov.io': '~0.1.6',
coveralls: '^2.11.15',
'curl-amd': '~0.8.12',
docdown: '~0.7.2',
dojo: '^1.12.1',
ecstatic: '^2.1.0',
eslint: '^3.15.0',
'eslint-plugin-import': '^2.2.0',
'fs-extra': '~1.0.0',
glob: '^7.1.1',
istanbul: '0.4.5',
jquery: '^3.1.1',
lodash: '4.17.3',
'lodash-doc-globals': '^0.1.1',
'markdown-doctest': '^0.9.1',
'optional-dev-dependency': '^2.0.0',
platform: '^1.3.3',
'qunit-extras': '^3.0.0',
qunitjs: '^2.1.0',
request: '^2.79.0',
requirejs: '^2.3.2',
'sauce-tunnel': '^2.5.0',
'uglify-js': '2.7.5',
webpack: '^1.14.0'
},
greenkeeper: {
ignore: ['lodash']
}
}
];

View File

@@ -1,668 +0,0 @@
export const packageMeta = {
name: 'verdaccio',
'dist-tags': { latest: '2.7.1', beta: '2.4.1-beta' },
time: {
modified: '2017-12-14T15:43:27.317Z',
created: '2016-07-28T12:48:43.536Z',
'1.4.0': '2016-07-28T12:48:43.536Z',
'2.0.0': '2016-08-26T22:36:41.762Z',
'2.0.1': '2016-08-29T13:26:21.754Z',
'2.1.0': '2016-10-12T00:48:03.025Z',
'2.1.1': '2017-02-07T06:43:22.801Z',
'2.2.0-v20170212': '2017-02-12T14:48:27.322Z',
'2.1.2': '2017-03-09T06:25:28.107Z',
'2.1.3': '2017-03-29T20:03:36.850Z',
'2.1.4': '2017-04-13T20:08:41.131Z',
'2.1.5': '2017-04-22T09:07:39.821Z',
'2.1.6': '2017-05-12T07:43:36.616Z',
'2.1.7': '2017-05-14T13:50:14.016Z',
'2.1.10': '2017-06-03T09:53:52.449Z',
'2.2.0': '2017-06-08T19:02:53.618Z',
'2.2.1': '2017-06-17T16:23:14.158Z',
'2.2.2': '2017-07-02T13:13:13.304Z',
'2.2.3': '2017-07-04T20:43:59.442Z',
'2.2.4': '2017-07-05T17:28:07.187Z',
'2.2.5': '2017-07-05T17:34:11.089Z',
'2.2.6': '2017-07-13T05:04:54.418Z',
'2.2.7': '2017-07-15T23:27:24.523Z',
'2.3.0-beta': '2017-07-15T23:31:31.664Z',
'2.2.7-r': '2017-07-18T19:44:48.946Z',
'2.3.0-beta-1': '2017-07-22T16:27:45.025Z',
'2.3.0-beta-2': '2017-07-22T17:12:09.905Z',
'2.3.0-beta-3': '2017-07-22T17:35:05.771Z',
'2.3.0-beta-4': '2017-07-22T18:22:42.563Z',
'2.3.0': '2017-07-22T23:08:37.513Z',
'2.3.1-pre': '2017-07-24T05:50:40.852Z',
'2.3.1': '2017-07-25T05:24:27.651Z',
'2.3.2': '2017-07-28T23:05:36.431Z',
'2.3.3': '2017-07-29T10:05:30.120Z',
'2.3.4': '2017-07-29T10:18:44.061Z',
'2.3.5': '2017-08-14T06:22:57.686Z',
'2.3.6': '2017-08-17T04:30:44.872Z',
'2.4.0': '2017-09-23T08:01:22.780Z',
'2.4.1-beta': '2017-10-01T08:57:14.509Z',
'2.5.0': '2017-10-01T12:31:06.333Z',
'2.5.1': '2017-10-01T13:32:06.584Z',
'2.6.0': '2017-10-18T20:22:32.836Z',
'2.6.1': '2017-10-19T17:26:24.083Z',
'2.6.2': '2017-10-21T08:37:16.527Z',
'2.6.3': '2017-10-21T16:04:05.556Z',
'2.6.4': '2017-10-31T17:47:03.647Z',
'2.6.5': '2017-11-05T09:09:31.332Z',
'2.6.6': '2017-11-08T22:47:16.504Z',
'2.7.0': '2017-12-05T23:25:06.372Z',
'2.7.1': '2017-12-14T15:43:27.317Z'
},
_uplinks: {
abc: { etag: 'ddfdxjn8m8n6gn70-8m', fetched: 1532297472000},
npmjs: { etag: '"5a272ad2-4f6b1"', fetched: 1513266232741 },
xyz: { etag: '564748hydydygs-s7ehj', fetched: 1532124672000}
},
_rev: '16-ba1b806df0298246',
_attachments: {},
latest: {
name: 'verdaccio',
version: '2.7.1',
description: 'Private npm repository server',
author: {
name: 'User NPM',
email: 'test@author.local',
avatar: 'https://www.gravatar.com/avatar/a5a236ba477ee98908600c40cda74f4a'
},
repository: {
type: 'git',
url: 'git://github.com/verdaccio/verdaccio.git'
},
main: 'index.js',
bin: { verdaccio: './bin/verdaccio' },
dependencies: {
'@verdaccio/file-locking': '0.0.3',
'@verdaccio/streams': '0.0.2',
JSONStream: '^1.1.1',
'apache-md5': '^1.1.2',
async: '^2.0.1',
'body-parser': '^1.15.0',
bunyan: '^1.8.0',
chalk: '^2.0.1',
commander: '^2.11.0',
compression: '1.6.2',
cookies: '^0.7.0',
cors: '^2.8.3',
express: '4.15.3',
global: '^4.3.2',
handlebars: '4.0.5',
'http-errors': '^1.4.0',
'js-string-escape': '1.0.1',
'js-yaml': '^3.6.0',
jsonwebtoken: '^7.4.1',
lockfile: '^1.0.1',
lodash: '4.17.4',
lunr: '^0.7.0',
marked: '0.3.6',
mime: '^1.3.6',
minimatch: '^3.0.2',
mkdirp: '^0.5.1',
pkginfo: '^0.4.0',
request: '^2.72.0',
semver: '^5.1.0',
'unix-crypt-td-js': '^1.0.0'
},
devDependencies: {
axios: '0.16.2',
'babel-cli': '6.24.1',
'babel-core': '6.25.0',
'babel-eslint': '7.2.3',
'babel-loader': '7.1.1',
'babel-plugin-flow-runtime': '0.11.1',
'babel-plugin-transform-decorators-legacy': '1.3.4',
'babel-plugin-transform-runtime': '6.23.0',
'babel-polyfill': '^6.26.0',
'babel-preset-env': '1.5.2',
'babel-preset-flow': '6.23.0',
'babel-preset-react': '6.24.1',
'babel-preset-stage-2': '6.24.1',
'babel-preset-stage-3': '6.24.1',
'babel-runtime': '6.23.0',
'codacy-coverage': '2.0.2',
codecov: '2.2.0',
coveralls: '2.13.1',
'css-loader': '0.28.4',
'element-react': '1.0.16',
'element-theme-default': '1.3.7',
eslint: '4.2.0',
'eslint-config-google': '0.8.0',
'eslint-loader': '1.8.0',
'eslint-plugin-babel': '4.1.1',
'eslint-plugin-flowtype': '2.35.0',
'eslint-plugin-import': '2.6.1',
'eslint-plugin-react': '7.1.0',
'extract-text-webpack-plugin': '3.0.0',
'file-loader': '0.11.2',
'flow-runtime': '0.13.0',
'friendly-errors-webpack-plugin': '1.6.1',
'fs-extra': '4.0.1',
'github-markdown-css': '2.8.0',
'html-webpack-plugin': '2.29.0',
'in-publish': '2.0.0',
'localstorage-memory': '1.0.2',
mocha: '3.4.2',
'mocha-lcov-reporter': '1.3.0',
'node-sass': '4.5.3',
'normalize.css': '7.0.0',
nyc: '11.0.3',
ora: '1.3.0',
'prop-types': '15.5.10',
react: '15.6.1',
'react-dom': '15.6.1',
'react-hot-loader': '3.0.0-beta.7',
'react-router-dom': '4.1.1',
'react-syntax-highlighter': '5.6.2',
rimraf: '2.6.1',
'sass-loader': '6.0.6',
'source-map-loader': '0.2.1',
'standard-version': '4.2.0',
'style-loader': '0.18.2',
stylelint: '7.13.0',
'stylelint-config-standard': '16.0.0',
'stylelint-webpack-plugin': '0.8.0',
'url-loader': '0.5.8',
webpack: '3.2.0',
'webpack-dev-server': '2.5.0',
'webpack-merge': '4.1.0'
},
keywords: [
'private',
'package',
'repository',
'registry',
'enterprise',
'modules',
'proxy',
'server'
],
scripts: {
release: 'standard-version -a -s',
prepublish: 'in-publish && npm run build:webui || not-in-publish',
test: 'mocha ./test/functional ./test/unit --reporter=spec --full-trace',
'pre:ci': 'npm run build:webui',
'test:ci': 'npm run test:coverage',
'test:only': 'mocha ./test/functional ./test/unit',
'test:coverage': 'nyc npm t',
'coverage:html': 'nyc report --reporter=html',
'coverage:publish': 'nyc report --reporter=lcov | codecov',
lint: 'eslint .',
'lint:css': "stylelint 'src/**/*.scss' --syntax scss",
'pre:webpack': 'npm run lint && rimraf static/*',
'dev:webui': 'babel-node tools/dev.server.js',
'build:webui':
'npm run pre:webpack && webpack --config tools/webpack.prod.config.babel.js',
'build:docker': 'docker build -t verdaccio . --no-cache',
'build:docker:rpi': 'docker build -f Dockerfile.rpi -t verdaccio:rpi .'
},
jest: { snapshotSerializers: ['jest-serializer-enzyme'] },
engines: { node: '>=4.6.1', npm: '>=2.15.9' },
preferGlobal: true,
publishConfig: { registry: 'http://localhost:4873/' },
license: 'WTFPL',
contributors: [
{
name: '030',
email: 'test1@test.local',
avatar:
'https://www.gravatar.com/avatar/4ef03c2bf8d8689527903212d96fb45b'
},
{
name: 'User NPM',
email: 'test2@test.local',
avatar:
'https://www.gravatar.com/avatar/a5a236ba477ee98908600c40cda74f4a'
},
{
name: 'User NPM',
email: 'test3@test.comu',
avatar:
'https://www.gravatar.com/avatar/41a61049006855759bd6ec82ef0543a0'
},
{
name: 'Alex Vernacchia',
email: 'tes4@test.local',
avatar:
'https://www.gravatar.com/avatar/06975001f7f2be7052bcf978700c6112'
},
{
name: 'Alexander Makarenko',
email: 'test5@test.local',
avatar:
'https://www.gravatar.com/avatar/d9acfc4ed4e49a436738ff26a722dce4'
},
{
name: 'Alexandre-io',
email: 'test6@test.local',
avatar:
'https://www.gravatar.com/avatar/2e095c7cfd278f72825d0fed6e12e3b1'
},
{
name: 'Aram Drevekenin',
email: 'test7@test.local',
avatar:
'https://www.gravatar.com/avatar/371edff6d79c39bb9e36bde39d41a4b0'
},
{
name: 'Bart Dubois',
email: 'test8@test.local',
avatar:
'https://www.gravatar.com/avatar/4acf72b14fcb459286c988c4523bafc8'
},
{
name: 'Barthélemy Vessemont',
email: 'test9@test.local',
avatar:
'https://www.gravatar.com/avatar/322cd2fad528a55c4351ec76d85ef525'
},
{
name: 'Brandon Nicholls',
email: 'test10@test.local',
avatar:
'https://www.gravatar.com/avatar/2d3b462f08f214ed459967aa7ef206f7'
},
{
name: 'Bren Norris',
email: 'test11@test.local',
avatar:
'https://www.gravatar.com/avatar/465a42204a22efada0f15b46a7cdad3a'
},
{
name: 'Brett Trotter',
email: 'test12@test.local',
avatar:
'https://www.gravatar.com/avatar/27a54519dcbe64c6d705f3cc4854595a'
},
{
name: 'Brian Peacock',
email: 'test13@test.local',
avatar:
'https://www.gravatar.com/avatar/3dd3d627330e7e048c13a7480f19842e'
},
{
name: 'Cedric Darne',
email: 'test14@test.local',
avatar:
'https://www.gravatar.com/avatar/0a617cebc6539940d7956c86e86c72a6'
},
{
name: 'Chad Killingsworth',
email: 'test15@test.local',
avatar:
'https://www.gravatar.com/avatar/a5825b2d69311e559e28a535e5f0d483'
},
{
name: 'Chris Breneman',
email: 'test16@test.local',
avatar:
'https://www.gravatar.com/avatar/3c5c3edef955c93edac672cbad04d7cd'
},
{
name: 'Cody Droz',
email: 'test17@test.local',
avatar:
'https://www.gravatar.com/avatar/b762ce4d14acfece36e783b1592d882b'
},
{
name: 'Daniel Rodríguez Rivero',
email: 'test18@test.local',
avatar:
'https://www.gravatar.com/avatar/ac7f548c31e8a002cfa41bd4c71e222d'
},
{
name: 'Denis Babineau',
email: 'test19@test.local',
avatar:
'https://www.gravatar.com/avatar/ee5a522e067759ba0403824ecebeab4d'
},
{
name: 'Emmanuel Narh',
email: 'test20@test.local',
avatar:
'https://www.gravatar.com/avatar/93a84a6120969fd181785ff9de834f0a'
},
{
name: 'Fabio Poloni',
email: 'test21@test.local',
avatar:
'https://www.gravatar.com/avatar/f9a05677360e5f52fcca6e1af9b0f2ee'
},
{
name: 'Facundo Chambó',
email: 'test22@test.local',
avatar:
'https://www.gravatar.com/avatar/ec9e7c590ba4081c25fcf197f90a4ea0'
},
{
name: 'Guilherme Bernal',
email: 'test23@test.local',
avatar:
'https://www.gravatar.com/avatar/e5d55dcf2495618e8b9f8778f8353ee0'
},
{
name: 'Jakub Jirutka',
email: 'test24@test.local',
avatar:
'https://www.gravatar.com/avatar/061bdb74aa4a543108658b277a257b4b'
},
{
name: 'James Newell',
email: 'test25@test.local',
avatar:
'https://www.gravatar.com/avatar/825190aaae6ec7fd95085e1fb6f261d2'
},
{
name: 'Jan Vansteenkiste',
email: 'test26@test.local',
avatar:
'https://www.gravatar.com/avatar/41835625a324201c796a0a0cffe4796b'
},
{
name: 'Jannis Achstetter',
email: 'test27@test.local',
avatar:
'https://www.gravatar.com/avatar/92d1cce007b032f4a63c6df764f18030'
},
{
name: 'Jeremy Moritz',
email: 'test28@test.local',
avatar:
'https://www.gravatar.com/avatar/008127e8f10293f43e62de3b7b3520e1'
},
{
name: 'John Gozde',
email: 'test29@test.local',
avatar:
'https://www.gravatar.com/avatar/3e8927c60cb043a56fdd6531cfcaddbc'
},
{
name: 'Jon de la Motte',
email: 'test30@test.local',
avatar:
'https://www.gravatar.com/avatar/126c1ea4fdb20bbb85c3ff735b7b0964'
},
{
name: 'Joseph Gentle',
email: 'test31@test.local',
avatar:
'https://www.gravatar.com/avatar/484f0b8ba8b7cc43db0be8f910a91254'
},
{
name: 'José De Paz',
email: 'test32@test.local',
avatar:
'https://www.gravatar.com/avatar/2532122835f5ebf1642b707ae088c895'
},
{
name: 'Juan Carlos Picado',
email: 'test33@test.local',
avatar:
'https://www.gravatar.com/avatar/c676605ff39f9c7a43f5518a8ce54e12'
},
{
name: 'Juan Carlos Picado',
email: 'test34@test.local',
avatar:
'https://www.gravatar.com/avatar/fba48015a688c38cc84e5b55b07858c0'
},
{
name: 'User NPM',
email: 'test35@test.local',
avatar:
'https://www.gravatar.com/avatar/fba48015a688c38cc84e5b55b07858c0'
},
{
name: 'User NPM @nickname',
email: 'test36@test.local',
avatar:
'https://www.gravatar.com/avatar/fba48015a688c38cc84e5b55b07858c0'
},
{
name: 'Kalman Speier',
email: 'test37@test.local',
avatar:
'https://www.gravatar.com/avatar/272806ba17639e2fbf811e51eb8bfb99'
},
{
name: 'Keyvan Fatehi',
email: 'test38@test.local',
avatar:
'https://www.gravatar.com/avatar/22735d1ba5765955914eb2d597dfaab5'
},
{
name: 'Kody J. Peterson',
email: 'test39@test.local',
avatar:
'https://www.gravatar.com/avatar/918a15afc52e9b0a67b2651191b23d04'
},
{
name: 'Madison Grubb',
email: 'test40@test.local',
avatar:
'https://www.gravatar.com/avatar/73b84fdf661c11d48d3370bfa197162b'
},
{
name: 'Manuel de Brito Fontes',
email: 'test41@test.local',
avatar:
'https://www.gravatar.com/avatar/8798ca0a499428e5e8f25d3614ac8b6e'
},
{
name: 'Mark Doeswijk',
email: 'test42@test.local',
avatar:
'https://www.gravatar.com/avatar/0d70ebd6c46dc01502bfab5f8c2d2bc5'
},
{
name: 'Meeeeow',
email: 'test43@test.local',
avatar:
'https://www.gravatar.com/avatar/baa061890d7b352ba121082272419a8a'
},
{
name: 'Meeeeow',
email: 'test44@test.local',
avatar:
'https://www.gravatar.com/avatar/12a36e093451d4c0f75d4240960ce29b'
},
{
name: 'Michael Arnel',
email: 'test45@test.local',
avatar:
'https://www.gravatar.com/avatar/5f9a5ed24c63609d52651258f6dd8c12'
},
{
name: 'Michael Crowe',
email: 'test46@test.local',
avatar:
'https://www.gravatar.com/avatar/eec9ee62019852da28a3bc91c57907f9'
},
{
name: 'Miguel Mejias',
email: 'test47@test.local',
avatar:
'https://www.gravatar.com/avatar/7289a01fedfdb9ddf855ee4dd4d41ae2'
},
{
name: 'Miroslav Bajtoš',
email: 'test48@test.local',
avatar:
'https://www.gravatar.com/avatar/b4d8831300713259f74aea79f842ca57'
},
{
name: 'Nate Ziarek',
email: 'test49@test.local',
avatar:
'https://www.gravatar.com/avatar/6442023756294fd43aa518bbe5cc6dcc'
},
{
name: 'Nick',
email: 'test50@test.local',
avatar:
'https://www.gravatar.com/avatar/8a810f12c9624ea2092852fe7c19f1ee'
},
{
name: 'Piotr Synowiec',
email: 'test51@test.local',
avatar:
'https://www.gravatar.com/avatar/87028f33a3e1e5b4201c371abddf93e2'
},
{
name: 'Rafael Cesar',
email: 'test52@test.local',
avatar:
'https://www.gravatar.com/avatar/204ed93fa5be7e2f9f299ad8bca6431f'
},
{
name: 'Robert Ewald',
email: 'test53@test.local',
avatar:
'https://www.gravatar.com/avatar/ec2166ce419f78fb354f128b01a4a44d'
},
{
name: 'Robert Groh',
email: 'test54@test.local',
avatar:
'https://www.gravatar.com/avatar/565ccb5374a3e0e31a75f11da2eb57aa'
},
{
name: 'Robin Persson',
email: 'test55@test.local',
avatar:
'https://www.gravatar.com/avatar/99da46e4d59664134b176869340f464b'
},
{
name: 'Romain Lai-King',
email: 'test56@test.local',
avatar:
'https://www.gravatar.com/avatar/69d0370c58399d0e0bbd15ccabfe1ec5'
},
{
name: 'Ryan Graham',
email: 'test57@test.local',
avatar:
'https://www.gravatar.com/avatar/8bd1dd86bbf8705a5a702b86a2f3a390'
},
{
name: 'Ryan Graham',
email: 'test58@test.local',
avatar:
'https://www.gravatar.com/avatar/e272ab422c1c629e9be26cba8b6c0166'
},
{
name: 'Sam Day',
email: 'test59@test.local',
avatar:
'https://www.gravatar.com/avatar/1886554b0562a0eeeb78a4d1f27917ea'
},
{
name: 'Tarun Garg',
email: 'test60@test.local',
avatar:
'https://www.gravatar.com/avatar/185e200c3451cfbe341f0e758626303a'
},
{
name: 'Thomas Cort',
email: 'test61@test.local',
avatar:
'https://www.gravatar.com/avatar/120d2921c33c1bd8dedfce67a28dcc63'
},
{
name: 'Tom Vincent',
email: 'test62@test.local',
avatar:
'https://www.gravatar.com/avatar/fb0c7faeda7f5d5632182a3d80381bfa'
},
{
name: 'Trent Earl',
email: 'test63@test.local',
avatar:
'https://www.gravatar.com/avatar/1e30abe66d21824b89c28d05e5b57d84'
},
{
name: 'Yannick Croissant',
email: 'test64@test.local',
avatar:
'https://www.gravatar.com/avatar/1e619ddb2a180222dd3d9f0348e65b9b'
},
{
name: 'Yannick Galatol',
email: 'test65@test.local',
avatar:
'https://www.gravatar.com/avatar/2f624f92326fef845bb2c07b392b7e48'
},
{
name: 'cklein',
email: 'test66@test.local',
avatar:
'https://www.gravatar.com/avatar/f8288370380881cf3afc5a92a63d652d'
},
{
name: 'danielo515',
email: 'test67@test.local',
avatar:
'https://www.gravatar.com/avatar/ac7f548c31e8a002cfa41bd4c71e222d'
},
{
name: 'jmwilkinson',
email: 'test68@test.local',
avatar:
'https://www.gravatar.com/avatar/3b99683f0a4c26a8906ecbe7968a4ade'
},
{
name: 'nickname',
email: 'test69@test.local',
avatar:
'https://www.gravatar.com/avatar/fba48015a688c38cc84e5b55b07858c0'
},
{
name: 'nickname',
email: 'test70@test.local',
avatar:
'https://www.gravatar.com/avatar/047ba1e853d20459e531619af5493c56'
},
{
name: 'maxlaverse',
email: 'test71@test.local',
avatar:
'https://www.gravatar.com/avatar/74324a2900906c45949a8c5cee6d0730'
},
{
name: 'saheba',
email: 'test72@test.local',
avatar:
'https://www.gravatar.com/avatar/77644c51856cab149e0f550c5f0c6ed8'
},
{
name: 'steve-p-com',
email: 'test73@test.local',
avatar:
'https://www.gravatar.com/avatar/bef1821d3036b8b9242c4999826c1c3c'
},
{
name: 'trent.earl',
email: 'test74@test.local',
avatar:
'https://www.gravatar.com/avatar/f84b8ae496f7c988dce5a71d773e75bb'
}
],
readmeFilename: 'README.md',
gitHead: '567dbe327819ed30afb96906f8d43f19740e2e3d',
bugs: { url: 'https://github.com/verdaccio/verdaccio/issues' },
homepage: 'https://github.com/verdaccio/verdaccio#readme',
_id: 'verdaccio@2.7.1',
_shasum: '958c919180e7f2ed6775f48d4ec64bd8de2a14df',
_from: '.',
_npmVersion: '3.10.10',
_nodeVersion: '6.9.5',
_npmUser: {},
dist: {
shasum: '958c919180e7f2ed6775f48d4ec64bd8de2a14df',
tarball: 'http://localhost:4873/verdaccio/-/verdaccio-2.7.1.tgz'
}
}
};

View File

@@ -1 +0,0 @@
export default {};

View File

@@ -1,21 +0,0 @@
/**
* @prettier
* Setup configuration for Jest
* This file includes global settings for the JEST environment.
*/
import 'raf/polyfill';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
global.__APP_VERSION__ = '1.0.0';
global.__VERDACCIO_BASENAME_UI_OPTIONS = {};
// mocking few DOM methods
if (global.document) {
document.createRange = jest.fn(() => ({
selectNodeContents: () => {},
}));
document.execCommand = jest.fn();
}

View File

@@ -1,98 +0,0 @@
import { isTokenExpire, makeLogin } from '../../../src/webui/utils/login';
import {
generateTokenWithTimeRange,
generateTokenWithExpirationAsString,
generateTokenWithOutExpiration
} from '../components/__mocks__/token';
console.error = jest.fn();
jest.mock('.../../../../src/webui/utils/api', () => ({
request: require('../components/__mocks__/api').default.request
}));
describe('isTokenExpire', () => {
test('isTokenExpire - token is not present', () => {
expect(isTokenExpire()).toBeTruthy();
});
test('isTokenExpire - token is not a valid payload', () => {
expect(isTokenExpire('not_a_valid_token')).toBeTruthy();
});
test('isTokenExpire - token should not expire in 24 hrs range', () => {
const token = generateTokenWithTimeRange(24);
expect(isTokenExpire(token)).toBeFalsy();
});
test('isTokenExpire - token should expire for current time', () => {
const token = generateTokenWithTimeRange();
expect(isTokenExpire(token)).toBeTruthy();
});
test('isTokenExpire - token expiration is not available', () => {
const token = generateTokenWithOutExpiration();
expect(isTokenExpire(token)).toBeTruthy();
});
test('isTokenExpire - token is not a valid json token', () => {
const token = generateTokenWithExpirationAsString();
const result = [
'Invalid token:',
SyntaxError('Unexpected token o in JSON at position 1'),
'xxxxxx.W29iamVjdCBPYmplY3Rd.xxxxxx'
];
expect(isTokenExpire(token)).toBeTruthy();
expect(console.error).toHaveBeenCalledWith(...result);
});
});
describe('makeLogin', () => {
test('makeLogin - should give error for blank username and password', async () => {
const result = {
error: {
description: "Username or password can't be empty!",
title: 'Unable to login',
type: 'error'
}
};
const login = await makeLogin();
expect(login).toEqual(result);
});
test('makeLogin - should login successfully', async () => {
const { username, password } = { username: 'sam', password: '1234' };
const result = { token: 'TEST_TOKEN', username: 'sam' };
const login = await makeLogin(username, password);
expect(login).toEqual(result);
});
test('makeLogin - login should failed with 401', async () => {
const result = {
error: {
description: 'bad username/password, access denied',
title: 'Unable to login',
type: 'error'
}
};
const { username, password } = { username: 'sam', password: '123456' };
const login = await makeLogin(username, password);
expect(login).toEqual(result);
});
test('makeLogin - login should failed with when no data is sent', async () => {
const result = {
error: {
title: 'Unable to login',
type: 'error',
description: "Username or password can't be empty!"
}
};
const { username, password } = { username: '', password: '' };
const login = await makeLogin(username, password);
expect(login).toEqual(result);
});
});

View File

@@ -1,97 +0,0 @@
import {
formatLicense,
formatRepository,
formatDate,
formatDateDistance,
getLastUpdatedPackageTime,
getRecentReleases
} from '../../../src/webui/utils/package';
import { packageMeta } from '../components/store/packageMeta';
describe('formatLicense', () => {
test('should check license field different values', () => {
expect(formatLicense('MIT')).toEqual('MIT');
});
test('should check license field for object value', () => {
const license = { type: 'ISC', url: 'https://opensource.org/licenses/ISC' };
expect(formatLicense(license)).toEqual('ISC');
});
test('should check license field for other value', () => {
expect(formatLicense(null)).toBeNull();
expect(formatLicense({})).toBeNull();
expect(formatLicense([])).toBeNull();
});
});
describe('formatRepository', () => {
test('should check repository field different values', () => {
const repository = 'https://github.com/verdaccio/verdaccio';
expect(formatRepository(repository)).toEqual(repository);
});
test('should check repository field for object value', () => {
const license = {
type: 'git',
url: 'https://github.com/verdaccio/verdaccio'
};
expect(formatRepository(license)).toEqual(license.url);
});
test('should check repository field for other value', () => {
expect(formatRepository(null)).toBeNull();
expect(formatRepository({})).toBeNull();
expect(formatRepository([])).toBeNull();
});
});
describe('formatDate', () => {
test('should format the date', () => {
const date = 1532211072138;
expect(formatDate(date)).toEqual('21.07.2018, 22:11:12');
});
});
describe('formatDateDistance', () => {
test('should calculate the distance', () => {
const dateAboutTwoMonthsAgo = () => {
const date = new Date();
date.setMonth(date.getMonth() - 1);
date.setDate(date.getDay() - 20);
return date;
};
const dateTwoMonthsAgo = () => {
const date = new Date();
date.setMonth(date.getMonth() - 2);
return date;
};
const date1 = dateAboutTwoMonthsAgo();
const date2 = dateTwoMonthsAgo();
expect(formatDateDistance(date1)).toEqual('about 2 months');
expect(formatDateDistance(date2)).toEqual('2 months');
});
});
describe('getLastUpdatedPackageTime', () => {
test('should get the last update time', () => {
const lastUpdated = packageMeta._uplinks;
expect(getLastUpdatedPackageTime(lastUpdated)).toEqual(
'22.07.2018, 22:11:12'
);
});
test('should get the last update time for blank uplink', () => {
const lastUpdated = {};
expect(getLastUpdatedPackageTime(lastUpdated)).toEqual('');
});
});
describe('getRecentReleases', () => {
test('should get the recent releases', () => {
const { time } = packageMeta;
const result = [
{ time: '14.12.2017, 15:43:27', version: '2.7.1' },
{ time: '05.12.2017, 23:25:06', version: '2.7.0' },
{ time: '08.11.2017, 22:47:16', version: '2.6.6' }
];
expect(getRecentReleases(time)).toEqual(result);
expect(getRecentReleases()).toEqual([]);
});
});