mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-02-21 07:29:37 +01:00
Merge pull request #787 from verdaccio/refactor-unit-test
refactor: unit test
This commit is contained in:
commit
197aecbe4d
@ -9,6 +9,10 @@
|
||||
# path to a directory with all packages
|
||||
storage: ./storage
|
||||
|
||||
web:
|
||||
# WebUI is enabled as default, if you want disable it, just uncomment this line
|
||||
title: Verdaccio
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd
|
||||
|
@ -13,6 +13,10 @@
|
||||
# path to a directory with all packages
|
||||
storage: /verdaccio/storage
|
||||
|
||||
web:
|
||||
# WebUI is enabled as default, if you want disable it, just uncomment this line
|
||||
title: Verdaccio
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: /verdaccio/conf/htpasswd
|
||||
|
@ -16,10 +16,11 @@ auth:
|
||||
# You can set this to -1 to disable registration.
|
||||
#max_users: 1000
|
||||
|
||||
# Experimental built-in middlewares
|
||||
#middlewares:
|
||||
# audit:
|
||||
# enabled: true
|
||||
# Configure plugins that can register custom middlewares
|
||||
# To use `npm audit` uncomment the following section
|
||||
middlewares:
|
||||
audit:
|
||||
enabled: true
|
||||
|
||||
# a list of other known repositories we can talk to
|
||||
uplinks:
|
||||
@ -141,34 +142,34 @@ logs:
|
||||
# webhooks, but will also deliver a simple payload to
|
||||
# any endpoint. Currently only active for publish / create
|
||||
# commands.
|
||||
notify:
|
||||
#notify:
|
||||
# Choose a method. Technically this will accept any HTTP
|
||||
# request method, but probably stick to GET or POST
|
||||
method: POST
|
||||
# method: POST
|
||||
# Only run this notification if the package name matches the regular
|
||||
# expression
|
||||
packagePattern: ^example-package$
|
||||
# packagePattern: ^example-package$
|
||||
# Any flags to be used with the regular expression
|
||||
packagePatternFlags: i
|
||||
# packagePatternFlags: i
|
||||
# If this endpoint requires specific headers, set them here
|
||||
# as an array of key: value objects.
|
||||
headers: [{'Content-type': 'application/x-www-form-urlencoded'}]
|
||||
# headers: [{'Content-type': 'application/x-www-form-urlencoded'}]
|
||||
# set the URL endpoint for this call
|
||||
endpoint: https://hooks.slack.com/...
|
||||
# endpoint: https://hooks.slack.com/...
|
||||
# Finally, the content you will be sending in the body.
|
||||
# This data will first be run through Handlebars to parse
|
||||
# any Handlebar expressions. All data housed in the metadata object
|
||||
# is available for use within the expressions.
|
||||
content: ' {{ handlebar-expression }}'
|
||||
# content: ' {{ handlebar-expression }}'
|
||||
# For Slack, follow the following format:
|
||||
# content: '{ "text": "Package *{{ name }}* published to version *{{ dist-tags.latest }}*", "username": "Verdaccio", "icon_emoji": ":package:" }'
|
||||
|
||||
# Multiple notification endpoints can be created by specifying a collection
|
||||
'example-package-1':
|
||||
method: POST
|
||||
# 'example-package-1':
|
||||
# method: POST
|
||||
# Only run this notification if the package name matches the regular
|
||||
# expression
|
||||
packagePattern: ^example-package-regex$
|
||||
# packagePattern: ^example-package-regex$
|
||||
# Any flags to be used with the regular expression
|
||||
# since verdaccio 2.2.2 this property has been disabled read #108
|
||||
# it will be re-enabled after 2.5.0
|
||||
@ -176,18 +177,14 @@ notify:
|
||||
# If this endpoint requires specific headers, set them here
|
||||
# as an array of key: value objects.
|
||||
# headers supports as well a literal object
|
||||
headers: {'Content-type': 'application/x-www-form-urlencoded'}
|
||||
# headers: {'Content-type': 'application/x-www-form-urlencoded'}
|
||||
# set the URL endpoint for this call
|
||||
endpoint: https://hooks.slack.com/...
|
||||
# endpoint: https://hooks.slack.com/...
|
||||
# Finally, the content you will be sending in the body.
|
||||
# This data will first be run through Handlebars to parse
|
||||
# any Handlebar expressions. All data housed in the metadata object
|
||||
# is available for use within the expressions.
|
||||
content: ' {{ handlebar-expression }}'
|
||||
# content: ' {{ handlebar-expression }}'
|
||||
# For Slack, follow the following format:
|
||||
# content: '{ "text": "Package *{{ name }}* published to version *{{ dist-tags.latest }}*", "username": "Verdaccio", "icon_emoji": ":package:" }'
|
||||
|
||||
# Configure plugins that can register custom middlewares
|
||||
#middlewares:
|
||||
# plugin-name:
|
||||
# setting: true
|
||||
|
143
flow-typed/npm/axios_v0.17.x.js
vendored
143
flow-typed/npm/axios_v0.17.x.js
vendored
@ -1,143 +0,0 @@
|
||||
// flow-typed signature: 9fd7b9287df55ee8cfa980889d107499
|
||||
// flow-typed version: a8b5058d19/axios_v0.17.x/flow_>=v0.25.x
|
||||
|
||||
declare module "axios" {
|
||||
declare interface ProxyConfig {
|
||||
host: string;
|
||||
port: number;
|
||||
}
|
||||
declare interface Cancel {
|
||||
constructor(message?: string): Cancel;
|
||||
message: string;
|
||||
}
|
||||
declare interface Canceler {
|
||||
(message?: string): void;
|
||||
}
|
||||
declare interface CancelTokenSource {
|
||||
token: CancelToken;
|
||||
cancel: Canceler;
|
||||
}
|
||||
declare class CancelToken {
|
||||
constructor(executor: (cancel: Canceler) => void): CancelToken;
|
||||
static source(): CancelTokenSource;
|
||||
promise: Promise<Cancel>;
|
||||
reason?: Cancel;
|
||||
throwIfRequested(): void;
|
||||
}
|
||||
declare interface AxiosXHRConfigBase<T> {
|
||||
adapter?: <T>(config: AxiosXHRConfig<T>) => Promise<AxiosXHR<T>>;
|
||||
auth?: {
|
||||
username: string,
|
||||
password: string
|
||||
};
|
||||
baseURL?: string;
|
||||
cancelToken?: CancelToken;
|
||||
headers?: Object;
|
||||
httpAgent?: mixed; // Missing the type in the core flow node libdef
|
||||
httpsAgent?: mixed; // Missing the type in the core flow node libdef
|
||||
maxContentLength?: number;
|
||||
maxRedirects?: 5;
|
||||
params?: Object;
|
||||
paramsSerializer?: (params: Object) => string;
|
||||
progress?: (progressEvent: Event) => void | mixed;
|
||||
proxy?: ProxyConfig | false;
|
||||
responseType?:
|
||||
| "arraybuffer"
|
||||
| "blob"
|
||||
| "document"
|
||||
| "json"
|
||||
| "text"
|
||||
| "stream";
|
||||
timeout?: number;
|
||||
transformRequest?: Array<<U>(data: T) => U | Array<<U>(data: T) => U>>;
|
||||
transformResponse?: Array<<U>(data: T) => U>;
|
||||
validateStatus?: (status: number) => boolean;
|
||||
withCredentials?: boolean;
|
||||
xsrfCookieName?: string;
|
||||
xsrfHeaderName?: string;
|
||||
}
|
||||
declare type $AxiosXHRConfigBase<T> = AxiosXHRConfigBase<T>;
|
||||
declare interface AxiosXHRConfig<T> extends AxiosXHRConfigBase<T> {
|
||||
data?: T;
|
||||
method?: string;
|
||||
url: string;
|
||||
}
|
||||
declare type $AxiosXHRConfig<T> = AxiosXHRConfig<T>;
|
||||
declare class AxiosXHR<T> {
|
||||
config: AxiosXHRConfig<T>;
|
||||
data: T;
|
||||
headers?: Object;
|
||||
status: number;
|
||||
statusText: string;
|
||||
request: http$ClientRequest | XMLHttpRequest;
|
||||
}
|
||||
declare type $AxiosXHR<T> = AxiosXHR<T>;
|
||||
declare class AxiosInterceptorIdent extends String {}
|
||||
declare class AxiosRequestInterceptor<T> {
|
||||
use(
|
||||
successHandler: ?(
|
||||
response: AxiosXHRConfig<T>
|
||||
) => Promise<AxiosXHRConfig<*>> | AxiosXHRConfig<*>,
|
||||
errorHandler: ?(error: mixed) => mixed
|
||||
): AxiosInterceptorIdent;
|
||||
eject(ident: AxiosInterceptorIdent): void;
|
||||
}
|
||||
declare class AxiosResponseInterceptor<T> {
|
||||
use(
|
||||
successHandler: ?(response: AxiosXHR<T>) => mixed,
|
||||
errorHandler: ?(error: $AxiosError<any>) => mixed
|
||||
): AxiosInterceptorIdent;
|
||||
eject(ident: AxiosInterceptorIdent): void;
|
||||
}
|
||||
declare type AxiosPromise<T> = Promise<AxiosXHR<T>>;
|
||||
declare class Axios {
|
||||
constructor<T>(config?: AxiosXHRConfigBase<T>): void;
|
||||
$call: <T>(
|
||||
config: AxiosXHRConfig<T> | string,
|
||||
config?: AxiosXHRConfig<T>
|
||||
) => AxiosPromise<T>;
|
||||
request<T>(config: AxiosXHRConfig<T>): AxiosPromise<T>;
|
||||
delete<T>(url: string, config?: AxiosXHRConfigBase<T>): AxiosPromise<T>;
|
||||
get<T>(url: string, config?: AxiosXHRConfigBase<T>): AxiosPromise<T>;
|
||||
head<T>(url: string, config?: AxiosXHRConfigBase<T>): AxiosPromise<T>;
|
||||
post<T>(
|
||||
url: string,
|
||||
data?: mixed,
|
||||
config?: AxiosXHRConfigBase<T>
|
||||
): AxiosPromise<T>;
|
||||
put<T>(
|
||||
url: string,
|
||||
data?: mixed,
|
||||
config?: AxiosXHRConfigBase<T>
|
||||
): AxiosPromise<T>;
|
||||
patch<T>(
|
||||
url: string,
|
||||
data?: mixed,
|
||||
config?: AxiosXHRConfigBase<T>
|
||||
): AxiosPromise<T>;
|
||||
interceptors: {
|
||||
request: AxiosRequestInterceptor<mixed>,
|
||||
response: AxiosResponseInterceptor<mixed>
|
||||
};
|
||||
defaults: { headers: Object } & AxiosXHRConfig<*>;
|
||||
}
|
||||
|
||||
declare class AxiosError<T> extends Error {
|
||||
config: AxiosXHRConfig<T>;
|
||||
response: AxiosXHR<T>;
|
||||
code?: string;
|
||||
}
|
||||
|
||||
declare type $AxiosError<T> = AxiosError<T>;
|
||||
|
||||
declare interface AxiosExport extends Axios {
|
||||
Axios: typeof Axios;
|
||||
Cancel: Class<Cancel>;
|
||||
CancelToken: Class<CancelToken>;
|
||||
isCancel(value: any): boolean;
|
||||
create(config?: AxiosXHRConfigBase<any>): Axios;
|
||||
all: typeof Promise.all;
|
||||
spread(callback: Function): (arr: Array<any>) => Function;
|
||||
}
|
||||
declare module.exports: AxiosExport;
|
||||
}
|
@ -4,20 +4,39 @@ module.exports = {
|
||||
name: 'verdaccio-unit-jest',
|
||||
verbose: true,
|
||||
collectCoverage: true,
|
||||
coveragePathIgnorePatterns: [
|
||||
'node_modules',
|
||||
'fixtures'
|
||||
],
|
||||
testEnvironment: 'jest-environment-jsdom-global',
|
||||
testRegex: '(test/unit.*\\.spec|test/unit/webui/.*\\.spec)\\.js',
|
||||
setupFiles: [
|
||||
'./test/unit/setup.js'
|
||||
],
|
||||
// Some unit tests rely on data folders that look like packages. This confuses jest-hast-map
|
||||
// when it tries to scan for package.json files.
|
||||
modulePathIgnorePatterns: [
|
||||
'setup.js'
|
||||
'<rootDir>/test/unit/partials/mock-store/.*/package.json',
|
||||
'<rootDir>/test/functional/store/.*/package.json',
|
||||
'<rootDir>/test/unit/partials/store/.*/package.json',
|
||||
'<rootDir>/coverage',
|
||||
'<rootDir>/docs',
|
||||
'<rootDir>/debug',
|
||||
'<rootDir>/scripts',
|
||||
'<rootDir>/.circleci',
|
||||
'<rootDir>/tools',
|
||||
'<rootDir>/wiki',
|
||||
'<rootDir>/systemd',
|
||||
'<rootDir>/flow-typed',
|
||||
'<rootDir>test/unit/partials/mock-store/.*/package.json',
|
||||
'<rootDir>/test/functional/store/.*/package.json',
|
||||
'<rootDir>/build',
|
||||
'<rootDir>/.vscode/',
|
||||
],
|
||||
testPathIgnorePatterns: [
|
||||
'__snapshots__'
|
||||
'__snapshots__',
|
||||
'<rootDir>/build',
|
||||
],
|
||||
coveragePathIgnorePatterns: [
|
||||
'node_modules',
|
||||
'fixtures',
|
||||
'<rootDir>/test',
|
||||
],
|
||||
moduleNameMapper: {
|
||||
'\\.(scss)$': '<rootDir>/node_modules/identity-obj-proxy',
|
||||
|
@ -6,6 +6,7 @@ import {media, allow} from '../../middleware';
|
||||
import {DIST_TAGS} from '../../../lib/utils';
|
||||
import type {Router} from 'express';
|
||||
import type {IAuth, $ResponseExtend, $RequestExtend, $NextFunctionVer, IStorageHandler} from '../../../../types';
|
||||
import {API_MESSAGE, HTTP_STATUS} from '../../../lib/constants';
|
||||
|
||||
export default function(route: Router, auth: IAuth, storage: IStorageHandler) {
|
||||
const can = allow(auth);
|
||||
@ -20,8 +21,8 @@ export default function(route: Router, auth: IAuth, storage: IStorageHandler) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
res.status(201);
|
||||
return next({ok: 'package tagged'});
|
||||
res.status(HTTP_STATUS.CREATED);
|
||||
return next({ok: API_MESSAGE.TAG_ADDED});
|
||||
});
|
||||
};
|
||||
|
||||
@ -39,9 +40,9 @@ export default function(route: Router, auth: IAuth, storage: IStorageHandler) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
res.status(201);
|
||||
res.status(HTTP_STATUS.CREATED);
|
||||
return next({
|
||||
ok: 'tag removed',
|
||||
ok: API_MESSAGE.TAG_REMOVED,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -65,8 +66,10 @@ export default function(route: Router, auth: IAuth, storage: IStorageHandler) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
res.status(201);
|
||||
return next({ok: 'tags updated'});
|
||||
res.status(HTTP_STATUS.CREATED);
|
||||
return next({
|
||||
ok: API_MESSAGE.TAG_UPDATED,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
// @flow
|
||||
|
||||
import express from 'express';
|
||||
import Error from 'http-errors';
|
||||
import compression from 'compression';
|
||||
import _ from 'lodash';
|
||||
import express from 'express';
|
||||
import compression from 'compression';
|
||||
import cors from 'cors';
|
||||
import Storage from '../lib/storage';
|
||||
import {loadPlugin} from '../lib/plugin-loader';
|
||||
@ -14,6 +13,8 @@ import apiEndpoint from './endpoint';
|
||||
import type {$Application} from 'express';
|
||||
import type {$ResponseExtend, $RequestExtend, $NextFunctionVer, IStorageHandler, IAuth} from '../../types';
|
||||
import type {Config as IConfig} from '@verdaccio/types';
|
||||
import {ErrorCode} from '../lib/utils';
|
||||
import {API_ERROR, HTTP_STATUS} from '../lib/constants';
|
||||
|
||||
const LoggerApp = require('../lib/logger');
|
||||
const Config = require('../lib/config');
|
||||
@ -69,18 +70,18 @@ const defineAPI = function(config: Config, storage: IStorageHandler) {
|
||||
app.use('/-/verdaccio/', require('./web/api')(config, auth, storage));
|
||||
} else {
|
||||
app.get('/', function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) {
|
||||
next(Error[404]('Web interface is disabled in the config file'));
|
||||
next(ErrorCode.getNotFound(API_ERROR.WEB_DISABLED));
|
||||
});
|
||||
}
|
||||
|
||||
// Catch 404
|
||||
app.get('/*', function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) {
|
||||
next(Error[404]('File not found'));
|
||||
next(ErrorCode.getNotFound(API_ERROR.FILE_NOT_FOUND));
|
||||
});
|
||||
|
||||
app.use(function(err, req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) {
|
||||
if (_.isError(err)) {
|
||||
if (err.code === 'ECONNABORT' && res.statusCode === 304) {
|
||||
if (err.code === 'ECONNABORT' && res.statusCode === HTTP_STATUS.NOT_MODIFIED) {
|
||||
return next();
|
||||
}
|
||||
if (_.isFunction(res.report_error) === false) {
|
||||
|
@ -3,6 +3,7 @@ import _ from 'lodash';
|
||||
import fs from 'fs';
|
||||
import Search from '../../lib/search';
|
||||
import * as Utils from '../../lib/utils';
|
||||
import {WEB_TITLE} from '../../lib/constants';
|
||||
|
||||
const {securityIframe} = require('../middleware');
|
||||
/* eslint new-cap:off */
|
||||
@ -40,10 +41,9 @@ module.exports = function(config, auth, storage) {
|
||||
|
||||
router.get('/', function(req, res) {
|
||||
const base = Utils.combineBaseUrl(Utils.getWebProtocol(req), req.get('host'), config.url_prefix);
|
||||
const defaultTitle = 'Verdaccio';
|
||||
let webPage = template
|
||||
.replace(/ToReplaceByVerdaccio/g, base)
|
||||
.replace(/ToReplaceByTitle/g, _.get(config, 'web.title') ? config.web.title : defaultTitle);
|
||||
.replace(/ToReplaceByTitle/g, _.get(config, 'web.title') ? config.web.title : WEB_TITLE);
|
||||
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
|
||||
|
@ -8,6 +8,7 @@ import {aesDecrypt, aesEncrypt, signPayload, verifyPayload} from './crypto-utils
|
||||
import type {Config, Logger, Callback} from '@verdaccio/types';
|
||||
import type {$Response, NextFunction} from 'express';
|
||||
import type {$RequestExtend, JWTPayload} from '../../types';
|
||||
import {ROLES} from './constants';
|
||||
|
||||
|
||||
const LoggerApi = require('./logger');
|
||||
@ -148,13 +149,13 @@ class Auth {
|
||||
let pkg = Object.assign({name: packageName}, this.config.getMatchedPackagesSpec(packageName));
|
||||
|
||||
(function next() {
|
||||
let p = plugins.shift();
|
||||
const plugin = plugins.shift();
|
||||
|
||||
if (typeof(p.allow_access) !== 'function') {
|
||||
if (typeof(plugin.allow_access) !== 'function') {
|
||||
return next();
|
||||
}
|
||||
|
||||
p.allow_access(user, pkg, function(err, ok) {
|
||||
plugin.allow_access(user, pkg, function(err, ok) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
@ -360,7 +361,7 @@ function buildAnonymousUser() {
|
||||
*/
|
||||
function authenticatedUser(name: string, pluginGroups: Array<any>) {
|
||||
const isGroupValid: boolean = _.isArray(pluginGroups);
|
||||
const groups = (isGroupValid ? pluginGroups : []).concat(['$all', '$authenticated', '@all', '@authenticated', 'all']);
|
||||
const groups = (isGroupValid ? pluginGroups : []).concat([ROLES.$ALL, ROLES.$AUTH, ROLES.DEPRECATED_ALL, ROLES.DEPRECATED_AUTH, ROLES.ALL]);
|
||||
|
||||
return {
|
||||
name,
|
||||
|
3
src/lib/bootstrap.js
vendored
3
src/lib/bootstrap.js
vendored
@ -13,6 +13,7 @@ import {parse_address} from './utils';
|
||||
|
||||
import type {Callback} from '@verdaccio/types';
|
||||
import type {$Application} from 'express';
|
||||
import {DEFAULT_PORT} from './constants';
|
||||
|
||||
const logger = require('./logger');
|
||||
|
||||
@ -37,7 +38,7 @@ export function getListListenAddresses(argListen: string, configListen: mixed) {
|
||||
} else if (configListen) {
|
||||
addresses = [configListen];
|
||||
} else {
|
||||
addresses = ['4873'];
|
||||
addresses = [DEFAULT_PORT];
|
||||
}
|
||||
addresses = addresses.map(function(addr) {
|
||||
const parsedAddr = parse_address(addr);
|
||||
|
@ -1,9 +1,13 @@
|
||||
// @flow
|
||||
|
||||
export const DEFAULT_PORT = '4873';
|
||||
export const DEFAULT_DOMAIN = 'localhost';
|
||||
|
||||
export const HEADERS = {
|
||||
JSON: 'application/json',
|
||||
JSON_CHARSET: 'application/json; charset=utf-8',
|
||||
OCTET_STREAM: 'application/octet-stream',
|
||||
OCTET_STREAM: 'application/octet-stream; charset=utf-8',
|
||||
TEXT_CHARSET: 'text/plain; charset=utf-8',
|
||||
GZIP: 'gzip',
|
||||
};
|
||||
|
||||
@ -20,13 +24,22 @@ export const ERROR_CODE = {
|
||||
|
||||
export const TOKEN_BASIC = 'Basic';
|
||||
export const TOKEN_BEARER = 'Bearer';
|
||||
export const DEFAULT_REGISTRY = 'https://registry.npmjs.org/';
|
||||
export const DEFAULT_REGISTRY = 'https://registry.npmjs.org';
|
||||
export const DEFAULT_UPLINK = 'npmjs';
|
||||
|
||||
export const ROLES = {
|
||||
$ALL: '$all',
|
||||
$AUTH: '$authenticated',
|
||||
DEPRECATED_ALL: '@all',
|
||||
DEPRECATED_AUTH: '@authenticated',
|
||||
ALL: 'all',
|
||||
};
|
||||
|
||||
export const HTTP_STATUS = {
|
||||
OK: 200,
|
||||
CREATED: 201,
|
||||
MULTIPLE_CHOICES: 300,
|
||||
NOT_MODIFIED: 304,
|
||||
BAD_REQUEST: 400,
|
||||
UNAUTHORIZED: 401,
|
||||
FORBIDDEN: 403,
|
||||
@ -45,6 +58,10 @@ export const API_MESSAGE = {
|
||||
PKG_REMOVED: 'package removed',
|
||||
PKG_PUBLISHED: 'package published',
|
||||
TARBALL_REMOVED: 'tarball removed',
|
||||
TAG_UPDATED: 'tags updated',
|
||||
TAG_REMOVED: 'tag removed',
|
||||
TAG_ADDED: 'package tagged',
|
||||
|
||||
};
|
||||
|
||||
export const API_ERROR = {
|
||||
@ -57,6 +74,12 @@ export const API_ERROR = {
|
||||
NOT_FILE_UPLINK: 'file doesn\'t exist on uplink',
|
||||
MAX_USERS_REACHED: 'maximum amount of users reached',
|
||||
VERSION_NOT_EXIST: 'this version doesn\'t exist',
|
||||
FILE_NOT_FOUND: 'File not found',
|
||||
BAD_STATUS_CODE: 'bad status code',
|
||||
WEB_DISABLED: 'Web interface is disabled in the config file',
|
||||
};
|
||||
|
||||
export const DEFAULT_NO_README = 'ERROR: No README data found!';
|
||||
|
||||
|
||||
export const WEB_TITLE = 'Verdaccio';
|
||||
|
@ -745,7 +745,10 @@ class LocalStorage implements IStorage {
|
||||
json._rev = DEFAULT_REVISION;
|
||||
}
|
||||
|
||||
json._rev = generateRevision(json._rev);
|
||||
// this is intended in debug mode we do not want modify the store revision
|
||||
if (_.isNil(this.config._debug)) {
|
||||
json._rev = generateRevision(json._rev);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
@ -411,7 +411,7 @@ class ProxyStorage implements IProxy {
|
||||
return callback( ErrorCode.getNotFound(API_ERROR.NOT_PACKAGE_UPLINK));
|
||||
}
|
||||
if (!(res.statusCode >= HTTP_STATUS.OK && res.statusCode < HTTP_STATUS.MULTIPLE_CHOICES)) {
|
||||
const error = ErrorCode.getInternalError(`bad status code: ${res.statusCode}`);
|
||||
const error = ErrorCode.getInternalError(`${API_ERROR.BAD_STATUS_CODE}: ${res.statusCode}`);
|
||||
// $FlowFixMe
|
||||
error.remoteStatus = res.statusCode;
|
||||
return callback(error);
|
||||
|
@ -1,16 +1,16 @@
|
||||
// @flow
|
||||
|
||||
import {generateGravatarUrl} from '../utils/user';
|
||||
import _ from 'lodash';
|
||||
import fs from 'fs';
|
||||
import assert from 'assert';
|
||||
import semver from 'semver';
|
||||
import YAML from 'js-yaml';
|
||||
import URL from 'url';
|
||||
import fs from 'fs';
|
||||
import _ from 'lodash';
|
||||
import asciidoctor from 'asciidoctor.js';
|
||||
import createError from 'http-errors';
|
||||
import marked from 'marked';
|
||||
import {HTTP_STATUS, API_ERROR} from './constants';
|
||||
|
||||
import {HTTP_STATUS, API_ERROR, DEFAULT_PORT, DEFAULT_DOMAIN} from './constants';
|
||||
import {generateGravatarUrl} from '../utils/user';
|
||||
|
||||
import type {Package} from '@verdaccio/types';
|
||||
import type {$Request} from 'express';
|
||||
@ -219,8 +219,8 @@ function parse_address(urlAddress: any) {
|
||||
if (urlPattern) {
|
||||
return {
|
||||
proto: urlPattern[2] || 'http',
|
||||
host: urlPattern[6] || urlPattern[7] || 'localhost',
|
||||
port: urlPattern[8] || '4873',
|
||||
host: urlPattern[6] || urlPattern[7] || DEFAULT_DOMAIN,
|
||||
port: urlPattern[8] || DEFAULT_PORT,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
import {DOMAIN_SERVERS as localhost} from '../test.conf';
|
||||
|
||||
export const CREDENTIALS = {
|
||||
user: 'test',
|
||||
password: 'test'
|
||||
@ -8,4 +10,5 @@ export const PORT_SERVER_APP = '55550';
|
||||
export const PORT_SERVER_1 = '55551';
|
||||
export const PORT_SERVER_2 = '55552';
|
||||
export const PORT_SERVER_3 = '55553';
|
||||
export const DOMAIN_SERVERS = 'localhost';
|
||||
|
||||
export const DOMAIN_SERVERS = localhost;
|
||||
|
@ -77,9 +77,7 @@ class FunctionalEnvironment extends NodeEnvironment {
|
||||
async teardown() {
|
||||
await super.teardown();
|
||||
console.log(chalk.yellow('Teardown Test Environment.'));
|
||||
// this.global.__VERDACCIO_E2E__.stop();
|
||||
// this.global.__VERDACCIO__PROTECTED_E2E__.stop();
|
||||
// close verdaccios
|
||||
// shutdown verdaccio
|
||||
for (let server of this.global.__SERVERS_PROCESS__) {
|
||||
server[0].stop();
|
||||
}
|
||||
|
@ -120,7 +120,5 @@ packages:
|
||||
access: test $anonymous
|
||||
publish: test $anonymous
|
||||
|
||||
listen: 55551
|
||||
|
||||
# expose internal methods
|
||||
_debug: true
|
||||
|
@ -93,7 +93,5 @@ packages:
|
||||
access: test $anonymous
|
||||
publish: test $anonymous
|
||||
|
||||
listen: 55552
|
||||
|
||||
# expose internal methods
|
||||
_debug: true
|
||||
|
@ -38,7 +38,5 @@ packages:
|
||||
'*':
|
||||
access: $all
|
||||
|
||||
listen: 55553
|
||||
|
||||
# expose internal methods
|
||||
_debug: true
|
||||
|
@ -7,5 +7,23 @@ module.exports = {
|
||||
globalSetup: './e2e/pre-setup.js',
|
||||
globalTeardown: './e2e/teardown.js',
|
||||
testEnvironment: './e2e/puppeteer_environment.js',
|
||||
testRegex: '(/e2e.*\\.spec)\\.js'
|
||||
testRegex: '(/e2e.*\\.spec)\\.js',
|
||||
modulePathIgnorePatterns: [
|
||||
'<rootDir>/unit/partials/mock-store/.*/package.json',
|
||||
'<rootDir>/functional/store/.*/package.json',
|
||||
'<rootDir>/unit/partials/store/.*/package.json',
|
||||
'<rootDir>/../coverage',
|
||||
'<rootDir>/../docs',
|
||||
'<rootDir>/../debug',
|
||||
'<rootDir>/../scripts',
|
||||
'<rootDir>/../.circleci',
|
||||
'<rootDir>/../tools',
|
||||
'<rootDir>/../wiki',
|
||||
'<rootDir>/../systemd',
|
||||
'<rootDir>/../flow-typed',
|
||||
'<rootDir>unit/partials/mock-store/.*/package.json',
|
||||
'<rootDir>functional/store/.*/package.json',
|
||||
'<rootDir>/../build',
|
||||
'<rootDir>/../.vscode/',
|
||||
]
|
||||
};
|
||||
|
@ -6,5 +6,25 @@ module.exports = {
|
||||
globalSetup: './functional/pre-setup.js',
|
||||
globalTeardown: './functional/teardown.js',
|
||||
testEnvironment: './functional/test-environment.js',
|
||||
// Some unit tests rely on data folders that look like packages. This confuses jest-hast-map
|
||||
// when it tries to scan for package.json files.
|
||||
modulePathIgnorePatterns: [
|
||||
'<rootDir>/unit/partials/mock-store/.*/package.json',
|
||||
'<rootDir>/functional/store/.*/package.json',
|
||||
'<rootDir>/unit/partials/store/.*/package.json',
|
||||
'<rootDir>/../coverage',
|
||||
'<rootDir>/../docs',
|
||||
'<rootDir>/../debug',
|
||||
'<rootDir>/../scripts',
|
||||
'<rootDir>/../.circleci',
|
||||
'<rootDir>/../tools',
|
||||
'<rootDir>/../wiki',
|
||||
'<rootDir>/../systemd',
|
||||
'<rootDir>/../flow-typed',
|
||||
'<rootDir>unit/partials/mock-store/.*/package.json',
|
||||
'<rootDir>functional/store/.*/package.json',
|
||||
'<rootDir>/../build',
|
||||
'<rootDir>/../.vscode/',
|
||||
],
|
||||
collectCoverage: false
|
||||
};
|
||||
|
@ -14,65 +14,78 @@ export default class VerdaccioProcess implements IServerProcess {
|
||||
childFork: any;
|
||||
isDebug: boolean;
|
||||
silence: boolean;
|
||||
cleanStore: boolean;
|
||||
|
||||
constructor(config: IVerdaccioConfig, bridge: IServerBridge, silence: boolean = true, isDebug: boolean = false) {
|
||||
constructor(config: IVerdaccioConfig,
|
||||
bridge: IServerBridge,
|
||||
silence: boolean = true,
|
||||
isDebug: boolean = false,
|
||||
cleanStore: boolean = true) {
|
||||
this.config = config;
|
||||
this.bridge = bridge;
|
||||
this.silence = silence;
|
||||
this.isDebug = isDebug;
|
||||
this.cleanStore = cleanStore;
|
||||
}
|
||||
|
||||
init(): Promise<any> {
|
||||
init(verdaccioPath: string = '../../bin/verdaccio'): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const verdaccioRegisterWrap: string = path.join(__dirname, '../../bin/verdaccio');
|
||||
|
||||
rimRaf(this.config.storagePath, (err) => {
|
||||
if (_.isNil(err) === false) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
let childOptions = {
|
||||
silent: this.silence
|
||||
};
|
||||
|
||||
if (this.isDebug) {
|
||||
const debugPort = parseInt(this.config.port, 10) + 5;
|
||||
|
||||
childOptions = Object.assign({}, childOptions, {
|
||||
execArgv: [`--inspect=${debugPort}`]
|
||||
});
|
||||
}
|
||||
|
||||
this.childFork = fork(verdaccioRegisterWrap, ['-c', this.config.configPath], childOptions);
|
||||
|
||||
this.childFork.on('message', (msg) => {
|
||||
if ('verdaccio_started' in msg) {
|
||||
this.bridge.debug().status(HTTP_STATUS.OK).then((body) => {
|
||||
this.bridge.auth(CREDENTIALS.user, CREDENTIALS.password)
|
||||
.status(HTTP_STATUS.CREATED)
|
||||
.body_ok(new RegExp(CREDENTIALS.user))
|
||||
.then(() => {
|
||||
resolve([this, body.pid]);
|
||||
}, reject)
|
||||
}, reject);
|
||||
if(this.cleanStore) {
|
||||
rimRaf(this.config.storagePath, (err) => {
|
||||
if (_.isNil(err) === false) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
|
||||
this.childFork.on('error', (err) => {
|
||||
console.log('error process', err);
|
||||
reject([err, this]);
|
||||
this._start(verdaccioPath, resolve, reject);
|
||||
});
|
||||
} else {
|
||||
this._start(verdaccioPath, resolve, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.childFork.on('disconnect', (err) => {
|
||||
reject([err, this]);
|
||||
});
|
||||
_start(verdaccioPath: string, resolve: Function, reject: Function) {
|
||||
const verdaccioRegisterWrap: string = path.join(__dirname, verdaccioPath);
|
||||
let childOptions = {
|
||||
silent: this.silence
|
||||
};
|
||||
|
||||
this.childFork.on('exit', (err) => {
|
||||
reject([err, this]);
|
||||
});
|
||||
if (this.isDebug) {
|
||||
const debugPort = parseInt(this.config.port, 10) + 5;
|
||||
|
||||
childOptions = Object.assign({}, childOptions, {
|
||||
execArgv: [`--inspect=${debugPort}`]
|
||||
});
|
||||
}
|
||||
|
||||
const {configPath, port} = this.config;
|
||||
// $FlowFixMe
|
||||
this.childFork = fork(verdaccioRegisterWrap, ['-c', configPath, '-l', port], childOptions);
|
||||
|
||||
this.childFork.on('message', (msg) => {
|
||||
if ('verdaccio_started' in msg) {
|
||||
this.bridge.debug().status(HTTP_STATUS.OK).then((body) => {
|
||||
this.bridge.auth(CREDENTIALS.user, CREDENTIALS.password)
|
||||
.status(HTTP_STATUS.CREATED)
|
||||
.body_ok(new RegExp(CREDENTIALS.user))
|
||||
.then(() => {
|
||||
resolve([this, body.pid]);
|
||||
}, reject)
|
||||
}, reject);
|
||||
}
|
||||
});
|
||||
|
||||
this.childFork.on('error', (err) => {
|
||||
console.log('error process', err);
|
||||
reject([err, this]);
|
||||
});
|
||||
|
||||
this.childFork.on('disconnect', (err) => {
|
||||
reject([err, this]);
|
||||
});
|
||||
|
||||
this.childFork.on('exit', (err) => {
|
||||
reject([err, this]);
|
||||
});
|
||||
}
|
||||
|
||||
|
1
test/test.conf.js
Normal file
1
test/test.conf.js
Normal file
@ -0,0 +1 @@
|
||||
export const DOMAIN_SERVERS = '0.0.0.0';
|
@ -8,7 +8,11 @@ import publishMetadata from '../partials/publish-api';
|
||||
import forbiddenPlace from '../partials/forbidden-place';
|
||||
import Config from '../../../src/lib/config';
|
||||
import endPointAPI from '../../../src/api/index';
|
||||
import {HEADERS, API_ERROR} from '../../../src/lib/constants';
|
||||
|
||||
import {HEADERS, API_ERROR, HTTP_STATUS, HEADER_TYPE, API_MESSAGE} from '../../../src/lib/constants';
|
||||
import {mockServer} from './mock';
|
||||
import {DOMAIN_SERVERS} from '../../functional/config.functional';
|
||||
import {DIST_TAGS} from '../../../src/lib/utils';
|
||||
|
||||
require('../../../src/lib/logger').setup([]);
|
||||
const credentials = { name: 'Jota', password: 'secretPass' };
|
||||
@ -16,10 +20,11 @@ const credentials = { name: 'Jota', password: 'secretPass' };
|
||||
describe('endpoint unit test', () => {
|
||||
let config;
|
||||
let app;
|
||||
jest.setTimeout(10000);
|
||||
let mockRegistry;
|
||||
|
||||
beforeAll(function(done) {
|
||||
const store = path.join(__dirname, '../partials/store/test-storage');
|
||||
const mockServerPort = 55549;
|
||||
rimraf(store, async () => {
|
||||
const configForTest = _.clone(configDefault);
|
||||
configForTest.auth = {
|
||||
@ -27,22 +32,33 @@ describe('endpoint unit test', () => {
|
||||
file: './test-storage/htpasswd-test'
|
||||
}
|
||||
};
|
||||
configForTest.uplinks = {
|
||||
npmjs: {
|
||||
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`
|
||||
}
|
||||
};
|
||||
configForTest.self_path = store;
|
||||
config = new Config(configForTest);
|
||||
app = await endPointAPI(config);
|
||||
mockRegistry = await mockServer(mockServerPort).init();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(function(done) {
|
||||
mockRegistry[0].stop();
|
||||
done();
|
||||
});
|
||||
|
||||
describe('Registry API Endpoints', () => {
|
||||
|
||||
describe('should test ping api', () => {
|
||||
test('should test endpoint /-/ping', (done) => {
|
||||
request(app)
|
||||
.get('/-/ping')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
@ -55,8 +71,8 @@ describe('endpoint unit test', () => {
|
||||
test('should test /-/whoami endpoint', (done) => {
|
||||
request(app)
|
||||
.get('/-/whoami')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -68,8 +84,8 @@ describe('endpoint unit test', () => {
|
||||
test('should test /whoami endpoint', (done) => {
|
||||
request(app)
|
||||
.get('/-/whoami')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -86,8 +102,8 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.get('/auth-package')
|
||||
.set('authorization', 'FakeHader')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(403)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HTTP_STATUS.FORBIDDEN)
|
||||
.end(function(err, res) {
|
||||
expect(res.body.error).toBeDefined();
|
||||
expect(res.body.error).toMatch(/unregistered users are not allowed to access package auth-package/);
|
||||
@ -99,8 +115,8 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.get('/auth-package')
|
||||
.set('authorization', 'Bearer')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(403)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HTTP_STATUS.FORBIDDEN)
|
||||
.end(function(err, res) {
|
||||
expect(res.body.error).toBeDefined();
|
||||
expect(res.body.error).toMatch(/unregistered users are not allowed to access package auth-package/);
|
||||
@ -112,8 +128,8 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.get('/auth-package')
|
||||
.set('authorization', 'Bearer 12345')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(403)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HTTP_STATUS.FORBIDDEN)
|
||||
.end(function(err, res) {
|
||||
expect(res.body.error).toBeDefined();
|
||||
expect(res.body.error).toMatch(/unregistered users are not allowed to access package auth-package/);
|
||||
@ -127,8 +143,8 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.put('/-/user/org.couchdb.user:jota')
|
||||
.send(credentials)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(201)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.CREATED)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -144,8 +160,8 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.get('/vue')
|
||||
.set('authorization', `Bearer ${token}`)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
expect(err).toBeNull();
|
||||
expect(res.body).toBeDefined();
|
||||
@ -163,8 +179,8 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.put('/-/user/org.couchdb.user:jota')
|
||||
.send(credentialsShort)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(400)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.BAD_REQUEST)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -184,8 +200,8 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.put('/-/user/org.couchdb.user:jota')
|
||||
.send(credentialsShort)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(400)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.BAD_REQUEST)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -205,8 +221,8 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.put('/-/user/org.couchdb.user:jotaNew')
|
||||
.send(newCredentials)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(201)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.CREATED)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -220,8 +236,8 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.put('/-/user/org.couchdb.user:jotaNew')
|
||||
.send(credentials)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(409)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.CONFLICT)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -240,8 +256,8 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.put('/-/user/org.couchdb.user:jota')
|
||||
.send(credentialsShort)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(401)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.UNAUTHORIZED)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -261,9 +277,9 @@ describe('endpoint unit test', () => {
|
||||
|
||||
request(app)
|
||||
.get('/jquery')
|
||||
.set('content-type', HEADERS.JSON_CHARSET)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -279,9 +295,9 @@ describe('endpoint unit test', () => {
|
||||
|
||||
request(app)
|
||||
.get('/jquery/1.5.1')
|
||||
.set('content-type', HEADERS.JSON_CHARSET)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -297,9 +313,9 @@ describe('endpoint unit test', () => {
|
||||
|
||||
request(app)
|
||||
.get('/jquery/latest')
|
||||
.set('content-type', HEADERS.JSON_CHARSET)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -315,10 +331,10 @@ describe('endpoint unit test', () => {
|
||||
|
||||
request(app)
|
||||
.get('/jquery/never-will-exist-this-tag')
|
||||
.set('content-type', HEADERS.JSON_CHARSET)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(404)
|
||||
.end(function(err, res) {
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.NOT_FOUND)
|
||||
.end(function(err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
@ -330,9 +346,9 @@ describe('endpoint unit test', () => {
|
||||
|
||||
request(app)
|
||||
.get('/@verdaccio/not-found')
|
||||
.set('content-type', HEADERS.JSON_CHARSET)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(404)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.NOT_FOUND)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -345,10 +361,10 @@ describe('endpoint unit test', () => {
|
||||
|
||||
request(app)
|
||||
.get('/forbidden-place')
|
||||
.set('content-type', HEADERS.JSON_CHARSET)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(403)
|
||||
.end(function(err, res) {
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.FORBIDDEN)
|
||||
.end(function(err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
@ -360,8 +376,8 @@ describe('endpoint unit test', () => {
|
||||
|
||||
request(app)
|
||||
.get('/jquery/-/jquery-1.5.1.tgz')
|
||||
.expect('Content-Type', /application\/octet-stream/)
|
||||
.expect(200)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.OCTET_STREAM)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
@ -376,10 +392,11 @@ describe('endpoint unit test', () => {
|
||||
|
||||
request(app)
|
||||
.get('/jquery/-/jquery-0.0.1.tgz')
|
||||
.expect('Content-Type', /application\/octet-stream/)
|
||||
.expect(404)
|
||||
.end(function(err, res) {
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.OCTET_STREAM)
|
||||
.expect(HTTP_STATUS.NOT_FOUND)
|
||||
.end(function(err) {
|
||||
if (err) {
|
||||
expect(err).not.toBeNull();
|
||||
return done(err);
|
||||
}
|
||||
|
||||
@ -403,10 +420,11 @@ describe('endpoint unit test', () => {
|
||||
.send(JSON.stringify(jqueryVersion))
|
||||
.set('accept', 'gzip')
|
||||
.set('accept-encoding', HEADERS.JSON)
|
||||
.set('content-type', HEADERS.JSON)
|
||||
.expect(201)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HTTP_STATUS.CREATED)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
expect.toBeNull();
|
||||
return done(err);
|
||||
}
|
||||
|
||||
@ -421,10 +439,11 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.get('/-/package/jquery/dist-tags')
|
||||
.set('accept-encoding', HEADERS.JSON)
|
||||
.set('content-type', HEADERS.JSON)
|
||||
.expect(200)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
expect.toBeNull();
|
||||
return done(err);
|
||||
}
|
||||
|
||||
@ -439,15 +458,16 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.post('/-/package/jquery/dist-tags')
|
||||
.send(JSON.stringify(jqueryUpdatedVersion))
|
||||
.set('content-type', HEADERS.JSON)
|
||||
.expect(201)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HTTP_STATUS.CREATED)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
expect.toBeNull();
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(res.body.ok).toBeDefined();
|
||||
expect(res.body.ok).toMatch(/tags updated/);
|
||||
expect(res.body.ok).toMatch(API_MESSAGE.TAG_UPDATED);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -457,10 +477,11 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.get('/-/package/jquery/dist-tags')
|
||||
.set('accept-encoding', HEADERS.JSON)
|
||||
.set('content-type', HEADERS.JSON)
|
||||
.expect(200)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
expect.toBeNull();
|
||||
return done(err);
|
||||
}
|
||||
|
||||
@ -475,16 +496,17 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.del('/-/package/jquery/dist-tags/verdaccio-tag')
|
||||
.set('accept-encoding', HEADERS.JSON)
|
||||
.set('content-type', HEADERS.JSON)
|
||||
//.expect('Content-Type', /json/)
|
||||
.expect(201)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
//.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.CREATED)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
expect.toBeNull();
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(res.body.ok).toBeDefined();
|
||||
expect(res.body.ok).toMatch(/tag removed/);
|
||||
expect(res.body.ok).toMatch(API_MESSAGE.TAG_REMOVED);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -498,11 +520,12 @@ describe('endpoint unit test', () => {
|
||||
request(app)
|
||||
.get('/-/all/since?stale=update_after&startkey=' + cacheTime)
|
||||
// .set('accept-encoding', HEADERS.JSON)
|
||||
// .set('content-type', HEADERS.JSON)
|
||||
//.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
// .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
//.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err) {
|
||||
if (err) {
|
||||
expect.toBeNull();
|
||||
return done(err);
|
||||
}
|
||||
//TODO: we have to catch the stream check whether it returns something
|
||||
@ -517,17 +540,18 @@ describe('endpoint unit test', () => {
|
||||
test('should publish a new package', (done) => {
|
||||
request(app)
|
||||
.put('/@scope%2fpk1-test')
|
||||
.set('content-type', HEADERS.JSON)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.send(JSON.stringify(publishMetadata))
|
||||
.expect(201)
|
||||
.expect(HTTP_STATUS.CREATED)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
expect.toBeNull();
|
||||
return done(err);
|
||||
}
|
||||
expect(res.body.ok).toBeDefined();
|
||||
expect(res.body.success).toBeDefined();
|
||||
expect(res.body.success).toBeTruthy();
|
||||
expect(res.body.ok).toMatch(/created new package/);
|
||||
expect(res.body.ok).toMatch(API_MESSAGE.PKG_CREATED);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -536,14 +560,15 @@ describe('endpoint unit test', () => {
|
||||
//FUTURE: for some reason it does not remove the scope folder
|
||||
request(app)
|
||||
.del('/@scope%2fpk1-test/-rev/4-6abcdb4efd41a576')
|
||||
.set('content-type', HEADERS.JSON)
|
||||
.expect(201)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HTTP_STATUS.CREATED)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
expect.toBeNull();
|
||||
return done(err);
|
||||
}
|
||||
expect(res.body.ok).toBeDefined();
|
||||
expect(res.body.ok).toMatch(/package removed/);
|
||||
expect(res.body.ok).toMatch(API_MESSAGE.PKG_REMOVED);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -554,15 +579,15 @@ describe('endpoint unit test', () => {
|
||||
beforeAll(async function() {
|
||||
await request(app)
|
||||
.put('/@scope%2fpk1-test')
|
||||
.set('content-type', HEADERS.JSON)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.send(JSON.stringify(publishMetadata))
|
||||
.expect(201);
|
||||
.expect(HTTP_STATUS.CREATED);
|
||||
|
||||
await request(app)
|
||||
.put('/forbidden-place')
|
||||
.set('content-type', HEADERS.JSON)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.send(JSON.stringify(forbiddenPlace))
|
||||
.expect(201);
|
||||
.expect(HTTP_STATUS.CREATED);
|
||||
});
|
||||
|
||||
describe('Packages', () => {
|
||||
@ -570,7 +595,7 @@ describe('endpoint unit test', () => {
|
||||
test('should display all packages', (done) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/packages' )
|
||||
.expect(200)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
expect(res.body).toHaveLength(1);
|
||||
done();
|
||||
@ -580,8 +605,8 @@ describe('endpoint unit test', () => {
|
||||
test.skip('should display scoped readme', (done) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/package/readme/@scope/pk1-test')
|
||||
.expect(200)
|
||||
.expect('Content-Type', 'text/plain; charset=utf-8')
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_CHARSET)
|
||||
.end(function(err, res) {
|
||||
expect(res.text).toMatch('<h1 id="test">test</h1>\n');
|
||||
done();
|
||||
@ -592,8 +617,8 @@ describe('endpoint unit test', () => {
|
||||
test.skip('should display scoped readme 404', (done) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/package/readme/@scope/404')
|
||||
.expect(200)
|
||||
.expect('Content-Type', 'text/plain; charset=utf-8')
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_CHARSET)
|
||||
.end(function(err, res) {
|
||||
expect(res.body.error).toMatch(API_ERROR.NO_PACKAGE);
|
||||
done();
|
||||
@ -603,11 +628,11 @@ describe('endpoint unit test', () => {
|
||||
test('should display sidebar info', (done) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/sidebar/@scope/pk1-test')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.end(function(err, res) {
|
||||
const sideBarInfo = res.body;
|
||||
const latestVersion = publishMetadata.versions[publishMetadata['dist-tags'].latest];
|
||||
const latestVersion = publishMetadata.versions[publishMetadata[DIST_TAGS].latest];
|
||||
|
||||
expect(sideBarInfo.latest.author).toBeDefined();
|
||||
expect(sideBarInfo.latest.author.avatar).toMatch(/www.gravatar.com/);
|
||||
@ -620,9 +645,9 @@ describe('endpoint unit test', () => {
|
||||
test('should display sidebar info 404', (done) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/sidebar/@scope/404')
|
||||
.expect(404)
|
||||
.expect('Content-Type', /json/)
|
||||
.end(function(err, res) {
|
||||
.expect(HTTP_STATUS.NOT_FOUND)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.end(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -633,7 +658,7 @@ describe('endpoint unit test', () => {
|
||||
test('should search pk1-test', (done) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/search/scope')
|
||||
.expect(200)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
expect(res.body).toHaveLength(1);
|
||||
done();
|
||||
@ -643,7 +668,7 @@ describe('endpoint unit test', () => {
|
||||
test('should search with 404', (done) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/search/@')
|
||||
.expect(200)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
// in a normal world, the output would be 1
|
||||
// https://github.com/verdaccio/verdaccio/issues/345
|
||||
@ -656,7 +681,7 @@ describe('endpoint unit test', () => {
|
||||
test('should not find forbidden-place', (done) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/search/forbidden-place')
|
||||
.expect(200)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
//this is expected since we are not logged
|
||||
// and forbidden-place is allow_access: 'nobody'
|
||||
@ -675,7 +700,7 @@ describe('endpoint unit test', () => {
|
||||
username: credentials.name,
|
||||
password: credentials.password
|
||||
})
|
||||
.expect(200)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
expect(res.body.error).toBeUndefined();
|
||||
expect(res.body.token).toBeDefined();
|
||||
@ -693,7 +718,7 @@ describe('endpoint unit test', () => {
|
||||
password: 'fake'
|
||||
}))
|
||||
//FIXME: there should be 401
|
||||
.expect(200)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function(err, res) {
|
||||
expect(res.body.error).toMatch(/bad username\/password, access denied/);
|
||||
done();
|
||||
|
@ -1,11 +1,10 @@
|
||||
import endPointAPI from '../../../src/api/index';
|
||||
import {API_ERROR} from '../../../src/lib/constants';
|
||||
|
||||
const assert = require('assert');
|
||||
const express = require('express');
|
||||
const request = require('request');
|
||||
const rimraf = require('rimraf');
|
||||
|
||||
const config = require('../partials/config/index');
|
||||
import express from 'express';
|
||||
import request from 'request';
|
||||
import rimraf from 'rimraf';
|
||||
import config from '../partials/config/index';
|
||||
|
||||
const app = express();
|
||||
const server = require('http').createServer(app);
|
||||
@ -35,18 +34,18 @@ describe('basic system test', () => {
|
||||
request({
|
||||
url: 'http://localhost:' + port + '/',
|
||||
}, function(err, res, body) {
|
||||
assert.equal(err, null);
|
||||
assert(body.match(/<title>Verdaccio<\/title>/));
|
||||
expect(err).toBeNull();
|
||||
expect(body).toMatch(/<title>Verdaccio<\/title>/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('server should respond on /whatever', done => {
|
||||
request({
|
||||
url: 'http://localhost:' + port + '/whatever',
|
||||
url: `http://localhost:${port}/whatever`,
|
||||
}, function(err, res, body) {
|
||||
assert.equal(err, null);
|
||||
assert(body.match(/no such package available/));
|
||||
expect(err).toBeNull();
|
||||
expect(body).toMatch(API_ERROR.NO_PACKAGE);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -1,8 +1,10 @@
|
||||
import path from 'path';
|
||||
import _ from 'lodash';
|
||||
|
||||
import startServer from '../../../src/index';
|
||||
import {getListListenAddresses} from '../../../src/lib/bootstrap';
|
||||
import config from '../partials/config/index';
|
||||
import path from 'path';
|
||||
import _ from 'lodash';
|
||||
import {DEFAULT_DOMAIN, DEFAULT_PORT} from '../../../src/lib/constants';
|
||||
|
||||
require('../../../src/lib/logger').setup([]);
|
||||
|
||||
@ -11,18 +13,21 @@ describe('startServer via API', () => {
|
||||
describe('startServer launcher', () => {
|
||||
test('should provide all server data await/async', async (done) => {
|
||||
const store = path.join(__dirname, 'partials/store');
|
||||
const serverName = 'verdaccio-test';
|
||||
const version = '1.0.0';
|
||||
const port = '6000';
|
||||
|
||||
await startServer(config, 6000, store, '1.0.0', 'verdaccio-test',
|
||||
await startServer(config, port, store, version, serverName,
|
||||
(webServer, addrs, pkgName, pkgVersion) => {
|
||||
expect(webServer).toBeDefined();
|
||||
expect(addrs).toBeDefined();
|
||||
expect(addrs.proto).toBe('http');
|
||||
expect(addrs.host).toBe('localhost');
|
||||
expect(addrs.port).toBe('6000');
|
||||
expect(addrs.port).toBe(port);
|
||||
expect(pkgName).toBeDefined();
|
||||
expect(pkgVersion).toBeDefined();
|
||||
expect(pkgVersion).toBe('1.0.0');
|
||||
expect(pkgName).toBe('verdaccio-test');
|
||||
expect(pkgVersion).toBe(version);
|
||||
expect(pkgName).toBe(serverName);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -38,12 +43,12 @@ describe('startServer via API', () => {
|
||||
});
|
||||
|
||||
describe('getListListenAddresses test', () => {
|
||||
test('should return by default 4873', () => {
|
||||
test(`should return by default ${DEFAULT_PORT}`, () => {
|
||||
const addrs = getListListenAddresses()[0];
|
||||
|
||||
expect(addrs.proto).toBe('http');
|
||||
expect(addrs.host).toBe('localhost');
|
||||
expect(addrs.port).toBe('4873');
|
||||
expect(addrs.host).toBe(DEFAULT_DOMAIN);
|
||||
expect(addrs.port).toBe(DEFAULT_PORT);
|
||||
});
|
||||
|
||||
test('should return a list of address and no cli argument provided', () => {
|
||||
|
@ -1,55 +1,91 @@
|
||||
const assert = require('assert');
|
||||
const Utils = require('../../../src/lib/utils');
|
||||
const Config = require('../../../src/lib/config');
|
||||
const path = require('path');
|
||||
const _ = require('lodash');
|
||||
import path from 'path';
|
||||
import _ from 'lodash';
|
||||
|
||||
import Config from '../../../src/lib/config';
|
||||
import {parseConfigFile} from '../../../src/lib/utils';
|
||||
import {DEFAULT_REGISTRY, DEFAULT_UPLINK, ROLES, WEB_TITLE} from '../../../src/lib/constants';
|
||||
|
||||
const resolveConf = (conf) => path.join(__dirname, `../../../conf/${conf}.yaml`);
|
||||
|
||||
const checkUplink = (config) => {
|
||||
assert.equal(_.isObject(config.uplinks['npmjs']), true);
|
||||
assert.equal(config.uplinks['npmjs'].url, 'https://registry.npmjs.org');
|
||||
const checkDefaultUplink = (config) => {
|
||||
expect(_.isObject(config.uplinks[DEFAULT_UPLINK])).toBeTruthy();
|
||||
expect(config.uplinks[DEFAULT_UPLINK].url).toMatch(DEFAULT_REGISTRY);
|
||||
};
|
||||
|
||||
const checkPackages = (config) => {
|
||||
assert.equal(_.isObject(config.packages), true);
|
||||
assert.equal(Object.keys(config.packages).join('|'), '@*/*|**');
|
||||
assert.equal(config.packages['@*/*'].access, '$all');
|
||||
assert.equal(config.packages['@*/*'].publish, '$authenticated');
|
||||
assert.equal(config.packages['@*/*'].proxy, 'npmjs');
|
||||
assert.equal(config.packages['**'].access, '$all');
|
||||
assert.equal(config.packages['**'].publish, '$authenticated');
|
||||
assert.equal(config.packages['**'].proxy, 'npmjs');
|
||||
assert.equal(config.uplinks['npmjs'].url, 'https://registry.npmjs.org');
|
||||
const checkDefaultConfPackages = (config) => {
|
||||
//auth
|
||||
expect(_.isObject(config.auth)).toBeTruthy();
|
||||
expect(_.isObject(config.auth.htpasswd)).toBeTruthy();
|
||||
expect(config.auth.htpasswd.file).toMatch(/htpasswd/);
|
||||
|
||||
//web
|
||||
expect(_.isObject(config.web)).toBeTruthy();
|
||||
expect(config.web.title).toBe(WEB_TITLE);
|
||||
expect(config.web.enable).toBeUndefined();
|
||||
|
||||
// packages
|
||||
expect(_.isObject(config.packages)).toBeTruthy();
|
||||
expect(Object.keys(config.packages).join('|')).toBe('@*/*|**');
|
||||
expect(config.packages['@*/*'].access).toBeDefined();
|
||||
expect(config.packages['@*/*'].access).toContainEqual(ROLES.$ALL);
|
||||
expect(config.packages['@*/*'].publish).toBeDefined();
|
||||
expect(config.packages['@*/*'].publish).toContainEqual(ROLES.$AUTH);
|
||||
expect(config.packages['@*/*'].proxy).toBeDefined();
|
||||
expect(config.packages['@*/*'].proxy).toContainEqual(DEFAULT_UPLINK);
|
||||
expect(config.packages['**'].access).toBeDefined();
|
||||
expect(config.packages['**'].access).toContainEqual(ROLES.$ALL);
|
||||
expect(config.packages['**'].publish).toBeDefined();
|
||||
expect(config.packages['**'].publish).toContainEqual(ROLES.$AUTH);
|
||||
expect(config.packages['**'].proxy).toBeDefined();
|
||||
expect(config.packages['**'].proxy,).toContainEqual(DEFAULT_UPLINK);
|
||||
// uplinks
|
||||
expect(config.uplinks[DEFAULT_UPLINK]).toBeDefined();
|
||||
expect(config.uplinks[DEFAULT_UPLINK].url).toEqual(DEFAULT_REGISTRY);
|
||||
// audit
|
||||
expect(config.middlewares).toBeDefined();
|
||||
expect(config.middlewares.audit).toBeDefined();
|
||||
expect(config.middlewares.audit.enabled).toBeTruthy();
|
||||
// logs
|
||||
expect(config.logs).toBeDefined();
|
||||
expect(config.logs[0].type).toEqual('stdout');
|
||||
expect(config.logs[0].format).toEqual('pretty');
|
||||
expect(config.logs[0].level).toEqual('http');
|
||||
//must not be enabled by default
|
||||
expect(config.notify).toBeUndefined();
|
||||
expect(config.store).toBeUndefined();
|
||||
expect(config.publish).toBeUndefined();
|
||||
expect(config.url_prefix).toBeUndefined();
|
||||
expect(config.url_prefix).toBeUndefined();
|
||||
};
|
||||
|
||||
describe('Config file', () => {
|
||||
beforeAll(function() {
|
||||
|
||||
this.config = new Config(Utils.parseConfigFile(resolveConf('full')));
|
||||
this.config = new Config(parseConfigFile(resolveConf('full')));
|
||||
});
|
||||
|
||||
describe('Config file', () => {
|
||||
test('parse full.yaml', () => {
|
||||
const config = new Config(Utils.parseConfigFile(resolveConf('full')));
|
||||
checkUplink(config);
|
||||
assert.equal(config.storage, './storage');
|
||||
assert.equal(config.web.title, 'Verdaccio');
|
||||
checkPackages(config);
|
||||
const config = new Config(parseConfigFile(resolveConf('full')));
|
||||
checkDefaultUplink(config);
|
||||
expect(config.storage).toBe('./storage');
|
||||
checkDefaultConfPackages(config);
|
||||
});
|
||||
|
||||
test('parse docker.yaml', () => {
|
||||
const config = new Config(Utils.parseConfigFile(resolveConf('docker')));
|
||||
checkUplink(config);
|
||||
assert.equal(config.storage, '/verdaccio/storage');
|
||||
assert.equal(config.auth.htpasswd.file, '/verdaccio/conf/htpasswd');
|
||||
const config = new Config(parseConfigFile(resolveConf('docker')));
|
||||
checkDefaultUplink(config);
|
||||
expect(config.storage).toBe('/verdaccio/storage');
|
||||
expect(config.auth.htpasswd.file).toBe('/verdaccio/conf/htpasswd');
|
||||
checkDefaultConfPackages(config);
|
||||
});
|
||||
|
||||
test('parse default.yaml', () => {
|
||||
const config = new Config(Utils.parseConfigFile(resolveConf('default')));
|
||||
checkUplink(config);
|
||||
assert.equal(config.storage, './storage');
|
||||
assert.equal(config.auth.htpasswd.file, './htpasswd');
|
||||
const config = new Config(parseConfigFile(resolveConf('default')));
|
||||
checkDefaultUplink(config);
|
||||
expect(config.storage).toBe('./storage');
|
||||
expect(config.auth.htpasswd.file).toBe('./htpasswd');
|
||||
checkDefaultConfPackages(config);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,40 +1,44 @@
|
||||
const assert = require('assert');
|
||||
const _ = require('lodash');
|
||||
const parse = require('../../../src/lib/utils').parse_address;
|
||||
import _ from 'lodash';
|
||||
import {parse_address as parse} from '../../../src/lib/utils';
|
||||
import {DEFAULT_DOMAIN, DEFAULT_PORT} from '../../../src/lib/constants';
|
||||
|
||||
describe('Parse listen address', () => {
|
||||
function addTest(what, proto, host, port) {
|
||||
test(what, () => {
|
||||
function addTest(uri, proto, host, port) {
|
||||
test(`should parse ${uri}`, () => {
|
||||
const parsed = parse(uri);
|
||||
|
||||
if (_.isNull(proto)) {
|
||||
assert.strictEqual(parse(what), null);
|
||||
expect(parsed).toBeNull();
|
||||
} else if (port) {
|
||||
assert.deepEqual(parse(what), {
|
||||
proto: proto,
|
||||
host: host,
|
||||
port: port,
|
||||
expect(parsed).toEqual({
|
||||
proto,
|
||||
host,
|
||||
port,
|
||||
});
|
||||
} else {
|
||||
assert.deepEqual(parse(what), {
|
||||
proto: proto,
|
||||
expect(parsed).toEqual({
|
||||
proto,
|
||||
path: host,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addTest('4873', 'http', 'localhost', '4873');
|
||||
addTest(':4873', 'http', 'localhost', '4873');
|
||||
addTest('blah:4873', 'http', 'blah', '4873');
|
||||
addTest('http://:4873', 'http', 'localhost', '4873');
|
||||
addTest('https::4873', 'https', 'localhost', '4873');
|
||||
addTest('https:blah:4873', 'https', 'blah', '4873');
|
||||
addTest('https://blah:4873/', 'https', 'blah', '4873');
|
||||
addTest('[::1]:4873', 'http', '::1', '4873');
|
||||
addTest('https:[::1]:4873', 'https', '::1', '4873');
|
||||
addTest(DEFAULT_PORT, 'http', DEFAULT_DOMAIN, DEFAULT_PORT);
|
||||
addTest(':4873', 'http', DEFAULT_DOMAIN, DEFAULT_PORT);
|
||||
addTest('blah:4873', 'http', 'blah', DEFAULT_PORT);
|
||||
addTest('http://:4873', 'http', DEFAULT_DOMAIN, DEFAULT_PORT);
|
||||
addTest('https::4873', 'https', DEFAULT_DOMAIN, DEFAULT_PORT);
|
||||
addTest('https:blah:4873', 'https', 'blah', DEFAULT_PORT);
|
||||
addTest('https://blah:4873/', 'https', 'blah', DEFAULT_PORT);
|
||||
addTest('[::1]:4873', 'http', '::1', DEFAULT_PORT);
|
||||
addTest('https:[::1]:4873', 'https', '::1', DEFAULT_PORT);
|
||||
|
||||
addTest('unix:/tmp/foo.sock', 'http', '/tmp/foo.sock');
|
||||
addTest('http:unix:foo.sock', 'http', 'foo.sock');
|
||||
addTest('https://unix:foo.sock', 'https', 'foo.sock');
|
||||
addTest('https://unix:foo.sock:34', 'https', 'foo.sock:34');
|
||||
addTest('http://foo.sock:34', 'http', 'foo.sock', '34');
|
||||
|
||||
addTest('blah', null);
|
||||
addTest('blah://4873', null);
|
||||
|
18
test/unit/api/mock.js
Normal file
18
test/unit/api/mock.js
Normal file
@ -0,0 +1,18 @@
|
||||
// @flow
|
||||
|
||||
import path from 'path';
|
||||
import {DOMAIN_SERVERS} from '../../functional/config.functional';
|
||||
import VerdaccioProcess from '../../lib/server_process';
|
||||
import {VerdaccioConfig} from '../../lib/verdaccio-server';
|
||||
import Server from '../../lib/server';
|
||||
import type {IServerBridge} from '../../types';
|
||||
|
||||
export function mockServer(port: number) {
|
||||
const pathStore = path.join(__dirname, '../partials');
|
||||
const verdaccioConfig = new VerdaccioConfig(
|
||||
path.join(pathStore, '/mock-store'),
|
||||
path.join(pathStore, '/config-unit-test.yaml'), `http://${DOMAIN_SERVERS}:${port}/`, port);
|
||||
const server: IServerBridge = new Server(verdaccioConfig.domainPath);
|
||||
|
||||
return new VerdaccioProcess(verdaccioConfig, server, false, false, false);
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import _ from 'lodash';
|
||||
import httpMocks from 'node-mocks-http';
|
||||
import path from 'path';
|
||||
// $FlowFixMe
|
||||
import configExample from '../partials/config/index';
|
||||
import AppConfig from '../../../src/lib/config';
|
||||
@ -10,74 +10,85 @@ import {setup} from '../../../src/lib/logger';
|
||||
|
||||
import type {Config} from '@verdaccio/types';
|
||||
import type {IStorageHandler} from '../../../types/index';
|
||||
import {API_ERROR} from '../../../src/lib/constants';
|
||||
import {API_ERROR, HTTP_STATUS} from '../../../src/lib/constants';
|
||||
import {mockServer} from './mock';
|
||||
import {DOMAIN_SERVERS} from '../../functional/config.functional';
|
||||
|
||||
setup(configExample.logs);
|
||||
|
||||
const generateStorage = async function() {
|
||||
const storageConfig = _.clone(configExample);
|
||||
const storage = `./unit/partials/store/test-storage-store.spec`;
|
||||
const mockServerPort: number = 55548;
|
||||
const generateStorage = async function(port = mockServerPort, configDefault = configExample) {
|
||||
const storageConfig = _.clone(configDefault);
|
||||
const storage = path.join(__dirname, '../partials/store/test-storage-store.spec');
|
||||
storageConfig.self_path = __dirname;
|
||||
storageConfig.storage = storage;
|
||||
const config: Config = new AppConfig(storageConfig);
|
||||
storageConfig.uplinks = {
|
||||
npmjs: {
|
||||
url: `http://${DOMAIN_SERVERS}:${port}`
|
||||
}
|
||||
};
|
||||
const config: Config = new AppConfig(storageConfig);
|
||||
const store: IStorageHandler = new Storage(config);
|
||||
await store.init(config);
|
||||
|
||||
return store;
|
||||
return store;
|
||||
}
|
||||
|
||||
describe('StorageTest', () => {
|
||||
let mockRegistry;
|
||||
|
||||
jest.setTimeout(10000);
|
||||
beforeAll(async () => {
|
||||
mockRegistry = await mockServer(mockServerPort).init();
|
||||
});
|
||||
|
||||
beforeAll(async (done)=> {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
var request = httpMocks.createRequest({
|
||||
method: 'GET',
|
||||
url: '/react',
|
||||
params: {}
|
||||
});
|
||||
afterAll(function(done) {
|
||||
mockRegistry[0].stop();
|
||||
done();
|
||||
});
|
||||
|
||||
storage.getPackage({
|
||||
name: 'react',
|
||||
req: request,
|
||||
callback: () => {
|
||||
const stream = storage.getTarball('react', 'react-16.1.0.tgz');
|
||||
stream.on('content-length', function(content) {
|
||||
if (content) {
|
||||
expect(content).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('should be defined', async () => {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
test('should be defined', async () => {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
|
||||
expect(storage).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
test('should fetch from uplink react metadata from nmpjs', async (done) => {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
describe('test _syncUplinksMetadata', () => {
|
||||
test('should fetch from uplink jquery metadata from registry', async (done) => {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
|
||||
// $FlowFixMe
|
||||
storage._syncUplinksMetadata('react', null, {}, (err, metadata, errors) => {
|
||||
expect(metadata).toBeInstanceOf(Object);
|
||||
done();
|
||||
});
|
||||
});
|
||||
// $FlowFixMe
|
||||
storage._syncUplinksMetadata('jquery', null, {}, (err, metadata, errors) => {
|
||||
expect(err).toBeNull();
|
||||
expect(metadata).toBeDefined();
|
||||
expect(metadata).toBeInstanceOf(Object);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should fails on fetch from uplink metadata from nmpjs', async (done) => {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
test('should fails on fetch from uplink non existing from registry', async (done) => {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
|
||||
// $FlowFixMe
|
||||
storage._syncUplinksMetadata('@verdaccio/404', null, {}, (err, metadata, errors) => {
|
||||
expect(errors).toBeInstanceOf(Array);
|
||||
expect(errors[0][0].statusCode).toBe(404);
|
||||
expect(errors[0][0].message).toMatch(API_ERROR.NOT_PACKAGE_UPLINK);
|
||||
done();
|
||||
});
|
||||
// $FlowFixMe
|
||||
storage._syncUplinksMetadata('@verdaccio/404', null, {}, (err, metadata, errors) => {
|
||||
expect(err).not.toBeNull();
|
||||
expect(errors).toBeInstanceOf(Array);
|
||||
expect(errors[0][0].statusCode).toBe(HTTP_STATUS.NOT_FOUND);
|
||||
expect(errors[0][0].message).toMatch(API_ERROR.NOT_PACKAGE_UPLINK);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should fails on fetch from uplink corrupted pkg from registry', async (done) => {
|
||||
const storage: IStorageHandler = await generateStorage();
|
||||
|
||||
// $FlowFixMe
|
||||
storage._syncUplinksMetadata('corrupted-package', null, {}, (err, metadata, errors) => {
|
||||
expect(err).not.toBeNull();
|
||||
expect(errors).toBeInstanceOf(Array);
|
||||
expect(errors[0][0].statusCode).toBe(HTTP_STATUS.INTERNAL_ERROR);
|
||||
expect(errors[0][0].message).toMatch(API_ERROR.BAD_STATUS_CODE);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -8,15 +8,17 @@ import {setup} from '../../../src/lib/logger';
|
||||
|
||||
import type {Config, UpLinkConf} from '@verdaccio/types';
|
||||
import type {IProxy} from '../../../types/index';
|
||||
import {API_ERROR, DEFAULT_REGISTRY} from "../../../src/lib/constants";
|
||||
import {API_ERROR} from "../../../src/lib/constants";
|
||||
import {mockServer} from './mock';
|
||||
import {DOMAIN_SERVERS} from '../../functional/config.functional';
|
||||
|
||||
setup([]);
|
||||
|
||||
describe('UpStorge', () => {
|
||||
jest.setTimeout(10000);
|
||||
|
||||
const mockServerPort: number = 55547;
|
||||
let mockRegistry;
|
||||
const uplinkDefault = {
|
||||
url: DEFAULT_REGISTRY
|
||||
url: `http://0.0.0.0:${mockServerPort}`
|
||||
};
|
||||
const generateProxy = (config: UpLinkConf = uplinkDefault) => {
|
||||
const appConfig: Config = new AppConfig(configExample);
|
||||
@ -24,6 +26,15 @@ describe('UpStorge', () => {
|
||||
return new ProxyStorage(config, appConfig);
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
mockRegistry = await mockServer(mockServerPort).init();
|
||||
});
|
||||
|
||||
afterAll(function(done) {
|
||||
mockRegistry[0].stop();
|
||||
done();
|
||||
});
|
||||
|
||||
test('should be defined', () => {
|
||||
const proxy = generateProxy();
|
||||
|
||||
@ -69,7 +80,7 @@ describe('UpStorge', () => {
|
||||
describe('UpStorge::fetchTarball', () => {
|
||||
test('should fetch a tarball from uplink', (done) => {
|
||||
const proxy = generateProxy();
|
||||
const tarball:string = 'https://registry.npmjs.org/aaa/-/aaa-0.0.1.tgz';
|
||||
const tarball:string = `http://${DOMAIN_SERVERS}:${mockServerPort}/jquery/-/jquery-1.5.1.tgz`;
|
||||
const stream = proxy.fetchTarball(tarball);
|
||||
|
||||
stream.on('error', function(err) {
|
||||
@ -86,7 +97,7 @@ describe('UpStorge', () => {
|
||||
|
||||
test('should throw a 404 on fetch a tarball from uplink', (done) => {
|
||||
const proxy = generateProxy();
|
||||
const tarball:string = 'https://google.es/aaa/-/aaa-0.0.1.tgz';
|
||||
const tarball:string = `http://${DOMAIN_SERVERS}:${mockServerPort}/jquery/-/no-exist-1.5.1.tgz`;
|
||||
const stream = proxy.fetchTarball(tarball);
|
||||
|
||||
stream.on('error', function(err) {
|
||||
|
@ -2,11 +2,14 @@
|
||||
|
||||
import _ from 'lodash';
|
||||
import smartRequest, {PromiseAssert} from '../../lib/request';
|
||||
import {mockServer} from '../api/mock';
|
||||
import {HTTP_STATUS} from '../../../src/lib/constants';
|
||||
import type {IRequestPromise} from '../../types';
|
||||
|
||||
describe('Request Functional', () => {
|
||||
|
||||
const restTest: string = "http://registry.npmjs.org/aaa";
|
||||
const mockServerPort = 55547;
|
||||
const restTest: string = `http://localhost:${55547}/jquery`;
|
||||
let mockRegistry;
|
||||
|
||||
describe('Request Functional', () => {
|
||||
test('PromiseAssert', () => {
|
||||
@ -26,6 +29,15 @@ describe('Request Functional', () => {
|
||||
});
|
||||
describe('smartRequest Rest', () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
mockRegistry = await mockServer(mockServerPort).init();
|
||||
});
|
||||
|
||||
afterAll(function(done) {
|
||||
mockRegistry[0].stop();
|
||||
done();
|
||||
});
|
||||
|
||||
test('basic rest', (done) => {
|
||||
const options: any = {
|
||||
url: restTest,
|
||||
@ -46,8 +58,8 @@ describe('Request Functional', () => {
|
||||
method: 'GET'
|
||||
};
|
||||
// $FlowFixMe
|
||||
smartRequest(options).status(200).then((result)=> {
|
||||
expect(JSON.parse(result).name).toBe('aaa');
|
||||
smartRequest(options).status(HTTP_STATUS.OK).then((result)=> {
|
||||
expect(JSON.parse(result).name).toBe('jquery');
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
25
test/unit/partials/config-unit-test.yaml
Normal file
25
test/unit/partials/config-unit-test.yaml
Normal file
@ -0,0 +1,25 @@
|
||||
storage: ./mock-store
|
||||
|
||||
web:
|
||||
enable: false
|
||||
title: verdaccio-server-unit-test
|
||||
|
||||
auth:
|
||||
auth-memory:
|
||||
users:
|
||||
test:
|
||||
name: test
|
||||
password: test
|
||||
|
||||
logs:
|
||||
- {type: stdout, format: pretty, level: warn}
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: none
|
||||
'**':
|
||||
access: $all
|
||||
publish: none
|
||||
|
||||
_debug: true
|
@ -1,10 +1,11 @@
|
||||
import path from 'path';
|
||||
import {DEFAULT_REGISTRY} from '../../../../src/lib/constants';
|
||||
|
||||
const config = {
|
||||
storage: path.join(__dirname, '../store/access-storage'),
|
||||
uplinks: {
|
||||
'npmjs': {
|
||||
'url': 'https://registry.npmjs.org/'
|
||||
'url': DEFAULT_REGISTRY
|
||||
}
|
||||
},
|
||||
packages: {
|
||||
|
@ -5,48 +5,54 @@ const config = {
|
||||
storage: path.join(__dirname, '../store/test-storage'),
|
||||
uplinks: {
|
||||
'npmjs': {
|
||||
'url': 'https://registry.npmjs.org/'
|
||||
'url': 'http://localhost:4873/'
|
||||
}
|
||||
},
|
||||
packages: {
|
||||
'@*/*': {
|
||||
allow_access: '$all',
|
||||
allow_publish: '$all',
|
||||
access: '$all',
|
||||
publish: '$all',
|
||||
proxy: 'npmjs'
|
||||
},
|
||||
|
||||
'forbidden-place': {
|
||||
allow_access: 'nobody',
|
||||
allow_publish: '$all'
|
||||
access: 'nobody',
|
||||
publish: '$all'
|
||||
},
|
||||
|
||||
'react': {
|
||||
allow_access: '$all',
|
||||
allow_publish: '$all',
|
||||
access: '$all',
|
||||
publish: '$all',
|
||||
proxy: 'npmjs'
|
||||
},
|
||||
|
||||
'corrupted-package': {
|
||||
access: '$all',
|
||||
publish: '$all',
|
||||
proxy: 'npmjs'
|
||||
},
|
||||
|
||||
'jquery': {
|
||||
allow_access: '$all',
|
||||
allow_publish: '$all',
|
||||
access: '$all',
|
||||
publish: '$all',
|
||||
proxy: 'npmjs'
|
||||
},
|
||||
'auth-package': {
|
||||
allow_access: '$authenticated',
|
||||
allow_publish: '$authenticated'
|
||||
access: '$authenticated',
|
||||
publish: '$authenticated'
|
||||
},
|
||||
'vue': {
|
||||
allow_access: '$authenticated',
|
||||
allow_publish: '$authenticated',
|
||||
access: '$authenticated',
|
||||
publish: '$authenticated',
|
||||
proxy: 'npmjs'
|
||||
},
|
||||
'*': {
|
||||
allow_access: '$all',
|
||||
allow_publish: '$all'
|
||||
access: '$all',
|
||||
publish: '$all'
|
||||
},
|
||||
},
|
||||
logs: [
|
||||
{type: 'stdout', format: 'pretty', level: 'fatal'},
|
||||
{type: 'stdout', format: 'pretty', level: 'warn'},
|
||||
],
|
||||
};
|
||||
|
||||
|
1
test/unit/partials/mock-store/.sinopia-db.json
Normal file
1
test/unit/partials/mock-store/.sinopia-db.json
Normal file
@ -0,0 +1 @@
|
||||
{"list":[],"secret":"12c39716d7c75d50b9988255fff332e1b066bad04e10fff9cba42434bc5fe19e"}
|
12
test/unit/partials/mock-store/corrupted-package/package.json
Normal file
12
test/unit/partials/mock-store/corrupted-package/package.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "corrupted-package"
|
||||
"version": {},
|
||||
"dist-tags": {},
|
||||
"_distfiles": {},
|
||||
"_attachments": {},
|
||||
"_uplinks": {},
|
||||
"time": {},
|
||||
"_rev": "0-0000000000000000",
|
||||
"readme": "",
|
||||
"versions": {}
|
||||
}
|
BIN
test/unit/partials/mock-store/jquery/jquery-1.5.1.tgz
Normal file
BIN
test/unit/partials/mock-store/jquery/jquery-1.5.1.tgz
Normal file
Binary file not shown.
4919
test/unit/partials/mock-store/jquery/package.json
Normal file
4919
test/unit/partials/mock-store/jquery/package.json
Normal file
File diff suppressed because it is too large
Load Diff
25169
test/unit/partials/mock-store/vue/package.json
Normal file
25169
test/unit/partials/mock-store/vue/package.json
Normal file
File diff suppressed because one or more lines are too long
@ -5,6 +5,7 @@ import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import PackageDetail from '../../../../src/webui/src/components/PackageDetail/index';
|
||||
import Readme from '../../../../src/webui/src/components/Readme/index';
|
||||
import {WEB_TITLE} from '../../../../src/lib/constants';
|
||||
|
||||
console.error = jest.fn();
|
||||
|
||||
@ -17,11 +18,11 @@ describe('<PackageDetail /> component', () => {
|
||||
it('should load the component', () => {
|
||||
const props = {
|
||||
readMe: 'Test readme',
|
||||
package: 'Verdaccio'
|
||||
package: WEB_TITLE
|
||||
};
|
||||
const wrapper = shallow(<PackageDetail {...props} />);
|
||||
|
||||
expect(wrapper.find('h1').text()).toEqual('Verdaccio');
|
||||
expect(wrapper.find('h1').text()).toEqual(WEB_TITLE);
|
||||
expect(
|
||||
wrapper
|
||||
.find(Readme)
|
||||
|
Loading…
Reference in New Issue
Block a user