@verdaccio/web 6.0.0-6-next.26 → 6.0.0-6-next.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,66 +1,71 @@
1
1
  {
2
- "name": "@verdaccio/web",
3
- "version": "6.0.0-6-next.26",
4
- "description": "web ui middleware",
5
- "main": "./build/index.js",
6
- "types": "build/index.d.ts",
7
- "repository": {
8
- "type": "https",
9
- "url": "https://github.com/verdaccio/verdaccio"
10
- },
11
- "keywords": [
12
- "private",
13
- "package",
14
- "repository",
15
- "registry",
16
- "enterprise",
17
- "modules",
18
- "proxy",
19
- "server",
20
- "verdaccio"
21
- ],
22
- "engines": {
23
- "node": ">=14",
24
- "npm": ">=6"
25
- },
26
- "license": "MIT",
27
- "dependencies": {
28
- "@verdaccio/auth": "6.0.0-6-next.20",
29
- "@verdaccio/core": "6.0.0-6-next.4",
30
- "@verdaccio/config": "6.0.0-6-next.12",
31
- "@verdaccio/loaders": "6.0.0-6-next.11",
32
- "@verdaccio/logger": "6.0.0-6-next.10",
33
- "@verdaccio/middleware": "6.0.0-6-next.20",
34
- "@verdaccio/readme": "11.0.0-6-next.4",
35
- "@verdaccio/store": "6.0.0-6-next.20",
36
- "@verdaccio/tarball": "11.0.0-6-next.11",
37
- "@verdaccio/url": "11.0.0-6-next.8",
38
- "@verdaccio/utils": "6.0.0-6-next.10",
39
- "body-parser": "1.19.1",
40
- "debug": "4.3.3",
41
- "express": "4.17.2",
42
- "lodash": "4.17.21",
43
- "lru-cache": "6.0.0"
44
- },
45
- "devDependencies": {
46
- "@types/node": "16.11.21",
47
- "@verdaccio/types": "11.0.0-6-next.10",
48
- "node-html-parser": "4.1.5",
49
- "supertest": "6.2.2",
50
- "verdaccio-auth-memory": "11.0.0-6-next.7",
51
- "verdaccio-memory": "11.0.0-6-next.8"
52
- },
53
- "funding": {
54
- "type": "opencollective",
55
- "url": "https://opencollective.com/verdaccio"
56
- },
57
- "scripts": {
58
- "clean": "rimraf ./build",
59
- "test": "cross-env NODE_ENV=test BABEL_ENV=test jest",
60
- "type-check": "tsc --noEmit -p tsconfig.build.json",
61
- "build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
62
- "build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
63
- "watch": "pnpm build:js -- --watch",
64
- "build": "pnpm run build:js && pnpm run build:types"
65
- }
66
- }
2
+ "name": "@verdaccio/web",
3
+ "version": "6.0.0-6-next.29",
4
+ "description": "web ui middleware",
5
+ "main": "./build/index.js",
6
+ "types": "build/index.d.ts",
7
+ "repository": {
8
+ "type": "https",
9
+ "url": "https://github.com/verdaccio/verdaccio"
10
+ },
11
+ "keywords": [
12
+ "private",
13
+ "package",
14
+ "repository",
15
+ "registry",
16
+ "enterprise",
17
+ "modules",
18
+ "proxy",
19
+ "server",
20
+ "verdaccio"
21
+ ],
22
+ "engines": {
23
+ "node": ">=14",
24
+ "npm": ">=6"
25
+ },
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "@verdaccio/auth": "6.0.0-6-next.22",
29
+ "@verdaccio/core": "6.0.0-6-next.5",
30
+ "@verdaccio/config": "6.0.0-6-next.14",
31
+ "@verdaccio/loaders": "6.0.0-6-next.12",
32
+ "@verdaccio/logger": "6.0.0-6-next.11",
33
+ "@verdaccio/middleware": "6.0.0-6-next.22",
34
+ "@verdaccio/readme": "11.0.0-6-next.4",
35
+ "@verdaccio/store": "6.0.0-6-next.22",
36
+ "@verdaccio/tarball": "11.0.0-6-next.12",
37
+ "@verdaccio/url": "11.0.0-6-next.9",
38
+ "@verdaccio/utils": "6.0.0-6-next.11",
39
+ "body-parser": "1.19.1",
40
+ "debug": "4.3.3",
41
+ "express": "4.17.2",
42
+ "lodash": "4.17.21",
43
+ "lru-cache": "6.0.0"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "16.11.21",
47
+ "@verdaccio/types": "11.0.0-6-next.12",
48
+ "@verdaccio/test-helper": "1.1.0-6-next.1",
49
+ "@verdaccio/api": "6.0.0-6-next.25",
50
+ "node-html-parser": "4.1.5",
51
+ "supertest": "6.2.2",
52
+ "nock": "13.2.2",
53
+ "jsdom": "20.0.0",
54
+ "undici": "4.15.0",
55
+ "verdaccio-auth-memory": "11.0.0-6-next.8",
56
+ "verdaccio-memory": "11.0.0-6-next.10"
57
+ },
58
+ "funding": {
59
+ "type": "opencollective",
60
+ "url": "https://opencollective.com/verdaccio"
61
+ },
62
+ "scripts": {
63
+ "clean": "rimraf ./build",
64
+ "test": "jest",
65
+ "type-check": "tsc --noEmit -p tsconfig.build.json",
66
+ "build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
67
+ "build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
68
+ "watch": "pnpm build:js -- --watch",
69
+ "build": "pnpm run build:js && pnpm run build:types"
70
+ }
71
+ }
package/src/api/readme.ts CHANGED
@@ -39,12 +39,11 @@ function addReadmeWebApi(storage: Storage, auth: IAuth): Router {
39
39
  uplinksLook: true,
40
40
  req,
41
41
  callback: function (err, info): void {
42
- debug('readme plg %o', info?.name);
42
+ debug('readme pkg %o', info?.name);
43
+ res.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8);
43
44
  if (err) {
44
45
  return next(err);
45
46
  }
46
-
47
- res.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8);
48
47
  try {
49
48
  next(parseReadme(info.name, info.readme));
50
49
  } catch {
package/src/api/search.ts CHANGED
@@ -1,55 +1,39 @@
1
1
  import buildDebug from 'debug';
2
2
  import { Router } from 'express';
3
+ import _ from 'lodash';
4
+ import { URLSearchParams } from 'url';
3
5
 
4
6
  import { IAuth } from '@verdaccio/auth';
5
- import { DIST_TAGS } from '@verdaccio/core';
6
- import { SearchInstance } from '@verdaccio/store';
7
+ import { errorUtils, searchUtils } from '@verdaccio/core';
8
+ import { SearchQuery } from '@verdaccio/core/src/search-utils';
7
9
  import { Storage } from '@verdaccio/store';
8
- import { Package } from '@verdaccio/types';
10
+ import { Manifest } from '@verdaccio/types';
9
11
 
10
12
  import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from './package';
11
13
 
12
14
  const debug = buildDebug('verdaccio:web:api:search');
13
15
 
14
- function addSearchWebApi(storage: Storage, auth: IAuth): Router {
15
- const router = Router(); /* eslint new-cap: 0 */
16
- const getPackageInfo = async function (name, remoteUser): Promise<any> {
17
- return new Promise((resolve, reject) => {
18
- debug('searching for %o', name);
19
- try {
20
- // @ts-ignore
21
- storage.getPackage({
22
- name,
23
- uplinksLook: false,
24
- callback: (err, pkg: Package): void => {
25
- debug('callback get package err %o', err?.message);
26
- if (!err && pkg) {
27
- debug('valid package %o', pkg?.name);
28
- auth.allow_access(
29
- { packageName: pkg.name },
30
- remoteUser,
31
- function (err, allowed): void {
32
- debug('is allowed %o', allowed);
33
- if (err || !allowed) {
34
- debug('deny access');
35
- reject(err);
36
- return;
37
- }
38
- debug('access succeed');
39
- resolve(pkg.versions[pkg[DIST_TAGS].latest]);
40
- }
41
- );
42
- } else {
43
- reject(err);
44
- }
45
- },
46
- });
47
- } catch (err: any) {
48
- reject(err);
16
+ function checkAccess(pkg: any, auth: any, remoteUser): Promise<Manifest | null> {
17
+ return new Promise((resolve, reject) => {
18
+ auth.allow_access({ packageName: pkg?.package?.name }, remoteUser, function (err, allowed) {
19
+ if (err) {
20
+ if (err.status && String(err.status).match(/^4\d\d$/)) {
21
+ // auth plugin returns 4xx user error,
22
+ // that's equivalent of !allowed basically
23
+ allowed = false;
24
+ return resolve(null);
25
+ } else {
26
+ reject(err);
27
+ }
28
+ } else {
29
+ return resolve(allowed ? pkg : null);
49
30
  }
50
31
  });
51
- };
32
+ });
33
+ }
52
34
 
35
+ function addSearchWebApi(storage: Storage, auth: IAuth): Router {
36
+ const router = Router(); /* eslint new-cap: 0 */
53
37
  router.get(
54
38
  '/search/:anything',
55
39
  async function (
@@ -57,22 +41,47 @@ function addSearchWebApi(storage: Storage, auth: IAuth): Router {
57
41
  res: $ResponseExtend,
58
42
  next: $NextFunctionVer
59
43
  ): Promise<void> {
60
- const results = SearchInstance.query(req.params.anything);
61
- debug('search results %o', results);
62
- if (results.length > 0) {
63
- let packages: Package[] = [];
64
- for (let result of results) {
65
- try {
66
- const pkg = await getPackageInfo(result.ref, req.remote_user);
67
- debug('package found %o', result.ref);
68
- packages.push(pkg);
69
- } catch (err: any) {
70
- debug('search for %o failed err %o', result.ref, err?.message);
71
- }
72
- }
73
- next(packages);
74
- } else {
75
- next([]);
44
+ try {
45
+ let data;
46
+ const abort = new AbortController();
47
+ req.on('aborted', () => {
48
+ debug('search web aborted');
49
+ abort.abort();
50
+ });
51
+ const text: string = (req.params.anything as string) ?? '';
52
+ // These values are declared as optimal by npm cli
53
+ // FUTURE: could be overwritten by ui settings.
54
+ const size = 20;
55
+ const from = 0;
56
+ const query: SearchQuery = {
57
+ from: 0,
58
+ maintenance: 0.5,
59
+ popularity: 0.98,
60
+ quality: 0.65,
61
+ size: 20,
62
+ text,
63
+ };
64
+ // @ts-ignore
65
+ const urlParams = new URLSearchParams(query);
66
+ debug('search web init');
67
+ data = await storage.searchManager?.search({
68
+ query,
69
+ url: `/-/v1/search?${urlParams.toString()}`,
70
+ abort,
71
+ });
72
+ const checkAccessPromises: searchUtils.SearchItemPkg[] = await Promise.all(
73
+ data.map((pkgItem) => {
74
+ return checkAccess(pkgItem, auth, req.remote_user);
75
+ })
76
+ );
77
+
78
+ const final: searchUtils.SearchItemPkg[] = checkAccessPromises
79
+ .filter((i) => !_.isNull(i))
80
+ .slice(from, size);
81
+
82
+ next(final);
83
+ } catch (err: any) {
84
+ next(errorUtils.getInternalError(err.message));
76
85
  }
77
86
  }
78
87
  );
@@ -5,7 +5,6 @@ import path from 'path';
5
5
 
6
6
  import { HTTP_STATUS } from '@verdaccio/core';
7
7
  import { loadPlugin } from '@verdaccio/loaders';
8
- import { SearchInstance } from '@verdaccio/store';
9
8
  import { isURLhasValidProtocol } from '@verdaccio/url';
10
9
 
11
10
  import renderHTML from '../renderHTML';
@@ -40,10 +39,9 @@ const sendFileCallback = (next) => (err) => {
40
39
  }
41
40
  };
42
41
 
43
- export function renderWebMiddleware(config, auth, storage): any {
42
+ export function renderWebMiddleware(config, auth): any {
44
43
  const { staticPath, manifest, manifestFiles } = require('@verdaccio/ui-theme')();
45
44
  debug('static path %o', staticPath);
46
- SearchInstance.configureStorage(storage);
47
45
 
48
46
  /* eslint new-cap:off */
49
47
  const router = express.Router();
@@ -3,7 +3,6 @@ import { Router } from 'express';
3
3
 
4
4
  import { IAuth } from '@verdaccio/auth';
5
5
  import { match, validateName, validatePackage } from '@verdaccio/middleware';
6
- import { SearchInstance } from '@verdaccio/store';
7
6
  import { Storage } from '@verdaccio/store';
8
7
  import { Config } from '@verdaccio/types';
9
8
 
@@ -13,7 +12,6 @@ import { setSecurityWebHeaders } from './security';
13
12
  export function webAPI(config: Config, auth: IAuth, storage: Storage): Router {
14
13
  // eslint-disable-next-line new-cap
15
14
  const route = Router();
16
- SearchInstance.configureStorage(storage);
17
15
  // validate all of these params as a package name
18
16
  // this might be too harsh, so ask if it causes trouble=
19
17
  route.param('package', validatePackage);
package/src/renderHTML.ts CHANGED
@@ -4,6 +4,7 @@ import { URL } from 'url';
4
4
 
5
5
  import { WEB_TITLE } from '@verdaccio/config';
6
6
  import { HEADERS } from '@verdaccio/core';
7
+ import { TemplateUIOptions } from '@verdaccio/types';
7
8
  import { getPublicUrl } from '@verdaccio/url';
8
9
 
9
10
  import renderTemplate from './template';
@@ -25,6 +26,9 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
25
26
  const base = getPublicUrl(config?.url_prefix, req);
26
27
  const basename = new URL(base).pathname;
27
28
  const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;
29
+ const needHtmlCache = [undefined, null].includes(config?.web?.html_cache)
30
+ ? true
31
+ : config.web.html_cache;
28
32
  const darkMode = config?.web?.darkMode ?? false;
29
33
  const title = config?.web?.title ?? WEB_TITLE;
30
34
  const login = hasLogin(config);
@@ -32,8 +36,21 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
32
36
  const logoURI = config?.web?.logo ?? '';
33
37
  const pkgManagers = config?.web?.pkgManagers ?? ['yarn', 'pnpm', 'npm'];
34
38
  const version = pkgJSON.version;
39
+ const flags = {
40
+ ...config.flags,
41
+ };
35
42
  const primaryColor = validatePrimaryColor(config?.web?.primary_color) ?? '#4b5e40';
36
- const { scriptsBodyAfter, metaScripts, scriptsbodyBefore } = Object.assign(
43
+ const {
44
+ scriptsBodyAfter,
45
+ metaScripts,
46
+ scriptsbodyBefore,
47
+ showInfo,
48
+ showSettings,
49
+ showThemeSwitch,
50
+ showFooter,
51
+ showSearch,
52
+ showDownloadTarball,
53
+ } = Object.assign(
37
54
  {},
38
55
  {
39
56
  scriptsBodyAfter: [],
@@ -42,7 +59,13 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
42
59
  },
43
60
  config?.web
44
61
  );
45
- const options = {
62
+ const options: TemplateUIOptions = {
63
+ showInfo,
64
+ showSettings,
65
+ showThemeSwitch,
66
+ showFooter,
67
+ showSearch,
68
+ showDownloadTarball,
46
69
  darkMode,
47
70
  url_prefix,
48
71
  basename,
@@ -50,6 +73,7 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
50
73
  primaryColor,
51
74
  version,
52
75
  logoURI,
76
+ flags,
53
77
  login,
54
78
  pkgManagers,
55
79
  title,
@@ -61,10 +85,7 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
61
85
 
62
86
  try {
63
87
  webPage = cache.get('template');
64
-
65
88
  if (!webPage) {
66
- debug('web options %o', options);
67
- debug('web manifestFiles %o', manifestFiles);
68
89
  webPage = renderTemplate(
69
90
  {
70
91
  manifest: manifestFiles ?? defaultManifestFiles,
@@ -75,9 +96,10 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
75
96
  },
76
97
  manifest
77
98
  );
78
- debug('template :: %o', webPage);
79
- cache.set('template', webPage);
80
- debug('set template cache');
99
+ if (needHtmlCache) {
100
+ cache.set('template', webPage);
101
+ debug('set template cache');
102
+ }
81
103
  } else {
82
104
  debug('reuse template cache');
83
105
  }
@@ -86,5 +108,5 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
86
108
  }
87
109
  res.setHeader('Content-Type', HEADERS.TEXT_HTML);
88
110
  res.send(webPage);
89
- debug('render web');
111
+ debug('web rendered');
90
112
  }
@@ -10,7 +10,7 @@ export type AuthorAvatar = Author & { avatar?: string };
10
10
  const debug = buildDebug('verdaccio:web:utils');
11
11
 
12
12
  export function validatePrimaryColor(primaryColor) {
13
- const isHex = /^#+([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/i.test(primaryColor);
13
+ const isHex = /^#([0-9A-F]{3}){1,2}$/i.test(primaryColor);
14
14
  if (!isHex) {
15
15
  debug('invalid primary color %o', primaryColor);
16
16
  return;
@@ -7,7 +7,7 @@ export default (config, auth, storage) => {
7
7
  // eslint-disable-next-line new-cap
8
8
  const app = express.Router();
9
9
  // load application
10
- app.use('/', renderWebMiddleware(config, auth, storage));
10
+ app.use('/', renderWebMiddleware(config, auth));
11
11
  // web endpoints, search, packages, etc
12
12
  app.use('/-/verdaccio/', webAPI(config, auth, storage));
13
13
  return app;
@@ -3,7 +3,7 @@ import supertest from 'supertest';
3
3
 
4
4
  import { HEADERS, HEADER_TYPE, HTTP_STATUS } from '@verdaccio/core';
5
5
  import { setup } from '@verdaccio/logger';
6
- import { IGetPackageOptions } from '@verdaccio/store';
6
+ import { publishVersion } from '@verdaccio/test-helper';
7
7
 
8
8
  import { NOT_README_FOUND } from '../src/api/readme';
9
9
  import { initializeServer } from './helper';
@@ -13,30 +13,6 @@ setup([]);
13
13
  const mockManifest = jest.fn();
14
14
  jest.mock('@verdaccio/ui-theme', () => mockManifest());
15
15
 
16
- jest.mock('@verdaccio/store', () => ({
17
- Storage: class {
18
- public init() {
19
- return Promise.resolve();
20
- }
21
- public getPackage({ name, callback }: IGetPackageOptions) {
22
- callback(null, {
23
- name,
24
- ['dist-tags']: {
25
- latest: '1.0.0',
26
- },
27
- versions: {
28
- ['1.0.0']: {
29
- name,
30
- },
31
- },
32
- });
33
- }
34
- },
35
- SearchInstance: {
36
- configureStorage: () => {},
37
- },
38
- }));
39
-
40
16
  describe('readme api', () => {
41
17
  beforeAll(() => {
42
18
  mockManifest.mockReturnValue(() => ({
@@ -54,7 +30,20 @@ describe('readme api', () => {
54
30
  });
55
31
 
56
32
  test('should fetch readme scoped package', async () => {
57
- const response = await supertest(await initializeServer('default-test.yaml'))
33
+ const app = await initializeServer('default-test.yaml');
34
+ await publishVersion(app, '@scope/pk1-test', '1.0.0', { readme: 'my readme scoped' });
35
+ const response = await supertest(app)
36
+ .get('/-/verdaccio/data/package/readme/@scope/pk1-test')
37
+ .set('Accept', HEADERS.TEXT_PLAIN)
38
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8)
39
+ .expect(HTTP_STATUS.OK);
40
+ expect(response.text).toMatch('my readme scoped');
41
+ });
42
+
43
+ test('should fetch readme scoped package with not found message', async () => {
44
+ const app = await initializeServer('default-test.yaml');
45
+ await publishVersion(app, '@scope/pk1-test', '1.0.0', { readme: null });
46
+ const response = await supertest(app)
58
47
  .get('/-/verdaccio/data/package/readme/@scope/pk1-test')
59
48
  .set('Accept', HEADERS.TEXT_PLAIN)
60
49
  .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8)
@@ -63,7 +52,20 @@ describe('readme api', () => {
63
52
  });
64
53
 
65
54
  test('should fetch readme a package', async () => {
66
- const response = await supertest(await initializeServer('default-test.yaml'))
55
+ const app = await initializeServer('default-test.yaml');
56
+ await publishVersion(app, 'pk1-test', '1.0.0', { readme: 'my readme' });
57
+ const response = await supertest(app)
58
+ .get('/-/verdaccio/data/package/readme/pk1-test')
59
+ .set('Accept', HEADERS.TEXT_PLAIN)
60
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8)
61
+ .expect(HTTP_STATUS.OK);
62
+ expect(response.text).toMatch('my readme');
63
+ });
64
+
65
+ test('should fetch readme a package with not found message', async () => {
66
+ const app = await initializeServer('default-test.yaml');
67
+ await publishVersion(app, 'pk1-test', '1.0.0', { readme: null });
68
+ const response = await supertest(app)
67
69
  .get('/-/verdaccio/data/package/readme/pk1-test')
68
70
  .set('Accept', HEADERS.TEXT_PLAIN)
69
71
  .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8)
@@ -3,44 +3,15 @@ import supertest from 'supertest';
3
3
 
4
4
  import { HEADERS, HEADER_TYPE, HTTP_STATUS } from '@verdaccio/core';
5
5
  import { setup } from '@verdaccio/logger';
6
- import { IGetPackageOptions } from '@verdaccio/store';
6
+ import { publishVersion } from '@verdaccio/test-helper';
7
7
 
8
8
  import { initializeServer } from './helper';
9
9
 
10
10
  setup([]);
11
11
 
12
12
  const mockManifest = jest.fn();
13
- const mockQuery = jest.fn(() => [
14
- { ref: 'pkg1', score: 1 },
15
- { ref: 'pk2', score: 0.9 },
16
- ]);
17
13
  jest.mock('@verdaccio/ui-theme', () => mockManifest());
18
14
 
19
- jest.mock('@verdaccio/store', () => ({
20
- Storage: class {
21
- public init() {
22
- return Promise.resolve();
23
- }
24
- public getPackage({ name, callback }: IGetPackageOptions) {
25
- callback(null, {
26
- name,
27
- ['dist-tags']: {
28
- latest: '1.0.0',
29
- },
30
- versions: {
31
- ['1.0.0']: {
32
- name,
33
- },
34
- },
35
- });
36
- }
37
- },
38
- SearchInstance: {
39
- configureStorage: () => {},
40
- query: () => mockQuery(),
41
- },
42
- }));
43
-
44
15
  describe('test web server', () => {
45
16
  beforeAll(() => {
46
17
  mockManifest.mockReturnValue(() => ({
@@ -53,21 +24,24 @@ describe('test web server', () => {
53
24
  });
54
25
 
55
26
  afterEach(() => {
27
+ Date.now = jest.fn(() => new Date(Date.UTC(2017, 1, 14)).valueOf());
56
28
  jest.clearAllMocks();
57
29
  mockManifest.mockClear();
58
30
  });
59
31
 
60
- test('should OK to search api', async () => {
61
- const response = await supertest(await initializeServer('default-test.yaml'))
62
- .get('/-/verdaccio/data/search/keyword')
32
+ test('should find results to search api', async () => {
33
+ const app = await initializeServer('default-test.yaml');
34
+ await publishVersion(app, 'foo', '1.0.0');
35
+ const response = await supertest(app)
36
+ .get('/-/verdaccio/data/search/foo')
63
37
  .set('Accept', HEADERS.JSON_CHARSET)
64
38
  .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
65
39
  .expect(HTTP_STATUS.OK);
66
- expect(response.body).toHaveLength(2);
40
+ expect(response.body).toHaveLength(1);
41
+ // FUTURE: we can improve here matching the right outcome
67
42
  });
68
43
 
69
- test('should 404 to search api', async () => {
70
- mockQuery.mockReturnValue([]);
44
+ test('should found no results to search', async () => {
71
45
  const response = await supertest(await initializeServer('default-test.yaml'))
72
46
  .get('/-/verdaccio/data/search/notFound')
73
47
  .set('Accept', HEADERS.JSON_CHARSET)
@@ -76,19 +50,18 @@ describe('test web server', () => {
76
50
  expect(response.body).toHaveLength(0);
77
51
  });
78
52
 
79
- test('should fail search api', async () => {
80
- mockQuery.mockImplementation(() => {
81
- return [
82
- { ref: 'aa', score: 1 },
83
- { ref: 'bb', score: 0.8 },
84
- { ref: 'cc', score: 0.6 },
85
- ];
86
- });
53
+ // TODO: need a way to make this fail
54
+ test.skip('should fail search api', async () => {
87
55
  const response = await supertest(await initializeServer('default-test.yaml'))
88
- .get('/-/verdaccio/data/search/notFound')
56
+ .get('/-/verdaccio/data/search/thisWillFail')
89
57
  .set('Accept', HEADERS.JSON_CHARSET)
90
58
  .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
91
59
  .expect(HTTP_STATUS.OK);
92
60
  expect(response.body).toHaveLength(3);
93
61
  });
62
+
63
+ test.todo('search abort request');
64
+ // maybe these could be done in storage package to avoid have specifics on this level
65
+ test.todo('search allow request permissions');
66
+ test.todo('search query params, pagination etc');
94
67
  });