@verdaccio/api 6.0.0-6-next.23 → 6.0.0-6-next.26

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.
Files changed (64) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/build/dist-tags.js +40 -35
  3. package/build/dist-tags.js.map +1 -1
  4. package/build/index.js +1 -7
  5. package/build/index.js.map +1 -1
  6. package/build/package.js +33 -28
  7. package/build/package.js.map +1 -1
  8. package/build/ping.js.map +1 -1
  9. package/build/publish.d.ts +79 -22
  10. package/build/publish.js +89 -313
  11. package/build/publish.js.map +1 -1
  12. package/build/search.js.map +1 -1
  13. package/build/star.js +53 -54
  14. package/build/star.js.map +1 -1
  15. package/build/stars.js +6 -6
  16. package/build/stars.js.map +1 -1
  17. package/build/user.js +19 -1
  18. package/build/user.js.map +1 -1
  19. package/build/v1/profile.js.map +1 -1
  20. package/build/v1/search.js +2 -4
  21. package/build/v1/search.js.map +1 -1
  22. package/build/v1/token.js.map +1 -1
  23. package/build/whoami.js +11 -25
  24. package/build/whoami.js.map +1 -1
  25. package/jest.config.js +8 -1
  26. package/package.json +71 -69
  27. package/src/dist-tags.ts +63 -50
  28. package/src/index.ts +1 -6
  29. package/src/package.ts +35 -44
  30. package/src/publish.ts +115 -336
  31. package/src/star.ts +53 -52
  32. package/src/stars.ts +9 -11
  33. package/src/user.ts +19 -2
  34. package/src/v1/search.ts +3 -3
  35. package/src/whoami.ts +8 -24
  36. package/test/integration/_helper.ts +97 -53
  37. package/test/integration/config/distTag.yaml +25 -0
  38. package/test/integration/config/package.yaml +4 -9
  39. package/test/integration/config/ping.yaml +3 -7
  40. package/test/integration/config/publish.yaml +5 -11
  41. package/test/integration/config/search.yaml +29 -0
  42. package/test/integration/config/token.jwt.yaml +27 -0
  43. package/test/integration/config/token.yaml +19 -0
  44. package/test/integration/config/user.jwt.yaml +37 -0
  45. package/test/integration/config/user.yaml +9 -15
  46. package/test/integration/config/whoami.yaml +5 -12
  47. package/test/integration/distTag.spec.ts +76 -0
  48. package/test/integration/package.spec.ts +33 -76
  49. package/test/integration/ping.spec.ts +4 -3
  50. package/test/integration/publish.spec.ts +61 -26
  51. package/test/integration/search.spec.ts +126 -0
  52. package/test/integration/token.spec.ts +124 -0
  53. package/test/integration/user.jwt.spec.ts +87 -0
  54. package/test/integration/user.spec.ts +1 -0
  55. package/test/integration/whoami.spec.ts +21 -39
  56. package/test/unit/publish.disabled.ts +252 -0
  57. package/tsconfig.json +1 -1
  58. package/__mocks__/@verdaccio/logger/index.js +0 -21
  59. package/build/utils.d.ts +0 -7
  60. package/build/utils.js +0 -36
  61. package/build/utils.js.map +0 -1
  62. package/src/utils.ts +0 -25
  63. package/test/unit/__snapshots__/publish.spec.ts.snap +0 -49
  64. package/test/unit/publish.spec.ts +0 -300
package/src/user.ts CHANGED
@@ -8,7 +8,7 @@ import { createRemoteUser } from '@verdaccio/config';
8
8
  import { API_ERROR, API_MESSAGE, HTTP_STATUS, errorUtils } from '@verdaccio/core';
9
9
  import { logger } from '@verdaccio/logger';
10
10
  import { Config, RemoteUser } from '@verdaccio/types';
11
- import { getAuthenticatedMessage, validatePassword } from '@verdaccio/utils';
11
+ import { getAuthenticatedMessage, mask, validatePassword } from '@verdaccio/utils';
12
12
 
