@verdaccio/e2e-cli 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/e2e-cli.js +6 -26
- package/build/adapters/adapter.d.ts +1 -0
- package/build/adapters/bun.d.ts +2 -0
- package/build/adapters/deno.d.ts +2 -0
- package/build/adapters/index.d.ts +5 -0
- package/build/adapters/npm.d.ts +2 -0
- package/build/adapters/pnpm.d.ts +2 -0
- package/build/adapters/yarn-modern.d.ts +2 -0
- package/build/cjs/_virtual/_rolldown/runtime.cjs +23 -0
- package/build/cjs/adapters/bun.cjs +64 -0
- package/build/cjs/adapters/bun.cjs.map +1 -0
- package/build/cjs/adapters/deno.cjs +61 -0
- package/build/cjs/adapters/deno.cjs.map +1 -0
- package/build/cjs/adapters/index.cjs +10 -0
- package/build/cjs/adapters/npm.cjs +85 -0
- package/build/cjs/adapters/npm.cjs.map +1 -0
- package/build/cjs/adapters/pnpm.cjs +114 -0
- package/build/cjs/adapters/pnpm.cjs.map +1 -0
- package/build/cjs/adapters/yarn-modern.cjs +207 -0
- package/build/cjs/adapters/yarn-modern.cjs.map +1 -0
- package/build/cjs/index.cjs +186 -11
- package/build/cjs/index.cjs.map +1 -0
- package/build/cjs/reporter.cjs +113 -0
- package/build/cjs/reporter.cjs.map +1 -0
- package/build/cjs/runner.cjs +141 -0
- package/build/cjs/runner.cjs.map +1 -0
- package/build/cjs/scenarios/index.cjs +25 -0
- package/build/cjs/scenarios/index.cjs.map +1 -0
- package/build/cjs/scenarios/install-multiple-deps.cjs +119 -0
- package/build/cjs/scenarios/install-multiple-deps.cjs.map +1 -0
- package/build/cjs/scenarios/metadata.cjs +121 -0
- package/build/cjs/scenarios/metadata.cjs.map +1 -0
- package/build/cjs/scenarios/minimum-release-age.cjs +111 -0
- package/build/cjs/scenarios/minimum-release-age.cjs.map +1 -0
- package/build/cjs/scenarios/search.cjs +136 -0
- package/build/cjs/scenarios/search.cjs.map +1 -0
- package/build/cjs/scenarios/tarballs.cjs +147 -0
- package/build/cjs/scenarios/tarballs.cjs.map +1 -0
- package/build/cjs/scenarios/uplink-failure.cjs +141 -0
- package/build/cjs/scenarios/uplink-failure.cjs.map +1 -0
- package/build/cjs/tests/audit.cjs +60 -0
- package/build/cjs/tests/audit.cjs.map +1 -0
- package/build/cjs/tests/ci.cjs +83 -0
- package/build/cjs/tests/ci.cjs.map +1 -0
- package/build/cjs/tests/deprecate.cjs +108 -0
- package/build/cjs/tests/deprecate.cjs.map +1 -0
- package/build/cjs/tests/dist-tags.cjs +43 -0
- package/build/cjs/tests/dist-tags.cjs.map +1 -0
- package/build/cjs/tests/index.cjs +49 -0
- package/build/cjs/tests/index.cjs.map +1 -0
- package/build/cjs/tests/info.cjs +31 -0
- package/build/cjs/tests/info.cjs.map +1 -0
- package/build/cjs/tests/install.cjs +30 -0
- package/build/cjs/tests/install.cjs.map +1 -0
- package/build/cjs/tests/login.cjs +126 -0
- package/build/cjs/tests/login.cjs.map +1 -0
- package/build/cjs/tests/ping.cjs +26 -0
- package/build/cjs/tests/ping.cjs.map +1 -0
- package/build/cjs/tests/publish.cjs +36 -0
- package/build/cjs/tests/publish.cjs.map +1 -0
- package/build/cjs/tests/search.cjs +23 -0
- package/build/cjs/tests/search.cjs.map +1 -0
- package/build/cjs/tests/unpublish.cjs +40 -0
- package/build/cjs/tests/unpublish.cjs.map +1 -0
- package/build/cjs/utils/e2e-config.cjs +59 -0
- package/build/cjs/utils/e2e-config.cjs.map +1 -0
- package/build/cjs/utils/http-client.cjs +111 -0
- package/build/cjs/utils/http-client.cjs.map +1 -0
- package/build/cjs/utils/info.cjs +25 -0
- package/build/cjs/utils/info.cjs.map +1 -0
- package/build/cjs/utils/mock-uplink.cjs +196 -0
- package/build/cjs/utils/mock-uplink.cjs.map +1 -0
- package/build/cjs/utils/process.cjs +96 -0
- package/build/cjs/utils/process.cjs.map +1 -0
- package/build/cjs/utils/project.cjs +55 -0
- package/build/cjs/utils/project.cjs.map +1 -0
- package/build/cjs/utils/publish.cjs +117 -0
- package/build/cjs/utils/publish.cjs.map +1 -0
- package/build/cjs/utils/registry-client.cjs +56 -0
- package/build/cjs/utils/registry-client.cjs.map +1 -0
- package/build/esm/adapters/bun.js +62 -0
- package/build/esm/adapters/bun.js.map +1 -0
- package/build/esm/adapters/deno.js +59 -0
- package/build/esm/adapters/deno.js.map +1 -0
- package/build/esm/adapters/index.js +6 -0
- package/build/esm/adapters/npm.js +83 -0
- package/build/esm/adapters/npm.js.map +1 -0
- package/build/esm/adapters/pnpm.js +112 -0
- package/build/esm/adapters/pnpm.js.map +1 -0
- package/build/esm/adapters/yarn-modern.js +204 -0
- package/build/esm/adapters/yarn-modern.js.map +1 -0
- package/build/esm/index.js +174 -10
- package/build/esm/index.js.map +1 -0
- package/build/esm/reporter.js +108 -0
- package/build/esm/reporter.js.map +1 -0
- package/build/esm/runner.js +138 -0
- package/build/esm/runner.js.map +1 -0
- package/build/esm/scenarios/index.js +19 -0
- package/build/esm/scenarios/index.js.map +1 -0
- package/build/esm/scenarios/install-multiple-deps.js +117 -0
- package/build/esm/scenarios/install-multiple-deps.js.map +1 -0
- package/build/esm/scenarios/metadata.js +119 -0
- package/build/esm/scenarios/metadata.js.map +1 -0
- package/build/esm/scenarios/minimum-release-age.js +108 -0
- package/build/esm/scenarios/minimum-release-age.js.map +1 -0
- package/build/esm/scenarios/search.js +134 -0
- package/build/esm/scenarios/search.js.map +1 -0
- package/build/esm/scenarios/tarballs.js +145 -0
- package/build/esm/scenarios/tarballs.js.map +1 -0
- package/build/esm/scenarios/uplink-failure.js +139 -0
- package/build/esm/scenarios/uplink-failure.js.map +1 -0
- package/build/esm/tests/audit.js +57 -0
- package/build/esm/tests/audit.js.map +1 -0
- package/build/esm/tests/ci.js +80 -0
- package/build/esm/tests/ci.js.map +1 -0
- package/build/esm/tests/deprecate.js +105 -0
- package/build/esm/tests/deprecate.js.map +1 -0
- package/build/esm/tests/dist-tags.js +41 -0
- package/build/esm/tests/dist-tags.js.map +1 -0
- package/build/esm/tests/index.js +37 -0
- package/build/esm/tests/index.js.map +1 -0
- package/build/esm/tests/info.js +29 -0
- package/build/esm/tests/info.js.map +1 -0
- package/build/esm/tests/install.js +28 -0
- package/build/esm/tests/install.js.map +1 -0
- package/build/esm/tests/login.js +122 -0
- package/build/esm/tests/login.js.map +1 -0
- package/build/esm/tests/ping.js +24 -0
- package/build/esm/tests/ping.js.map +1 -0
- package/build/esm/tests/publish.js +34 -0
- package/build/esm/tests/publish.js.map +1 -0
- package/build/esm/tests/search.js +21 -0
- package/build/esm/tests/search.js.map +1 -0
- package/build/esm/tests/unpublish.js +38 -0
- package/build/esm/tests/unpublish.js.map +1 -0
- package/build/esm/utils/e2e-config.js +58 -0
- package/build/esm/utils/e2e-config.js.map +1 -0
- package/build/esm/utils/http-client.js +105 -0
- package/build/esm/utils/http-client.js.map +1 -0
- package/build/esm/utils/info.js +24 -0
- package/build/esm/utils/info.js.map +1 -0
- package/build/esm/utils/mock-uplink.js +194 -0
- package/build/esm/utils/mock-uplink.js.map +1 -0
- package/build/esm/utils/process.js +92 -0
- package/build/esm/utils/process.js.map +1 -0
- package/build/esm/utils/project.js +50 -0
- package/build/esm/utils/project.js.map +1 -0
- package/build/esm/utils/publish.js +113 -0
- package/build/esm/utils/publish.js.map +1 -0
- package/build/esm/utils/registry-client.js +53 -0
- package/build/esm/utils/registry-client.js.map +1 -0
- package/build/index.d.ts +6 -15
- package/build/reporter.d.ts +7 -0
- package/build/runner.d.ts +13 -0
- package/build/scenarios/index.d.ts +9 -0
- package/build/scenarios/install-multiple-deps.d.ts +2 -0
- package/build/scenarios/metadata.d.ts +2 -0
- package/build/scenarios/minimum-release-age.d.ts +11 -0
- package/build/scenarios/search.d.ts +2 -0
- package/build/scenarios/tarballs.d.ts +2 -0
- package/build/scenarios/uplink-failure.d.ts +2 -0
- package/build/tests/audit.d.ts +2 -0
- package/build/tests/ci.d.ts +2 -0
- package/build/tests/deprecate.d.ts +2 -0
- package/build/tests/dist-tags.d.ts +2 -0
- package/build/tests/index.d.ts +15 -0
- package/build/tests/info.d.ts +2 -0
- package/build/tests/install.d.ts +2 -0
- package/build/tests/login.d.ts +2 -0
- package/build/tests/ping.d.ts +2 -0
- package/build/tests/publish.d.ts +2 -0
- package/build/tests/search.d.ts +2 -0
- package/build/tests/unpublish.d.ts +2 -0
- package/build/types.d.ts +91 -0
- package/build/utils/e2e-config.d.ts +21 -0
- package/build/utils/http-client.d.ts +49 -0
- package/build/utils/index.d.ts +4 -0
- package/build/utils/info.d.ts +14 -0
- package/build/utils/mock-uplink.d.ts +47 -0
- package/build/utils/process.d.ts +11 -0
- package/build/utils/project.d.ts +6 -0
- package/build/utils/publish.d.ts +17 -0
- package/build/utils/registry-client.d.ts +15 -0
- package/package.json +16 -14
- package/Cargo.lock +0 -1591
- package/Cargo.toml +0 -19
- package/build/bin/verdaccio-e2e +0 -0
- package/scripts/build-js-package.mjs +0 -25
- package/src/e2e_tests/audit.rs +0 -51
- package/src/e2e_tests/ci.rs +0 -32
- package/src/e2e_tests/deprecate.rs +0 -64
- package/src/e2e_tests/dist_tags.rs +0 -56
- package/src/e2e_tests/info.rs +0 -43
- package/src/e2e_tests/install.rs +0 -27
- package/src/e2e_tests/login.rs +0 -64
- package/src/e2e_tests/mod.rs +0 -104
- package/src/e2e_tests/ping.rs +0 -33
- package/src/e2e_tests/publish.rs +0 -68
- package/src/e2e_tests/search.rs +0 -14
- package/src/e2e_tests/unpublish.rs +0 -37
- package/src/main.rs +0 -1411
- package/src/scenarios/install_multiple_deps.rs +0 -99
- package/src/scenarios/minimum_release_age.rs +0 -45
- package/src/scenarios/mod.rs +0 -11
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { publishLocalPackage } from "../utils/publish.js";
|
|
2
|
+
import buildDebug from "debug";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { rm } from "fs/promises";
|
|
5
|
+
import assert from "assert";
|
|
6
|
+
//#region src/tests/ci.ts
|
|
7
|
+
var debug = buildDebug("verdaccio:e2e-cli:test:ci");
|
|
8
|
+
/**
|
|
9
|
+
* Test: ci
|
|
10
|
+
*
|
|
11
|
+
* Verifies that lockfile-based install works correctly.
|
|
12
|
+
* Unlike `install`, CI commands skip metadata fetches and resolve
|
|
13
|
+
* tarballs directly from the URLs stored in the lockfile.
|
|
14
|
+
*
|
|
15
|
+
* Flow:
|
|
16
|
+
* 1. Prepare a project with dependencies
|
|
17
|
+
* 2. Run `install` to generate the lockfile
|
|
18
|
+
* 3. Remove node_modules
|
|
19
|
+
* 4. Run the CI-equivalent command (npm ci / pnpm install --frozen-lockfile / yarn --frozen-lockfile / yarn --immutable)
|
|
20
|
+
* 5. Verify it completes successfully
|
|
21
|
+
*/
|
|
22
|
+
function getCiArgs(ctx) {
|
|
23
|
+
switch (ctx.adapter.type) {
|
|
24
|
+
case "npm": return ["ci", ...ctx.adapter.registryArg(ctx.registryUrl)];
|
|
25
|
+
case "pnpm": return [
|
|
26
|
+
"install",
|
|
27
|
+
"--frozen-lockfile",
|
|
28
|
+
...ctx.adapter.registryArg(ctx.registryUrl)
|
|
29
|
+
];
|
|
30
|
+
case "yarn-modern": return ["install", "--immutable"];
|
|
31
|
+
case "bun": return [
|
|
32
|
+
"install",
|
|
33
|
+
"--frozen-lockfile",
|
|
34
|
+
...ctx.adapter.registryArg(ctx.registryUrl)
|
|
35
|
+
];
|
|
36
|
+
default: return ["ci", ...ctx.adapter.registryArg(ctx.registryUrl)];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function testCi(ctx) {
|
|
40
|
+
if (ctx.adapter.type === "deno") {
|
|
41
|
+
debug("skipping ci test for deno (no ci command)");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const depName = `e2e-ci-dep-${ctx.runId}`;
|
|
45
|
+
await publishLocalPackage(ctx, depName, "1.0.0");
|
|
46
|
+
const { tempFolder } = await ctx.adapter.prepareProject(`ci-test-${ctx.runId}`, "1.0.0", ctx.registryUrl, ctx.port, ctx.token, { [depName]: "1.0.0" });
|
|
47
|
+
debug("running initial install to generate lockfile in %s", tempFolder);
|
|
48
|
+
await ctx.adapter.exec({ cwd: tempFolder }, "install", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
49
|
+
debug("lockfile generated, removing node_modules");
|
|
50
|
+
const nodeModulesPath = join(tempFolder, "node_modules");
|
|
51
|
+
await rm(nodeModulesPath, {
|
|
52
|
+
recursive: true,
|
|
53
|
+
force: true
|
|
54
|
+
});
|
|
55
|
+
const pnpmStorePath = join(tempFolder, ".pnpm-store");
|
|
56
|
+
await rm(pnpmStorePath, {
|
|
57
|
+
recursive: true,
|
|
58
|
+
force: true
|
|
59
|
+
});
|
|
60
|
+
debug("node_modules removed, running ci command");
|
|
61
|
+
const ciArgs = getCiArgs(ctx);
|
|
62
|
+
debug("ci args: %o", ciArgs);
|
|
63
|
+
const resp = await ctx.adapter.exec({ cwd: tempFolder }, ...ciArgs);
|
|
64
|
+
if (ctx.adapter.type === "npm") {
|
|
65
|
+
debug("npm ci output: %s", resp.stdout + resp.stderr);
|
|
66
|
+
assert.ok(true, "npm ci completed successfully");
|
|
67
|
+
} else {
|
|
68
|
+
debug("ci completed successfully for %s", ctx.adapter.type);
|
|
69
|
+
assert.ok(true, `CI install completed successfully for ${ctx.adapter.type}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
var ciTest = {
|
|
73
|
+
name: "ci",
|
|
74
|
+
requires: ["install"],
|
|
75
|
+
run: testCi
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
export { ciTest };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=ci.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci.js","names":[],"sources":["../../../src/tests/ci.ts"],"sourcesContent":["import assert from 'assert';\nimport buildDebug from 'debug';\nimport { rm } from 'fs/promises';\nimport { join } from 'path';\n\nimport { TestContext, TestDefinition } from '../types';\nimport { publishLocalPackage } from '../utils/publish';\n\nconst debug = buildDebug('verdaccio:e2e-cli:test:ci');\n\n/**\n * Test: ci\n *\n * Verifies that lockfile-based install works correctly.\n * Unlike `install`, CI commands skip metadata fetches and resolve\n * tarballs directly from the URLs stored in the lockfile.\n *\n * Flow:\n * 1. Prepare a project with dependencies\n * 2. Run `install` to generate the lockfile\n * 3. Remove node_modules\n * 4. Run the CI-equivalent command (npm ci / pnpm install --frozen-lockfile / yarn --frozen-lockfile / yarn --immutable)\n * 5. Verify it completes successfully\n */\n\nfunction getCiArgs(ctx: TestContext): string[] {\n switch (ctx.adapter.type) {\n case 'npm':\n // `npm ci` — separate command, reads package-lock.json\n return ['ci', ...ctx.adapter.registryArg(ctx.registryUrl)];\n case 'pnpm':\n // `pnpm install --frozen-lockfile` — same command, strict mode\n return ['install', '--frozen-lockfile', ...ctx.adapter.registryArg(ctx.registryUrl)];\n case 'yarn-modern':\n // `yarn install --immutable`\n return ['install', '--immutable'];\n case 'bun':\n // `bun install --frozen-lockfile`\n return ['install', '--frozen-lockfile', ...ctx.adapter.registryArg(ctx.registryUrl)];\n default:\n return ['ci', ...ctx.adapter.registryArg(ctx.registryUrl)];\n }\n}\n\nasync function testCi(ctx: TestContext): Promise<void> {\n // deno doesn't have a CI/frozen-lockfile equivalent\n if (ctx.adapter.type === 'deno') {\n debug('skipping ci test for deno (no ci command)');\n return;\n }\n\n // Publish the dependency locally first — the suite must run offline\n const depName = `e2e-ci-dep-${ctx.runId}`;\n await publishLocalPackage(ctx, depName, '1.0.0');\n\n const { tempFolder } = await ctx.adapter.prepareProject(\n `ci-test-${ctx.runId}`,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token,\n { [depName]: '1.0.0' }\n );\n\n debug('running initial install to generate lockfile in %s', tempFolder);\n\n // Step 1: Run install to generate the lockfile\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'install',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n debug('lockfile generated, removing node_modules');\n\n // Step 2: Remove node_modules to force a clean install from lockfile\n const nodeModulesPath = join(tempFolder, 'node_modules');\n await rm(nodeModulesPath, { recursive: true, force: true });\n\n // For pnpm, also clean the virtual store\n const pnpmStorePath = join(tempFolder, '.pnpm-store');\n await rm(pnpmStorePath, { recursive: true, force: true });\n\n debug('node_modules removed, running ci command');\n\n // Step 3: Run CI-equivalent command (tarball-only, no metadata fetches)\n const ciArgs = getCiArgs(ctx);\n debug('ci args: %o', ciArgs);\n const resp = await ctx.adapter.exec({ cwd: tempFolder }, ...ciArgs);\n\n // Step 4: Verify success\n if (ctx.adapter.type === 'npm') {\n // npm ci with --json is not reliable, just check exit code 0\n // and verify output mentions added packages\n const output = resp.stdout + resp.stderr;\n debug('npm ci output: %s', output);\n assert.ok(true, 'npm ci completed successfully');\n } else {\n debug('ci completed successfully for %s', ctx.adapter.type);\n assert.ok(true, `CI install completed successfully for ${ctx.adapter.type}`);\n }\n}\n\nexport const ciTest: TestDefinition = {\n name: 'ci',\n requires: ['install'],\n run: testCi,\n};\n"],"mappings":";;;;;;AAQA,IAAM,QAAQ,WAAW,2BAA2B;;;;;;;;;;;;;;;AAiBpD,SAAS,UAAU,KAA4B;CAC7C,QAAQ,IAAI,QAAQ,MAApB;EACE,KAAK,OAEH,OAAO,CAAC,MAAM,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAAC;EAC3D,KAAK,QAEH,OAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW;EAAC;EACrF,KAAK,eAEH,OAAO,CAAC,WAAW,aAAa;EAClC,KAAK,OAEH,OAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW;EAAC;EACrF,SACE,OAAO,CAAC,MAAM,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAAC;CAC7D;AACF;AAEA,eAAe,OAAO,KAAiC;CAErD,IAAI,IAAI,QAAQ,SAAS,QAAQ;EAC/B,MAAM,2CAA2C;EACjD;CACF;CAGA,MAAM,UAAU,cAAc,IAAI;CAClC,MAAM,oBAAoB,KAAK,SAAS,OAAO;CAE/C,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,WAAW,IAAI,SACf,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,OACJ,GAAG,UAAU,QAAQ,CACvB;CAEA,MAAM,sDAAsD,UAAU;CAGtE,MAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,WAAW,GAClB,WACA,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;CAEA,MAAM,2CAA2C;CAGjD,MAAM,kBAAkB,KAAK,YAAY,cAAc;CACvD,MAAM,GAAG,iBAAiB;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAG1D,MAAM,gBAAgB,KAAK,YAAY,aAAa;CACpD,MAAM,GAAG,eAAe;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAExD,MAAM,0CAA0C;CAGhD,MAAM,SAAS,UAAU,GAAG;CAC5B,MAAM,eAAe,MAAM;CAC3B,MAAM,OAAO,MAAM,IAAI,QAAQ,KAAK,EAAE,KAAK,WAAW,GAAG,GAAG,MAAM;CAGlE,IAAI,IAAI,QAAQ,SAAS,OAAO;EAI9B,MAAM,qBADS,KAAK,SAAS,KAAK,MACD;EACjC,OAAO,GAAG,MAAM,+BAA+B;CACjD,OAAO;EACL,MAAM,oCAAoC,IAAI,QAAQ,IAAI;EAC1D,OAAO,GAAG,MAAM,yCAAyC,IAAI,QAAQ,MAAM;CAC7E;AACF;AAEA,IAAa,SAAyB;CACpC,MAAM;CACN,UAAU,CAAC,SAAS;CACpB,KAAK;AACP"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { parseInfoJson } from "../utils/info.js";
|
|
2
|
+
import buildDebug from "debug";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { readFile, writeFile } from "fs/promises";
|
|
5
|
+
import assert from "assert";
|
|
6
|
+
//#region src/tests/deprecate.ts
|
|
7
|
+
var debug = buildDebug("verdaccio:e2e-cli:test:deprecate");
|
|
8
|
+
async function publishPkg(ctx, tempFolder, pkgName) {
|
|
9
|
+
if (ctx.adapter.type === "yarn-modern") {
|
|
10
|
+
debug("running yarn install before publish for %s", pkgName);
|
|
11
|
+
await ctx.adapter.exec({ cwd: tempFolder }, "install");
|
|
12
|
+
}
|
|
13
|
+
debug("publishing %s from %s", pkgName, tempFolder);
|
|
14
|
+
await ctx.adapter.exec({ cwd: tempFolder }, "publish", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
15
|
+
debug("published %s successfully", pkgName);
|
|
16
|
+
}
|
|
17
|
+
async function deprecate(ctx, tempFolder, packageVersion, message) {
|
|
18
|
+
debug("deprecating %s with message: %s", packageVersion, message || "(empty, un-deprecate)");
|
|
19
|
+
const jsonFlag = ctx.adapter.type === "yarn-modern" ? [] : ["--json"];
|
|
20
|
+
await ctx.adapter.exec({ cwd: tempFolder }, "deprecate", packageVersion, message, ...jsonFlag, ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
21
|
+
debug("deprecate command completed for %s", packageVersion);
|
|
22
|
+
}
|
|
23
|
+
async function getInfo(ctx, tempFolder, pkgName) {
|
|
24
|
+
debug("fetching info for %s", pkgName);
|
|
25
|
+
const resp = await ctx.adapter.exec({ cwd: tempFolder }, "info", pkgName, "--json", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
26
|
+
const parsed = parseInfoJson(resp.stdout);
|
|
27
|
+
debug("info for %s: deprecated=%s", pkgName, parsed.deprecated ?? "(not set)");
|
|
28
|
+
return parsed;
|
|
29
|
+
}
|
|
30
|
+
async function bumpVersion(ctx, tempFolder) {
|
|
31
|
+
debug("bumping version (minor) in %s", tempFolder);
|
|
32
|
+
if (ctx.adapter.type === "yarn-modern") {
|
|
33
|
+
const pkgPath = join(tempFolder, "package.json");
|
|
34
|
+
const pkg = JSON.parse(await readFile(pkgPath, "utf8"));
|
|
35
|
+
const [major, minor, patch] = pkg.version.split(".").map(Number);
|
|
36
|
+
pkg.version = `${major}.${minor + 1}.${patch}`;
|
|
37
|
+
debug("bumped %s to %s", pkgPath, pkg.version);
|
|
38
|
+
await writeFile(pkgPath, JSON.stringify(pkg, null, 2));
|
|
39
|
+
} else await ctx.adapter.exec({ cwd: tempFolder }, "version", "minor", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
40
|
+
}
|
|
41
|
+
async function prepareDeprecateProject(ctx, pkgName, version) {
|
|
42
|
+
debug("preparing project for %s@%s", pkgName, version);
|
|
43
|
+
const { tempFolder } = await ctx.adapter.prepareProject(pkgName, version, ctx.registryUrl, ctx.port, ctx.token);
|
|
44
|
+
if (ctx.adapter.importPlugin) {
|
|
45
|
+
debug("importing npm-deprecate plugin into %s", tempFolder);
|
|
46
|
+
await ctx.adapter.importPlugin(tempFolder, "npm-deprecate");
|
|
47
|
+
}
|
|
48
|
+
return tempFolder;
|
|
49
|
+
}
|
|
50
|
+
async function testDeprecate(ctx) {
|
|
51
|
+
const id = ctx.runId;
|
|
52
|
+
const message = "some message";
|
|
53
|
+
await ctx.subTest("deprecate single version", async () => {
|
|
54
|
+
const pkgName = `@verdaccio/dep1-${id}`;
|
|
55
|
+
const tf = await prepareDeprecateProject(ctx, pkgName, "1.0.0");
|
|
56
|
+
await publishPkg(ctx, tf, pkgName);
|
|
57
|
+
await deprecate(ctx, tf, `${pkgName}@1.0.0`, message);
|
|
58
|
+
const info = await getInfo(ctx, tf, pkgName);
|
|
59
|
+
assert.strictEqual(info.name, pkgName);
|
|
60
|
+
assert.strictEqual(info.deprecated, message, "Package should be deprecated");
|
|
61
|
+
});
|
|
62
|
+
await ctx.subTest("un-deprecate", async () => {
|
|
63
|
+
const pkgName = `@verdaccio/dep2-${id}`;
|
|
64
|
+
const tf = await prepareDeprecateProject(ctx, pkgName, "1.0.0");
|
|
65
|
+
await publishPkg(ctx, tf, pkgName);
|
|
66
|
+
await deprecate(ctx, tf, `${pkgName}@1.0.0`, message);
|
|
67
|
+
const info1 = await getInfo(ctx, tf, pkgName);
|
|
68
|
+
assert.strictEqual(info1.deprecated, message);
|
|
69
|
+
await deprecate(ctx, tf, `${pkgName}@1.0.0`, "");
|
|
70
|
+
const info2 = await getInfo(ctx, tf, pkgName);
|
|
71
|
+
assert.strictEqual(info2.deprecated, void 0, "Package should be un-deprecated");
|
|
72
|
+
});
|
|
73
|
+
await ctx.subTest("deprecate multiple versions", async () => {
|
|
74
|
+
const pkgName = `@verdaccio/dep3-${id}`;
|
|
75
|
+
const tf = await prepareDeprecateProject(ctx, pkgName, "1.0.0");
|
|
76
|
+
await publishPkg(ctx, tf, pkgName);
|
|
77
|
+
for (let i = 0; i < 3; i++) {
|
|
78
|
+
await bumpVersion(ctx, tf);
|
|
79
|
+
await publishPkg(ctx, tf, pkgName);
|
|
80
|
+
}
|
|
81
|
+
await deprecate(ctx, tf, pkgName, message);
|
|
82
|
+
for (const v of [
|
|
83
|
+
"1.0.0",
|
|
84
|
+
"1.1.0",
|
|
85
|
+
"1.2.0",
|
|
86
|
+
"1.3.0"
|
|
87
|
+
]) {
|
|
88
|
+
const info = await getInfo(ctx, tf, `${pkgName}@${v}`);
|
|
89
|
+
assert.strictEqual(info.deprecated, message, `Version ${v} should be deprecated`);
|
|
90
|
+
}
|
|
91
|
+
await bumpVersion(ctx, tf);
|
|
92
|
+
await publishPkg(ctx, tf, pkgName);
|
|
93
|
+
const info = await getInfo(ctx, tf, `${pkgName}@1.4.0`);
|
|
94
|
+
assert.strictEqual(info.deprecated, void 0, "New version should not be deprecated");
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
var deprecateTest = {
|
|
98
|
+
name: "deprecate",
|
|
99
|
+
requires: ["deprecate"],
|
|
100
|
+
run: testDeprecate
|
|
101
|
+
};
|
|
102
|
+
//#endregion
|
|
103
|
+
export { deprecateTest };
|
|
104
|
+
|
|
105
|
+
//# sourceMappingURL=deprecate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deprecate.js","names":[],"sources":["../../../src/tests/deprecate.ts"],"sourcesContent":["import assert from 'assert';\nimport buildDebug from 'debug';\nimport { readFile, writeFile } from 'fs/promises';\nimport { join } from 'path';\n\nimport { TestContext, TestDefinition } from '../types';\nimport { parseInfoJson } from '../utils/info';\n\nconst debug = buildDebug('verdaccio:e2e-cli:test:deprecate');\n\nasync function publishPkg(ctx: TestContext, tempFolder: string, pkgName: string) {\n if (ctx.adapter.type === 'yarn-modern') {\n debug('running yarn install before publish for %s', pkgName);\n await ctx.adapter.exec({ cwd: tempFolder }, 'install');\n }\n debug('publishing %s from %s', pkgName, tempFolder);\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'publish',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n debug('published %s successfully', pkgName);\n}\n\nasync function deprecate(\n ctx: TestContext,\n tempFolder: string,\n packageVersion: string,\n message: string\n) {\n debug('deprecating %s with message: %s', packageVersion, message || '(empty, un-deprecate)');\n const jsonFlag = ctx.adapter.type === 'yarn-modern' ? [] : ['--json'];\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'deprecate',\n packageVersion,\n message,\n ...jsonFlag,\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n debug('deprecate command completed for %s', packageVersion);\n}\n\nasync function getInfo(ctx: TestContext, tempFolder: string, pkgName: string) {\n debug('fetching info for %s', pkgName);\n const resp = await ctx.adapter.exec(\n { cwd: tempFolder },\n 'info',\n pkgName,\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n const parsed = parseInfoJson(resp.stdout);\n debug('info for %s: deprecated=%s', pkgName, parsed.deprecated ?? '(not set)');\n return parsed;\n}\n\nasync function bumpVersion(ctx: TestContext, tempFolder: string) {\n debug('bumping version (minor) in %s', tempFolder);\n if (ctx.adapter.type === 'yarn-modern') {\n // Bump version by editing package.json directly to avoid\n // requiring the version plugin (not bundled in Yarn 3)\n const pkgPath = join(tempFolder, 'package.json');\n const pkg = JSON.parse(await readFile(pkgPath, 'utf8'));\n const [major, minor, patch] = pkg.version.split('.').map(Number);\n pkg.version = `${major}.${minor + 1}.${patch}`;\n debug('bumped %s to %s', pkgPath, pkg.version);\n await writeFile(pkgPath, JSON.stringify(pkg, null, 2));\n } else {\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'version',\n 'minor',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n }\n}\n\nasync function prepareDeprecateProject(\n ctx: TestContext,\n pkgName: string,\n version: string\n): Promise<string> {\n debug('preparing project for %s@%s', pkgName, version);\n const { tempFolder } = await ctx.adapter.prepareProject(\n pkgName,\n version,\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n if (ctx.adapter.importPlugin) {\n debug('importing npm-deprecate plugin into %s', tempFolder);\n await ctx.adapter.importPlugin(tempFolder, 'npm-deprecate');\n }\n return tempFolder;\n}\n\nasync function testDeprecate(ctx: TestContext): Promise<void> {\n const id = ctx.runId;\n\n const message = 'some message';\n\n await ctx.subTest('deprecate single version', async () => {\n const pkgName = `@verdaccio/dep1-${id}`;\n const tf = await prepareDeprecateProject(ctx, pkgName, '1.0.0');\n await publishPkg(ctx, tf, pkgName);\n await deprecate(ctx, tf, `${pkgName}@1.0.0`, message);\n const info = await getInfo(ctx, tf, pkgName);\n assert.strictEqual(info.name, pkgName);\n assert.strictEqual(info.deprecated, message, 'Package should be deprecated');\n });\n\n await ctx.subTest('un-deprecate', async () => {\n const pkgName = `@verdaccio/dep2-${id}`;\n const tf = await prepareDeprecateProject(ctx, pkgName, '1.0.0');\n await publishPkg(ctx, tf, pkgName);\n await deprecate(ctx, tf, `${pkgName}@1.0.0`, message);\n const info1 = await getInfo(ctx, tf, pkgName);\n assert.strictEqual(info1.deprecated, message);\n await deprecate(ctx, tf, `${pkgName}@1.0.0`, '');\n const info2 = await getInfo(ctx, tf, pkgName);\n assert.strictEqual(info2.deprecated, undefined, 'Package should be un-deprecated');\n });\n\n await ctx.subTest('deprecate multiple versions', async () => {\n const pkgName = `@verdaccio/dep3-${id}`;\n const tf = await prepareDeprecateProject(ctx, pkgName, '1.0.0');\n await publishPkg(ctx, tf, pkgName);\n for (let i = 0; i < 3; i++) {\n await bumpVersion(ctx, tf);\n await publishPkg(ctx, tf, pkgName);\n }\n await deprecate(ctx, tf, pkgName, message);\n for (const v of ['1.0.0', '1.1.0', '1.2.0', '1.3.0']) {\n const info = await getInfo(ctx, tf, `${pkgName}@${v}`);\n assert.strictEqual(info.deprecated, message, `Version ${v} should be deprecated`);\n }\n await bumpVersion(ctx, tf);\n await publishPkg(ctx, tf, pkgName);\n const info = await getInfo(ctx, tf, `${pkgName}@1.4.0`);\n assert.strictEqual(info.deprecated, undefined, 'New version should not be deprecated');\n });\n}\n\nexport const deprecateTest: TestDefinition = {\n name: 'deprecate',\n requires: ['deprecate'],\n run: testDeprecate,\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
//#region src/tests/dist-tags.ts
|
|
3
|
+
async function publishPkg(ctx, tempFolder, extraArgs = []) {
|
|
4
|
+
await ctx.adapter.exec({ cwd: tempFolder }, "publish", ...extraArgs, ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
5
|
+
}
|
|
6
|
+
async function bumpVersion(ctx, tempFolder) {
|
|
7
|
+
await ctx.adapter.exec({ cwd: tempFolder }, "version", "minor", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
8
|
+
}
|
|
9
|
+
async function testDistTags(ctx) {
|
|
10
|
+
const id = ctx.runId;
|
|
11
|
+
const pkgName1 = `@foo/dt1-${id}`;
|
|
12
|
+
const { tempFolder: tf1 } = await ctx.adapter.prepareProject(pkgName1, "1.0.0", ctx.registryUrl, ctx.port, ctx.token);
|
|
13
|
+
await publishPkg(ctx, tf1);
|
|
14
|
+
await bumpVersion(ctx, tf1);
|
|
15
|
+
await publishPkg(ctx, tf1, ["--tag", "beta"]);
|
|
16
|
+
const resp1 = await ctx.adapter.exec({ cwd: tf1 }, "dist-tag", "ls", "--json", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
17
|
+
assert.strictEqual(resp1.stdout, "beta: 1.1.0latest: 1.0.0");
|
|
18
|
+
const pkgName2 = `@verdaccio/dt2-${id}`;
|
|
19
|
+
const { tempFolder: tf2 } = await ctx.adapter.prepareProject(pkgName2, "1.0.0", ctx.registryUrl, ctx.port, ctx.token);
|
|
20
|
+
await publishPkg(ctx, tf2);
|
|
21
|
+
await bumpVersion(ctx, tf2);
|
|
22
|
+
await publishPkg(ctx, tf2, ["--tag", "beta"]);
|
|
23
|
+
const resp2 = await ctx.adapter.exec({ cwd: tf2 }, "dist-tag", "rm", `${pkgName2}@1.1.0`, "beta", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
24
|
+
assert.strictEqual(resp2.stdout, `-beta: ${pkgName2}@1.1.0`);
|
|
25
|
+
const pkgName3 = `@verdaccio/dt3-${id}`;
|
|
26
|
+
const { tempFolder: tf3 } = await ctx.adapter.prepareProject(pkgName3, "1.0.0", ctx.registryUrl, ctx.port, ctx.token);
|
|
27
|
+
await publishPkg(ctx, tf3);
|
|
28
|
+
await bumpVersion(ctx, tf3);
|
|
29
|
+
await publishPkg(ctx, tf3);
|
|
30
|
+
const resp3 = await ctx.adapter.exec({ cwd: tf3 }, "dist-tag", "add", `${pkgName3}@1.1.0`, "alfa", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
31
|
+
assert.strictEqual(resp3.stdout, `+alfa: ${pkgName3}@1.1.0`);
|
|
32
|
+
}
|
|
33
|
+
var distTagsTest = {
|
|
34
|
+
name: "dist-tags",
|
|
35
|
+
requires: ["dist-tag"],
|
|
36
|
+
run: testDistTags
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { distTagsTest };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=dist-tags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dist-tags.js","names":[],"sources":["../../../src/tests/dist-tags.ts"],"sourcesContent":["import assert from 'assert';\n\nimport { TestContext, TestDefinition } from '../types';\n\nasync function publishPkg(ctx: TestContext, tempFolder: string, extraArgs: string[] = []) {\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'publish',\n ...extraArgs,\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n}\n\nasync function bumpVersion(ctx: TestContext, tempFolder: string) {\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'version',\n 'minor',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n}\n\nasync function testDistTags(ctx: TestContext): Promise<void> {\n const id = ctx.runId;\n\n // Test 1: list dist-tags\n const pkgName1 = `@foo/dt1-${id}`;\n const { tempFolder: tf1 } = await ctx.adapter.prepareProject(\n pkgName1,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n await publishPkg(ctx, tf1);\n await bumpVersion(ctx, tf1);\n await publishPkg(ctx, tf1, ['--tag', 'beta']);\n const resp1 = await ctx.adapter.exec(\n { cwd: tf1 },\n 'dist-tag',\n 'ls',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.strictEqual(resp1.stdout, 'beta: 1.1.0latest: 1.0.0');\n\n // Test 2: remove tag\n const pkgName2 = `@verdaccio/dt2-${id}`;\n const { tempFolder: tf2 } = await ctx.adapter.prepareProject(\n pkgName2,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n await publishPkg(ctx, tf2);\n await bumpVersion(ctx, tf2);\n await publishPkg(ctx, tf2, ['--tag', 'beta']);\n const resp2 = await ctx.adapter.exec(\n { cwd: tf2 },\n 'dist-tag',\n 'rm',\n `${pkgName2}@1.1.0`,\n 'beta',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.strictEqual(resp2.stdout, `-beta: ${pkgName2}@1.1.0`);\n\n // Test 3: add tag\n const pkgName3 = `@verdaccio/dt3-${id}`;\n const { tempFolder: tf3 } = await ctx.adapter.prepareProject(\n pkgName3,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n await publishPkg(ctx, tf3);\n await bumpVersion(ctx, tf3);\n await publishPkg(ctx, tf3);\n const resp3 = await ctx.adapter.exec(\n { cwd: tf3 },\n 'dist-tag',\n 'add',\n `${pkgName3}@1.1.0`,\n 'alfa',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.strictEqual(resp3.stdout, `+alfa: ${pkgName3}@1.1.0`);\n}\n\nexport const distTagsTest: TestDefinition = {\n name: 'dist-tags',\n requires: ['dist-tag'],\n run: testDistTags,\n};\n"],"mappings":";;AAIA,eAAe,WAAW,KAAkB,YAAoB,YAAsB,CAAC,GAAG;CACxF,MAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,WAAW,GAClB,WACA,GAAG,WACH,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;AACF;AAEA,eAAe,YAAY,KAAkB,YAAoB;CAC/D,MAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,WAAW,GAClB,WACA,SACA,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;AACF;AAEA,eAAe,aAAa,KAAiC;CAC3D,MAAM,KAAK,IAAI;CAGf,MAAM,WAAW,YAAY;CAC7B,MAAM,EAAE,YAAY,QAAQ,MAAM,IAAI,QAAQ,eAC5C,UACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,KACN;CACA,MAAM,WAAW,KAAK,GAAG;CACzB,MAAM,YAAY,KAAK,GAAG;CAC1B,MAAM,WAAW,KAAK,KAAK,CAAC,SAAS,MAAM,CAAC;CAC5C,MAAM,QAAQ,MAAM,IAAI,QAAQ,KAC9B,EAAE,KAAK,IAAI,GACX,YACA,MACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;CACA,OAAO,YAAY,MAAM,QAAQ,0BAA0B;CAG3D,MAAM,WAAW,kBAAkB;CACnC,MAAM,EAAE,YAAY,QAAQ,MAAM,IAAI,QAAQ,eAC5C,UACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,KACN;CACA,MAAM,WAAW,KAAK,GAAG;CACzB,MAAM,YAAY,KAAK,GAAG;CAC1B,MAAM,WAAW,KAAK,KAAK,CAAC,SAAS,MAAM,CAAC;CAC5C,MAAM,QAAQ,MAAM,IAAI,QAAQ,KAC9B,EAAE,KAAK,IAAI,GACX,YACA,MACA,GAAG,SAAS,SACZ,QACA,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;CACA,OAAO,YAAY,MAAM,QAAQ,UAAU,SAAS,OAAO;CAG3D,MAAM,WAAW,kBAAkB;CACnC,MAAM,EAAE,YAAY,QAAQ,MAAM,IAAI,QAAQ,eAC5C,UACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,KACN;CACA,MAAM,WAAW,KAAK,GAAG;CACzB,MAAM,YAAY,KAAK,GAAG;CAC1B,MAAM,WAAW,KAAK,GAAG;CACzB,MAAM,QAAQ,MAAM,IAAI,QAAQ,KAC9B,EAAE,KAAK,IAAI,GACX,YACA,OACA,GAAG,SAAS,SACZ,QACA,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;CACA,OAAO,YAAY,MAAM,QAAQ,UAAU,SAAS,OAAO;AAC7D;AAEA,IAAa,eAA+B;CAC1C,MAAM;CACN,UAAU,CAAC,UAAU;CACrB,KAAK;AACP"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import "../scenarios/install-multiple-deps.js";
|
|
2
|
+
import "../scenarios/metadata.js";
|
|
3
|
+
import "../scenarios/minimum-release-age.js";
|
|
4
|
+
import "../scenarios/search.js";
|
|
5
|
+
import "../scenarios/tarballs.js";
|
|
6
|
+
import "../scenarios/uplink-failure.js";
|
|
7
|
+
import { allScenarios } from "../scenarios/index.js";
|
|
8
|
+
import { auditTest } from "./audit.js";
|
|
9
|
+
import { ciTest } from "./ci.js";
|
|
10
|
+
import { deprecateTest } from "./deprecate.js";
|
|
11
|
+
import { distTagsTest } from "./dist-tags.js";
|
|
12
|
+
import { infoTest } from "./info.js";
|
|
13
|
+
import { installTest } from "./install.js";
|
|
14
|
+
import { loginTest } from "./login.js";
|
|
15
|
+
import { pingTest } from "./ping.js";
|
|
16
|
+
import { publishTest } from "./publish.js";
|
|
17
|
+
import { searchTest } from "./search.js";
|
|
18
|
+
import { unpublishTest } from "./unpublish.js";
|
|
19
|
+
//#region src/tests/index.ts
|
|
20
|
+
var allTests = [
|
|
21
|
+
publishTest,
|
|
22
|
+
installTest,
|
|
23
|
+
ciTest,
|
|
24
|
+
auditTest,
|
|
25
|
+
infoTest,
|
|
26
|
+
deprecateTest,
|
|
27
|
+
distTagsTest,
|
|
28
|
+
loginTest,
|
|
29
|
+
pingTest,
|
|
30
|
+
searchTest,
|
|
31
|
+
unpublishTest,
|
|
32
|
+
...allScenarios
|
|
33
|
+
];
|
|
34
|
+
//#endregion
|
|
35
|
+
export { allScenarios, allTests, auditTest, ciTest, deprecateTest, distTagsTest, infoTest, installTest, loginTest, pingTest, publishTest, searchTest, unpublishTest };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/tests/index.ts"],"sourcesContent":["import {\n allScenarios,\n installMultipleDepsScenario,\n metadataScenario,\n minimumReleaseAgeScenario,\n searchScenario,\n tarballsScenario,\n uplinkFailureScenario,\n} from '../scenarios';\nimport { TestDefinition } from '../types';\nimport { auditTest } from './audit';\nimport { ciTest } from './ci';\nimport { deprecateTest } from './deprecate';\nimport { distTagsTest } from './dist-tags';\nimport { infoTest } from './info';\nimport { installTest } from './install';\nimport { loginTest } from './login';\nimport { pingTest } from './ping';\nimport { publishTest } from './publish';\nimport { searchTest } from './search';\nimport { unpublishTest } from './unpublish';\n\nexport const allTests: TestDefinition[] = [\n publishTest,\n installTest,\n ciTest,\n auditTest,\n infoTest,\n deprecateTest,\n distTagsTest,\n loginTest,\n pingTest,\n searchTest,\n unpublishTest,\n // Scenarios (complex, multi-step tests)\n ...allScenarios,\n];\n\nexport {\n publishTest,\n installTest,\n ciTest,\n auditTest,\n infoTest,\n deprecateTest,\n distTagsTest,\n loginTest,\n pingTest,\n searchTest,\n unpublishTest,\n // Scenarios\n installMultipleDepsScenario,\n minimumReleaseAgeScenario,\n tarballsScenario,\n metadataScenario,\n searchScenario,\n uplinkFailureScenario,\n allScenarios,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAsBA,IAAa,WAA6B;CACxC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,GAAG;AACL"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { parseInfoJson } from "../utils/info.js";
|
|
2
|
+
import { publishLocalPackage } from "../utils/publish.js";
|
|
3
|
+
import assert from "assert";
|
|
4
|
+
//#region src/tests/info.ts
|
|
5
|
+
async function testInfo(ctx) {
|
|
6
|
+
const depName = `e2e-info-dep-${ctx.runId}`;
|
|
7
|
+
const pkgName = `e2e-info-${ctx.runId}`;
|
|
8
|
+
await publishLocalPackage(ctx, depName, "1.0.0");
|
|
9
|
+
await publishLocalPackage(ctx, pkgName, "1.0.0", { [depName]: "1.0.0" });
|
|
10
|
+
const { tempFolder } = await ctx.adapter.prepareProject(`info-client-${ctx.runId}`, "1.0.0", ctx.registryUrl, ctx.port, ctx.token);
|
|
11
|
+
const resp = await ctx.adapter.exec({ cwd: tempFolder }, "info", pkgName, "--json", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
12
|
+
if (ctx.adapter.type === "deno") {
|
|
13
|
+
const output = resp.stdout + resp.stderr;
|
|
14
|
+
assert.ok(output.includes(pkgName), `Expected deno info output to reference ${pkgName}`);
|
|
15
|
+
} else {
|
|
16
|
+
const parsedBody = parseInfoJson(resp.stdout);
|
|
17
|
+
assert.strictEqual(parsedBody.name, pkgName, `Expected package name "${pkgName}"`);
|
|
18
|
+
assert.ok(parsedBody.dependencies !== void 0, "Expected \"dependencies\" to be defined");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
var infoTest = {
|
|
22
|
+
name: "info",
|
|
23
|
+
requires: ["info"],
|
|
24
|
+
run: testInfo
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { infoTest };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"info.js","names":[],"sources":["../../../src/tests/info.ts"],"sourcesContent":["import assert from 'assert';\n\nimport { TestContext, TestDefinition } from '../types';\nimport { parseInfoJson } from '../utils/info';\nimport { publishLocalPackage } from '../utils/publish';\n\nasync function testInfo(ctx: TestContext): Promise<void> {\n // Publish the package we inspect (with one dependency, also local) — asking\n // for a real npmjs package would need an uplink and the suite must run\n // offline. deno resolves the dependency tree, so the dep must exist too.\n const depName = `e2e-info-dep-${ctx.runId}`;\n const pkgName = `e2e-info-${ctx.runId}`;\n await publishLocalPackage(ctx, depName, '1.0.0');\n await publishLocalPackage(ctx, pkgName, '1.0.0', { [depName]: '1.0.0' });\n\n // Run from a prepared project: it gives yarn modern a project context, and\n // its .npmrc (fresh token) shields the test from stale credentials in\n // ~/.npmrc.\n const { tempFolder } = await ctx.adapter.prepareProject(\n `info-client-${ctx.runId}`,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n\n const resp = await ctx.adapter.exec(\n { cwd: tempFolder },\n 'info',\n pkgName,\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n if (ctx.adapter.type === 'deno') {\n // deno info npm:<pkg> outputs a text dependency tree\n const output = resp.stdout + resp.stderr;\n assert.ok(output.includes(pkgName), `Expected deno info output to reference ${pkgName}`);\n } else {\n const parsedBody = parseInfoJson(resp.stdout);\n assert.strictEqual(parsedBody.name, pkgName, `Expected package name \"${pkgName}\"`);\n assert.ok(parsedBody.dependencies !== undefined, 'Expected \"dependencies\" to be defined');\n }\n}\n\nexport const infoTest: TestDefinition = {\n name: 'info',\n requires: ['info'],\n run: testInfo,\n};\n"],"mappings":";;;;AAMA,eAAe,SAAS,KAAiC;CAIvD,MAAM,UAAU,gBAAgB,IAAI;CACpC,MAAM,UAAU,YAAY,IAAI;CAChC,MAAM,oBAAoB,KAAK,SAAS,OAAO;CAC/C,MAAM,oBAAoB,KAAK,SAAS,SAAS,GAAG,UAAU,QAAQ,CAAC;CAKvE,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,eAAe,IAAI,SACnB,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,KACN;CAEA,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,WAAW,GAClB,QACA,SACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;CAEA,IAAI,IAAI,QAAQ,SAAS,QAAQ;EAE/B,MAAM,SAAS,KAAK,SAAS,KAAK;EAClC,OAAO,GAAG,OAAO,SAAS,OAAO,GAAG,0CAA0C,SAAS;CACzF,OAAO;EACL,MAAM,aAAa,cAAc,KAAK,MAAM;EAC5C,OAAO,YAAY,WAAW,MAAM,SAAS,0BAA0B,QAAQ,EAAE;EACjF,OAAO,GAAG,WAAW,iBAAiB,KAAA,GAAW,yCAAuC;CAC1F;AACF;AAEA,IAAa,WAA2B;CACtC,MAAM;CACN,UAAU,CAAC,MAAM;CACjB,KAAK;AACP"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { publishLocalPackage } from "../utils/publish.js";
|
|
2
|
+
import assert from "assert";
|
|
3
|
+
//#region src/tests/install.ts
|
|
4
|
+
async function testInstall(ctx) {
|
|
5
|
+
const depName = `e2e-install-dep-${ctx.runId}`;
|
|
6
|
+
await publishLocalPackage(ctx, depName, "1.0.0");
|
|
7
|
+
const { tempFolder } = await ctx.adapter.prepareProject(`install-test-${ctx.runId}`, "1.0.0", ctx.registryUrl, ctx.port, ctx.token, { [depName]: "1.0.0" });
|
|
8
|
+
const isNpm = ctx.adapter.type === "npm";
|
|
9
|
+
const args = isNpm ? [
|
|
10
|
+
"install",
|
|
11
|
+
"--json",
|
|
12
|
+
...ctx.adapter.registryArg(ctx.registryUrl)
|
|
13
|
+
] : ["install", ...ctx.adapter.registryArg(ctx.registryUrl)];
|
|
14
|
+
const resp = await ctx.adapter.exec({ cwd: tempFolder }, ...args);
|
|
15
|
+
if (isNpm) {
|
|
16
|
+
const parsedBody = JSON.parse(resp.stdout);
|
|
17
|
+
assert.ok(parsedBody.added !== void 0, "Expected \"added\" field in install response");
|
|
18
|
+
} else assert.ok(true, "Install completed successfully");
|
|
19
|
+
}
|
|
20
|
+
var installTest = {
|
|
21
|
+
name: "install",
|
|
22
|
+
requires: ["install"],
|
|
23
|
+
run: testInstall
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
export { installTest };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","names":[],"sources":["../../../src/tests/install.ts"],"sourcesContent":["import assert from 'assert';\n\nimport { TestContext, TestDefinition } from '../types';\nimport { publishLocalPackage } from '../utils/publish';\n\nasync function testInstall(ctx: TestContext): Promise<void> {\n // Publish the dependency locally first — the suite must work offline, so\n // nothing is ever resolved from an external registry.\n const depName = `e2e-install-dep-${ctx.runId}`;\n await publishLocalPackage(ctx, depName, '1.0.0');\n\n const { tempFolder } = await ctx.adapter.prepareProject(\n `install-test-${ctx.runId}`,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token,\n { [depName]: '1.0.0' }\n );\n\n const isNpm = ctx.adapter.type === 'npm';\n\n // pnpm doesn't support --json on install\n const args = isNpm\n ? ['install', '--json', ...ctx.adapter.registryArg(ctx.registryUrl)]\n : ['install', ...ctx.adapter.registryArg(ctx.registryUrl)];\n\n const resp = await ctx.adapter.exec({ cwd: tempFolder }, ...args);\n\n if (isNpm) {\n const parsedBody = JSON.parse(resp.stdout);\n assert.ok(parsedBody.added !== undefined, 'Expected \"added\" field in install response');\n } else {\n // for pnpm/yarn just verify it completed without error (exit code 0)\n assert.ok(true, 'Install completed successfully');\n }\n}\n\nexport const installTest: TestDefinition = {\n name: 'install',\n requires: ['install'],\n run: testInstall,\n};\n"],"mappings":";;;AAKA,eAAe,YAAY,KAAiC;CAG1D,MAAM,UAAU,mBAAmB,IAAI;CACvC,MAAM,oBAAoB,KAAK,SAAS,OAAO;CAE/C,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,gBAAgB,IAAI,SACpB,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,OACJ,GAAG,UAAU,QAAQ,CACvB;CAEA,MAAM,QAAQ,IAAI,QAAQ,SAAS;CAGnC,MAAM,OAAO,QACT;EAAC;EAAW;EAAU,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW;CAAC,IACjE,CAAC,WAAW,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAAC;CAE3D,MAAM,OAAO,MAAM,IAAI,QAAQ,KAAK,EAAE,KAAK,WAAW,GAAG,GAAG,IAAI;CAEhE,IAAI,OAAO;EACT,MAAM,aAAa,KAAK,MAAM,KAAK,MAAM;EACzC,OAAO,GAAG,WAAW,UAAU,KAAA,GAAW,8CAA4C;CACxF,OAEE,OAAO,GAAG,MAAM,gCAAgC;AAEpD;AAEA,IAAa,cAA8B;CACzC,MAAM;CACN,UAAU,CAAC,SAAS;CACpB,KAAK;AACP"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { createTempFolder, getPackageJSON, getREADME } from "../utils/project.js";
|
|
2
|
+
import buildDebug from "debug";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { writeFile } from "fs/promises";
|
|
5
|
+
import * as YAML from "js-yaml";
|
|
6
|
+
import assert from "assert";
|
|
7
|
+
//#region src/tests/login.ts
|
|
8
|
+
var debug = buildDebug("verdaccio:e2e-cli:test:login");
|
|
9
|
+
/**
|
|
10
|
+
* Creates a project with registry config but WITHOUT auth token,
|
|
11
|
+
* so whoami will use the token saved by login to ~/.yarnrc.yml.
|
|
12
|
+
*/
|
|
13
|
+
async function prepareLoginProject(ctx, name) {
|
|
14
|
+
debug("preparing project for %s (no auth token)", name);
|
|
15
|
+
const tempFolder = await createTempFolder(name);
|
|
16
|
+
const yamlContent = YAML.dump({
|
|
17
|
+
npmRegistryServer: ctx.registryUrl,
|
|
18
|
+
enableImmutableInstalls: false,
|
|
19
|
+
unsafeHttpWhitelist: ["localhost"]
|
|
20
|
+
});
|
|
21
|
+
await writeFile(join(tempFolder, ".yarnrc.yml"), yamlContent);
|
|
22
|
+
await writeFile(join(tempFolder, "package.json"), JSON.stringify({
|
|
23
|
+
name,
|
|
24
|
+
version: "1.0.0"
|
|
25
|
+
}));
|
|
26
|
+
if (ctx.adapter.importPlugin) {
|
|
27
|
+
debug("importing npm-login plugin into %s", tempFolder);
|
|
28
|
+
await ctx.adapter.importPlugin(tempFolder, "npm-login");
|
|
29
|
+
}
|
|
30
|
+
return tempFolder;
|
|
31
|
+
}
|
|
32
|
+
async function yarnLogin(ctx, cwd, user, password, email) {
|
|
33
|
+
debug("yarn npm login as %s", user);
|
|
34
|
+
return ctx.adapter.exec({ cwd }, "login", "--auth-type=legacy", `--user=${user}`, `--password=${password}`, `--email=${email}`);
|
|
35
|
+
}
|
|
36
|
+
async function yarnWhoami(ctx, cwd) {
|
|
37
|
+
const resp = await ctx.adapter.exec({ cwd }, "whoami");
|
|
38
|
+
debug("yarn npm whoami: %s", resp.stdout);
|
|
39
|
+
return resp.stdout;
|
|
40
|
+
}
|
|
41
|
+
async function testLogin(ctx) {
|
|
42
|
+
const type = ctx.adapter.type;
|
|
43
|
+
const id = ctx.runId;
|
|
44
|
+
if (type !== "yarn-modern") {
|
|
45
|
+
debug("login test only supported for yarn-modern, skipping %s", type);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const user1 = `login-a-${id}`;
|
|
49
|
+
const password1 = "test-password-123";
|
|
50
|
+
const email1 = `${user1}@test.example.com`;
|
|
51
|
+
await ctx.subTest("create new user + whoami", async () => {
|
|
52
|
+
const tf = await prepareLoginProject(ctx, `verdaccio-login1-${id}`);
|
|
53
|
+
const loginResp = await yarnLogin(ctx, tf, user1, password1, email1);
|
|
54
|
+
assert.ok(loginResp.stdout.includes("Logged in") || loginResp.stdout.includes("token saved"), `Expected login success message but got "${loginResp.stdout}"`);
|
|
55
|
+
const who = await yarnWhoami(ctx, tf);
|
|
56
|
+
assert.ok(who.includes(user1), `Expected whoami "${user1}" but got "${who}"`);
|
|
57
|
+
});
|
|
58
|
+
await ctx.subTest("legacy re-login is rejected without basic auth", async () => {
|
|
59
|
+
const tf = await prepareLoginProject(ctx, `verdaccio-login2-${id}`);
|
|
60
|
+
let loginFailed = false;
|
|
61
|
+
try {
|
|
62
|
+
await yarnLogin(ctx, tf, user1, password1, email1);
|
|
63
|
+
} catch {
|
|
64
|
+
loginFailed = true;
|
|
65
|
+
}
|
|
66
|
+
assert.ok(loginFailed, "Legacy re-login for an existing user should fail without Basic auth");
|
|
67
|
+
});
|
|
68
|
+
await ctx.subTest("wrong password fails", async () => {
|
|
69
|
+
const tf = await prepareLoginProject(ctx, `verdaccio-login3-${id}`);
|
|
70
|
+
let loginFailed = false;
|
|
71
|
+
try {
|
|
72
|
+
await yarnLogin(ctx, tf, user1, "wrong-password", email1);
|
|
73
|
+
} catch {
|
|
74
|
+
loginFailed = true;
|
|
75
|
+
}
|
|
76
|
+
assert.ok(loginFailed, "Login with wrong password should have failed");
|
|
77
|
+
});
|
|
78
|
+
await ctx.subTest("login then publish", async () => {
|
|
79
|
+
const pkgName = `@verdaccio/login-pub-${id}`;
|
|
80
|
+
const publishUser = `login-pub-${id}`;
|
|
81
|
+
const publishPassword = "publish-password-123";
|
|
82
|
+
const publishEmail = `${publishUser}@test.example.com`;
|
|
83
|
+
const tf = await createTempFolder(`login-pub-${id}`);
|
|
84
|
+
const yamlContent = YAML.dump({
|
|
85
|
+
npmRegistryServer: ctx.registryUrl,
|
|
86
|
+
enableImmutableInstalls: false,
|
|
87
|
+
unsafeHttpWhitelist: ["localhost"]
|
|
88
|
+
});
|
|
89
|
+
await writeFile(join(tf, ".yarnrc.yml"), yamlContent);
|
|
90
|
+
await writeFile(join(tf, "package.json"), getPackageJSON(pkgName, "1.0.0"));
|
|
91
|
+
await writeFile(join(tf, "README.md"), getREADME(pkgName));
|
|
92
|
+
if (ctx.adapter.importPlugin) await ctx.adapter.importPlugin(tf, "npm-login");
|
|
93
|
+
await yarnLogin(ctx, tf, publishUser, publishPassword, publishEmail);
|
|
94
|
+
await ctx.adapter.exec({ cwd: tf }, "install");
|
|
95
|
+
const pubResp = await ctx.adapter.exec({ cwd: tf }, "publish");
|
|
96
|
+
assert.ok(pubResp.stdout.includes("Package archive published"), `Expected publish success but got "${pubResp.stdout}"`);
|
|
97
|
+
});
|
|
98
|
+
await ctx.subTest("switch users", async () => {
|
|
99
|
+
const switchUser1 = `login-switch-a-${id}`;
|
|
100
|
+
const switchPassword1 = "switch-password-123";
|
|
101
|
+
const switchEmail1 = `${switchUser1}@test.example.com`;
|
|
102
|
+
const user2 = `login-b-${id}`;
|
|
103
|
+
const password2 = "other-password-456";
|
|
104
|
+
const email2 = `${user2}@test.example.com`;
|
|
105
|
+
const tf = await prepareLoginProject(ctx, `verdaccio-login5-${id}`);
|
|
106
|
+
await yarnLogin(ctx, tf, switchUser1, switchPassword1, switchEmail1);
|
|
107
|
+
const who1 = await yarnWhoami(ctx, tf);
|
|
108
|
+
assert.ok(who1.includes(switchUser1), `Expected "${switchUser1}" but got "${who1}"`);
|
|
109
|
+
await yarnLogin(ctx, tf, user2, password2, email2);
|
|
110
|
+
const who2 = await yarnWhoami(ctx, tf);
|
|
111
|
+
assert.ok(who2.includes(user2), `Expected "${user2}" after switch but got "${who2}"`);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
var loginTest = {
|
|
115
|
+
name: "login",
|
|
116
|
+
requires: ["login"],
|
|
117
|
+
run: testLogin
|
|
118
|
+
};
|
|
119
|
+
//#endregion
|
|
120
|
+
export { loginTest };
|
|
121
|
+
|
|
122
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","names":[],"sources":["../../../src/tests/login.ts"],"sourcesContent":["import assert from 'assert';\nimport buildDebug from 'debug';\nimport { writeFile } from 'fs/promises';\nimport * as YAML from 'js-yaml';\nimport { join } from 'path';\n\nimport { TestContext, TestDefinition } from '../types';\nimport { createTempFolder, getPackageJSON, getREADME } from '../utils/project';\n\nconst debug = buildDebug('verdaccio:e2e-cli:test:login');\n\n/**\n * Creates a project with registry config but WITHOUT auth token,\n * so whoami will use the token saved by login to ~/.yarnrc.yml.\n */\nasync function prepareLoginProject(ctx: TestContext, name: string): Promise<string> {\n debug('preparing project for %s (no auth token)', name);\n const tempFolder = await createTempFolder(name);\n const yamlContent = YAML.dump({\n npmRegistryServer: ctx.registryUrl,\n enableImmutableInstalls: false,\n unsafeHttpWhitelist: ['localhost'],\n });\n await writeFile(join(tempFolder, '.yarnrc.yml'), yamlContent);\n await writeFile(join(tempFolder, 'package.json'), JSON.stringify({ name, version: '1.0.0' }));\n if (ctx.adapter.importPlugin) {\n debug('importing npm-login plugin into %s', tempFolder);\n await ctx.adapter.importPlugin(tempFolder, 'npm-login');\n }\n return tempFolder;\n}\n\nasync function yarnLogin(\n ctx: TestContext,\n cwd: string,\n user: string,\n password: string,\n email: string\n) {\n debug('yarn npm login as %s', user);\n return ctx.adapter.exec(\n { cwd },\n 'login',\n '--auth-type=legacy',\n `--user=${user}`,\n `--password=${password}`,\n `--email=${email}`\n );\n}\n\nasync function yarnWhoami(ctx: TestContext, cwd: string): Promise<string> {\n const resp = await ctx.adapter.exec({ cwd }, 'whoami');\n debug('yarn npm whoami: %s', resp.stdout);\n return resp.stdout;\n}\n\nasync function testLogin(ctx: TestContext): Promise<void> {\n const type = ctx.adapter.type;\n const id = ctx.runId;\n\n if (type !== 'yarn-modern') {\n debug('login test only supported for yarn-modern, skipping %s', type);\n return;\n }\n\n const user1 = `login-a-${id}`;\n const password1 = 'test-password-123';\n const email1 = `${user1}@test.example.com`;\n\n await ctx.subTest('create new user + whoami', async () => {\n const tf = await prepareLoginProject(ctx, `verdaccio-login1-${id}`);\n const loginResp = await yarnLogin(ctx, tf, user1, password1, email1);\n assert.ok(\n loginResp.stdout.includes('Logged in') || loginResp.stdout.includes('token saved'),\n `Expected login success message but got \"${loginResp.stdout}\"`\n );\n const who = await yarnWhoami(ctx, tf);\n assert.ok(who.includes(user1), `Expected whoami \"${user1}\" but got \"${who}\"`);\n });\n\n await ctx.subTest('legacy re-login is rejected without basic auth', async () => {\n const tf = await prepareLoginProject(ctx, `verdaccio-login2-${id}`);\n let loginFailed = false;\n try {\n await yarnLogin(ctx, tf, user1, password1, email1);\n } catch {\n loginFailed = true;\n }\n assert.ok(loginFailed, 'Legacy re-login for an existing user should fail without Basic auth');\n });\n\n await ctx.subTest('wrong password fails', async () => {\n const tf = await prepareLoginProject(ctx, `verdaccio-login3-${id}`);\n let loginFailed = false;\n try {\n await yarnLogin(ctx, tf, user1, 'wrong-password', email1);\n } catch {\n loginFailed = true;\n }\n assert.ok(loginFailed, 'Login with wrong password should have failed');\n });\n\n await ctx.subTest('login then publish', async () => {\n const pkgName = `@verdaccio/login-pub-${id}`;\n const publishUser = `login-pub-${id}`;\n const publishPassword = 'publish-password-123';\n const publishEmail = `${publishUser}@test.example.com`;\n const tf = await createTempFolder(`login-pub-${id}`);\n const yamlContent = YAML.dump({\n npmRegistryServer: ctx.registryUrl,\n enableImmutableInstalls: false,\n unsafeHttpWhitelist: ['localhost'],\n });\n await writeFile(join(tf, '.yarnrc.yml'), yamlContent);\n await writeFile(join(tf, 'package.json'), getPackageJSON(pkgName, '1.0.0'));\n await writeFile(join(tf, 'README.md'), getREADME(pkgName));\n if (ctx.adapter.importPlugin) {\n await ctx.adapter.importPlugin(tf, 'npm-login');\n }\n await yarnLogin(ctx, tf, publishUser, publishPassword, publishEmail);\n await ctx.adapter.exec({ cwd: tf }, 'install');\n const pubResp = await ctx.adapter.exec({ cwd: tf }, 'publish');\n assert.ok(\n pubResp.stdout.includes('Package archive published'),\n `Expected publish success but got \"${pubResp.stdout}\"`\n );\n });\n\n await ctx.subTest('switch users', async () => {\n const switchUser1 = `login-switch-a-${id}`;\n const switchPassword1 = 'switch-password-123';\n const switchEmail1 = `${switchUser1}@test.example.com`;\n const user2 = `login-b-${id}`;\n const password2 = 'other-password-456';\n const email2 = `${user2}@test.example.com`;\n const tf = await prepareLoginProject(ctx, `verdaccio-login5-${id}`);\n\n await yarnLogin(ctx, tf, switchUser1, switchPassword1, switchEmail1);\n const who1 = await yarnWhoami(ctx, tf);\n assert.ok(who1.includes(switchUser1), `Expected \"${switchUser1}\" but got \"${who1}\"`);\n\n await yarnLogin(ctx, tf, user2, password2, email2);\n const who2 = await yarnWhoami(ctx, tf);\n assert.ok(who2.includes(user2), `Expected \"${user2}\" after switch but got \"${who2}\"`);\n });\n}\n\nexport const loginTest: TestDefinition = {\n name: 'login',\n requires: ['login'],\n run: testLogin,\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
//#region src/tests/ping.ts
|
|
3
|
+
async function testPing(ctx) {
|
|
4
|
+
const type = ctx.adapter.type;
|
|
5
|
+
const { tempFolder } = await ctx.adapter.prepareProject(`verdaccio-ping-${ctx.runId}`, "1.0.0", ctx.registryUrl, ctx.port, ctx.token);
|
|
6
|
+
const cwd = tempFolder;
|
|
7
|
+
if (type === "yarn-modern" && ctx.adapter.importPlugin) await ctx.adapter.importPlugin(tempFolder, "npm-ping");
|
|
8
|
+
const jsonFlag = type === "yarn-modern" ? [] : ["--json"];
|
|
9
|
+
const resp = await ctx.adapter.exec({ cwd }, "ping", ...jsonFlag, ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
10
|
+
if (type === "yarn-modern") assert.ok(true, "ping succeeded");
|
|
11
|
+
else {
|
|
12
|
+
const parsedBody = JSON.parse(resp.stdout);
|
|
13
|
+
assert.strictEqual(parsedBody.registry, ctx.registryUrl + "/", `Expected registry "${ctx.registryUrl}/" but got "${parsedBody.registry}"`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
var pingTest = {
|
|
17
|
+
name: "ping",
|
|
18
|
+
requires: ["ping"],
|
|
19
|
+
run: testPing
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { pingTest };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=ping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ping.js","names":[],"sources":["../../../src/tests/ping.ts"],"sourcesContent":["import assert from 'assert';\n\nimport { TestContext, TestDefinition } from '../types';\n\nasync function testPing(ctx: TestContext): Promise<void> {\n const type = ctx.adapter.type;\n\n // Always run from a prepared project: its .npmrc carries the fresh token and\n // shields the test from whatever the developer's global ~/.npmrc has for\n // this registry (a stale token there would turn into a spurious E401).\n const { tempFolder } = await ctx.adapter.prepareProject(\n `verdaccio-ping-${ctx.runId}`,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n const cwd = tempFolder;\n if (type === 'yarn-modern' && ctx.adapter.importPlugin) {\n await ctx.adapter.importPlugin(tempFolder, 'npm-ping');\n }\n\n const jsonFlag = type === 'yarn-modern' ? [] : ['--json'];\n const resp = await ctx.adapter.exec(\n { cwd },\n 'ping',\n ...jsonFlag,\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n if (type === 'yarn-modern') {\n // yarn npm ping succeeding (exit code 0) is sufficient proof the registry is reachable\n assert.ok(true, 'ping succeeded');\n } else {\n const parsedBody = JSON.parse(resp.stdout);\n assert.strictEqual(\n parsedBody.registry,\n ctx.registryUrl + '/',\n `Expected registry \"${ctx.registryUrl}/\" but got \"${parsedBody.registry}\"`\n );\n }\n}\n\nexport const pingTest: TestDefinition = {\n name: 'ping',\n requires: ['ping'],\n run: testPing,\n};\n"],"mappings":";;AAIA,eAAe,SAAS,KAAiC;CACvD,MAAM,OAAO,IAAI,QAAQ;CAKzB,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,kBAAkB,IAAI,SACtB,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,KACN;CACA,MAAM,MAAM;CACZ,IAAI,SAAS,iBAAiB,IAAI,QAAQ,cACxC,MAAM,IAAI,QAAQ,aAAa,YAAY,UAAU;CAGvD,MAAM,WAAW,SAAS,gBAAgB,CAAC,IAAI,CAAC,QAAQ;CACxD,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,IAAI,GACN,QACA,GAAG,UACH,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;CAEA,IAAI,SAAS,eAEX,OAAO,GAAG,MAAM,gBAAgB;MAC3B;EACL,MAAM,aAAa,KAAK,MAAM,KAAK,MAAM;EACzC,OAAO,YACL,WAAW,UACX,IAAI,cAAc,KAClB,sBAAsB,IAAI,YAAY,cAAc,WAAW,SAAS,EAC1E;CACF;AACF;AAEA,IAAa,WAA2B;CACtC,MAAM;CACN,UAAU,CAAC,MAAM;CACjB,KAAK;AACP"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
//#region src/tests/publish.ts
|
|
3
|
+
async function testPublish(ctx) {
|
|
4
|
+
const packages = [
|
|
5
|
+
`verdaccio-memory-${ctx.runId}`,
|
|
6
|
+
`verdaccio-${ctx.runId}`,
|
|
7
|
+
`@verdaccio/foo-${ctx.runId}`,
|
|
8
|
+
`@verdaccio/some-foo-${ctx.runId}`
|
|
9
|
+
];
|
|
10
|
+
const type = ctx.adapter.type;
|
|
11
|
+
for (const pkgName of packages) {
|
|
12
|
+
const { tempFolder } = await ctx.adapter.prepareProject(pkgName, "1.0.0", ctx.registryUrl, ctx.port, ctx.token);
|
|
13
|
+
if (type === "yarn-modern") await ctx.adapter.exec({ cwd: tempFolder }, "install");
|
|
14
|
+
const resp = await ctx.adapter.exec({ cwd: tempFolder }, "publish", "--json", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
15
|
+
if (type === "yarn-modern") assert.ok(resp.stdout.match(/Package archive published/), `Expected "Package archive published" for ${pkgName} but got "${resp.stdout}"`);
|
|
16
|
+
else if (type === "bun") assert.ok(true, `Publish succeeded for ${pkgName}`);
|
|
17
|
+
else try {
|
|
18
|
+
const parsedBody = JSON.parse(resp.stdout);
|
|
19
|
+
assert.strictEqual(parsedBody.name, pkgName, `Expected package name "${pkgName}" but got "${parsedBody.name}"`);
|
|
20
|
+
assert.ok(parsedBody.files, `Expected files to be defined for ${pkgName}`);
|
|
21
|
+
} catch {
|
|
22
|
+
assert.ok(true, `Publish succeeded for ${pkgName}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
var publishTest = {
|
|
27
|
+
name: "publish",
|
|
28
|
+
requires: ["publish"],
|
|
29
|
+
run: testPublish
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { publishTest };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","names":[],"sources":["../../../src/tests/publish.ts"],"sourcesContent":["import assert from 'assert';\n\nimport { TestContext, TestDefinition } from '../types';\n\nasync function testPublish(ctx: TestContext): Promise<void> {\n const packages = [\n `verdaccio-memory-${ctx.runId}`,\n `verdaccio-${ctx.runId}`,\n `@verdaccio/foo-${ctx.runId}`,\n `@verdaccio/some-foo-${ctx.runId}`,\n ];\n\n const type = ctx.adapter.type;\n\n for (const pkgName of packages) {\n const { tempFolder } = await ctx.adapter.prepareProject(\n pkgName,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n\n // yarn modern requires install before publish to generate lockfile\n if (type === 'yarn-modern') {\n await ctx.adapter.exec({ cwd: tempFolder }, 'install');\n }\n\n const resp = await ctx.adapter.exec(\n { cwd: tempFolder },\n 'publish',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n if (type === 'yarn-modern') {\n assert.ok(\n resp.stdout.match(/Package archive published/),\n `Expected \"Package archive published\" for ${pkgName} but got \"${resp.stdout}\"`\n );\n } else if (type === 'bun') {\n // bun publish outputs text confirmation — exit code 0 is sufficient\n assert.ok(true, `Publish succeeded for ${pkgName}`);\n } else {\n // npm / pnpm\n try {\n const parsedBody = JSON.parse(resp.stdout);\n assert.strictEqual(\n parsedBody.name,\n pkgName,\n `Expected package name \"${pkgName}\" but got \"${parsedBody.name}\"`\n );\n assert.ok(parsedBody.files, `Expected files to be defined for ${pkgName}`);\n } catch {\n // pnpm v11+ native publish doesn't output JSON — exit code 0 is sufficient\n assert.ok(true, `Publish succeeded for ${pkgName}`);\n }\n }\n }\n}\n\nexport const publishTest: TestDefinition = {\n name: 'publish',\n requires: ['publish'],\n run: testPublish,\n};\n"],"mappings":";;AAIA,eAAe,YAAY,KAAiC;CAC1D,MAAM,WAAW;EACf,oBAAoB,IAAI;EACxB,aAAa,IAAI;EACjB,kBAAkB,IAAI;EACtB,uBAAuB,IAAI;CAC7B;CAEA,MAAM,OAAO,IAAI,QAAQ;CAEzB,KAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,SACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,KACN;EAGA,IAAI,SAAS,eACX,MAAM,IAAI,QAAQ,KAAK,EAAE,KAAK,WAAW,GAAG,SAAS;EAGvD,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,WAAW,GAClB,WACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;EAEA,IAAI,SAAS,eACX,OAAO,GACL,KAAK,OAAO,MAAM,2BAA2B,GAC7C,4CAA4C,QAAQ,YAAY,KAAK,OAAO,EAC9E;OACK,IAAI,SAAS,OAElB,OAAO,GAAG,MAAM,yBAAyB,SAAS;OAGlD,IAAI;GACF,MAAM,aAAa,KAAK,MAAM,KAAK,MAAM;GACzC,OAAO,YACL,WAAW,MACX,SACA,0BAA0B,QAAQ,aAAa,WAAW,KAAK,EACjE;GACA,OAAO,GAAG,WAAW,OAAO,oCAAoC,SAAS;EAC3E,QAAQ;GAEN,OAAO,GAAG,MAAM,yBAAyB,SAAS;EACpD;CAEJ;AACF;AAEA,IAAa,cAA8B;CACzC,MAAM;CACN,UAAU,CAAC,SAAS;CACpB,KAAK;AACP"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { publishLocalPackage } from "../utils/publish.js";
|
|
2
|
+
import assert from "assert";
|
|
3
|
+
//#region src/tests/search.ts
|
|
4
|
+
async function testSearch(ctx) {
|
|
5
|
+
const pkgName = `verdaccio-search-${ctx.runId}`;
|
|
6
|
+
await publishLocalPackage(ctx, pkgName, "1.0.0");
|
|
7
|
+
const { tempFolder } = await ctx.adapter.prepareProject(`search-client-${ctx.runId}`, "1.0.0", ctx.registryUrl, ctx.port, ctx.token);
|
|
8
|
+
const resp = await ctx.adapter.exec({ cwd: tempFolder }, "search", pkgName, "--json", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
9
|
+
const pkgFind = JSON.parse(resp.stdout).find((item) => item.name === pkgName);
|
|
10
|
+
assert.ok(pkgFind, `Expected to find ${pkgName} in search results`);
|
|
11
|
+
assert.strictEqual(pkgFind.name, pkgName);
|
|
12
|
+
}
|
|
13
|
+
var searchTest = {
|
|
14
|
+
name: "search",
|
|
15
|
+
requires: ["search", "publish"],
|
|
16
|
+
run: testSearch
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
export { searchTest };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=search.js.map
|