mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-24 21:15:51 +01:00
e2e: command dist-tag (#3390)
* clean up tests * add dist-tag * chore: add npm 9 * Update CHANGELOG.md * Update publish.spec.js * add pnpm * yarn 1 * Update tag.spec.ts * Update README.md * more timeout * chore fix build * chore: fix export * chore: fix test * chore: fix tests
This commit is contained in:
parent
40ceb59d76
commit
e364d073d7
2
.github/workflows/e2e-ci.yml
vendored
2
.github/workflows/e2e-ci.yml
vendored
@ -85,7 +85,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
pkg: [npm6, npm7, npm8, pnpm6, pnpm7, yarn1, yarn2, yarn3, yarn4]
|
||||
pkg: [npm6, npm7, npm8, npm9, pnpm6, pnpm7, yarn1, yarn2, yarn3, yarn4]
|
||||
name: ${{ matrix.pkg }} / ${{ matrix.os }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
@ -3,23 +3,27 @@
|
||||
## What is included on these test?
|
||||
|
||||
- Default configuration only
|
||||
- Test with all popular package managers (`yarn classic` and `yarn modern (2,3, 4)`, `pnpm 6,7` and `npm 6, 7 and 8`)
|
||||
- Test with all popular package managers:
|
||||
- `yarn classic` and `yarn modern (2, 3, 4 RC)`
|
||||
- `pnpm 6, 7`
|
||||
- `npm 6, 7, 8 and 9`
|
||||
|
||||
### Commands Tested
|
||||
|
||||
| cmd | npm6 | npm7 | npm8 | pnpm6 | pnpm7 | yarn1 | yarn2 | yarn3 | yarn4 |
|
||||
| --------- | ---- | ---- | ---- | ----- | ----- | ----- | ----- | ----- | ----- |
|
||||
| publish | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| audit | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| install | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| deprecate | ✅ | ✅ | ✅ | ✅ | ✅ | ⛔ | ⛔ | ⛔ | ⛔ |
|
||||
| ping | ✅ | ✅ | ✅ | ✅ | ✅ | ⛔ | ⛔ | ⛔ | ⛔ |
|
||||
| search | ✅ | ✅ | ✅ | ✅ | ✅ | ⛔ | ⛔ | ⛔ | ⛔ |
|
||||
| cmd | npm6 | npm7 | npm8 | npm9 | pnpm6 | pnpm7 | yarn1 | yarn2 | yarn3 | yarn4 |
|
||||
| --------- | ---- | ---- | ---- | ---- | ----- | ----- | ----- | ----- | ----- | ----- |
|
||||
| publish | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| audit | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| install | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| deprecate | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⛔ | ⛔ | ⛔ | ⛔ |
|
||||
| ping | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⛔ | ⛔ | ⛔ | ⛔ |
|
||||
| search | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⛔ | ⛔ | ⛔ | ⛔ |
|
||||
| dist-tag | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
|
||||
> notes:
|
||||
>
|
||||
> - yarn search exist in modern but do not use the search registry endpoint
|
||||
> - yarn search cmd exist in _modern_ but, it do not uses the search registry endpoint.
|
||||
|
||||
❌ = no tested
|
||||
✅ = tested
|
||||
|
@ -8,6 +8,7 @@
|
||||
"debug": "4.3.4",
|
||||
"fs-extra": "10.1.0",
|
||||
"got": "11.8.5",
|
||||
"lodash": "4.17.21",
|
||||
"verdaccio": "workspace:6.0.0-6-next.47",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.47",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.47"
|
||||
|
@ -1,5 +1,7 @@
|
||||
export { getDefaultConfig } from '@verdaccio/config';
|
||||
export { initialSetup } from './registry';
|
||||
export { getDefaultConfig, ConfigBuilder } from '@verdaccio/config';
|
||||
export { constants } from '@verdaccio/core';
|
||||
export { Registry } from 'verdaccio';
|
||||
export { initialSetup, getConfigPath, Setup } from './registry';
|
||||
export {
|
||||
addNpmPrefix,
|
||||
addYarnClassicPrefix,
|
||||
@ -9,3 +11,4 @@ export {
|
||||
nJSONParse,
|
||||
} from './utils';
|
||||
export { exec, ExecOutput } from './process';
|
||||
export { callRegistry } from './web';
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* eslint-disable prefer-promise-reject-errors */
|
||||
import buildDebug from 'debug';
|
||||
import { merge } from 'lodash';
|
||||
import { Registry } from 'verdaccio';
|
||||
|
||||
import { getDefaultConfig } from '@verdaccio/config';
|
||||
@ -15,24 +16,25 @@ export type Setup = {
|
||||
const log =
|
||||
process.env.NODE_ENV === 'production'
|
||||
? { type: 'stdout', format: 'json', level: 'warn' }
|
||||
: { type: 'stdout', format: 'pretty', level: 'warn' };
|
||||
: { type: 'stdout', format: 'pretty', level: 'info' };
|
||||
|
||||
const defaultConfig = {
|
||||
...getDefaultConfig(),
|
||||
log,
|
||||
};
|
||||
|
||||
export async function initialSetup(customConfig?: ConfigYaml): Promise<Setup> {
|
||||
// @ts-ignore
|
||||
const { configPath, tempFolder } = await Registry.fromConfigToPath({
|
||||
...(customConfig
|
||||
? customConfig
|
||||
: {
|
||||
...defaultConfig,
|
||||
_debug: true,
|
||||
}),
|
||||
export function getConfigPath(customConfig) {
|
||||
return Registry.fromConfigToPath({
|
||||
...customConfig,
|
||||
_debug: true,
|
||||
});
|
||||
}
|
||||
|
||||
export async function initialSetup(customConfig?: ConfigYaml): Promise<Setup> {
|
||||
const config = merge(defaultConfig, customConfig);
|
||||
const { configPath, tempFolder } = await getConfigPath(config);
|
||||
debug(`configPath %o`, configPath);
|
||||
debug(`tempFolder %o`, tempFolder);
|
||||
const registry = new Registry(configPath);
|
||||
const registry = new Registry(configPath, { createUser: true });
|
||||
return { registry, tempFolder };
|
||||
}
|
||||
|
@ -1,26 +1,11 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
import { bumbUp, getInfoVersions, npm, publish } from './utils';
|
||||
|
||||
describe('deprecate a package', () => {
|
||||
jest.setTimeout(15000);
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
async function bumbUp(tempFolder, registry) {
|
||||
await npm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
async function publish(tempFolder, pkgName, registry) {
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
async function deprecate(tempFolder, packageVersion, registry, message) {
|
||||
await npm(
|
||||
{ cwd: tempFolder },
|
||||
@ -32,18 +17,6 @@ describe('deprecate a package', () => {
|
||||
);
|
||||
}
|
||||
|
||||
async function getInfoVersions(pkgName, registry) {
|
||||
const infoResp = await npm(
|
||||
{},
|
||||
'info',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const infoBody = JSON.parse(infoResp.stdout as string);
|
||||
return infoBody;
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
|
86
e2e/cli/e2e-npm6/dist-tags.spec.ts
Normal file
86
e2e/cli/e2e-npm6/dist-tags.spec.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { bumbUp, npm, publish } from './utils';
|
||||
|
||||
describe('publish a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@foo/foo', 'foo']])('should list dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'ls',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('beta: 1.1.0latest: 1.0.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should remove tag with dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'rm',
|
||||
`${pkgName}@1.1.0`,
|
||||
'beta',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('-beta: @verdaccio/bar@1.1.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/five']])(
|
||||
'should add tag to package and version with dist-tags for %s',
|
||||
async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'add',
|
||||
`${pkgName}@1.1.0`,
|
||||
'alfa',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual(`+alfa: ${pkgName}@1.1.0`);
|
||||
}
|
||||
);
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
@ -22,6 +22,7 @@ describe('publish a package', () => {
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
|
@ -2,6 +2,7 @@ import { SpawnOptions } from 'child_process';
|
||||
import { join } from 'path';
|
||||
|
||||
import { exec } from '@verdaccio/test-cli-commons';
|
||||
import { addRegistry } from '@verdaccio/test-cli-commons';
|
||||
|
||||
export function getCommand() {
|
||||
return join(__dirname, './node_modules/.bin/npm');
|
||||
@ -10,3 +11,31 @@ export function getCommand() {
|
||||
export function npm(options: SpawnOptions, ...args: string[]) {
|
||||
return exec(options, getCommand(), args);
|
||||
}
|
||||
|
||||
export async function bumbUp(tempFolder, registry) {
|
||||
await npm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
export async function publish(tempFolder, pkgName, registry, arg: string[] = []) {
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
...arg,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
export async function getInfoVersions(pkgName, registry) {
|
||||
const infoResp = await npm(
|
||||
{},
|
||||
'info',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const infoBody = JSON.parse(infoResp.stdout as string);
|
||||
return infoBody;
|
||||
}
|
||||
|
@ -1,26 +1,11 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
import { bumbUp, getInfoVersions, npm, publish } from './utils';
|
||||
|
||||
describe('deprecate a package', () => {
|
||||
jest.setTimeout(15000);
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
async function bumbUp(tempFolder, registry) {
|
||||
await npm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
async function publish(tempFolder, pkgName, registry) {
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
async function deprecate(tempFolder, packageVersion, registry, message) {
|
||||
await npm(
|
||||
{ cwd: tempFolder },
|
||||
@ -32,18 +17,6 @@ describe('deprecate a package', () => {
|
||||
);
|
||||
}
|
||||
|
||||
async function getInfoVersions(pkgName, registry) {
|
||||
const infoResp = await npm(
|
||||
{},
|
||||
'info',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const infoBody = JSON.parse(infoResp.stdout as string);
|
||||
return infoBody;
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
|
86
e2e/cli/e2e-npm7/dist-tags.spec.ts
Normal file
86
e2e/cli/e2e-npm7/dist-tags.spec.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { bumbUp, npm, publish } from './utils';
|
||||
|
||||
describe('publish a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@foo/foo', 'foo']])('should list dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'ls',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('beta: 1.1.0latest: 1.0.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should remove tag with dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'rm',
|
||||
`${pkgName}@1.1.0`,
|
||||
'beta',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('-beta: @verdaccio/bar@1.1.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/five']])(
|
||||
'should add tag to package and version with dist-tags for %s',
|
||||
async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'add',
|
||||
`${pkgName}@1.1.0`,
|
||||
'alfa',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual(`+alfa: ${pkgName}@1.1.0`);
|
||||
}
|
||||
);
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
@ -2,6 +2,7 @@ import { SpawnOptions } from 'child_process';
|
||||
import { join } from 'path';
|
||||
|
||||
import { exec } from '@verdaccio/test-cli-commons';
|
||||
import { addRegistry } from '@verdaccio/test-cli-commons';
|
||||
|
||||
export function getCommand() {
|
||||
return join(__dirname, './node_modules/.bin/npm');
|
||||
@ -10,3 +11,31 @@ export function getCommand() {
|
||||
export function npm(options: SpawnOptions, ...args: string[]) {
|
||||
return exec(options, getCommand(), args);
|
||||
}
|
||||
|
||||
export async function bumbUp(tempFolder, registry) {
|
||||
await npm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
export async function publish(tempFolder, pkgName, registry, arg: string[] = []) {
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
...arg,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
export async function getInfoVersions(pkgName, registry) {
|
||||
const infoResp = await npm(
|
||||
{},
|
||||
'info',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const infoBody = JSON.parse(infoResp.stdout as string);
|
||||
return infoBody;
|
||||
}
|
||||
|
@ -1,26 +1,11 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
import { bumbUp, getInfoVersions, npm, publish } from './utils';
|
||||
|
||||
describe('deprecate a package', () => {
|
||||
jest.setTimeout(15000);
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
async function bumbUp(tempFolder, registry) {
|
||||
await npm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
async function publish(tempFolder, pkgName, registry) {
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
async function deprecate(tempFolder, packageVersion, registry, message) {
|
||||
await npm(
|
||||
{ cwd: tempFolder },
|
||||
@ -32,18 +17,6 @@ describe('deprecate a package', () => {
|
||||
);
|
||||
}
|
||||
|
||||
async function getInfoVersions(pkgName, registry) {
|
||||
const infoResp = await npm(
|
||||
{},
|
||||
'info',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const infoBody = JSON.parse(infoResp.stdout as string);
|
||||
return infoBody;
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
|
86
e2e/cli/e2e-npm8/dist-tags.spec.ts
Normal file
86
e2e/cli/e2e-npm8/dist-tags.spec.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { bumbUp, npm, publish } from './utils';
|
||||
|
||||
describe('publish a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@foo/foo', 'foo']])('should list dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'ls',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('beta: 1.1.0latest: 1.0.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should remove tag with dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'rm',
|
||||
`${pkgName}@1.1.0`,
|
||||
'beta',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('-beta: @verdaccio/bar@1.1.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/five']])(
|
||||
'should add tag to package and version with dist-tags for %s',
|
||||
async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'add',
|
||||
`${pkgName}@1.1.0`,
|
||||
'alfa',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual(`+alfa: ${pkgName}@1.1.0`);
|
||||
}
|
||||
);
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
@ -4,7 +4,7 @@
|
||||
"version": "1.0.1-6-next.5",
|
||||
"dependencies": {
|
||||
"@verdaccio/test-cli-commons": "workspace:1.0.1-6-next.5",
|
||||
"npm": "next-8"
|
||||
"npm": "8.19.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest"
|
||||
|
@ -2,6 +2,7 @@ import { SpawnOptions } from 'child_process';
|
||||
import { join } from 'path';
|
||||
|
||||
import { exec } from '@verdaccio/test-cli-commons';
|
||||
import { addRegistry } from '@verdaccio/test-cli-commons';
|
||||
|
||||
export function getCommand() {
|
||||
return join(__dirname, './node_modules/.bin/npm');
|
||||
@ -10,3 +11,31 @@ export function getCommand() {
|
||||
export function npm(options: SpawnOptions, ...args: string[]) {
|
||||
return exec(options, getCommand(), args);
|
||||
}
|
||||
|
||||
export async function bumbUp(tempFolder, registry) {
|
||||
await npm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
export async function publish(tempFolder, pkgName, registry, arg: string[] = []) {
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
...arg,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
export async function getInfoVersions(pkgName, registry) {
|
||||
const infoResp = await npm(
|
||||
{},
|
||||
'info',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const infoBody = JSON.parse(infoResp.stdout as string);
|
||||
return infoBody;
|
||||
}
|
||||
|
3
e2e/cli/e2e-npm9/.babelrc
Normal file
3
e2e/cli/e2e-npm9/.babelrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../../../.babelrc"
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-console": 0,
|
||||
"@typescript-eslint/no-var-requires": 0,
|
||||
"@typescript-eslint/explicit-member-accessibility": 0
|
||||
}
|
||||
}
|
39
e2e/cli/e2e-npm9/CHANGELOG.md
Normal file
39
e2e/cli/e2e-npm9/CHANGELOG.md
Normal file
@ -0,0 +1,39 @@
|
||||
# @verdaccio/e2e-cli-npm9
|
||||
|
||||
## 1.0.1-6-next.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/test-cli-commons@1.0.1-6-next.5
|
||||
|
||||
## 1.0.1-6-next.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/test-cli-commons@1.0.1-6-next.4
|
||||
|
||||
## 1.0.1-6-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 351aeeaa: fix(deps): @verdaccio/utils should be a prod dep of local-storage
|
||||
- Updated dependencies [351aeeaa]
|
||||
- @verdaccio/test-cli-commons@1.0.1-6-next.3
|
||||
|
||||
## 1.0.1-6-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/test-cli-commons@1.0.1-6-next.2
|
||||
|
||||
## 1.0.1-6-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/test-cli-commons@1.0.1-6-next.1
|
||||
|
||||
## 1.0.1-6-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @verdaccio/test-cli-commons@1.0.1-6-next.0
|
44
e2e/cli/e2e-npm9/audit.spec.ts
Normal file
44
e2e/cli/e2e-npm9/audit.spec.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
|
||||
describe('audit a package', () => {
|
||||
jest.setTimeout(10000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['verdaccio-memory', '@verdaccio/cli']])(
|
||||
'should audit a package %s',
|
||||
async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl(),
|
||||
{ jquery: '3.6.1' }
|
||||
);
|
||||
// install is required to create package lock file
|
||||
await npm({ cwd: tempFolder }, 'install', ...addRegistry(registry.getRegistryUrl()));
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'audit',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.metadata).toBeDefined();
|
||||
expect(parsedBody.auditReportVersion).toBeDefined();
|
||||
expect(parsedBody.vulnerabilities).toBeDefined();
|
||||
}
|
||||
);
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
110
e2e/cli/e2e-npm9/deprecate.spec.ts
Normal file
110
e2e/cli/e2e-npm9/deprecate.spec.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { bumbUp, getInfoVersions, npm, publish } from './utils';
|
||||
|
||||
describe('deprecate a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
async function deprecate(tempFolder, packageVersion, registry, message) {
|
||||
await npm(
|
||||
{ cwd: tempFolder },
|
||||
'deprecate',
|
||||
packageVersion,
|
||||
message,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/deprecated-1']])(
|
||||
'should deprecate a single package %s',
|
||||
async (pkgName) => {
|
||||
const message = 'some message';
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
// deprecate one version
|
||||
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
|
||||
// verify is deprecated
|
||||
const infoBody = await getInfoVersions(`${pkgName}`, registry);
|
||||
expect(infoBody.name).toEqual(pkgName);
|
||||
expect(infoBody.deprecated).toEqual(message);
|
||||
}
|
||||
);
|
||||
|
||||
test.each([['@verdaccio/deprecated-2']])('should un-deprecate a package %s', async (pkgName) => {
|
||||
const message = 'some message';
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
// deprecate one version
|
||||
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
|
||||
// verify is deprecated
|
||||
const infoBody = await getInfoVersions(`${pkgName}`, registry);
|
||||
expect(infoBody.deprecated).toEqual(message);
|
||||
// empty string is same as undeprecate
|
||||
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, '');
|
||||
const infoBody2 = await getInfoVersions(`${pkgName}`, registry);
|
||||
expect(infoBody2.deprecated).toBeUndefined();
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/deprecated-3']])(
|
||||
'should deprecate a multiple packages %s',
|
||||
async (pkgName) => {
|
||||
const message = 'some message';
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
// publish 1.0.0
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
// publish 1.1.0
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
// publish 1.2.0
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
// publish 1.3.0
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
// // deprecate all version
|
||||
await deprecate(tempFolder, pkgName, registry, message);
|
||||
// verify is deprecated
|
||||
for (let v of ['1.0.0', '1.1.0', '1.2.0', '1.3.0']) {
|
||||
const infoResp = await getInfoVersions(`${pkgName}@${v}`, registry);
|
||||
expect(infoResp.deprecated).toEqual(message);
|
||||
}
|
||||
// publish normal version
|
||||
// publish 1.4.0
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
const infoResp = await getInfoVersions(`${pkgName}@1.4.0`, registry);
|
||||
// must be not deprecated
|
||||
expect(infoResp.deprecated).toBeUndefined();
|
||||
}
|
||||
);
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
86
e2e/cli/e2e-npm9/dist-tags.spec.ts
Normal file
86
e2e/cli/e2e-npm9/dist-tags.spec.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { bumbUp, npm, publish } from './utils';
|
||||
|
||||
describe('publish a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@foo/foo', 'foo']])('should list dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'ls',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('beta: 1.1.0latest: 1.0.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should remove tag with dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'rm',
|
||||
`${pkgName}@1.1.0`,
|
||||
'beta',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('-beta: @verdaccio/bar@1.1.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/five']])(
|
||||
'should add tag to package and version with dist-tags for %s',
|
||||
async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
const resp2 = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'add',
|
||||
`${pkgName}@1.1.0`,
|
||||
'alfa',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual(`+alfa: ${pkgName}@1.1.0`);
|
||||
}
|
||||
);
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
31
e2e/cli/e2e-npm9/info.spec.ts
Normal file
31
e2e/cli/e2e-npm9/info.spec.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { addRegistry, initialSetup } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
|
||||
describe('install a package', () => {
|
||||
jest.setTimeout(10000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test('should run npm info json body', async () => {
|
||||
const resp = await npm(
|
||||
{},
|
||||
'info',
|
||||
'verdaccio',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual('verdaccio');
|
||||
expect(parsedBody.dependencies).toBeDefined();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
38
e2e/cli/e2e-npm9/install.spec.ts
Normal file
38
e2e/cli/e2e-npm9/install.spec.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
|
||||
describe('install a project packages', () => {
|
||||
jest.setTimeout(100000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test('should run npm install json body', async () => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
'something',
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl(),
|
||||
{ react: '18.2.0' }
|
||||
);
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'install',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.added).toBeDefined();
|
||||
expect(parsedBody.audit).toBeDefined();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
3
e2e/cli/e2e-npm9/jest.config.js
Normal file
3
e2e/cli/e2e-npm9/jest.config.js
Normal file
@ -0,0 +1,3 @@
|
||||
const config = require('../jest.config');
|
||||
|
||||
module.exports = { ...config };
|
12
e2e/cli/e2e-npm9/package.json
Normal file
12
e2e/cli/e2e-npm9/package.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@verdaccio/e2e-cli-npm9",
|
||||
"version": "1.0.1-6-next.5",
|
||||
"dependencies": {
|
||||
"@verdaccio/test-cli-commons": "workspace:1.0.1-6-next.5",
|
||||
"npm": "9.0.0-pre.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest"
|
||||
}
|
||||
}
|
24
e2e/cli/e2e-npm9/ping.spec.ts
Normal file
24
e2e/cli/e2e-npm9/ping.spec.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { addRegistry, initialSetup } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
|
||||
describe('ping registry', () => {
|
||||
jest.setTimeout(10000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test('should ping registry', async () => {
|
||||
const resp = await npm({}, 'ping', '--json', ...addRegistry(registry.getRegistryUrl()));
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.registry).toEqual(registry.getRegistryUrl() + '/');
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
41
e2e/cli/e2e-npm9/publish.spec.ts
Normal file
41
e2e/cli/e2e-npm9/publish.spec.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
|
||||
describe('install a package', () => {
|
||||
jest.setTimeout(10000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['verdaccio-memory', 'verdaccio', '@verdaccio/foo', '@verdaccio/some-foo']])(
|
||||
'should publish a package %s',
|
||||
async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
expect(parsedBody.files).toBeDefined();
|
||||
expect(parsedBody.files).toBeDefined();
|
||||
}
|
||||
);
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
33
e2e/cli/e2e-npm9/search.spec.ts
Normal file
33
e2e/cli/e2e-npm9/search.spec.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { addRegistry, initialSetup } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { npm } from './utils';
|
||||
|
||||
describe('search a package', () => {
|
||||
jest.setTimeout(10000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test('should search a package', async () => {
|
||||
const resp = await npm(
|
||||
{},
|
||||
'search',
|
||||
'@verdaccio/cli',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
const pkgFind = parsedBody.find((item) => {
|
||||
return item.name === '@verdaccio/cli';
|
||||
});
|
||||
expect(pkgFind.name).toEqual('@verdaccio/cli');
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
8
e2e/cli/e2e-npm9/tsconfig.json
Normal file
8
e2e/cli/e2e-npm9/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.reference.json",
|
||||
"references": [
|
||||
{
|
||||
"path": "../cli-commons"
|
||||
}
|
||||
]
|
||||
}
|
41
e2e/cli/e2e-npm9/utils.ts
Normal file
41
e2e/cli/e2e-npm9/utils.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { SpawnOptions } from 'child_process';
|
||||
import { join } from 'path';
|
||||
|
||||
import { exec } from '@verdaccio/test-cli-commons';
|
||||
import { addRegistry } from '@verdaccio/test-cli-commons';
|
||||
|
||||
export function getCommand() {
|
||||
return join(__dirname, './node_modules/.bin/npm');
|
||||
}
|
||||
|
||||
export function npm(options: SpawnOptions, ...args: string[]) {
|
||||
return exec(options, getCommand(), args);
|
||||
}
|
||||
|
||||
export async function bumbUp(tempFolder, registry) {
|
||||
await npm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
export async function publish(tempFolder, pkgName, registry, arg: string[] = []) {
|
||||
const resp = await npm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
...arg,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
export async function getInfoVersions(pkgName, registry) {
|
||||
const infoResp = await npm(
|
||||
{},
|
||||
'info',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const infoBody = JSON.parse(infoResp.stdout as string);
|
||||
return infoBody;
|
||||
}
|
@ -1,26 +1,11 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { pnpm } from './utils';
|
||||
import { bumbUp, getInfoVersions, pnpm, publish } from './utils';
|
||||
|
||||
describe('deprecate a package', () => {
|
||||
jest.setTimeout(15000);
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
async function bumbUp(tempFolder, registry) {
|
||||
await pnpm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
async function publish(tempFolder, pkgName, registry) {
|
||||
const resp = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
async function deprecate(tempFolder, packageVersion, registry, message) {
|
||||
await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
@ -32,18 +17,6 @@ describe('deprecate a package', () => {
|
||||
);
|
||||
}
|
||||
|
||||
async function getInfoVersions(pkgName, registry) {
|
||||
const infoResp = await pnpm(
|
||||
{},
|
||||
'info',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const infoBody = JSON.parse(infoResp.stdout as string);
|
||||
return infoBody;
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
|
102
e2e/cli/e2e-pnpm6/dist-tags.spec.ts
Normal file
102
e2e/cli/e2e-pnpm6/dist-tags.spec.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { pnpm } from './utils';
|
||||
|
||||
async function bumbUp(tempFolder, registry) {
|
||||
await pnpm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
async function publish(tempFolder, pkgName, registry, arg: string[] = []) {
|
||||
const resp = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
...arg,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
describe('publish a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@foo/foo', 'foo']])('should list dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'ls',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('beta: 1.1.0latest: 1.0.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should remove tag with dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'rm',
|
||||
`${pkgName}@1.1.0`,
|
||||
'beta',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('-beta: @verdaccio/bar@1.1.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/five']])(
|
||||
'should add tag to package and version with dist-tags for %s',
|
||||
async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
const resp2 = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'add',
|
||||
`${pkgName}@1.1.0`,
|
||||
'alfa',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual(`+alfa: ${pkgName}@1.1.0`);
|
||||
}
|
||||
);
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
@ -27,7 +27,7 @@ describe('install a project packages', () => {
|
||||
'--reporter=default',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toMatch(/react 18.2.0/);
|
||||
expect(resp.stdout).toMatch(/react/);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
|
@ -2,11 +2,42 @@ import { SpawnOptions } from 'child_process';
|
||||
import { join } from 'path';
|
||||
|
||||
import { exec } from '@verdaccio/test-cli-commons';
|
||||
import { addRegistry } from '@verdaccio/test-cli-commons';
|
||||
|
||||
export function getCommand() {
|
||||
function getCommand() {
|
||||
return join(__dirname, './node_modules/.bin/pnpm');
|
||||
}
|
||||
|
||||
export function pnpm(options: SpawnOptions, ...args: string[]) {
|
||||
function pnpm(options: SpawnOptions, ...args: string[]) {
|
||||
return exec(options, getCommand(), args);
|
||||
}
|
||||
|
||||
async function bumbUp(tempFolder, registry) {
|
||||
await pnpm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
async function publish(tempFolder, pkgName, registry, arg: string[] = []) {
|
||||
const resp = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
...arg,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
async function getInfoVersions(pkgName, registry) {
|
||||
const infoResp = await pnpm(
|
||||
{},
|
||||
'info',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const infoBody = JSON.parse(infoResp.stdout as string);
|
||||
return infoBody;
|
||||
}
|
||||
|
||||
export { getInfoVersions, pnpm, publish, bumbUp };
|
||||
|
@ -1,26 +1,11 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { pnpm } from './utils';
|
||||
import { bumbUp, getInfoVersions, pnpm, publish } from './utils';
|
||||
|
||||
describe('deprecate a package', () => {
|
||||
jest.setTimeout(15000);
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
async function bumbUp(tempFolder, registry) {
|
||||
await pnpm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
async function publish(tempFolder, pkgName, registry) {
|
||||
const resp = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
async function deprecate(tempFolder, packageVersion, registry, message) {
|
||||
await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
@ -32,18 +17,6 @@ describe('deprecate a package', () => {
|
||||
);
|
||||
}
|
||||
|
||||
async function getInfoVersions(pkgName, registry) {
|
||||
const infoResp = await pnpm(
|
||||
{},
|
||||
'info',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const infoBody = JSON.parse(infoResp.stdout as string);
|
||||
return infoBody;
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
|
102
e2e/cli/e2e-pnpm7/dist-tags.spec.ts
Normal file
102
e2e/cli/e2e-pnpm7/dist-tags.spec.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { pnpm } from './utils';
|
||||
|
||||
async function bumbUp(tempFolder, registry) {
|
||||
await pnpm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
async function publish(tempFolder, pkgName, registry, arg: string[] = []) {
|
||||
const resp = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
...arg,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
describe('publish a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@foo/foo', 'foo']])('should list dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'ls',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('beta: 1.1.0latest: 1.0.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should remove tag with dist-tags for %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry, ['--tag', 'beta']);
|
||||
const resp2 = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'rm',
|
||||
`${pkgName}@1.1.0`,
|
||||
'beta',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual('-beta: @verdaccio/bar@1.1.0');
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/five']])(
|
||||
'should add tag to package and version with dist-tags for %s',
|
||||
async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
await bumbUp(tempFolder, registry);
|
||||
await publish(tempFolder, pkgName, registry);
|
||||
const resp2 = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'dist-tag',
|
||||
'add',
|
||||
`${pkgName}@1.1.0`,
|
||||
'alfa',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp2.stdout).toEqual(`+alfa: ${pkgName}@1.1.0`);
|
||||
}
|
||||
);
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
@ -27,7 +27,7 @@ describe('install a project packages', () => {
|
||||
'--reporter=default',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp.stdout).toMatch(/react 18.2.0/);
|
||||
expect(resp.stdout).toMatch(/react/);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
|
@ -2,11 +2,42 @@ import { SpawnOptions } from 'child_process';
|
||||
import { join } from 'path';
|
||||
|
||||
import { exec } from '@verdaccio/test-cli-commons';
|
||||
import { addRegistry } from '@verdaccio/test-cli-commons';
|
||||
|
||||
export function getCommand() {
|
||||
function getCommand() {
|
||||
return join(__dirname, './node_modules/.bin/pnpm');
|
||||
}
|
||||
|
||||
export function pnpm(options: SpawnOptions, ...args: string[]) {
|
||||
function pnpm(options: SpawnOptions, ...args: string[]) {
|
||||
return exec(options, getCommand(), args);
|
||||
}
|
||||
|
||||
async function bumbUp(tempFolder, registry) {
|
||||
await pnpm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
async function publish(tempFolder, pkgName, registry, arg: string[] = []) {
|
||||
const resp = await pnpm(
|
||||
{ cwd: tempFolder },
|
||||
'publish',
|
||||
...arg,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const parsedBody = JSON.parse(resp.stdout as string);
|
||||
expect(parsedBody.name).toEqual(pkgName);
|
||||
}
|
||||
|
||||
async function getInfoVersions(pkgName, registry) {
|
||||
const infoResp = await pnpm(
|
||||
{},
|
||||
'info',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
const infoBody = JSON.parse(infoResp.stdout as string);
|
||||
return infoBody;
|
||||
}
|
||||
|
||||
export { getInfoVersions, pnpm, publish, bumbUp };
|
||||
|
147
e2e/cli/e2e-yarn1/tag.spec.ts
Normal file
147
e2e/cli/e2e-yarn1/tag.spec.ts
Normal file
@ -0,0 +1,147 @@
|
||||
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
|
||||
|
||||
import { yarn } from './utils';
|
||||
|
||||
export async function bumbUp(tempFolder, registry) {
|
||||
await yarn({ cwd: tempFolder }, 'version', '--minor', ...addRegistry(registry.getRegistryUrl()));
|
||||
}
|
||||
|
||||
describe('install a package', () => {
|
||||
jest.setTimeout(20000);
|
||||
let registry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const setup = await initialSetup();
|
||||
registry = setup.registry;
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/bar']])('should list tags of a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0-patch',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await yarn({ cwd: tempFolder }, 'publish', '--json', ...addRegistry(registry.getRegistryUrl()));
|
||||
|
||||
const resp2 = await yarn(
|
||||
{ cwd: tempFolder },
|
||||
'tag',
|
||||
'list',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
|
||||
expect(resp2.stdout).toMatch(
|
||||
'{"type":"info","data":"Package @verdaccio%2fbar"}{"type":"info","data":"latest: 1.0.0-patch"}'
|
||||
);
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/foo']])('should add tag of a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await yarn({ cwd: tempFolder }, 'publish', '--json', ...addRegistry(registry.getRegistryUrl()));
|
||||
await bumbUp(tempFolder, registry);
|
||||
await yarn({ cwd: tempFolder }, 'publish', '--json', ...addRegistry(registry.getRegistryUrl()));
|
||||
|
||||
await yarn(
|
||||
{ cwd: tempFolder },
|
||||
'tag',
|
||||
'add',
|
||||
`${pkgName}@1.0.0`,
|
||||
'beta',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
|
||||
const resp2 = await yarn(
|
||||
{ cwd: tempFolder },
|
||||
'tag',
|
||||
'list',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
|
||||
expect(resp2.stdout).toMatch(
|
||||
'{"type":"info","data":"Package @verdaccio%2ffoo"}{"type":"info","data":"latest: 1.1.0"}{"type":"info","data":"beta: 1.0.0"}'
|
||||
);
|
||||
});
|
||||
|
||||
test.each([['@verdaccio/third']])('should remove tag of a package %s', async (pkgName) => {
|
||||
const { tempFolder } = await prepareGenericEmptyProject(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
registry.port,
|
||||
registry.getToken(),
|
||||
registry.getRegistryUrl()
|
||||
);
|
||||
|
||||
await yarn({ cwd: tempFolder }, 'publish', '--json', ...addRegistry(registry.getRegistryUrl()));
|
||||
await bumbUp(tempFolder, registry);
|
||||
await yarn({ cwd: tempFolder }, 'publish', '--json', ...addRegistry(registry.getRegistryUrl()));
|
||||
|
||||
await yarn(
|
||||
{ cwd: tempFolder },
|
||||
'tag',
|
||||
'add',
|
||||
`${pkgName}@1.0.0`,
|
||||
'beta',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
|
||||
const resp2 = await yarn(
|
||||
{ cwd: tempFolder },
|
||||
'tag',
|
||||
'list',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
|
||||
expect(resp2.stdout).toMatch(
|
||||
'{"type":"info","data":"Package @verdaccio%2fthird"}{"type":"info","data":"latest: 1.1.0"}{"type":"info","data":"beta: 1.0.0"}'
|
||||
);
|
||||
|
||||
const resp4 = await yarn(
|
||||
{ cwd: tempFolder },
|
||||
'tag',
|
||||
'remove',
|
||||
pkgName,
|
||||
'beta',
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
expect(resp4.stdout).toMatch(
|
||||
'{"type":"step","data":{"message":"Deleting tag","current":2,"total":3}}{"type":"success","data":"Deleted tag."}'
|
||||
);
|
||||
|
||||
const resp3 = await yarn(
|
||||
{ cwd: tempFolder },
|
||||
'tag',
|
||||
'list',
|
||||
pkgName,
|
||||
'--json',
|
||||
...addRegistry(registry.getRegistryUrl())
|
||||
);
|
||||
|
||||
expect(resp3.stdout).toMatch(
|
||||
'{"type":"info","data":"Package @verdaccio%2fthird"}{"type":"info","data":"latest: 1.1.0"}'
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
registry.stop();
|
||||
});
|
||||
});
|
@ -18,7 +18,7 @@ describe('publish package', () => {
|
||||
...configProtected,
|
||||
storage: registry1storage,
|
||||
});
|
||||
registry1 = new Registry(protectedRegistry.configPath);
|
||||
registry1 = new Registry(protectedRegistry.configPath, { createUser: true });
|
||||
await registry1.init();
|
||||
|
||||
const query1 = new ServerQuery(registry1.getRegistryUrl());
|
||||
|
@ -17,30 +17,43 @@ const buildAuthHeader = (token: string): string => {
|
||||
|
||||
const debug = buildDebug('verdaccio:registry');
|
||||
|
||||
const defaultOptions: Options = {
|
||||
domain: 'localhost',
|
||||
port: 4873,
|
||||
createUser: false,
|
||||
credentials: {
|
||||
user: 'foo',
|
||||
password: '12345',
|
||||
},
|
||||
debug: false,
|
||||
};
|
||||
|
||||
type Options = {
|
||||
domain: string;
|
||||
port: number;
|
||||
createUser: boolean;
|
||||
credentials: { user: string; password: string };
|
||||
debug: boolean;
|
||||
};
|
||||
|
||||
export class Registry {
|
||||
private childFork: any;
|
||||
private configPath: string;
|
||||
private domain: string;
|
||||
private createUser: boolean;
|
||||
private authstr: string | null = null;
|
||||
private port: number;
|
||||
private credentials;
|
||||
private token: string | null = null;
|
||||
private debug: boolean;
|
||||
public constructor(
|
||||
configPath: string,
|
||||
domain: string = 'localhost',
|
||||
port: number = 8080,
|
||||
credentials = {
|
||||
user: 'fooooo',
|
||||
password: 'sms_8tn>V%zPZ_+6', // pragma: allowlist secret
|
||||
},
|
||||
debug = false
|
||||
) {
|
||||
public constructor(configPath: string, options: Partial<Options> = {}) {
|
||||
const _options = { ...defaultOptions, ...options };
|
||||
this.configPath = configPath;
|
||||
this.port = port;
|
||||
this.domain = domain;
|
||||
this.debug = debug;
|
||||
this.credentials = credentials;
|
||||
this.createUser = _options.createUser;
|
||||
this.port = _options.port;
|
||||
this.domain = _options.domain;
|
||||
this.debug = _options.debug;
|
||||
this.credentials = _options.credentials;
|
||||
}
|
||||
|
||||
public static async fromConfigToPath(
|
||||
@ -126,19 +139,20 @@ export class Registry {
|
||||
try {
|
||||
if ('verdaccio_started' in msg) {
|
||||
const server = new ServerQuery(`http://${this.domain}:` + port);
|
||||
// const req = await server.debug();
|
||||
// req.status(HTTP_STATUS.OK);
|
||||
const user = await server.createUser(
|
||||
this.credentials.user,
|
||||
this.credentials.password
|
||||
);
|
||||
user.status(HTTP_STATUS.CREATED).body_ok(new RegExp(this.credentials.user));
|
||||
// @ts-ignore
|
||||
this.token = user?.response?.body.token;
|
||||
this.authstr = buildAuthHeader(this.token as string);
|
||||
if (this.createUser) {
|
||||
const user = await server.createUser(
|
||||
this.credentials.user,
|
||||
this.credentials.password
|
||||
);
|
||||
user.status(HTTP_STATUS.CREATED).body_ok(new RegExp(this.credentials.user));
|
||||
// @ts-ignore
|
||||
this.token = user?.response?.body.token;
|
||||
this.authstr = buildAuthHeader(this.token as string);
|
||||
}
|
||||
|
||||
return resolve(this.childFork);
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(e);
|
||||
// eslint-disable-next-line prefer-promise-reject-errors
|
||||
|
@ -138,7 +138,7 @@ export class ServerQuery {
|
||||
public constructor(url) {
|
||||
this.url = url.replace(/\/$/, '');
|
||||
debug('server url %s', this.url);
|
||||
this.userAgent = 'node/v8.1.2 linux x64';
|
||||
this.userAgent = 'node/v14.1.2 linux x64';
|
||||
}
|
||||
|
||||
private request(options: any): Promise<ResponseAssert> {
|
||||
|
@ -1,34 +1,8 @@
|
||||
{
|
||||
"extends": [
|
||||
"eslint:recommended"
|
||||
],
|
||||
"env": {
|
||||
"node": true,
|
||||
"mocha": true,
|
||||
"es6": true,
|
||||
"browser": true
|
||||
},
|
||||
"globals": {
|
||||
"jsdom": true
|
||||
},
|
||||
{
|
||||
"rules": {
|
||||
"valid-jsdoc": 0,
|
||||
"no-redeclare": 1,
|
||||
"no-console": [
|
||||
2,
|
||||
{
|
||||
"allow": [
|
||||
"log",
|
||||
"error"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-useless-escape": 0,
|
||||
"@typescript-eslint/explicit-function-return-type": 0,
|
||||
"@typescript-eslint/no-empty-function": 0,
|
||||
"handle-callback-err": 0,
|
||||
"jest/no-disabled-tests": 0,
|
||||
"jest/no-commented-out-tests": 0,
|
||||
"jest/no-standalone-expect": 0,
|
||||
"prefer-const": 0,
|
||||
"prefer-promise-reject-errors": 1
|
||||
}
|
||||
"no-console": 0
|
||||
}
|
||||
}
|
||||
|
@ -1,299 +0,0 @@
|
||||
## How to test Verdaccio
|
||||
|
||||
Welcome to the testing folder at Verdaccio. This document aims to help you understand how Verdaccio should be tested.
|
||||
|
||||
First of all, we should explain the testing frameworks being used. We use `jest` and other tools such as **`supertest`** to be able to test the API, and **`puppeteer`** for End-to-End testing.
|
||||
|
||||
### Before getting started
|
||||
|
||||
We go along with the following rules in order to be consistent with all tests which will make your code review smooth and fast:
|
||||
|
||||
- We **type** all our tests. eg `const foo: number = 3;`
|
||||
- **Each test should be as small as possible**: You should use the `test()` block to test only one thing and do not depend on other tests. If the test requires different steps, group them with a `describe()` block.
|
||||
- All `test()` **headers titles** should begin with `test('should test ...')`: For consistency with reporting tools, this makes it easier to match the test with the feature needed to be tested.
|
||||
- **Any mock data** should be located in the `partials` folder in each section.
|
||||
- Use `yaml` for **configuration files examples** instead of JSON.
|
||||
- If you use a **file based mock storage**, it should be located in the `store` folder in each section.
|
||||
- All tests **MUST NOT** rely on external sources and must be able to run them **offline**.
|
||||
- Tests **must run on the following Operating Systems**: Unix (Mac, Linux) and Windows (7 -> latest).
|
||||
- If you are creating mock data file which use the state and need a clean state, use `rimraf` to remove folders.
|
||||
|
||||
## Testing sections
|
||||
|
||||
Verdaccio testing is split in 3 sections, each of them has different setup and scope. The most important is the **unit test**. All sections have custom **jest configuration files**.
|
||||
|
||||
If you are adding new tests, comply with the following:
|
||||
|
||||
- If you add a new API endpoint, unit and functional tests are mandatory.
|
||||
- If you add a utility, unit test is mandatory.
|
||||
- If you are adding a new web API endpoint, the unit test, functional test and if such endpoint has new changes in the UI, E2E test is also mandatory.
|
||||
- If you add or refactor a core class, unit test is mandatory.
|
||||
- If you fix a bug, you **must** add a new `test()` block to prove that the patch fixes the bug.
|
||||
|
||||
## Unit test
|
||||
|
||||
Unit tests aim to test the CLI API and the Web API. The configuration file is located at `jest.config.js`.
|
||||
|
||||
> Unit testing does not need require pre-compile code, jest will catch any change done to the `{root}/src` files.
|
||||
|
||||
#### Testing an endpoint
|
||||
|
||||
We have prepared a template at `test/unit/api/api.__test.template.spec.ts` that you can follow to create your own unit test. Only the tests are appended with `.spec.ts` which will be found and used by `jest`.
|
||||
|
||||
> Feel free to suggest improvements to the template, there is still a lot of room for improvement.
|
||||
|
||||
We recommend the following approach when you create a unit test:
|
||||
|
||||
- For new utilities, we recommend creating a new spec.
|
||||
- For existing utilities, if the method is already being tested, just add a new `test()` block.
|
||||
- Notice that all API spec files are appended with `api.[feature].spec.js`, we recommend to follow the same approach. eg: `api.[deprecate].spec.js`.
|
||||
- Don't mix utilities with API tests.
|
||||
|
||||
### How the mockServer works?
|
||||
|
||||
Each `[xxx].spec.ts` file usually triggers a `mockServer` on in the`beforeAll` phase. This is is handy since we might need a `uplink` server to test different scenarios.
|
||||
|
||||
Let's analyze the following example:
|
||||
|
||||
```js
|
||||
const configForTest = configDefault(
|
||||
{
|
||||
auth: {
|
||||
htpasswd: {
|
||||
file: './test-storage-api-spec/.htpasswd',
|
||||
},
|
||||
},
|
||||
filters: {
|
||||
'../../modules/api/partials/plugin/filter': {
|
||||
pkg: 'npm_test',
|
||||
version: '2.0.0',
|
||||
},
|
||||
},
|
||||
storage: store,
|
||||
self_path: store,
|
||||
uplinks: {
|
||||
npmjs: {
|
||||
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`,
|
||||
},
|
||||
},
|
||||
log: [{ type: 'stdout', format: 'pretty', level: 'trace' }],
|
||||
},
|
||||
'api.spec.yaml'
|
||||
);
|
||||
|
||||
app = await endPointAPI(configForTest);
|
||||
mockRegistry = await mockServer(mockServerPort).init();
|
||||
```
|
||||
|
||||
The `configDefault({}, 'myConfig.yaml)` function is a method that returns a configuration file that will be the config used for your test.
|
||||
|
||||
- The _first argument_ allows you to override/extend the default configuration located `/test/unit/partials/config/yaml/default.yaml`.
|
||||
- The *second argument*s is being used to override the base configuration file, you only need to set the name `api.spec.yaml` you are willing to use, the relative location will be `test/unit/partials/config/yaml/` and will be prefixed on runtime.
|
||||
|
||||
> **The generated object will be used for run your test, not for mock the mock server.**
|
||||
|
||||
The `app = await endPointAPI(configForTest);` is the server that you are about to run your test against. The `app` object is used to call the endoints, for instance:
|
||||
|
||||
```js
|
||||
test('should fetch jquery package from remote uplink', (done) => {
|
||||
request(app)
|
||||
.get('/jquery')
|
||||
.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);
|
||||
}
|
||||
|
||||
expect(res.body).toBeDefined();
|
||||
expect(res.body.name).toMatch(/jquery/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
In the previous example, we are fetching `jquery` metadata from our server, we can define custom headers, expect some specific status and validate the body outcome.
|
||||
|
||||
> For more information about the **supertest** API, please [read their website](https://www.npmjs.com/package/supertest).
|
||||
|
||||
The `mockRegistry = await mockServer(mockServerPort).init();` mock registry will be used as `uplink` for the `app` object described above, **this is optional**, but, the most of the tests are using this approach for increase the number of tested scenarios.
|
||||
|
||||
The _mock server_ has a static storage which is located `test/unit/partials/mock-store`, if you need add new packages, those must be commited in such folder. **Any modification in the mock server might affect other test, since is a shared context**.
|
||||
|
||||
> It is not possible yet to override the mocks configuration server.
|
||||
|
||||
> The `config_path` is a legacy prop that must to be set manually, this prop is being generated by the CLI, but running the test without the CLI force use to generate it manually. **This might change in the future**.
|
||||
|
||||
> The `const mockServerPort = 55549;` mock server must be added manually, be careful and try to define a port that is not being used by another test, there is not automation here yet.
|
||||
|
||||
> To increase debugging you might override the `logs` property using `{ type: 'stdout', format: 'pretty', level: 'trace' }` level **trace**, thus the test will display the server request in your terminal, try to keep it in **warn** by default to avoid noise on run all your test.
|
||||
|
||||
#### Running a single Unit Test
|
||||
|
||||
To run a single test, use the following command:
|
||||
|
||||
```bash
|
||||
yarn jest test/unit/modules/api/api.spec.ts --coverage=false
|
||||
```
|
||||
|
||||
You might use the _jest_ feature `.only` to limit the test suites you want to run, for instance.
|
||||
|
||||
```js
|
||||
describe.only('should test package api', () => {
|
||||
```
|
||||
|
||||
That will help to run small chunk of tests and makes more easy the development.
|
||||
|
||||
#### Debugging Mock Server Request
|
||||
|
||||
In order to inspect more information about what is being sended between your test and the mock server, you might take advance of the `debug` library used by `request`, for instance.
|
||||
|
||||
```
|
||||
NODE_DEBUG=request yarn jest test/unit/modules/api/api.spec.ts --runInBand=true --coverage=false
|
||||
```
|
||||
|
||||
The outcome you will see in your terminal looks like:
|
||||
|
||||
```
|
||||
Ran all test suites matching /test\/unit\/modules\/api\/api.spec.ts/i.
|
||||
console.error node_modules/request/request.js:136
|
||||
REQUEST onRequestResponse http://0.0.0.0:55549/jquery 200 { 'x-powered-by': 'verdaccio/4.1.0',
|
||||
'access-control-allow-origin': '*',
|
||||
'content-type': 'application/json; charset=utf-8',
|
||||
etag: '"xxxxx"',
|
||||
vary: 'Accept-Encoding',
|
||||
'content-encoding': 'gzip',
|
||||
date: 'Sat, 27 Jul 2019 06:44:13 GMT',
|
||||
connection: 'close',
|
||||
'transfer-encoding': 'chunked' }
|
||||
|
||||
http --> 200, req: 'GET http://0.0.0.0:55549/jquery' (streaming)
|
||||
console.error node_modules/request/request.js:136
|
||||
REQUEST reading response's body
|
||||
|
||||
console.error node_modules/request/request.js:136
|
||||
REQUEST finish init function http://0.0.0.0:55549/jquery
|
||||
|
||||
console.error node_modules/request/request.js:136
|
||||
REQUEST response end http://0.0.0.0:55549/jquery 200 { 'x-powered-by': 'verdaccio/4.1.0',
|
||||
'access-control-allow-origin': '*',
|
||||
'content-type': 'application/json; charset=utf-8',
|
||||
etag: '"xxxxx"',
|
||||
vary: 'Accept-Encoding',
|
||||
'content-encoding': 'gzip',
|
||||
date: 'Sat, 27 Jul 2019 06:44:13 GMT',
|
||||
connection: 'close',
|
||||
'transfer-encoding': 'chunked' }
|
||||
|
||||
console.error node_modules/request/request.js:136
|
||||
REQUEST end event http://0.0.0.0:55549/jquery
|
||||
|
||||
console.error node_modules/request/request.js:136
|
||||
REQUEST has body http://0.0.0.0:55549/jquery 133608
|
||||
|
||||
console.error node_modules/request/request.js:136
|
||||
REQUEST emitting complete http://0.0.0.0:55549/jquery
|
||||
|
||||
http --> 200, req: 'GET http://0.0.0.0:55549/jquery', bytes: 0/133608
|
||||
debug-=- updating package jquery info
|
||||
http <-- 200, user: null(::ffff:127.0.0.1), req: 'GET /jquery', bytes: 0/10300
|
||||
```
|
||||
|
||||
The debug display request headers and other handy information about what is happening between your test and the mock server.
|
||||
|
||||
## Functional tests
|
||||
|
||||
The functional tests aim to run only **cli endpoint** and **web point** using real request to an existing and compiled running Verdaccio server.
|
||||
|
||||
> Be aware if you change something in the `{root}/src` source code, you must run `yarn code:build` before to be able to see your changes because functional tests use the transpiled code.
|
||||
|
||||
All tests must be included in the `test/functional/index.spec.ts` file, which bootstraps the whole process. There is only one spec file and **must be only one**.
|
||||
|
||||
The jest configuration file is defined in `test/jest.config.functional.js`. The configuration will create a custom environment launching 3 Verdaccio servers with different configurations.
|
||||
|
||||
The servers are linked as follows:
|
||||
|
||||
- Server 1
|
||||
- -> Server 2
|
||||
- -> Server 3
|
||||
- Server 2
|
||||
- -> Server 1
|
||||
- Server 3
|
||||
- -> Server 2
|
||||
- -> Server 1
|
||||
- Express app: (if you need to emulate any external endpoint, use the express app)
|
||||
|
||||
Server 1 runs on port `55551`, Server 2 on port `55552` and Server 3 on port `55553`.
|
||||
|
||||
> If you have the need to increase the number of servers running, it is possible, but please discuss with the team before you go in that path.
|
||||
|
||||
#### Adding a new block
|
||||
|
||||
To add a new feature you need to export the feature as a function that take as an argument any of the servers you want to interact.
|
||||
|
||||
```js
|
||||
// newFeature.ts
|
||||
|
||||
export default function (server) {
|
||||
describe('package access control', () => {
|
||||
test('should ...', (done) => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Then import the feature and run the function within the main `describe` block.
|
||||
|
||||
```js
|
||||
// index.spec.ts
|
||||
import newFeature from './newFeature';
|
||||
|
||||
describe('functional test verdaccio', function () {
|
||||
/ test are fast, but do not change this time out, 10 seconds should be more than enough
|
||||
jest.setTimeout(10000);
|
||||
/ servers are accessed via a global jest state.
|
||||
const server1: IServerBridge = global.__SERVERS__[0];
|
||||
const server2: IServerBridge = global.__SERVERS__[1];
|
||||
const server3: IServerBridge = global.__SERVERS__[2];
|
||||
const app = global.__WEB_SERVER__.app;
|
||||
/ include as much servers you need
|
||||
newFeature(server1, server2, server3);
|
||||
});
|
||||
```
|
||||
|
||||
Functional tests run over one single file, thus, it is not possible at this stage to run tests individually.
|
||||
|
||||
## E2E Test
|
||||
|
||||
Verdaccio includes a Web User Interface that must be tested. We use End-to-End testing to run some mock tests against the web API using the UI Theme
|
||||
include by default.
|
||||
|
||||
```bash
|
||||
yarn lint && yarn test:all
|
||||
```
|
||||
|
||||
The test does not have aim to test the integrity of the page, mostly, ensure the basic functionality still works. If you add or modify
|
||||
a UI feature, the tests must be updated.
|
||||
|
||||
> The tests rely on CSS classes naming convention, so, it is required some sort of coordination with the **verdaccio/ui** project.
|
||||
|
||||
We uses `puppeteer`, you can find more information about how to use it in their website.
|
||||
|
||||
## Before commit
|
||||
|
||||
We recommend run your tests and linters before commit.
|
||||
|
||||
```bash
|
||||
yarn lint && yarn test:all
|
||||
```
|
||||
|
||||
You can find more in our [guide about run and debugging test](https://github.com/verdaccio/verdaccio/wiki/Running-and-Debugging-tests#running-the-test).
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
Verdaccio uses [CircleCI](https://circleci.com/gh/verdaccio) as its primary Continuous Integration tool. We run the tests against the most common Node.js versions available. Among them is LTS and the latest release. Before the PR is being merged, all checks must be green.
|
||||
Node.js versions available, LTS and the latest release. Before the PR is being merged, all check must be green.
|
||||
|
||||
> You need a CircleCI account to be able see the test running
|
55
packages/verdaccio/test/basic.spec.ts
Normal file
55
packages/verdaccio/test/basic.spec.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { ConfigBuilder } from '@verdaccio/config';
|
||||
import { HTTP_STATUS, constants, fileUtils } from '@verdaccio/core';
|
||||
|
||||
import { Registry, ServerQuery } from '../src/server';
|
||||
|
||||
describe('basic test endpoints', () => {
|
||||
let registry;
|
||||
|
||||
beforeAll(async function () {
|
||||
const storage = await fileUtils.createTempStorageFolder('basic-test');
|
||||
const configuration = ConfigBuilder.build()
|
||||
.addStorage(storage)
|
||||
.addPackageAccess(constants.PACKAGE_ACCESS.ALL, {
|
||||
access: constants.ROLES.$ALL,
|
||||
publish: constants.ROLES.$ALL,
|
||||
})
|
||||
.addAuth({
|
||||
htpasswd: {
|
||||
file: './htpasswd',
|
||||
},
|
||||
})
|
||||
.addLogger({ level: 'debug', type: 'stdout', format: 'pretty' })
|
||||
.addUplink('upstream', { url: 'https://registry.verdaccio.org' });
|
||||
const { configPath } = await Registry.fromConfigToPath(configuration.getConfig());
|
||||
registry = new Registry(configPath);
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
registry.stop();
|
||||
});
|
||||
|
||||
describe('server health', () => {
|
||||
test('ping', async () => {
|
||||
const server = new ServerQuery(registry.getRegistryUrl());
|
||||
await server.ping();
|
||||
});
|
||||
});
|
||||
|
||||
describe('unpublish package', () => {
|
||||
test('shoud unpublish the whole package of many published', async function () {
|
||||
const server = new ServerQuery(registry.getRegistryUrl());
|
||||
await server.addPackage('unpublish-new-package', '1.0.0');
|
||||
await server.addPackage('unpublish-new-package', '1.0.1');
|
||||
await server.addPackage('unpublish-new-package', '1.0.2');
|
||||
(await server.getPackage('unpublish-new-package')).status(HTTP_STATUS.OK);
|
||||
(await server.removePackage('unpublish-new-package', '_rev')).status(HTTP_STATUS.CREATED);
|
||||
(await server.getPackage('unpublish-new-package')).status(HTTP_STATUS.NOT_FOUND);
|
||||
// FIXME: throws 500 instead 404
|
||||
// (await server.getTarball('unpublish-new-package', 'unpublish-new-package-1.0.0.tgz')).status(
|
||||
// HTTP_STATUS.NOT_FOUND
|
||||
// );
|
||||
});
|
||||
});
|
||||
});
|
201
packages/verdaccio/test/config.yaml
Normal file
201
packages/verdaccio/test/config.yaml
Normal file
@ -0,0 +1,201 @@
|
||||
#
|
||||
# This is the default configuration file. It allows all users to do anything,
|
||||
# please read carefully the documentation and best practices to
|
||||
# improve security.
|
||||
#
|
||||
# Look here for more config file examples:
|
||||
# https://github.com/verdaccio/verdaccio/tree/5.x/packages/config/src/conf/default.yaml
|
||||
#
|
||||
# Read about the best practices
|
||||
# https://verdaccio.org/docs/best
|
||||
|
||||
# path to a directory with all packages
|
||||
storage: ./storage
|
||||
# path to a directory with plugins to include, the plugins folder has the higher priority for loading plugins
|
||||
# disable this folder to avoid warnings if is not used
|
||||
# plugins: ./plugins
|
||||
|
||||
# https://verdaccio.org/docs/webui
|
||||
web:
|
||||
title: Verdaccio
|
||||
# comment out to disable gravatar support
|
||||
# gravatar: false
|
||||
# by default packages are ordercer ascendant (asc|desc)
|
||||
# sort_packages: asc
|
||||
# convert your UI to the dark side
|
||||
# darkMode: true
|
||||
# html_cache: true
|
||||
# by default all features are displayed
|
||||
# login: true
|
||||
# showInfo: true
|
||||
# showSettings: true
|
||||
# In combination with darkMode you can force specific theme
|
||||
# showThemeSwitch: true
|
||||
# showFooter: true
|
||||
# showSearch: true
|
||||
# showRaw: true
|
||||
# showDownloadTarball: true
|
||||
# HTML tags injected after manifest <scripts/>
|
||||
# scriptsBodyAfter:
|
||||
# - '<script type="text/javascript" src="https://my.company.com/customJS.min.js"></script>'
|
||||
# HTML tags injected before ends </head>
|
||||
# metaScripts:
|
||||
# - '<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>'
|
||||
# - '<script type="text/javascript" src="https://browser.sentry-cdn.com/5.15.5/bundle.min.js"></script>'
|
||||
# - '<meta name="robots" content="noindex" />'
|
||||
# HTML tags injected first child at <body/>
|
||||
# bodyBefore:
|
||||
# - '<div id="myId">html before webpack scripts</div>'
|
||||
# Public path for template manifest scripts (only manifest)
|
||||
# publicPath: http://somedomain.org/
|
||||
|
||||
# https://verdaccio.org/docs/configuration#authentication
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd
|
||||
# Maximum amount of users allowed to register, defaults to "+inf".
|
||||
# You can set this to -1 to disable registration.
|
||||
# max_users: 1000
|
||||
|
||||
# https://verdaccio.org/docs/configuration#uplinks
|
||||
# a list of other known repositories we can talk to
|
||||
uplinks:
|
||||
npmjs:
|
||||
url: https://registry.npmjs.org/
|
||||
|
||||
# Learn how to protect your packages
|
||||
# https://verdaccio.org/docs/protect-your-dependencies/
|
||||
# https://verdaccio.org/docs/configuration#packages
|
||||
packages:
|
||||
'@*/*':
|
||||
# scoped packages
|
||||
access: $all
|
||||
publish: $authenticated
|
||||
unpublish: $authenticated
|
||||
proxy: npmjs
|
||||
|
||||
'**':
|
||||
# allow all users (including non-authenticated users) to read and
|
||||
# publish all packages
|
||||
#
|
||||
# you can specify usernames/groupnames (depending on your auth plugin)
|
||||
# and three keywords: "$all", "$anonymous", "$authenticated"
|
||||
access: $all
|
||||
|
||||
# allow all known users to publish/publish packages
|
||||
# (anyone can register by default, remember?)
|
||||
publish: $authenticated
|
||||
unpublish: $authenticated
|
||||
|
||||
# if package is not available locally, proxy requests to 'npmjs' registry
|
||||
proxy: npmjs
|
||||
|
||||
# To improve your security configuration and avoid dependency confusion
|
||||
# consider removing the proxy property for private packages
|
||||
# https://verdaccio.org/docs/best#remove-proxy-to-increase-security-at-private-packages
|
||||
|
||||
# https://verdaccio.org/docs/configuration#server
|
||||
# You can specify HTTP/1.1 server keep alive timeout in seconds for incoming connections.
|
||||
# A value of 0 makes the http server behave similarly to Node.js versions prior to 8.0.0, which did not have a keep-alive timeout.
|
||||
# WORKAROUND: Through given configuration you can workaround following issue https://github.com/verdaccio/verdaccio/issues/301. Set to 0 in case 60 is not enough.
|
||||
server:
|
||||
keepAliveTimeout: 60
|
||||
# The pluginPrefix replaces the default plugins prefix which is `verdaccio`, please don't include `-`. If `something` is provided
|
||||
# the resolve package will be `something-xxxx`.
|
||||
# pluginPrefix: something
|
||||
# A regex for the password validation /.{3}$/ (3 characters min)
|
||||
# An example to limit to 10 characters minimum
|
||||
# passwordValidationRegex: /.{10}$/
|
||||
|
||||
# https://verdaccio.org/docs/configuration#offline-publish
|
||||
# publish:
|
||||
# allow_offline: false
|
||||
|
||||
# https://verdaccio.org/docs/configuration#url-prefix
|
||||
# url_prefix: /verdaccio/
|
||||
# VERDACCIO_PUBLIC_URL='https://somedomain.org';
|
||||
# url_prefix: '/my_prefix'
|
||||
# // url -> https://somedomain.org/my_prefix/
|
||||
# VERDACCIO_PUBLIC_URL='https://somedomain.org';
|
||||
# url_prefix: '/'
|
||||
# // url -> https://somedomain.org/
|
||||
# VERDACCIO_PUBLIC_URL='https://somedomain.org/first_prefix';
|
||||
# url_prefix: '/second_prefix'
|
||||
# // url -> https://somedomain.org/second_prefix/'
|
||||
|
||||
# https://verdaccio.org/docs/configuration#security
|
||||
# security:
|
||||
# api:
|
||||
# legacy: true
|
||||
# jwt:
|
||||
# sign:
|
||||
# expiresIn: 29d
|
||||
# verify:
|
||||
# someProp: [value]
|
||||
# web:
|
||||
# sign:
|
||||
# expiresIn: 1h # 1 hour by default
|
||||
# verify:
|
||||
# someProp: [value]
|
||||
|
||||
# https://verdaccio.org/docs/configuration#user-rate-limit
|
||||
# userRateLimit:
|
||||
# windowMs: 50000
|
||||
# max: 1000
|
||||
|
||||
# https://verdaccio.org/docs/configuration#max-body-size
|
||||
# max_body_size: 10mb
|
||||
|
||||
# https://verdaccio.org/docs/configuration#listen-port
|
||||
# listen:
|
||||
# - localhost:4873 # default value
|
||||
# - http://localhost:4873 # same thing
|
||||
# - 0.0.0.0:4873 # listen on all addresses (INADDR_ANY)
|
||||
# - https://example.org:4873 # if you want to use https
|
||||
# - "[::1]:4873" # ipv6
|
||||
# - unix:/tmp/verdaccio.sock # unix socket
|
||||
|
||||
# The HTTPS configuration is useful if you do not consider use a HTTP Proxy
|
||||
# https://verdaccio.org/docs/configuration#https
|
||||
# https:
|
||||
# key: ./path/verdaccio-key.pem
|
||||
# cert: ./path/verdaccio-cert.pem
|
||||
# ca: ./path/verdaccio-csr.pem
|
||||
|
||||
# https://verdaccio.org/docs/configuration#proxy
|
||||
# http_proxy: http://something.local/
|
||||
# https_proxy: https://something.local/
|
||||
|
||||
# https://verdaccio.org/docs/configuration#notifications
|
||||
# notify:
|
||||
# method: POST
|
||||
# headers: [{ "Content-Type": "application/json" }]
|
||||
# endpoint: https://usagge.hipchat.com/v2/room/3729485/notification?auth_token=mySecretToken
|
||||
# content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}'
|
||||
|
||||
middlewares:
|
||||
audit:
|
||||
enabled: true
|
||||
|
||||
# https://verdaccio.org/docs/logger
|
||||
# log settings
|
||||
log: { type: stdout, format: pretty, level: http }
|
||||
#experiments:
|
||||
# # support for npm token command
|
||||
# token: false
|
||||
# # disable writing body size to logs, read more on ticket 1912
|
||||
# bytesin_off: false
|
||||
# # enable tarball URL redirect for hosting tarball with a different server, the tarball_url_redirect can be a template string
|
||||
# tarball_url_redirect: 'https://mycdn.com/verdaccio/${packageName}/${filename}'
|
||||
# # the tarball_url_redirect can be a function, takes packageName and filename and returns the url, when working with a js configuration file
|
||||
# tarball_url_redirect(packageName, filename) {
|
||||
# const signedUrl = // generate a signed url
|
||||
# return signedUrl;
|
||||
# }
|
||||
|
||||
# translate your registry, api i18n not available yet
|
||||
i18n:
|
||||
# list of the available translations https://github.com/verdaccio/verdaccio/blob/master/packages/plugins/ui-theme/src/i18n/ABOUT_TRANSLATIONS.md
|
||||
web: en-US
|
||||
|
||||
_debug: true
|
0
packages/verdaccio/test/unit/__helper/api.ts → packages/verdaccio/test/disabled_test/__helper/api.ts
0
packages/verdaccio/test/unit/__helper/api.ts → packages/verdaccio/test/disabled_test/__helper/api.ts
0
packages/verdaccio/test/functional/tags/tags.ts → packages/verdaccio/test/disabled_test/tags/tags.ts
0
packages/verdaccio/test/functional/tags/tags.ts → packages/verdaccio/test/disabled_test/tags/tags.ts
@ -1,213 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { DIST_TAGS, HTTP_STATUS } from '@verdaccio/core';
|
||||
import { createTarballHash } from '@verdaccio/utils';
|
||||
|
||||
import {
|
||||
CREDENTIALS,
|
||||
DOMAIN_SERVERS,
|
||||
PORT_SERVER_1,
|
||||
PORT_SERVER_2,
|
||||
TARBALL,
|
||||
} from '../config.functional';
|
||||
import fixturePkg from '../fixtures/package';
|
||||
import ping from './ping';
|
||||
import whoIam from './whoIam';
|
||||
|
||||
function readfile(folderPath) {
|
||||
return fs.readFileSync(path.join(__dirname, '/', folderPath));
|
||||
}
|
||||
|
||||
function getPackage(name) {
|
||||
return fixturePkg(name);
|
||||
}
|
||||
|
||||
export default function (server: any, server2: any) {
|
||||
describe('basic test endpoints', () => {
|
||||
const PKG_NAME = 'testpkg';
|
||||
const PKG_VERSION = '0.0.1';
|
||||
|
||||
beforeAll(function () {
|
||||
return server
|
||||
.auth(CREDENTIALS.user, CREDENTIALS.password)
|
||||
.status(HTTP_STATUS.CREATED)
|
||||
.body_ok(/'test'/);
|
||||
});
|
||||
|
||||
whoIam(server);
|
||||
ping(server);
|
||||
|
||||
describe('handling packages', () => {
|
||||
beforeAll(function () {
|
||||
return server.addPackage(PKG_NAME);
|
||||
});
|
||||
|
||||
beforeAll(function () {
|
||||
return server.addPackage('testpkg-single-tarball');
|
||||
});
|
||||
|
||||
test('creating new package', () => {
|
||||
/* test for before() */
|
||||
});
|
||||
|
||||
test('downloading non-existent tarball', () => {
|
||||
return server
|
||||
.getTarball(PKG_NAME, TARBALL)
|
||||
.status(HTTP_STATUS.NOT_FOUND)
|
||||
.body_error(/no such file/);
|
||||
});
|
||||
|
||||
test('uploading incomplete tarball', () => {
|
||||
return server.putTarballIncomplete(
|
||||
PKG_NAME,
|
||||
'blahblah1',
|
||||
readfile('../fixtures/binary'),
|
||||
3000
|
||||
);
|
||||
});
|
||||
|
||||
describe('publishing package', () => {
|
||||
beforeAll(function () {
|
||||
return server
|
||||
.putTarball(PKG_NAME, TARBALL, readfile('../fixtures/binary'))
|
||||
.status(HTTP_STATUS.CREATED)
|
||||
.body_ok(/.*/);
|
||||
});
|
||||
|
||||
beforeAll(function () {
|
||||
return server
|
||||
.putTarball('testpkg-single-tarball', 'single', readfile('../fixtures/binary'))
|
||||
.status(HTTP_STATUS.CREATED)
|
||||
.body_ok(/.*/);
|
||||
});
|
||||
|
||||
afterAll(function () {
|
||||
return server.removeTarball(PKG_NAME).status(HTTP_STATUS.CREATED);
|
||||
});
|
||||
|
||||
test('remove non existing tarball', () => {
|
||||
return server.removeTarball('testpkg404').status(HTTP_STATUS.NOT_FOUND);
|
||||
});
|
||||
|
||||
test('remove non existing single tarball', () => {
|
||||
return server.removeSingleTarball('', 'fakeFile').status(HTTP_STATUS.NOT_FOUND);
|
||||
});
|
||||
|
||||
// testexp-incomplete
|
||||
|
||||
test('remove existing single tarball', () => {
|
||||
return server
|
||||
.removeSingleTarball('testpkg-single-tarball', 'single')
|
||||
.status(HTTP_STATUS.CREATED);
|
||||
});
|
||||
|
||||
// testexp-incomplete
|
||||
|
||||
test('downloading newly created tarball', () => {
|
||||
return server
|
||||
.getTarball(PKG_NAME, TARBALL)
|
||||
.status(200)
|
||||
.then(function (body) {
|
||||
expect(body).toEqual(readfile('../fixtures/binary'));
|
||||
});
|
||||
});
|
||||
|
||||
test('uploading new package version (bad sha)', () => {
|
||||
let pkg = getPackage(PKG_NAME);
|
||||
pkg.dist.shasum = createTarballHash().update('fake').digest('hex');
|
||||
|
||||
return server
|
||||
.putVersion(PKG_NAME, PKG_VERSION, pkg)
|
||||
.status(HTTP_STATUS.BAD_REQUEST)
|
||||
.body_error(/shasum error/);
|
||||
});
|
||||
|
||||
describe('publishing version', () => {
|
||||
beforeAll(function () {
|
||||
const pkg = getPackage(PKG_NAME);
|
||||
|
||||
pkg.dist.shasum = createTarballHash()
|
||||
.update(readfile('../fixtures/binary'))
|
||||
.digest('hex');
|
||||
return server
|
||||
.putVersion(PKG_NAME, PKG_VERSION, pkg)
|
||||
.status(HTTP_STATUS.CREATED)
|
||||
.body_ok(/published/);
|
||||
});
|
||||
|
||||
describe('should download a package', () => {
|
||||
beforeAll(function () {
|
||||
return server
|
||||
.auth(CREDENTIALS.user, CREDENTIALS.password)
|
||||
.status(HTTP_STATUS.CREATED)
|
||||
.body_ok(new RegExp(CREDENTIALS.user));
|
||||
});
|
||||
|
||||
test('should download a newly created package from server1', () => {
|
||||
return server
|
||||
.getPackage(PKG_NAME)
|
||||
.status(HTTP_STATUS.OK)
|
||||
.then(function (body) {
|
||||
expect(body.name).toEqual(PKG_NAME);
|
||||
expect(body.versions[PKG_VERSION].name).toEqual(PKG_NAME);
|
||||
expect(body.versions[PKG_VERSION].dist.tarball).toEqual(
|
||||
`http://${DOMAIN_SERVERS}:${PORT_SERVER_1}/${PKG_NAME}/-/${TARBALL}`
|
||||
);
|
||||
expect(body[DIST_TAGS]).toEqual({
|
||||
latest: PKG_VERSION,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should downloading a package from server2', () => {
|
||||
return server2
|
||||
.getPackage(PKG_NAME)
|
||||
.status(HTTP_STATUS.OK)
|
||||
.then(function (body) {
|
||||
expect(body.name).toEqual(PKG_NAME);
|
||||
expect(body.versions[PKG_VERSION].name).toEqual(PKG_NAME);
|
||||
expect(body.versions[PKG_VERSION].dist.tarball).toEqual(
|
||||
`http://${DOMAIN_SERVERS}:${PORT_SERVER_2}/${PKG_NAME}/-/${TARBALL}`
|
||||
);
|
||||
expect(body[DIST_TAGS]).toEqual({
|
||||
latest: PKG_VERSION,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('handle failures on endpoints', () => {
|
||||
test('should fails trying to fetch non-existent package', () => {
|
||||
return server
|
||||
.getPackage(PKG_NAME)
|
||||
.status(HTTP_STATUS.NOT_FOUND)
|
||||
.body_error(/no such package/);
|
||||
});
|
||||
|
||||
test('should fails on publish a version for non existing package', () => {
|
||||
return server
|
||||
.putVersion('testpxg', PKG_VERSION, getPackage('testpxg'))
|
||||
.status(HTTP_STATUS.NOT_FOUND)
|
||||
.body_error(/no such package/);
|
||||
});
|
||||
|
||||
test('should be a package not found', () => {
|
||||
return server
|
||||
.putTarball('nonExistingPackage', TARBALL, readfile('../fixtures/binary'))
|
||||
.status(HTTP_STATUS.NOT_FOUND)
|
||||
.body_error(/no such/);
|
||||
});
|
||||
|
||||
test('should fails on publish package in a bad uplink', () => {
|
||||
return server
|
||||
.putPackage('baduplink', getPackage('baduplink'))
|
||||
.status(HTTP_STATUS.SERVICE_UNAVAILABLE)
|
||||
.body_error(/one of the uplinks is down, refuse to publish/);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
export default function (server) {
|
||||
test('ping', () => {
|
||||
return server.ping().then(function (data) {
|
||||
// it's always an empty object
|
||||
expect(_.isObject(data)).toBeDefined();
|
||||
});
|
||||
});
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
import { CREDENTIALS } from '../config.functional';
|
||||
|
||||
export default function (server) {
|
||||
test('who am I?', () => {
|
||||
return server.whoami().then(function (username) {
|
||||
expect(username).toMatch(CREDENTIALS.user);
|
||||
});
|
||||
});
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import { DOMAIN_SERVERS as localhost } from '../test.conf';
|
||||
|
||||
export const CREDENTIALS = {
|
||||
user: 'test',
|
||||
password: 'test',
|
||||
};
|
||||
|
||||
export const TARBALL = 'tarball-blahblah-file.name';
|
||||
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;
|
@ -1,78 +0,0 @@
|
||||
// /* eslint-disable no-unused-vars */
|
||||
|
||||
// /* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
// // we need this for notifications
|
||||
// import { setup } from '@verdaccio/logger';
|
||||
// import { IServerBridge } from '@verdaccio/mock';
|
||||
|
||||
// import adduser from './adduser/adduser';
|
||||
// import logout from './adduser/logout';
|
||||
// import basic from './basic/basic';
|
||||
// import packageAccess from './package/access';
|
||||
// import packageGzip from './package/gzip';
|
||||
// import packageScoped from './package/scoped';
|
||||
// import race from './performance/race';
|
||||
// import pluginsAuth from './plugins/auth';
|
||||
// import middleware from './plugins/middleware';
|
||||
// import readme from './readme/readme';
|
||||
// import incomplete from './sanity/incomplete';
|
||||
// import mirror from './sanity/mirror';
|
||||
// import nullstorage from './sanity/nullstorage';
|
||||
// // import simpleSearch from './search/simple.search';
|
||||
// import racycrash from './sanity/racycrash';
|
||||
// import security from './sanity/security';
|
||||
// import gh29 from './scenarios/gh29';
|
||||
// import addtag from './tags/addtag';
|
||||
// import distTagsMerge from './tags/dist-tags-merge';
|
||||
// import tags from './tags/tags';
|
||||
// import upLinkCache from './uplinks/cache';
|
||||
// import uplinkTimeout from './uplinks/timeout';
|
||||
|
||||
// setup({});
|
||||
|
||||
// describe('functional test verdaccio', function () {
|
||||
// jest.setTimeout(20000);
|
||||
// // @ts-ignore
|
||||
// const server1: IServerBridge = global.__SERVERS__[0];
|
||||
// // @ts-ignore
|
||||
// const server2 = global.__SERVERS__[1];
|
||||
// // @ts-ignore
|
||||
// const server3 = global.__SERVERS__[2];
|
||||
// // @ts-ignore
|
||||
// // const simpleServer = global.__WEB_SERVER__.server;
|
||||
|
||||
// // list of test
|
||||
// // note: order of the following calls is important, the reason is legacy code.
|
||||
// packageAccess(server1);
|
||||
// // FIXME: use real cli test for this
|
||||
// gh29(server1, server2);
|
||||
// tags(server1);
|
||||
// // packageGzip(server1, simpleServer);
|
||||
// // incomplete(server1, simpleServer);
|
||||
// mirror(server1, server2);
|
||||
// distTagsMerge(server1, server2, server3);
|
||||
// readme(server1, server2);
|
||||
// nullstorage(server1, server2);
|
||||
// middleware(server2);
|
||||
// race(server1);
|
||||
// // racycrash(server1, simpleServer);
|
||||
// packageScoped(server1, server2);
|
||||
// security(server1);
|
||||
// addtag(server1);
|
||||
// pluginsAuth(server2);
|
||||
// uplinkTimeout(server1, server2, server3);
|
||||
// // // requires packages published to server1/server2
|
||||
// upLinkCache(server1, server2, server3);
|
||||
// adduser(server1);
|
||||
// logout(server1);
|
||||
// basic(server1, server2);
|
||||
// // FIXME: use real cli test for this
|
||||
// // simpleSearch(server1, server2, simpleServer);
|
||||
// });
|
||||
|
||||
// process.on('unhandledRejection', function (err) {
|
||||
// console.error('unhandledRejection', err);
|
||||
// process.nextTick(function () {
|
||||
// throw err;
|
||||
// });
|
||||
// });
|
@ -1,9 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
|
||||
require('@babel/register')({
|
||||
extensions: ['.ts', '.js'],
|
||||
});
|
||||
|
||||
module.exports = async function () {
|
||||
// here we should create dynamically config files
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
module.exports = async function () {
|
||||
// console.log(green('Teardown Verdaccio Functional'));
|
||||
// console.log(blue('Teardown:: all server were closed'));
|
||||
};
|
@ -1,6 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
|
||||
require('@babel/register')({
|
||||
extensions: ['.ts', '.js'],
|
||||
});
|
||||
module.exports = require('./lib/environment');
|
@ -3,7 +3,7 @@ import got from 'got';
|
||||
import { ConfigBuilder } from '@verdaccio/config';
|
||||
import { constants, fileUtils } from '@verdaccio/core';
|
||||
|
||||
import { Registry } from '../../src/server';
|
||||
import { Registry } from '../src/server';
|
||||
|
||||
describe('html', () => {
|
||||
let registry;
|
1
packages/verdaccio/test/htpasswd
Normal file
1
packages/verdaccio/test/htpasswd
Normal file
@ -0,0 +1 @@
|
||||
foo:$2a$10$GyuYqH94lODJY0tM.bfjYeBu1zsY74570PuufwKHf8JHRAqNyeddm:autocreated 2022-09-21T20:11:03.507Z
|
@ -1,6 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
|
||||
require('@babel/register')({
|
||||
sourceMap: 'inline',
|
||||
});
|
||||
require('@verdaccio/cli');
|
@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
require('@babel/register')({
|
||||
extensions: ['.ts', '.js'],
|
||||
});
|
||||
require('@verdaccio/cli');
|
@ -1,7 +1,7 @@
|
||||
import { ConfigBuilder } from '@verdaccio/config';
|
||||
import { constants, fileUtils } from '@verdaccio/core';
|
||||
|
||||
import { Registry, ServerQuery } from '../../src/server';
|
||||
import { Registry, ServerQuery } from '../src/server';
|
||||
|
||||
describe('race publishing packages', () => {
|
||||
let registry;
|
@ -1,7 +1,7 @@
|
||||
import { ConfigBuilder } from '@verdaccio/config';
|
||||
import { HTTP_STATUS, constants, fileUtils } from '@verdaccio/core';
|
||||
|
||||
import { Registry, ServerQuery } from '../../src/server';
|
||||
import { Registry, ServerQuery } from '../src/server';
|
||||
|
||||
describe('multiple proxy registries configuration', () => {
|
||||
let registry;
|
@ -1,7 +1,7 @@
|
||||
import { ConfigBuilder } from '@verdaccio/config';
|
||||
import { constants, fileUtils } from '@verdaccio/core';
|
||||
|
||||
import { Registry, ServerQuery } from '../../src/server';
|
||||
import { Registry, ServerQuery } from '../src/server';
|
||||
|
||||
describe('race publishing packages', () => {
|
||||
let registry;
|
@ -3,13 +3,14 @@ import path from 'path';
|
||||
|
||||
import { generateRemotePackageMetadata } from '@verdaccio/test-helper';
|
||||
|
||||
import { Registry, ServerQuery } from '../../src/server';
|
||||
import { Registry, ServerQuery } from '../src/server';
|
||||
|
||||
const configFile = path.join(__dirname, './config.yaml');
|
||||
|
||||
describe('server query', () => {
|
||||
test('server run', async () => {
|
||||
const configFile = path.join(__dirname, '../functional/store/server1/config-1.yaml');
|
||||
const registry = new Registry(configFile);
|
||||
const vPath = path.join(__dirname, '../../bin/verdaccio');
|
||||
const vPath = path.join(__dirname, '../bin/verdaccio');
|
||||
const d = await registry.init(vPath);
|
||||
expect(d.pid).toBeDefined();
|
||||
expect(registry.getPort()).toBeDefined();
|
||||
@ -18,24 +19,11 @@ describe('server query', () => {
|
||||
registry.stop();
|
||||
});
|
||||
|
||||
test('server get package', async () => {
|
||||
const pkgName = 'upstream';
|
||||
const upstreamManifest = generateRemotePackageMetadata(
|
||||
pkgName,
|
||||
'1.0.0',
|
||||
'https://registry.something.org'
|
||||
);
|
||||
nock('https://registry.verdaccio.org').get(`/upstream`).reply(201, upstreamManifest);
|
||||
const configFile = path.join(__dirname, '../functional/store/server1/config-1.yaml');
|
||||
const registry = new Registry(configFile);
|
||||
const vPath = path.join(__dirname, '../../bin/verdaccio');
|
||||
test('server create user', async () => {
|
||||
const registry = new Registry(configFile, { createUser: true });
|
||||
const vPath = path.join(__dirname, '../bin/verdaccio');
|
||||
const d = await registry.init(vPath);
|
||||
expect(d.pid).toBeDefined();
|
||||
expect(registry.getPort()).toBeDefined();
|
||||
expect(registry.getAuthStr()).toBeDefined();
|
||||
expect(registry.getToken).toBeDefined();
|
||||
const server = new ServerQuery('http://localhost:' + registry.getPort());
|
||||
(await server.getPackage('/upstream')).status(403);
|
||||
registry.stop();
|
||||
});
|
||||
|
@ -1 +0,0 @@
|
||||
export const DOMAIN_SERVERS = 'localhost';
|
@ -1,7 +0,0 @@
|
||||
# Types smoke test
|
||||
|
||||
This folder is intended to check whether any type update might break plugin implementations
|
||||
|
||||
## Contribute
|
||||
|
||||
- Add more scenarios, middleware, plugins, filters etc.
|
@ -1,102 +0,0 @@
|
||||
// this file is not aim to be tested, just to check flow definitions
|
||||
import { Callback } from '@verdaccio/types';
|
||||
import {
|
||||
Config as AppConfig,
|
||||
IPluginAuth,
|
||||
Logger,
|
||||
PackageAccess,
|
||||
PluginOptions,
|
||||
RemoteUser,
|
||||
} from '@verdaccio/types';
|
||||
|
||||
import Config from '../../../../packages/config/src/config';
|
||||
import { logger } from '../../../../packages/logger/src/logger';
|
||||
|
||||
class ExampleAuthPlugin implements IPluginAuth<{}> {
|
||||
config: AppConfig;
|
||||
logger: Logger;
|
||||
|
||||
constructor(config: AppConfig, options: PluginOptions) {
|
||||
this.config = config;
|
||||
this.logger = options.logger;
|
||||
}
|
||||
|
||||
adduser(user: string, password: string, cb: Callback): void {
|
||||
cb();
|
||||
}
|
||||
|
||||
changePassword(username, password, newPassword, cb: Callback): void {
|
||||
cb();
|
||||
}
|
||||
|
||||
authenticate(user: string, password: string, cb: Callback): void {
|
||||
cb();
|
||||
}
|
||||
|
||||
allow_access(user: RemoteUser, pkg: PackageAccess, cb: Callback): void {
|
||||
cb();
|
||||
}
|
||||
|
||||
allow_publish(user: RemoteUser, pkg: PackageAccess, cb: Callback): void {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
type SubTypePackageAccess = PackageAccess & {
|
||||
sub?: boolean;
|
||||
};
|
||||
|
||||
class ExampleAuthCustomPlugin implements IPluginAuth<{}> {
|
||||
config: AppConfig;
|
||||
logger: Logger;
|
||||
|
||||
constructor(config: AppConfig, options: PluginOptions) {
|
||||
this.config = config;
|
||||
this.logger = options.logger;
|
||||
}
|
||||
|
||||
adduser(user: string, password: string, cb: Callback): void {
|
||||
cb();
|
||||
}
|
||||
|
||||
changePassword(username, password, newPassword, cb: Callback): void {
|
||||
cb();
|
||||
}
|
||||
|
||||
authenticate(user: string, password: string, cb: Callback): void {
|
||||
cb();
|
||||
}
|
||||
|
||||
allow_access(user: RemoteUser, pkg: SubTypePackageAccess, cb: Callback): void {
|
||||
cb();
|
||||
}
|
||||
|
||||
allow_publish(user: RemoteUser, pkg: SubTypePackageAccess, cb: Callback): void {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
const config1: AppConfig = new Config({
|
||||
storage: './storage',
|
||||
config_path: '/home/sotrage',
|
||||
});
|
||||
|
||||
const options: PluginOptions = {
|
||||
config: config1,
|
||||
logger: logger.child(),
|
||||
};
|
||||
|
||||
const auth = new ExampleAuthPlugin(config1, options);
|
||||
const authSub = new ExampleAuthCustomPlugin(config1, options);
|
||||
const remoteUser: RemoteUser = {
|
||||
groups: [],
|
||||
real_groups: [],
|
||||
name: 'test',
|
||||
};
|
||||
|
||||
auth.authenticate('user', 'pass', () => {});
|
||||
auth.allow_access(remoteUser, { access: [], publish: [], proxy: [] }, () => {});
|
||||
auth.allow_publish(remoteUser, { access: [], publish: [], proxy: [] }, () => {});
|
||||
authSub.authenticate('user', 'pass', () => {});
|
||||
authSub.allow_access(remoteUser, { access: [], publish: [], proxy: [], sub: true }, () => {});
|
||||
authSub.allow_publish(remoteUser, { access: [], publish: [], proxy: [], sub: true }, () => {});
|
@ -1,45 +0,0 @@
|
||||
// // this file is not aim to be tested, just to check typescript definitions
|
||||
// /* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
// /* eslint-disable no-unused-vars */
|
||||
|
||||
// import { generatePackageTemplate, Storage } from '@verdaccio/store';
|
||||
// import { IBasicAuth } from '@verdaccio/auth';
|
||||
// import { readFile } from '../../../functional/lib/test.utils';
|
||||
// import { Package } from '@verdaccio/types';
|
||||
// import { Config as AppConfig, RemoteUser } from '@verdaccio/types';
|
||||
// import { generateVersion } from '../../../unit/__helper/utils';
|
||||
// // FIXME: add package here
|
||||
// import Config from '../../../../packages/config/src/config';
|
||||
|
||||
// const readMetadata = (fileName: string): Package =>
|
||||
// JSON.parse(readFile(`../../unit/partials/${fileName}`).toString()) as Package;
|
||||
|
||||
// export default class ExampleMiddlewarePlugin implements IPluginMiddleware<{}> {
|
||||
// register_middlewares(app: any, auth: IBasicAuth<{}>, storage: Storage): void {
|
||||
// const remoteUser: RemoteUser = {
|
||||
// groups: [],
|
||||
// real_groups: [],
|
||||
// name: 'test',
|
||||
// };
|
||||
// auth.authenticate('user', 'password', () => {});
|
||||
// auth.allow_access({ packageName: 'packageName' }, remoteUser, () => {});
|
||||
// auth.add_user('user', 'password', () => {});
|
||||
// auth.aesEncrypt(Buffer.from('pass'));
|
||||
// // storage
|
||||
// storage.addPackage('name', generatePackageTemplate('test'), () => {});
|
||||
// storage.addVersion('name', 'version', generateVersion('name', '1.0.0'), 'tag', () => {});
|
||||
// storage.mergeTags('name', { latest: '1.0.0' }, () => {});
|
||||
// storage.changePackage('name', readMetadata('metadata'), 'revision', () => {});
|
||||
// storage.removePackage('name', () => {});
|
||||
// storage.mergeTags('name', { latest: '1.0.0' }, () => {});
|
||||
// storage.removeTarball('name', 'filename', 'revision', () => {});
|
||||
// const config1: AppConfig = new Config({
|
||||
// storage: './storage',
|
||||
// config_path: '/home/sotrage',
|
||||
// });
|
||||
// const add: IUploadTarball = storage.addTarball('name', 'filename');
|
||||
// storage.getTarball('name', 'filename');
|
||||
// const read: IReadTarball = storage.getTarball('name', 'filename');
|
||||
// const search: IReadTarball = storage.search('test', {});
|
||||
// }
|
||||
// }
|
@ -1,180 +0,0 @@
|
||||
// // this file is not aim to be tested, just to check typescript definitions
|
||||
// import { generatePackageTemplate } from '@verdaccio/store';
|
||||
// import { ReadTarball, UploadTarball } from '@verdaccio/streams';
|
||||
// import {
|
||||
// Config as AppConfig,
|
||||
// Callback,
|
||||
// IReadTarball,
|
||||
// IUploadTarball,
|
||||
// Logger,
|
||||
// Package,
|
||||
// Token,
|
||||
// TokenFilter,
|
||||
// } from '@verdaccio/types';
|
||||
// import { IPackageStorage, IPackageStorageManager, IPluginStorage } from '@verdaccio/types';
|
||||
|
||||
// import Config from '../../../../packages/config/src/config';
|
||||
// import { logger } from '../../../../packages/logger/src/logger';
|
||||
|
||||
// class PackageStorage implements IPackageStorageManager {
|
||||
// path: string;
|
||||
// logger: Logger;
|
||||
|
||||
// constructor(path: string, logger: Logger) {
|
||||
// this.path = path;
|
||||
// this.logger = logger;
|
||||
// }
|
||||
|
||||
// updatePackage(
|
||||
// name: string,
|
||||
// updateHandler: Callback,
|
||||
// onWrite: Callback,
|
||||
// transformPackage: Function,
|
||||
// onEnd: Callback
|
||||
// ) {
|
||||
// onEnd();
|
||||
// }
|
||||
|
||||
// deletePackage(fileName: string, callback: Callback) {
|
||||
// callback();
|
||||
// }
|
||||
|
||||
// removePackage(callback: Callback): void {
|
||||
// callback();
|
||||
// }
|
||||
|
||||
// createPackage(name: string, value: Package, cb: Callback) {
|
||||
// cb();
|
||||
// }
|
||||
|
||||
// savePackage(name: string, value: Package, cb: Callback) {
|
||||
// cb();
|
||||
// }
|
||||
|
||||
// readPackage(name: string, cb: Callback) {
|
||||
// cb();
|
||||
// }
|
||||
|
||||
// writeTarball(name): IUploadTarball {
|
||||
// this.logger.debug({ name }, 'some name @name');
|
||||
// const uploadStream = new UploadTarball({});
|
||||
// uploadStream.on('close', () => {});
|
||||
// if (uploadStream.abort) {
|
||||
// uploadStream.abort();
|
||||
// }
|
||||
|
||||
// if (uploadStream.done) {
|
||||
// uploadStream.done();
|
||||
// }
|
||||
|
||||
// return uploadStream;
|
||||
// }
|
||||
|
||||
// readTarball(name): IReadTarball {
|
||||
// this.logger.debug({ name }, 'some name @name');
|
||||
// const readTarballStream: IReadTarball = new ReadTarball({});
|
||||
|
||||
// if (readTarballStream.abort) {
|
||||
// readTarballStream.abort();
|
||||
// }
|
||||
|
||||
// return readTarballStream;
|
||||
// }
|
||||
// }
|
||||
|
||||
// class ExampleStoragePlugin implements IPluginStorage<{}> {
|
||||
// logger: Logger;
|
||||
// config: AppConfig;
|
||||
|
||||
// constructor(config: AppConfig, logger: Logger) {
|
||||
// this.config = config;
|
||||
// this.logger = logger;
|
||||
// }
|
||||
|
||||
// saveToken(token: Token): Promise<any> {
|
||||
// return Promise.resolve(token);
|
||||
// }
|
||||
// deleteToken(user: string, tokenKey: string): Promise<any> {
|
||||
// return Promise.resolve([user, tokenKey]);
|
||||
// }
|
||||
|
||||
// readTokens(filter: TokenFilter): Promise<Token[]> {
|
||||
// const token: Token = {
|
||||
// user: filter.user,
|
||||
// key: '12312',
|
||||
// token: '12321', // pragma: allowlist secret
|
||||
// readonly: false,
|
||||
// created: '123232',
|
||||
// };
|
||||
|
||||
// return Promise.resolve([token, token]);
|
||||
// }
|
||||
|
||||
// getSecret(): Promise<any> {
|
||||
// return Promise.resolve();
|
||||
// }
|
||||
|
||||
// setSecret(secret: string): Promise<any> {
|
||||
// // pragma: allowlist secret
|
||||
// return Promise.resolve(secret); // pragma: allowlist secret
|
||||
// }
|
||||
|
||||
// add(name: string, cb: Callback) {
|
||||
// cb();
|
||||
// }
|
||||
|
||||
// remove(name: string, cb: Callback) {
|
||||
// cb();
|
||||
// }
|
||||
|
||||
// get(cb: Callback) {
|
||||
// cb();
|
||||
// }
|
||||
|
||||
// getPackageStorage(packageInfo: string): IPackageStorage {
|
||||
// return new PackageStorage(packageInfo, this.logger);
|
||||
// }
|
||||
|
||||
// search(onPackage: Callback, onEnd: Callback, validateName: any): void {
|
||||
// onPackage(onEnd(validateName()));
|
||||
// }
|
||||
// }
|
||||
|
||||
// export default ExampleStoragePlugin;
|
||||
|
||||
// const config1: AppConfig = new Config({
|
||||
// storage: './storage',
|
||||
// config_path: '/home/sotrage',
|
||||
// });
|
||||
|
||||
// const storage = new ExampleStoragePlugin(config1, logger.child());
|
||||
|
||||
// storage.add('test', () => {});
|
||||
// storage.remove('test', () => {});
|
||||
// storage.getSecret().then(() => {});
|
||||
// storage.setSecret('newSecret').then(() => {});
|
||||
// storage.search(
|
||||
// () => {},
|
||||
// () => {},
|
||||
// 'validateName'
|
||||
// );
|
||||
// storage.get(() => {});
|
||||
|
||||
// const storageManager: IPackageStorage = storage.getPackageStorage('test');
|
||||
|
||||
// if (storageManager) {
|
||||
// storageManager.createPackage('test', generatePackageTemplate('test'), () => {});
|
||||
// storageManager.savePackage('fileName', generatePackageTemplate('test'), () => {});
|
||||
// // @ts-ignore
|
||||
// storageManager.updatePackage(
|
||||
// 'pkgFileName',
|
||||
// () => {},
|
||||
// () => {},
|
||||
// () => {},
|
||||
// () => {}
|
||||
// );
|
||||
// storageManager.deletePackage('test', () => {});
|
||||
// storageManager.removePackage(() => {});
|
||||
// storageManager.readPackage('test', () => {});
|
||||
// storageManager.writeTarball('test');
|
||||
// }
|
@ -1,95 +0,0 @@
|
||||
/**
|
||||
* PLEASE DO NOT MODIFY THIS FILE
|
||||
*
|
||||
* This test is just for teaching purpose, use this example as template for your new
|
||||
* endpoint API unit test
|
||||
*
|
||||
* If you have any questions, ask at the http://chat.verdaccio.org #questions channel.
|
||||
*
|
||||
*/
|
||||
import _ from 'lodash';
|
||||
import path from 'path';
|
||||
import rimraf from 'rimraf';
|
||||
import request from 'supertest';
|
||||
|
||||
import { parseConfigFile } from '@verdaccio/config';
|
||||
import { setup } from '@verdaccio/logger';
|
||||
import endPointAPI from '@verdaccio/server';
|
||||
|
||||
import { DOMAIN_SERVERS } from '../../../functional/config.functional';
|
||||
import { parseConfigurationFile } from '../../__helper';
|
||||
import { addUser } from '../../__helper/api';
|
||||
import { mockServer } from '../../__helper/mock';
|
||||
|
||||
// we must start logging without output
|
||||
setup([]);
|
||||
|
||||
const parseConfigurationJWTFile = () => {
|
||||
// Any new test must have a custom yaml file, try to name it based on the feature, the config
|
||||
// file does not need to include all configuration, just the part is needs
|
||||
// eg: test/unit/partials/config/yaml/api-jwt/jwt.yaml
|
||||
return parseConfigurationFile(`api-jwt/jwt`);
|
||||
};
|
||||
|
||||
describe('endpoint example unit test', () => {
|
||||
let app;
|
||||
let mockRegistry;
|
||||
|
||||
beforeAll(function (done) {
|
||||
// 1. We create a route for a custom storage folder for this test
|
||||
const store = path.join(__dirname, '../../partials/store/test-template-storage');
|
||||
// 2. The port must be unique (at this point this is not automated, need to be checked manually)
|
||||
const mockServerPort = 55546;
|
||||
// 3. Use rimraf to clean the state each time you run the test
|
||||
rimraf(store, async () => {
|
||||
// 4. Use a custom configuration file
|
||||
const confS = parseConfigFile(parseConfigurationJWTFile());
|
||||
// 5. Customise specific properties
|
||||
const configForTest = _.assign({}, _.cloneDeep(confS), {
|
||||
storage: store,
|
||||
uplinks: {
|
||||
npmjs: {
|
||||
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`,
|
||||
},
|
||||
},
|
||||
// 6. The self_path is important be the same as the store
|
||||
config_path: store,
|
||||
// 7. Define the location of the .htpasswd file, this is relative to self_path.
|
||||
auth: {
|
||||
htpasswd: {
|
||||
file: './test-jwt-storage/.htpasswd',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// 8. Use the helper `endPointAPI` to mock the API
|
||||
app = await endPointAPI(configForTest);
|
||||
// 9 . Use `mockServer` to mock launch the server.
|
||||
mockRegistry = await mockServer(mockServerPort).init();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(function (done) {
|
||||
// 10. Do not forget to stop the API, or it will run forever.
|
||||
mockRegistry[0].stop();
|
||||
done();
|
||||
});
|
||||
|
||||
test('should test add a new user with JWT enabled', async (done) => {
|
||||
// At this point the server is running and you can run the test
|
||||
|
||||
const credentials = { name: 'JotaJWT', password: 'secretPass' };
|
||||
// 11. Use helpers for repetitive tasks
|
||||
// @ts-ignore
|
||||
const [err, res] = await addUser(request(app), credentials.name, credentials);
|
||||
|
||||
// 12. test your output
|
||||
expect(err).toBeNull();
|
||||
expect(res.body.ok).toBeDefined();
|
||||
expect(res.body.token).toBeDefined();
|
||||
|
||||
// 13. end the async test
|
||||
done();
|
||||
});
|
||||
});
|
@ -1,43 +0,0 @@
|
||||
import { ConfigBuilder } from '@verdaccio/config';
|
||||
import { HTTP_STATUS, constants, fileUtils } from '@verdaccio/core';
|
||||
|
||||
import { Registry, ServerQuery } from '../../src/server';
|
||||
|
||||
describe('basic test endpoints', () => {
|
||||
let registry;
|
||||
|
||||
beforeAll(async function () {
|
||||
const storage = await fileUtils.createTempStorageFolder('basic-test');
|
||||
const configuration = ConfigBuilder.build()
|
||||
.addStorage(storage)
|
||||
.addPackageAccess(constants.PACKAGE_ACCESS.ALL, {
|
||||
access: constants.ROLES.$ALL,
|
||||
publish: constants.ROLES.$ALL,
|
||||
})
|
||||
.addAuth({
|
||||
htpasswd: {
|
||||
file: './htpasswd-user',
|
||||
},
|
||||
})
|
||||
.addLogger({ level: 'debug', type: 'stdout', format: 'pretty' })
|
||||
.addUplink('upstream', { url: 'https://registry.verdaccio.org' });
|
||||
const { configPath } = await Registry.fromConfigToPath(configuration.getConfig());
|
||||
registry = new Registry(configPath);
|
||||
await registry.init();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
registry.stop();
|
||||
});
|
||||
|
||||
test('add user', async () => {
|
||||
const server = new ServerQuery(registry.getRegistryUrl());
|
||||
(await server.createUser('foo', 'ramdomPassword')).status(HTTP_STATUS.CREATED);
|
||||
});
|
||||
|
||||
test('user already exist', async () => {
|
||||
const server = new ServerQuery(registry.getRegistryUrl());
|
||||
(await server.createUser('foo2', 'ramdomPAssword')).status(HTTP_STATUS.CREATED);
|
||||
(await server.createUser('foo2', 'ramdomPAssword')).status(HTTP_STATUS.CONFLICT);
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user