13
13
  import { $NextFunctionVer, $RequestExtend } from '../types/custom';
14
14
 
@@ -28,6 +28,23 @@ export default function (route: Router, auth: IAuth, config: Config): void {
28
28
  }
29
29
  );
30
30
 
31
+ /**
32
+ *
33
+ * body example
34
+ * req.body = {
35
+ _id: "org.couchdb.user:jjjj",
36
+ name: "jjjj",
37
+ password: "jjjj",
38
+ type: "user",
39
+ roles: [],
40
+ date: "2022-07-08T15:51:04.002Z",
41
+ }
42
+ *
43
+ * @export
44
+ * @param {Router} route
45
+ * @param {IAuth} auth
46
+ * @param {Config} config
47
+ */
31
48
  route.put(
32
49
  '/-/user/:org_couchdb_user/:_rev?/:revision?',
33
50
  function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {
@@ -92,7 +109,7 @@ export default function (route: Router, auth: IAuth, config: Config): void {
92
109
 
93
110
  const token =
94
111
  name && password ? await getApiToken(auth, config, user, password) : undefined;
95
- debug('adduser: new token %o', token);
112
+ debug('adduser: new token %o', mask(token as string, 4));
96
113
  if (!token) {
97
114
  return next(errorUtils.getUnauthorized());
98
115
  }
package/src/v1/search.ts CHANGED
@@ -5,7 +5,7 @@ import { IAuth } from '@verdaccio/auth';
5
5
  import { HTTP_STATUS, searchUtils } from '@verdaccio/core';
6
6
  import { logger } from '@verdaccio/logger';
7
7
  import { Storage } from '@verdaccio/store';
8
- import { Package } from '@verdaccio/types';
8
+ import { Manifest } from '@verdaccio/types';
9
9
 
10
10
  const debug = buildDebug('verdaccio:api:search');
11
11
 
@@ -16,7 +16,7 @@ const debug = buildDebug('verdaccio:api:search');
16
16
  * req: 'GET /-/v1/search?text=react&size=20&frpom=0&quality=0.65&popularity=0.98&maintenance=0.5'
17
17
  */
18
18
  export default function (route, auth: IAuth, storage: Storage): void {
19
- function checkAccess(pkg: any, auth: any, remoteUser): Promise<Package | null> {
19
+ function checkAccess(pkg: any, auth: any, remoteUser): Promise<Manifest | null> {
20
20
  return new Promise((resolve, reject) => {
21
21
  auth.allow_access({ packageName: pkg?.package?.name }, remoteUser, function (err, allowed) {
22
22
  if (err) {
@@ -49,7 +49,7 @@ export default function (route, auth: IAuth, storage: Storage): void {
49
49
  from = parseInt(from, 10) || 0;
50
50
 
51
51
  try {
52
- data = await storage.searchManager?.search({
52
+ data = await storage.search({
53
53
  query,
54
54
  url,
55
55
  abort,
package/src/whoami.ts CHANGED
@@ -1,36 +1,20 @@
1
1
  import buildDebug from 'debug';
2
2
  import { Response, Router } from 'express';
3
3
 
4
+ import { errorUtils } from '@verdaccio/core';
5
+
4
6
  import { $NextFunctionVer, $RequestExtend } from '../types/custom';
5
7
 
6
8
  const debug = buildDebug('verdaccio:api:user');
7
9
 
8
10
  export default function (route: Router): void {
9
- route.get('/whoami', (req: $RequestExtend, res: Response, next: $NextFunctionVer): void => {
10
- debug('whoami: reditect');
11
- if (req.headers.referer === 'whoami') {
12
- const username = req.remote_user.name;
13
- // FIXME: this service should return 401 if user missing
14
- // if (!username) {
15
- // debug('whoami: user not found');
16
- // return next(getUnauthorized('Unauthorized'));
17
- // }
18
- debug('whoami: logged by user');
19
- return next({ username: username });
20
- } else {
21
- debug('whoami: redirect next route');
22
- // redirect to the route below
23
- return next('route');
11
+ route.get('/-/whoami', (req: $RequestExtend, _res: Response, next: $NextFunctionVer): any => {
12
+ // remote_user is set by the auth middleware
13
+ const username = req?.remote_user?.name;
14
+ if (!username) {
15
+ debug('whoami: user not found');
16
+ return next(errorUtils.getUnauthorized('Unauthorized'));
24
17
  }
25
- });
26
-
27
- route.get('/-/whoami', (req: $RequestExtend, res: Response, next: $NextFunctionVer): any => {
28
- const username = req.remote_user.name;
29
- // FIXME: this service should return 401 if user missing
30
- // if (!username) {
31
- // debug('whoami: user not found');
32
- // return next(getUnauthorized('Unauthorized'));
33
- // }
34
18
 
35
19
  debug('whoami: response %o', username);
36
20
  return next({ username: username });
@@ -1,82 +1,126 @@
1
- import bodyParser from 'body-parser';
2
- import express, { Application } from 'express';
1
+ import { Application } from 'express';
2
+ import _ from 'lodash';
3
3
  import path from 'path';
4
4
  import supertest from 'supertest';
5
5
 
6
- import { Auth, IAuth } from '@verdaccio/auth';
7
- import { Config, parseConfigFile } from '@verdaccio/config';
8
- import { HEADERS, HEADER_TYPE, HTTP_STATUS } from '@verdaccio/core';
9
- import { generatePackageMetadata } from '@verdaccio/helper';
10
- import { errorReportingMiddleware, final, handleError } from '@verdaccio/middleware';
6
+ import { parseConfigFile } from '@verdaccio/config';
7
+ import { HEADERS, HEADER_TYPE, HTTP_STATUS, TOKEN_BEARER } from '@verdaccio/core';
8
+ import { setup } from '@verdaccio/logger';
11
9
  import { Storage } from '@verdaccio/store';
10
+ import {
11
+ generatePackageMetadata,
12
+ initializeServer as initializeServerHelper,
13
+ } from '@verdaccio/test-helper';
14
+ import { GenericBody } from '@verdaccio/types';
15
+ import { buildToken, generateRandomHexString } from '@verdaccio/utils';
12
16
 
13
- import apiEndpoints from '../../src';
17
+ import apiMiddleware from '../../src';
14
18
 
15
- const getConf = (conf) => {
16
- const configPath = path.join(__dirname, 'config', conf);
19
+ setup();
17
20
 
18
- return parseConfigFile(configPath);
21
+ export const getConf = (conf) => {
22
+ const configPath = path.join(__dirname, 'config', conf);
23
+ const config = parseConfigFile(configPath);
24
+ // custom config to avoid conflict with other tests
25
+ config.auth.htpasswd.file = `${config.auth.htpasswd.file}-${generateRandomHexString()}`;
26
+ return config;
19
27
  };
20
28
 
21
29
  export async function initializeServer(configName): Promise<Application> {
22
- const app = express();
23
- const config = new Config(getConf(configName));
24
- const storage = new Storage(config);
25
- await storage.init(config, []);
26
- const auth: IAuth = new Auth(config);
27
- // TODO: this might not be need it, used in apiEndpoints
28
- app.use(bodyParser.json({ strict: false, limit: '10mb' }));
29
- // @ts-ignore
30
- app.use(errorReportingMiddleware);
31
- // @ts-ignore
32
- app.use(apiEndpoints(config, auth, storage));
33
- // @ts-ignore
34
- app.use(handleError);
35
- // @ts-ignore
36
- app.use(final);
37
-
38
- app.use(function (request, response) {
39
- response.status(590);
40
- console.log('respo', response);
41
- response.json({ error: 'cannot handle this' });
42
- });
43
-
44
- return app;
30
+ return initializeServerHelper(getConf(configName), [apiMiddleware], Storage);
31
+ }
32
+
33
+ export function createUser(app, name: string, password: string): supertest.Test {
34
+ return supertest(app)
35
+ .put(`/-/user/org.couchdb.user:${name}`)
36
+ .send({
37
+ name: name,
38
+ password: password,
39
+ })
40
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
41
+ .expect(HTTP_STATUS.CREATED);
42
+ }
43
+
44
+ export async function getNewToken(app: any, credentials: any): Promise<string> {
45
+ const response = await createUser(app, credentials.name, credentials.password);
46
+ const { token, ok } = response.body;
47
+ expect(ok).toBeDefined();
48
+ expect(token).toBeDefined();
49
+ expect(typeof token).toBe('string');
50
+ return token;
51
+ }
52
+
53
+ export async function generateTokenCLI(app, token, payload): Promise<any> {
54
+ return supertest(app)
55
+ .post('/-/npm/v1/tokens')
56
+ .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
57
+ .send(JSON.stringify(payload))
58
+ .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token))
59
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET);
60
+ }
61
+
62
+ export async function deleteTokenCLI(app, token, tokenToDelete): Promise<any> {
63
+ return supertest(app)
64
+ .delete(`/-/npm/v1/tokens/token/${tokenToDelete}`)
65
+ .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
66
+ .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token))
67
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
68
+ .expect(HTTP_STATUS.OK);
45
69
  }
46
70
 
47
- export function publishVersion(app, _configFile, pkgName, version): supertest.Test {
48
- const pkgMetadata = generatePackageMetadata(pkgName, version);
71
+ export function publishVersionWithToken(
72
+ app,
73
+ pkgName: string,
74
+ version: string,
75
+ token: string,
76
+ distTags?: GenericBody
77
+ ): supertest.Test {
78
+ const pkgMetadata = generatePackageMetadata(pkgName, version, distTags);
49
79
 
50
80
  return supertest(app)
51
81
  .put(`/${encodeURIComponent(pkgName)}`)
52
82
  .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
83
+ .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token))
53
84
  .send(JSON.stringify(pkgMetadata))
54
85
  .set('accept', HEADERS.GZIP)
55
- .set(HEADER_TYPE.ACCEPT_ENCODING, HEADERS.JSON)
56
- .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON);
86
+ .set(HEADER_TYPE.ACCEPT_ENCODING, HEADERS.JSON);
57
87
  }
58
88
 
59
- export async function publishTaggedVersion(
89
+ export function publishVersion(
60
90
  app,
61
- configFile,
62
91
  pkgName: string,
63
92
  version: string,
64
- tag: string
65
- ) {
66
- const pkgMetadata = generatePackageMetadata(pkgName, version, {
67
- [tag]: version,
68
- });
93
+ distTags?: GenericBody
94
+ ): supertest.Test {
95
+ const pkgMetadata = generatePackageMetadata(pkgName, version, distTags);
69
96
 
70
97
  return supertest(app)
71
- .put(
72
- `/${encodeURIComponent(pkgName)}/${encodeURIComponent(version)}/-tag/${encodeURIComponent(
73
- tag
74
- )}`
75
- )
98
+ .put(`/${encodeURIComponent(pkgName)}`)
76
99
  .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
77
100
  .send(JSON.stringify(pkgMetadata))
78
- .expect(HTTP_STATUS.CREATED)
79
101
  .set('accept', HEADERS.GZIP)
80
- .set(HEADER_TYPE.ACCEPT_ENCODING, HEADERS.JSON)
81
- .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON);
102
+ .set(HEADER_TYPE.ACCEPT_ENCODING, HEADERS.JSON);
103
+ }
104
+
105
+ export function getDisTags(app, pkgName) {
106
+ return supertest(app)
107
+ .get(`/-/package/${encodeURIComponent(pkgName)}/dist-tags`)
108
+ .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
109
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
110
+ .expect(HTTP_STATUS.OK);
111
+ }
112
+
113
+ export function getPackage(
114
+ app: any,
115
+ token: string,
116
+ pkgName: string,
117
+ statusCode: number = HTTP_STATUS.OK
118
+ ): supertest.Test {
119
+ const test = supertest(app).get(`/${pkgName}`);
120
+
121
+ if (_.isNil(token) === false || _.isEmpty(token) === false) {
122
+ test.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token));
123
+ }
124
+
125
+ return test.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET).expect(statusCode);
82
126
  }
@@ -0,0 +1,25 @@
1
+ storage: ./storage
2
+
3
+ auth:
4
+ htpasswd:
5
+ file: ./htpasswd-distTag
6
+
7
+ web:
8
+ enable: true
9
+ title: verdaccio
10
+
11
+ publish:
12
+ allow_offline: false
13
+
14
+ uplinks:
15
+
16
+ log: { type: stdout, format: pretty, level: trace }
17
+
18
+ packages:
19
+ '@*/*':
20
+ access: $anonymous
21
+ publish: $anonymous
22
+ '**':
23
+ access: $anonymous
24
+ publish: $anonymous
25
+ _debug: true
@@ -1,13 +1,8 @@
1
- store:
2
- memory:
3
- limit: 1000
1
+ storage: ./storage
4
2
 
5
3
  auth:
6
- auth-memory:
7
- users:
8
- test:
9
- name: test
10
- password: test
4
+ htpasswd:
5
+ file: ./htpasswd-package
11
6
 
12
7
  web:
13
8
  enable: true
@@ -18,7 +13,7 @@ publish:
18
13
 
19
14
  uplinks:
20
15
 
21
- logs: { type: stdout, format: pretty, level: trace }
16
+ log: { type: stdout, format: pretty, level: trace }
22
17
 
23
18
  packages:
24
19
  '@*/*':
@@ -1,17 +1,13 @@
1
- store:
2
- memory:
3
- limit: 10
4
-
5
1
  auth:
6
- auth-memory:
7
- users:
2
+ htpasswd:
3
+ file: ./htpasswd-ping
8
4
  web:
9
5
  enable: true
10
6
  title: verdaccio
11
7
 
12
8
  uplinks:
13
9
 
14
- logs: { type: stdout, format: pretty, level: trace }
10
+ log: { type: stdout, format: pretty, level: trace }
15
11
 
16
12
  packages:
17
13
  '@*/*':
@@ -1,14 +1,6 @@
1
- store:
2
- memory:
3
- limit: 1000
4
-
5
1
  auth:
6
- auth-memory:
7
- users:
8
- test:
9
- name: test
10
- password: test
11
-
2
+ htpasswd:
3
+ file: ./htpasswd-publish
12
4
  web:
13
5
  enable: true
14
6
  title: verdaccio
@@ -18,13 +10,15 @@ publish:
18
10
 
19
11
  uplinks:
20
12
 
21
- logs: { type: stdout, format: pretty, level: trace }
13
+ log: { type: stdout, format: pretty, level: trace }
22
14
 
23
15
  packages:
24
16
  '@*/*':
25
17
  access: $anonymous
26
18
  publish: $anonymous
19
+ unpublish: $anonymous
27
20
  '**':
28
21
  access: $anonymous
29
22
  publish: $anonymous
23
+ unpublish: $anonymous
30
24
  _debug: true
@@ -0,0 +1,29 @@
1
+ storage: ./storage
2
+
3
+ auth:
4
+ htpasswd:
5
+ file: ./htpasswd-search
6
+
7
+ web:
8
+ enable: true
9
+ title: verdaccio
10
+
11
+ uplinks:
12
+
13
+ log: { type: stdout, format: pretty, level: trace }
14
+
15
+ packages:
16
+ 'private-*':
17
+ access: $all
18
+ publish: jota
19
+ '@private/*':
20
+ access: $all
21
+ publish: jota
22
+ '@*/*':
23
+ access: $all
24
+ publish: $authenticated
25
+ '**':
26
+ access: $all
27
+ publish: $authenticated
28
+
29
+ _debug: true
@@ -0,0 +1,27 @@
1
+ security:
2
+ api:
3
+ jwt:
4
+ sign:
5
+ expiresIn: 5m
6
+ # to avoid invalid verification token, more info on JWT page
7
+ notBefore: 0
8
+
9
+ storage: ./storage
10
+
11
+ auth:
12
+ htpasswd:
13
+ file: ./htpasswd
14
+
15
+ packages:
16
+ '@token/*':
17
+ access: $authenticated
18
+ publish: $authenticated
19
+ 'only-you-can-publish':
20
+ access: $authenticated
21
+ publish: $authenticated
22
+
23
+ log: { type: stdout, format: pretty, level: debug }
24
+
25
+ ## enable token for testing
26
+ flags:
27
+ token: true
@@ -0,0 +1,19 @@
1
+ storage: ./storage
2
+
3
+ auth:
4
+ htpasswd:
5
+ file: ./htpasswd
6
+
7
+ packages:
8
+ '@token/*':
9
+ access: $authenticated
10
+ publish: $authenticated
11
+ 'only-you-can-publish':
12
+ access: $authenticated
13
+ publish: $authenticated
14
+
15
+ log: { type: stdout, format: pretty, level: debug }
16
+
17
+ ## enable token for testing
18
+ flags:
19
+ token: true
@@ -0,0 +1,37 @@
1
+ storage: ./storage
2
+ plugins: ./plugins
3
+
4
+ web:
5
+ title: Verdaccio
6
+
7
+ auth:
8
+ htpasswd:
9
+ file: ./htpasswd
10
+
11
+ uplinks:
12
+ ver:
13
+ url: https://registry.verdaccio.org
14
+
15
+ security:
16
+ api:
17
+ jwt:
18
+ sign:
19
+ expiresIn: 10m
20
+ notBefore: 0
21
+ packages:
22
+ '@*/*':
23
+ access: $all
24
+ publish: $authenticated
25
+ 'vue':
26
+ access: $authenticated
27
+ publish: $authenticated
28
+ proxy: ver
29
+ '**':
30
+ access: $all
31
+ publish: $authenticated
32
+
33
+ middlewares:
34
+ audit:
35
+ enabled: true
36
+
37
+ log: { type: stdout, format: pretty, level: info }
@@ -1,36 +1,30 @@
1
- store:
2
- memory:
3
- limit: 1000
4
-
5
1
  auth:
6
- auth-memory:
7
- users:
8
- test:
9
- name: test
10
- password: test
11
-
2
+ htpasswd:
3
+ file: ./htpasswd-user
12
4
  web:
13
5
  enable: true
14
6
  title: verdaccio
15
7
 
16
8
  uplinks:
17
- npmjs:
18
- url: https://registry.npmjs.org/
9
+ ver:
10
+ url: https://registry.verdaccio.org
19
11
 
20
- logs: { type: stdout, format: pretty, level: trace }
12
+ log: { type: stdout, format: pretty, level: trace }
21
13
 
22
14
  packages:
23
15
  '@*/*':
24
16
  access: $all
25
17
  publish: $all
26
18
  unpublish: $all
27
- proxy: npmjs
28
19
  'verdaccio':
29
20
  access: $all
30
21
  publish: $all
22
+ 'vue':
23
+ access: $authenticated
24
+ publish: $authenticated
25
+ proxy: ver
31
26
  '**':
32
27
  access: $all
33
28
  publish: $all
34
29
  unpublish: $all
35
- proxy: npmjs
36
30
  _debug: true
@@ -1,14 +1,3 @@
1
- store:
2
- memory:
3
- limit: 1000
4
-
5
- auth:
6
- auth-memory:
7
- users:
8
- test:
9
- name: test
10
- password: test
11
-
12
1
  web:
13
2
  enable: true
14
3
  title: verdaccio
@@ -17,7 +6,11 @@ uplinks:
17
6
  npmjs:
18
7
  url: https://registry.npmjs.org/
19
8
 
20
- logs: { type: stdout, format: pretty, level: trace }
9
+ log: { type: stdout, format: pretty, level: trace }
10
+
11
+ auth:
12
+ htpasswd:
13
+ file: ./htpasswd-whoami
21
14
 
22
15
  packages:
23
16
  '@*/*':
@@ -0,0 +1,76 @@
1
+ import supertest from 'supertest';
2
+
3
+ import { API_MESSAGE, HEADERS, HEADER_TYPE, HTTP_STATUS } from '@verdaccio/core';
4
+
5
+ import { getDisTags, initializeServer, publishVersion } from './_helper';
6
+
7
+ describe('package', () => {
8
+ let app;
9
+ beforeEach(async () => {
10
+ app = await initializeServer('distTag.yaml');
11
+ });
12
+
13
+ test.each([['foo'], ['@scope/foo']])('should display dist-tag (npm dist-tag ls)', async (pkg) => {
14
+ await publishVersion(app, pkg, '1.0.0');
15
+ await publishVersion(app, pkg, '1.0.1');
16
+ const response = await getDisTags(app, pkg);
17
+ expect(response.body).toEqual({ latest: '1.0.1' });
18
+ });
19
+
20
+ test('should add a version to a tag (npm dist-tag add)', async () => {
21
+ await publishVersion(app, encodeURIComponent('foo'), '1.0.0');
22
+ await publishVersion(app, encodeURIComponent('foo'), '1.0.1');
23
+
24
+ const response = await supertest(app)
25
+ .put(`/${encodeURIComponent('foo')}/test`)
26
+ .set(HEADERS.ACCEPT, HEADERS.GZIP)
27
+ .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
28
+ .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
29
+ .send(JSON.stringify('1.0.1'))
30
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
31
+ .expect(HTTP_STATUS.CREATED);
32
+ expect(response.body.ok).toEqual(API_MESSAGE.TAG_ADDED);
33
+ const response2 = await getDisTags(app, 'foo');
34
+ expect(response2.body).toEqual({ latest: '1.0.1', test: '1.0.1' });
35
+ });
36
+
37
+ test('should fails if a version is missing (npm dist-tag add)', async () => {
38
+ await publishVersion(app, encodeURIComponent('foo'), '1.0.0');
39
+ await publishVersion(app, encodeURIComponent('foo'), '1.0.1');
40
+
41
+ await supertest(app)
42
+ .put(`/${encodeURIComponent('foo')}/test`)
43
+ .set(HEADERS.ACCEPT, HEADERS.GZIP)
44
+ .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
45
+ .send(JSON.stringify({}))
46
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
47
+ .expect(HTTP_STATUS.BAD_REQUEST);
48
+ });
49
+
50
+ test('should delete a previous added tag (npm dist-tag rm)', async () => {
51
+ await publishVersion(app, encodeURIComponent('foo'), '1.0.0');
52
+ await publishVersion(app, encodeURIComponent('foo'), '1.0.1');
53
+
54
+ const response = await supertest(app)
55
+ .put(`/${encodeURIComponent('foo')}/beta`)
56
+ .set(HEADERS.ACCEPT, HEADERS.GZIP)
57
+ .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
58
+ .send(JSON.stringify('1.0.1'))
59
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
60
+ .expect(HTTP_STATUS.CREATED);
61
+ expect(response.body.ok).toEqual(API_MESSAGE.TAG_ADDED);
62
+
63
+ const response2 = await getDisTags(app, 'foo');
64
+ expect(response2.body).toEqual({ latest: '1.0.1', beta: '1.0.1' });
65
+
66
+ const response3 = await supertest(app)
67
+ .delete(`/-/package/${encodeURIComponent('foo')}/dist-tags/beta`)
68
+ .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
69
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
70
+ .expect(HTTP_STATUS.CREATED);
71
+ expect(response3.body.ok).toEqual(API_MESSAGE.TAG_REMOVED);
72
+
73
+ const response4 = await getDisTags(app, 'foo');
74
+ expect(response4.body).toEqual({ latest: '1.0.1' });
75
+ });
76
+ });