@verdaccio/e2e-cli 2.7.0 → 2.8.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.
@@ -0,0 +1,2 @@
1
+ import { PackageManagerAdapter } from '../types';
2
+ export declare function createBunAdapter(binPath?: string, _version?: string): PackageManagerAdapter;
@@ -0,0 +1,2 @@
1
+ import { PackageManagerAdapter } from '../types';
2
+ export declare function createDenoAdapter(binPath?: string, _version?: string): PackageManagerAdapter;
@@ -1,3 +1,5 @@
1
+ export { createBunAdapter } from './bun';
2
+ export { createDenoAdapter } from './deno';
1
3
  export { createNpmAdapter } from './npm';
2
4
  export { createPnpmAdapter } from './pnpm';
3
5
  export { createYarnClassicAdapter } from './yarn-classic';
@@ -0,0 +1,63 @@
1
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_process = require("../utils/process.cjs");
3
+ const require_project = require("../utils/project.cjs");
4
+ let debug = require("debug");
5
+ debug = require_runtime.__toESM(debug);
6
+ let child_process = require("child_process");
7
+ //#region src/adapters/bun.ts
8
+ var debug$1 = (0, debug.default)("verdaccio:e2e-cli:bun");
9
+ var BUN_SUPPORTED_COMMANDS = new Set([
10
+ "publish",
11
+ "install",
12
+ "info",
13
+ "audit"
14
+ ]);
15
+ function detectVersion(bin) {
16
+ try {
17
+ return (0, child_process.execSync)(`${bin} --version`, {
18
+ encoding: "utf8",
19
+ timeout: 5e3
20
+ }).trim();
21
+ } catch {
22
+ return "unknown";
23
+ }
24
+ }
25
+ function resolveBunBin(binPath) {
26
+ if (binPath) return binPath;
27
+ return "bun";
28
+ }
29
+ function createBunAdapter(binPath, _version) {
30
+ const bin = resolveBunBin(binPath);
31
+ const resolved = detectVersion(bin);
32
+ debug$1("creating bun adapter with bin: %s (%s)", bin, resolved);
33
+ return {
34
+ name: `bun@${resolved}`,
35
+ type: "bun",
36
+ bin,
37
+ supports: BUN_SUPPORTED_COMMANDS,
38
+ registryArg(url) {
39
+ return ["--registry", url];
40
+ },
41
+ prefixArg(folder) {
42
+ return ["--cwd", folder];
43
+ },
44
+ exec(options, ...args) {
45
+ if (args[0] === "info") {
46
+ const pkgName = args[1];
47
+ return require_process.exec(options, bin, [
48
+ "info",
49
+ pkgName,
50
+ ...args.slice(2).filter((a) => a !== "--registry").filter((a) => !a.startsWith("http"))
51
+ ]);
52
+ }
53
+ return require_process.exec(options, bin, args);
54
+ },
55
+ async prepareProject(packageName, version, registryUrl, port, token, dependencies = {}, devDependencies = {}) {
56
+ return require_project.prepareGenericEmptyProject(packageName, version, port, token, registryUrl, dependencies, devDependencies);
57
+ }
58
+ };
59
+ }
60
+ //#endregion
61
+ exports.createBunAdapter = createBunAdapter;
62
+
63
+ //# sourceMappingURL=bun.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun.cjs","names":[],"sources":["../../../src/adapters/bun.ts"],"sourcesContent":["import { SpawnOptions, execSync } from 'child_process';\nimport buildDebug from 'debug';\n\nimport { ExecOutput, PackageManagerAdapter } from '../types';\nimport { exec } from '../utils/process';\nimport { prepareGenericEmptyProject } from '../utils/project';\n\nconst debug = buildDebug('verdaccio:e2e-cli:bun');\n\nconst BUN_SUPPORTED_COMMANDS = new Set([\n 'publish',\n 'install',\n 'info',\n 'audit',\n]);\n\nfunction detectVersion(bin: string): string {\n try {\n return execSync(`${bin} --version`, { encoding: 'utf8', timeout: 5000 }).trim();\n } catch {\n return 'unknown';\n }\n}\n\nfunction resolveBunBin(binPath?: string): string {\n if (binPath) return binPath;\n return 'bun';\n}\n\nexport function createBunAdapter(binPath?: string, _version?: string): PackageManagerAdapter {\n const bin = resolveBunBin(binPath);\n const resolved = detectVersion(bin);\n debug('creating bun adapter with bin: %s (%s)', bin, resolved);\n\n const adapter: PackageManagerAdapter = {\n name: `bun@${resolved}`,\n type: 'bun',\n bin,\n supports: BUN_SUPPORTED_COMMANDS,\n\n registryArg(url: string): string[] {\n return ['--registry', url];\n },\n\n prefixArg(folder: string): string[] {\n return ['--cwd', folder];\n },\n\n exec(options: SpawnOptions, ...args: string[]): Promise<ExecOutput> {\n const cmd = args[0];\n\n if (cmd === 'info') {\n // bun info <pkg> reads registry from .npmrc, strip --registry <url>\n const pkgName = args[1];\n const filteredArgs = args.slice(2).filter((a) => a !== '--registry');\n // also remove the URL that follows --registry\n const cleaned = filteredArgs.filter((a) => !a.startsWith('http'));\n return exec(options, bin, ['info', pkgName, ...cleaned]);\n }\n\n return exec(options, bin, args);\n },\n\n async prepareProject(\n packageName: string,\n version: string,\n registryUrl: string,\n port: number,\n token: string,\n dependencies: Record<string, string> = {},\n devDependencies: Record<string, string> = {}\n ): Promise<{ tempFolder: string }> {\n return prepareGenericEmptyProject(\n packageName,\n version,\n port,\n token,\n registryUrl,\n dependencies,\n devDependencies\n );\n },\n };\n\n return adapter;\n}\n"],"mappings":";;;;;;;AAOA,IAAM,WAAA,GAAA,MAAA,SAAmB,wBAAwB;AAEjD,IAAM,yBAAyB,IAAI,IAAI;CACrC;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,cAAc,KAAqB;AAC1C,KAAI;AACF,UAAA,GAAA,cAAA,UAAgB,GAAG,IAAI,aAAa;GAAE,UAAU;GAAQ,SAAS;GAAM,CAAC,CAAC,MAAM;SACzE;AACN,SAAO;;;AAIX,SAAS,cAAc,SAA0B;AAC/C,KAAI,QAAS,QAAO;AACpB,QAAO;;AAGT,SAAgB,iBAAiB,SAAkB,UAA0C;CAC3F,MAAM,MAAM,cAAc,QAAQ;CAClC,MAAM,WAAW,cAAc,IAAI;AACnC,SAAM,0CAA0C,KAAK,SAAS;AAoD9D,QAlDuC;EACrC,MAAM,OAAO;EACb,MAAM;EACN;EACA,UAAU;EAEV,YAAY,KAAuB;AACjC,UAAO,CAAC,cAAc,IAAI;;EAG5B,UAAU,QAA0B;AAClC,UAAO,CAAC,SAAS,OAAO;;EAG1B,KAAK,SAAuB,GAAG,MAAqC;AAGlE,OAFY,KAAK,OAEL,QAAQ;IAElB,MAAM,UAAU,KAAK;AAIrB,WAAO,gBAAA,KAAK,SAAS,KAAK;KAAC;KAAQ;KAAS,GAHvB,KAAK,MAAM,EAAE,CAAC,QAAQ,MAAM,MAAM,aAAa,CAEvC,QAAQ,MAAM,CAAC,EAAE,WAAW,OAAO,CAAC;KACV,CAAC;;AAG1D,UAAO,gBAAA,KAAK,SAAS,KAAK,KAAK;;EAGjC,MAAM,eACJ,aACA,SACA,aACA,MACA,OACA,eAAuC,EAAE,EACzC,kBAA0C,EAAE,EACX;AACjC,UAAO,gBAAA,2BACL,aACA,SACA,MACA,OACA,aACA,cACA,gBACD;;EAEJ"}
@@ -0,0 +1,58 @@
1
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_process = require("../utils/process.cjs");
3
+ const require_project = require("../utils/project.cjs");
4
+ let debug = require("debug");
5
+ debug = require_runtime.__toESM(debug);
6
+ let child_process = require("child_process");
7
+ //#region src/adapters/deno.ts
8
+ var debug$1 = (0, debug.default)("verdaccio:e2e-cli:deno");
9
+ var DENO_SUPPORTED_COMMANDS = new Set(["install", "info"]);
10
+ function detectVersion(bin) {
11
+ try {
12
+ const match = (0, child_process.execSync)(`${bin} --version`, {
13
+ encoding: "utf8",
14
+ timeout: 5e3
15
+ }).match(/deno (\S+)/);
16
+ return match ? match[1] : "unknown";
17
+ } catch {
18
+ return "unknown";
19
+ }
20
+ }
21
+ function resolveDenoBin(binPath) {
22
+ if (binPath) return binPath;
23
+ return "deno";
24
+ }
25
+ function createDenoAdapter(binPath, _version) {
26
+ const bin = resolveDenoBin(binPath);
27
+ const resolved = detectVersion(bin);
28
+ debug$1("creating deno adapter with bin: %s (%s)", bin, resolved);
29
+ return {
30
+ name: `deno@${resolved}`,
31
+ type: "deno",
32
+ bin,
33
+ supports: DENO_SUPPORTED_COMMANDS,
34
+ registryArg(_url) {
35
+ return [];
36
+ },
37
+ prefixArg(folder) {
38
+ return ["--root", folder];
39
+ },
40
+ exec(options, ...args) {
41
+ const cmd = args[0];
42
+ if (cmd === "info") return require_process.exec(options, bin, [
43
+ "info",
44
+ `npm:${args[1]}`,
45
+ "--node-modules-dir=auto"
46
+ ].concat(args.slice(2).filter((a) => a !== "--json")));
47
+ if (cmd === "install") return require_process.exec(options, bin, ["install"]);
48
+ return require_process.exec(options, bin, args);
49
+ },
50
+ async prepareProject(packageName, version, registryUrl, port, token, dependencies = {}, devDependencies = {}) {
51
+ return require_project.prepareGenericEmptyProject(packageName, version, port, token, registryUrl, dependencies, devDependencies);
52
+ }
53
+ };
54
+ }
55
+ //#endregion
56
+ exports.createDenoAdapter = createDenoAdapter;
57
+
58
+ //# sourceMappingURL=deno.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deno.cjs","names":[],"sources":["../../../src/adapters/deno.ts"],"sourcesContent":["import { SpawnOptions, execSync } from 'child_process';\nimport buildDebug from 'debug';\n\nimport { ExecOutput, PackageManagerAdapter } from '../types';\nimport { exec } from '../utils/process';\nimport { prepareGenericEmptyProject } from '../utils/project';\n\nconst debug = buildDebug('verdaccio:e2e-cli:deno');\n\nconst DENO_SUPPORTED_COMMANDS = new Set(['install', 'info']);\n\nfunction detectVersion(bin: string): string {\n try {\n const output = execSync(`${bin} --version`, { encoding: 'utf8', timeout: 5000 });\n const match = output.match(/deno (\\S+)/);\n return match ? match[1] : 'unknown';\n } catch {\n return 'unknown';\n }\n}\n\nfunction resolveDenoBin(binPath?: string): string {\n if (binPath) return binPath;\n return 'deno';\n}\n\nexport function createDenoAdapter(binPath?: string, _version?: string): PackageManagerAdapter {\n const bin = resolveDenoBin(binPath);\n const resolved = detectVersion(bin);\n debug('creating deno adapter with bin: %s (%s)', bin, resolved);\n\n const adapter: PackageManagerAdapter = {\n name: `deno@${resolved}`,\n type: 'deno',\n bin,\n supports: DENO_SUPPORTED_COMMANDS,\n\n registryArg(_url: string): string[] {\n // deno reads the registry from .npmrc (written by prepareProject), no CLI flag needed\n return [];\n },\n\n prefixArg(folder: string): string[] {\n return ['--root', folder];\n },\n\n exec(options: SpawnOptions, ...args: string[]): Promise<ExecOutput> {\n const cmd = args[0];\n\n if (cmd === 'info') {\n // deno info npm:<pkg> --node-modules-dir=auto\n const pkgName = args[1];\n const filteredArgs = ['info', `npm:${pkgName}`, '--node-modules-dir=auto'].concat(\n args.slice(2).filter((a) => a !== '--json')\n );\n return exec(options, bin, filteredArgs);\n }\n\n if (cmd === 'install') {\n // deno install — reads registry from .npmrc, no extra flags needed\n return exec(options, bin, ['install']);\n }\n\n return exec(options, bin, args);\n },\n\n async prepareProject(\n packageName: string,\n version: string,\n registryUrl: string,\n port: number,\n token: string,\n dependencies: Record<string, string> = {},\n devDependencies: Record<string, string> = {}\n ): Promise<{ tempFolder: string }> {\n return prepareGenericEmptyProject(\n packageName,\n version,\n port,\n token,\n registryUrl,\n dependencies,\n devDependencies\n );\n },\n };\n\n return adapter;\n}\n"],"mappings":";;;;;;;AAOA,IAAM,WAAA,GAAA,MAAA,SAAmB,yBAAyB;AAElD,IAAM,0BAA0B,IAAI,IAAI,CAAC,WAAW,OAAO,CAAC;AAE5D,SAAS,cAAc,KAAqB;AAC1C,KAAI;EAEF,MAAM,SAAA,GAAA,cAAA,UADkB,GAAG,IAAI,aAAa;GAAE,UAAU;GAAQ,SAAS;GAAM,CAAC,CAC3D,MAAM,aAAa;AACxC,SAAO,QAAQ,MAAM,KAAK;SACpB;AACN,SAAO;;;AAIX,SAAS,eAAe,SAA0B;AAChD,KAAI,QAAS,QAAO;AACpB,QAAO;;AAGT,SAAgB,kBAAkB,SAAkB,UAA0C;CAC5F,MAAM,MAAM,eAAe,QAAQ;CACnC,MAAM,WAAW,cAAc,IAAI;AACnC,SAAM,2CAA2C,KAAK,SAAS;AA0D/D,QAxDuC;EACrC,MAAM,QAAQ;EACd,MAAM;EACN;EACA,UAAU;EAEV,YAAY,MAAwB;AAElC,UAAO,EAAE;;EAGX,UAAU,QAA0B;AAClC,UAAO,CAAC,UAAU,OAAO;;EAG3B,KAAK,SAAuB,GAAG,MAAqC;GAClE,MAAM,MAAM,KAAK;AAEjB,OAAI,QAAQ,OAMV,QAAO,gBAAA,KAAK,SAAS,KAHA;IAAC;IAAQ,OADd,KAAK;IAC2B;IAA0B,CAAC,OACzE,KAAK,MAAM,EAAE,CAAC,QAAQ,MAAM,MAAM,SAAS,CAC5C,CACsC;AAGzC,OAAI,QAAQ,UAEV,QAAO,gBAAA,KAAK,SAAS,KAAK,CAAC,UAAU,CAAC;AAGxC,UAAO,gBAAA,KAAK,SAAS,KAAK,KAAK;;EAGjC,MAAM,eACJ,aACA,SACA,aACA,MACA,OACA,eAAuC,EAAE,EACzC,kBAA0C,EAAE,EACX;AACjC,UAAO,gBAAA,2BACL,aACA,SACA,MACA,OACA,aACA,cACA,gBACD;;EAEJ"}
@@ -1,3 +1,5 @@
1
+ require("./bun.cjs");
2
+ require("./deno.cjs");
1
3
  require("./npm.cjs");
2
4
  require("./pnpm.cjs");
3
5
  require("./yarn-classic.cjs");
@@ -1,5 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
3
+ const require_bun = require("./adapters/bun.cjs");
4
+ const require_deno = require("./adapters/deno.cjs");
3
5
  const require_npm = require("./adapters/npm.cjs");
4
6
  const require_pnpm = require("./adapters/pnpm.cjs");
5
7
  const require_yarn_classic = require("./adapters/yarn-classic.cjs");
@@ -35,7 +37,9 @@ function parseAdapters(pmFilters) {
35
37
  else if (name === "pnpm") adapters.push(require_pnpm.createPnpmAdapter(binPath, version));
36
38
  else if (name === "yarn-classic" || name === "yarn1") adapters.push(require_yarn_classic.createYarnClassicAdapter(binPath, version));
37
39
  else if (name === "yarn-modern" || name === "yarn") adapters.push(require_yarn_modern.createYarnModernAdapter(binPath, version));
38
- else throw new Error(`Unknown package manager: "${name}". Supported: npm, pnpm, yarn-classic, yarn-modern[@version]`);
40
+ else if (name === "bun") adapters.push(require_bun.createBunAdapter(binPath, version));
41
+ else if (name === "deno") adapters.push(require_deno.createDenoAdapter(binPath, version));
42
+ else throw new Error(`Unknown package manager: "${name}". Supported: npm, pnpm, yarn-classic, yarn-modern, bun, deno`);
39
43
  }
40
44
  return adapters;
41
45
  }
@@ -85,11 +89,12 @@ function printHelp() {
85
89
 
86
90
  Options:
87
91
  --pm <name[@version]> Package manager to test (can be repeated)
88
- Supported: npm, pnpm, yarn-classic, yarn-modern (or yarn)
92
+ Supported: npm, pnpm, yarn-classic, yarn-modern (or yarn), bun, deno
89
93
  Examples: --pm npm@10 --pm pnpm@9
90
94
  --pm yarn-modern@4
91
95
  --pm yarn-modern@3
92
96
  --pm yarn-classic
97
+ --pm bun
93
98
  --pm npm --pm pnpm (uses system version)
94
99
  Auto-installs the requested yarn version if needed
95
100
  Default: npm
@@ -147,6 +152,8 @@ async function main(argv = process.argv) {
147
152
  //#endregion
148
153
  exports.allScenarios = require_index$1.allScenarios;
149
154
  exports.allTests = require_index$2.allTests;
155
+ exports.createBunAdapter = require_bun.createBunAdapter;
156
+ exports.createDenoAdapter = require_deno.createDenoAdapter;
150
157
  exports.createNpmAdapter = require_npm.createNpmAdapter;
151
158
  exports.createPnpmAdapter = require_pnpm.createPnpmAdapter;
152
159
  exports.createYarnClassicAdapter = require_yarn_classic.createYarnClassicAdapter;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport {\n createNpmAdapter,\n createPnpmAdapter,\n createYarnClassicAdapter,\n createYarnModernAdapter,\n} from './adapters';\nimport { allTests } from './tests';\nimport { CliOptions, PackageManagerAdapter } from './types';\nimport { createUser, pingRegistry } from './utils/registry-client';\nimport { runAll } from './runner';\n\nconst debug = buildDebug('verdaccio:e2e-cli');\n\nfunction parsePmSpec(filter: string): { name: string; version?: string; binPath?: string } {\n // --pm yarn-modern@3, --pm yarn-classic@1.22.22, --pm npm=/path/to/bin\n const eqIdx = filter.indexOf('=');\n if (eqIdx !== -1) {\n return { name: filter.slice(0, eqIdx).toLowerCase(), binPath: filter.slice(eqIdx + 1) };\n }\n const atIdx = filter.indexOf('@');\n if (atIdx !== -1) {\n return { name: filter.slice(0, atIdx).toLowerCase(), version: filter.slice(atIdx + 1) };\n }\n return { name: filter.toLowerCase() };\n}\n\nfunction parseAdapters(pmFilters?: string[]): PackageManagerAdapter[] {\n if (!pmFilters || pmFilters.length === 0) {\n return [createNpmAdapter()];\n }\n\n const adapters: PackageManagerAdapter[] = [];\n\n for (const filter of pmFilters) {\n const { name, version, binPath } = parsePmSpec(filter);\n\n if (name === 'npm') {\n adapters.push(createNpmAdapter(binPath, version));\n } else if (name === 'pnpm') {\n adapters.push(createPnpmAdapter(binPath, version));\n } else if (name === 'yarn-classic' || name === 'yarn1') {\n adapters.push(createYarnClassicAdapter(binPath, version));\n } else if (name === 'yarn-modern' || name === 'yarn') {\n adapters.push(createYarnModernAdapter(binPath, version));\n } else {\n throw new Error(\n `Unknown package manager: \"${name}\". Supported: npm, pnpm, yarn-classic, yarn-modern[@version]`\n );\n }\n }\n\n return adapters;\n}\n\nfunction parseArgs(argv: string[]): CliOptions {\n const options: CliOptions = {\n registry: '',\n pm: [],\n test: [],\n concurrency: 1,\n timeout: 50000,\n verbose: false,\n };\n\n for (let i = 2; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg === '--registry' || arg === '-r') {\n options.registry = argv[++i];\n } else if (arg === '--pm') {\n options.pm!.push(argv[++i]);\n } else if (arg === '--test' || arg === '-t') {\n options.test!.push(argv[++i]);\n } else if (arg === '--concurrency' || arg === '-c') {\n options.concurrency = parseInt(argv[++i], 10);\n } else if (arg === '--timeout') {\n options.timeout = parseInt(argv[++i], 10);\n } else if (arg === '--token') {\n options.token = argv[++i];\n } else if (arg === '--verbose' || arg === '-v') {\n options.verbose = true;\n } else if (arg === '--help' || arg === '-h') {\n printHelp();\n process.exit(0);\n } else if (arg.startsWith('--registry=')) {\n options.registry = arg.split('=')[1];\n } else if (arg.startsWith('--pm=')) {\n options.pm!.push(arg.split('=')[1]);\n } else if (arg.startsWith('--test=')) {\n options.test!.push(arg.split('=')[1]);\n } else if (arg.startsWith('--token=')) {\n options.token = arg.split('=')[1];\n } else if (arg.startsWith('--timeout=')) {\n options.timeout = parseInt(arg.split('=')[1], 10);\n } else {\n console.error(`Unknown argument: ${arg}`);\n printHelp();\n process.exit(1);\n }\n }\n\n return options;\n}\n\nfunction printHelp(): void {\n console.log(`\n @verdaccio/e2e-cli - Run Verdaccio e2e tests against any running registry\n\n Usage:\n verdaccio-e2e --registry <url> [options]\n\n Required:\n -r, --registry <url> Verdaccio registry URL (e.g. http://localhost:4873)\n\n Options:\n --pm <name[@version]> Package manager to test (can be repeated)\n Supported: npm, pnpm, yarn-classic, yarn-modern (or yarn)\n Examples: --pm npm@10 --pm pnpm@9\n --pm yarn-modern@4\n --pm yarn-modern@3\n --pm yarn-classic\n --pm npm --pm pnpm (uses system version)\n Auto-installs the requested yarn version if needed\n Default: npm\n\n -t, --test <name> Filter tests by name (can be repeated)\n Available: publish, install, ci, audit, info, deprecate,\n dist-tags, ping, search, star, unpublish\n Scenarios: scenario:install-multiple-deps\n Default: all supported by the PM\n\n --token <token> Auth token (skips user creation)\n --timeout <ms> Per-test timeout (default: 50000)\n -v, --verbose Enable debug output\n -h, --help Show this help\n `);\n}\n\nexport async function main(argv: string[] = process.argv): Promise<void> {\n const options = parseArgs(argv);\n\n if (!options.registry) {\n console.error('Error: --registry is required\\n');\n printHelp();\n process.exit(1);\n }\n\n // Run from a temp dir to isolate from the host project's packageManager, .yarnrc.yml, etc.\n const { createTempFolder } = await import('./utils/project');\n const runDir = await createTempFolder('e2e-run');\n process.chdir(runDir);\n\n if (options.verbose) {\n const { setVerbose } = await import('./utils/process');\n setVerbose(true);\n }\n\n // Ensure registry is reachable\n console.log(`Checking registry at ${options.registry}...`);\n const alive = await pingRegistry(options.registry);\n if (!alive) {\n console.error(`Error: Registry at ${options.registry} is not reachable`);\n process.exit(1);\n }\n console.log(`Registry is alive.`);\n\n // Get auth token\n let token = options.token;\n if (!token) {\n console.log('Creating test user...');\n const auth = await createUser(options.registry);\n token = auth.token;\n console.log(`User \"${auth.user}\" created.`);\n }\n\n // Build adapter list\n const adapters = parseAdapters(options.pm);\n console.log(`Adapters: ${adapters.map((a) => a.name).join(', ')}`);\n\n // Filter tests\n const tests = options.test && options.test.length > 0\n ? allTests.filter((t) => options.test!.includes(t.name))\n : allTests;\n\n console.log(`Tests: ${tests.map((t) => t.name).join(', ')}`);\n\n // Run\n const { exitCode } = await runAll(adapters, tests, options.registry, token, {\n timeout: options.timeout,\n concurrency: options.concurrency,\n testFilter: options.test,\n });\n\n process.exit(exitCode);\n}\n\n// Re-export for programmatic usage\nexport { allTests } from './tests';\nexport { allScenarios } from './scenarios';\nexport { createNpmAdapter, createPnpmAdapter, createYarnClassicAdapter, createYarnModernAdapter } from './adapters';\nexport { runAll, runSuite } from './runner';\nexport type { PackageManagerAdapter, TestDefinition, TestContext, CliOptions } from './types';\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport {\n createBunAdapter,\n createDenoAdapter,\n createNpmAdapter,\n createPnpmAdapter,\n createYarnClassicAdapter,\n createYarnModernAdapter,\n} from './adapters';\nimport { allTests } from './tests';\nimport { CliOptions, PackageManagerAdapter } from './types';\nimport { createUser, pingRegistry } from './utils/registry-client';\nimport { runAll } from './runner';\n\nconst debug = buildDebug('verdaccio:e2e-cli');\n\nfunction parsePmSpec(filter: string): { name: string; version?: string; binPath?: string } {\n // --pm yarn-modern@3, --pm yarn-classic@1.22.22, --pm npm=/path/to/bin\n const eqIdx = filter.indexOf('=');\n if (eqIdx !== -1) {\n return { name: filter.slice(0, eqIdx).toLowerCase(), binPath: filter.slice(eqIdx + 1) };\n }\n const atIdx = filter.indexOf('@');\n if (atIdx !== -1) {\n return { name: filter.slice(0, atIdx).toLowerCase(), version: filter.slice(atIdx + 1) };\n }\n return { name: filter.toLowerCase() };\n}\n\nfunction parseAdapters(pmFilters?: string[]): PackageManagerAdapter[] {\n if (!pmFilters || pmFilters.length === 0) {\n return [createNpmAdapter()];\n }\n\n const adapters: PackageManagerAdapter[] = [];\n\n for (const filter of pmFilters) {\n const { name, version, binPath } = parsePmSpec(filter);\n\n if (name === 'npm') {\n adapters.push(createNpmAdapter(binPath, version));\n } else if (name === 'pnpm') {\n adapters.push(createPnpmAdapter(binPath, version));\n } else if (name === 'yarn-classic' || name === 'yarn1') {\n adapters.push(createYarnClassicAdapter(binPath, version));\n } else if (name === 'yarn-modern' || name === 'yarn') {\n adapters.push(createYarnModernAdapter(binPath, version));\n } else if (name === 'bun') {\n adapters.push(createBunAdapter(binPath, version));\n } else if (name === 'deno') {\n adapters.push(createDenoAdapter(binPath, version));\n } else {\n throw new Error(\n `Unknown package manager: \"${name}\". Supported: npm, pnpm, yarn-classic, yarn-modern, bun, deno`\n );\n }\n }\n\n return adapters;\n}\n\nfunction parseArgs(argv: string[]): CliOptions {\n const options: CliOptions = {\n registry: '',\n pm: [],\n test: [],\n concurrency: 1,\n timeout: 50000,\n verbose: false,\n };\n\n for (let i = 2; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg === '--registry' || arg === '-r') {\n options.registry = argv[++i];\n } else if (arg === '--pm') {\n options.pm!.push(argv[++i]);\n } else if (arg === '--test' || arg === '-t') {\n options.test!.push(argv[++i]);\n } else if (arg === '--concurrency' || arg === '-c') {\n options.concurrency = parseInt(argv[++i], 10);\n } else if (arg === '--timeout') {\n options.timeout = parseInt(argv[++i], 10);\n } else if (arg === '--token') {\n options.token = argv[++i];\n } else if (arg === '--verbose' || arg === '-v') {\n options.verbose = true;\n } else if (arg === '--help' || arg === '-h') {\n printHelp();\n process.exit(0);\n } else if (arg.startsWith('--registry=')) {\n options.registry = arg.split('=')[1];\n } else if (arg.startsWith('--pm=')) {\n options.pm!.push(arg.split('=')[1]);\n } else if (arg.startsWith('--test=')) {\n options.test!.push(arg.split('=')[1]);\n } else if (arg.startsWith('--token=')) {\n options.token = arg.split('=')[1];\n } else if (arg.startsWith('--timeout=')) {\n options.timeout = parseInt(arg.split('=')[1], 10);\n } else {\n console.error(`Unknown argument: ${arg}`);\n printHelp();\n process.exit(1);\n }\n }\n\n return options;\n}\n\nfunction printHelp(): void {\n console.log(`\n @verdaccio/e2e-cli - Run Verdaccio e2e tests against any running registry\n\n Usage:\n verdaccio-e2e --registry <url> [options]\n\n Required:\n -r, --registry <url> Verdaccio registry URL (e.g. http://localhost:4873)\n\n Options:\n --pm <name[@version]> Package manager to test (can be repeated)\n Supported: npm, pnpm, yarn-classic, yarn-modern (or yarn), bun, deno\n Examples: --pm npm@10 --pm pnpm@9\n --pm yarn-modern@4\n --pm yarn-modern@3\n --pm yarn-classic\n --pm bun\n --pm npm --pm pnpm (uses system version)\n Auto-installs the requested yarn version if needed\n Default: npm\n\n -t, --test <name> Filter tests by name (can be repeated)\n Available: publish, install, ci, audit, info, deprecate,\n dist-tags, ping, search, star, unpublish\n Scenarios: scenario:install-multiple-deps\n Default: all supported by the PM\n\n --token <token> Auth token (skips user creation)\n --timeout <ms> Per-test timeout (default: 50000)\n -v, --verbose Enable debug output\n -h, --help Show this help\n `);\n}\n\nexport async function main(argv: string[] = process.argv): Promise<void> {\n const options = parseArgs(argv);\n\n if (!options.registry) {\n console.error('Error: --registry is required\\n');\n printHelp();\n process.exit(1);\n }\n\n // Run from a temp dir to isolate from the host project's packageManager, .yarnrc.yml, etc.\n const { createTempFolder } = await import('./utils/project');\n const runDir = await createTempFolder('e2e-run');\n process.chdir(runDir);\n\n if (options.verbose) {\n const { setVerbose } = await import('./utils/process');\n setVerbose(true);\n }\n\n // Ensure registry is reachable\n console.log(`Checking registry at ${options.registry}...`);\n const alive = await pingRegistry(options.registry);\n if (!alive) {\n console.error(`Error: Registry at ${options.registry} is not reachable`);\n process.exit(1);\n }\n console.log(`Registry is alive.`);\n\n // Get auth token\n let token = options.token;\n if (!token) {\n console.log('Creating test user...');\n const auth = await createUser(options.registry);\n token = auth.token;\n console.log(`User \"${auth.user}\" created.`);\n }\n\n // Build adapter list\n const adapters = parseAdapters(options.pm);\n console.log(`Adapters: ${adapters.map((a) => a.name).join(', ')}`);\n\n // Filter tests\n const tests = options.test && options.test.length > 0\n ? allTests.filter((t) => options.test!.includes(t.name))\n : allTests;\n\n console.log(`Tests: ${tests.map((t) => t.name).join(', ')}`);\n\n // Run\n const { exitCode } = await runAll(adapters, tests, options.registry, token, {\n timeout: options.timeout,\n concurrency: options.concurrency,\n testFilter: options.test,\n });\n\n process.exit(exitCode);\n}\n\n// Re-export for programmatic usage\nexport { allTests } from './tests';\nexport { allScenarios } from './scenarios';\nexport { createBunAdapter, createDenoAdapter, createNpmAdapter, createPnpmAdapter, createYarnClassicAdapter, createYarnModernAdapter } from './adapters';\nexport { runAll, runSuite } from './runner';\nexport type { PackageManagerAdapter, TestDefinition, TestContext, CliOptions } from './types';\n"],"mappings":"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"}
@@ -6,8 +6,8 @@ assert = require_runtime.__toESM(assert);
6
6
  //#region src/tests/audit.ts
7
7
  var debug$1 = (0, debug.default)("verdaccio:e2e-cli:test:audit");
8
8
  async function testAudit(ctx) {
9
- if (ctx.adapter.type !== "npm") {
10
- debug$1("skipping audit test for %s (npm only)", ctx.adapter.type);
9
+ if (ctx.adapter.type !== "npm" && ctx.adapter.type !== "bun") {
10
+ debug$1("skipping audit test for %s (npm/bun only)", ctx.adapter.type);
11
11
  return;
12
12
  }
13
13
  const packages = [`verdaccio-audit-${ctx.runId}`, `@verdaccio/audit-${ctx.runId}`];
@@ -28,9 +28,12 @@ async function testAudit(ctx) {
28
28
  return;
29
29
  }
30
30
  const resp = await ctx.adapter.exec({ cwd: tempFolder }, "audit", "--json", ...ctx.adapter.registryArg(ctx.registryUrl));
31
- const parsedBody = JSON.parse(resp.stdout);
32
- assert.default.ok(parsedBody.auditReportVersion !== void 0, "Expected \"auditReportVersion\" in audit response");
33
- assert.default.ok(parsedBody.vulnerabilities !== void 0, "Expected \"vulnerabilities\" in audit response");
31
+ if (ctx.adapter.type === "bun") assert.default.ok(resp.stdout.length > 0 || resp.stderr.length > 0, "Expected audit output");
32
+ else {
33
+ const parsedBody = JSON.parse(resp.stdout);
34
+ assert.default.ok(parsedBody.auditReportVersion !== void 0, "Expected \"auditReportVersion\" in audit response");
35
+ assert.default.ok(parsedBody.vulnerabilities !== void 0, "Expected \"vulnerabilities\" in audit response");
36
+ }
34
37
  }
35
38
  }
36
39
  var auditTest = {
@@ -1 +1 @@
1
- {"version":3,"file":"audit.cjs","names":[],"sources":["../../../src/tests/audit.ts"],"sourcesContent":["import assert from 'assert';\nimport buildDebug from 'debug';\n\nimport { TestContext, TestDefinition } from '../types';\n\nconst debug = buildDebug('verdaccio:e2e-cli:test:audit');\n\nasync function testAudit(ctx: TestContext): Promise<void> {\n // Audit is only reliable with npm — pnpm/yarn audit output varies too much\n if (ctx.adapter.type !== 'npm') {\n debug('skipping audit test for %s (npm only)', ctx.adapter.type);\n return;\n }\n\n const packages = [`verdaccio-audit-${ctx.runId}`, `@verdaccio/audit-${ctx.runId}`];\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 { jquery: '3.6.1' }\n );\n\n // install is required to create package lock file\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'install',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n // npm audit exits with code 1 both when vulnerabilities are found AND when\n // the endpoint is unavailable. We need to distinguish between the two.\n // Probe the audit endpoint first to avoid false failures on registries\n // that don't support it (e.g. verdaccio next-7+).\n try {\n const probe = await fetch(`${ctx.registryUrl}/-/npm/v1/security/audits/quick`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: '{}',\n });\n if (probe.status === 404) {\n debug('audit endpoint not supported by this registry (404), skipping');\n return;\n }\n } catch {\n debug('audit endpoint probe failed, skipping');\n return;\n }\n\n const resp = await ctx.adapter.exec(\n { cwd: tempFolder },\n 'audit',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n const parsedBody = JSON.parse(resp.stdout);\n assert.ok(parsedBody.auditReportVersion !== undefined, 'Expected \"auditReportVersion\" in audit response');\n assert.ok(parsedBody.vulnerabilities !== undefined, 'Expected \"vulnerabilities\" in audit response');\n }\n}\n\nexport const auditTest: TestDefinition = {\n name: 'audit',\n requires: ['audit'],\n run: testAudit,\n};\n"],"mappings":";;;;;;AAKA,IAAM,WAAA,GAAA,MAAA,SAAmB,+BAA+B;AAExD,eAAe,UAAU,KAAiC;AAExD,KAAI,IAAI,QAAQ,SAAS,OAAO;AAC9B,UAAM,yCAAyC,IAAI,QAAQ,KAAK;AAChE;;CAGF,MAAM,WAAW,CAAC,mBAAmB,IAAI,SAAS,oBAAoB,IAAI,QAAQ;AAElF,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,SACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,OACJ,EAAE,QAAQ,SAAS,CACpB;AAGD,QAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,YAAY,EACnB,WACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAMD,MAAI;AAMF,QALc,MAAM,MAAM,GAAG,IAAI,YAAY,kCAAkC;IAC7E,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,MAAM;IACP,CAAC,EACQ,WAAW,KAAK;AACxB,YAAM,gEAAgE;AACtE;;UAEI;AACN,WAAM,wCAAwC;AAC9C;;EAGF,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,SACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;EAED,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,SAAA,QAAO,GAAG,WAAW,uBAAuB,KAAA,GAAW,oDAAkD;AACzG,SAAA,QAAO,GAAG,WAAW,oBAAoB,KAAA,GAAW,iDAA+C;;;AAIvG,IAAa,YAA4B;CACvC,MAAM;CACN,UAAU,CAAC,QAAQ;CACnB,KAAK;CACN"}
1
+ {"version":3,"file":"audit.cjs","names":[],"sources":["../../../src/tests/audit.ts"],"sourcesContent":["import assert from 'assert';\nimport buildDebug from 'debug';\n\nimport { TestContext, TestDefinition } from '../types';\n\nconst debug = buildDebug('verdaccio:e2e-cli:test:audit');\n\nasync function testAudit(ctx: TestContext): Promise<void> {\n // Audit is only reliable with npm and bun — pnpm/yarn audit output varies too much\n if (ctx.adapter.type !== 'npm' && ctx.adapter.type !== 'bun') {\n debug('skipping audit test for %s (npm/bun only)', ctx.adapter.type);\n return;\n }\n\n const packages = [`verdaccio-audit-${ctx.runId}`, `@verdaccio/audit-${ctx.runId}`];\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 { jquery: '3.6.1' }\n );\n\n // install is required to create package lock file\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'install',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n // npm audit exits with code 1 both when vulnerabilities are found AND when\n // the endpoint is unavailable. We need to distinguish between the two.\n // Probe the audit endpoint first to avoid false failures on registries\n // that don't support it (e.g. verdaccio next-7+).\n try {\n const probe = await fetch(`${ctx.registryUrl}/-/npm/v1/security/audits/quick`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: '{}',\n });\n if (probe.status === 404) {\n debug('audit endpoint not supported by this registry (404), skipping');\n return;\n }\n } catch {\n debug('audit endpoint probe failed, skipping');\n return;\n }\n\n const resp = await ctx.adapter.exec(\n { cwd: tempFolder },\n 'audit',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n if (ctx.adapter.type === 'bun') {\n // bun audit output may differ — exit code 0 is sufficient for basic validation\n assert.ok(resp.stdout.length > 0 || resp.stderr.length > 0, 'Expected audit output');\n } else {\n const parsedBody = JSON.parse(resp.stdout);\n assert.ok(parsedBody.auditReportVersion !== undefined, 'Expected \"auditReportVersion\" in audit response');\n assert.ok(parsedBody.vulnerabilities !== undefined, 'Expected \"vulnerabilities\" in audit response');\n }\n }\n}\n\nexport const auditTest: TestDefinition = {\n name: 'audit',\n requires: ['audit'],\n run: testAudit,\n};\n"],"mappings":";;;;;;AAKA,IAAM,WAAA,GAAA,MAAA,SAAmB,+BAA+B;AAExD,eAAe,UAAU,KAAiC;AAExD,KAAI,IAAI,QAAQ,SAAS,SAAS,IAAI,QAAQ,SAAS,OAAO;AAC5D,UAAM,6CAA6C,IAAI,QAAQ,KAAK;AACpE;;CAGF,MAAM,WAAW,CAAC,mBAAmB,IAAI,SAAS,oBAAoB,IAAI,QAAQ;AAElF,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,SACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,OACJ,EAAE,QAAQ,SAAS,CACpB;AAGD,QAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,YAAY,EACnB,WACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAMD,MAAI;AAMF,QALc,MAAM,MAAM,GAAG,IAAI,YAAY,kCAAkC;IAC7E,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,MAAM;IACP,CAAC,EACQ,WAAW,KAAK;AACxB,YAAM,gEAAgE;AACtE;;UAEI;AACN,WAAM,wCAAwC;AAC9C;;EAGF,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,SACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,MAAI,IAAI,QAAQ,SAAS,MAEvB,QAAA,QAAO,GAAG,KAAK,OAAO,SAAS,KAAK,KAAK,OAAO,SAAS,GAAG,wBAAwB;OAC/E;GACL,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,UAAA,QAAO,GAAG,WAAW,uBAAuB,KAAA,GAAW,oDAAkD;AACzG,UAAA,QAAO,GAAG,WAAW,oBAAoB,KAAA,GAAW,iDAA+C;;;;AAKzG,IAAa,YAA4B;CACvC,MAAM;CACN,UAAU,CAAC,QAAQ;CACnB,KAAK;CACN"}
@@ -35,10 +35,19 @@ function getCiArgs(ctx) {
35
35
  ...ctx.adapter.registryArg(ctx.registryUrl)
36
36
  ];
37
37
  case "yarn-modern": return ["install", "--immutable"];
38
+ case "bun": return [
39
+ "install",
40
+ "--frozen-lockfile",
41
+ ...ctx.adapter.registryArg(ctx.registryUrl)
42
+ ];
38
43
  default: return ["ci", ...ctx.adapter.registryArg(ctx.registryUrl)];
39
44
  }
40
45
  }
41
46
  async function testCi(ctx) {
47
+ if (ctx.adapter.type === "deno") {
48
+ debug$1("skipping ci test for deno (no ci command)");
49
+ return;
50
+ }
42
51
  const { tempFolder } = await ctx.adapter.prepareProject(`ci-test-${ctx.runId}`, "1.0.0", ctx.registryUrl, ctx.port, ctx.token, { "is-odd": "1.0.0" });
43
52
  debug$1("running initial install to generate lockfile in %s", tempFolder);
44
53
  await ctx.adapter.exec({ cwd: tempFolder }, "install", ...ctx.adapter.registryArg(ctx.registryUrl));
@@ -1 +1 @@
1
- {"version":3,"file":"ci.cjs","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';\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-classic':\n // `yarn install --frozen-lockfile`\n return ['install', '--frozen-lockfile', ...ctx.adapter.registryArg(ctx.registryUrl)];\n case 'yarn-modern':\n // `yarn install --immutable`\n return ['install', '--immutable'];\n default:\n return ['ci', ...ctx.adapter.registryArg(ctx.registryUrl)];\n }\n}\n\nasync function testCi(ctx: TestContext): Promise<void> {\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 { 'is-odd': '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":";;;;;;;;AAOA,IAAM,WAAA,GAAA,MAAA,SAAmB,4BAA4B;;;;;;;;;;;;;;;AAiBrD,SAAS,UAAU,KAA4B;AAC7C,SAAQ,IAAI,QAAQ,MAApB;EACE,KAAK,MAEH,QAAO,CAAC,MAAM,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAAC;EAC5D,KAAK,OAEH,QAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY;GAAC;EACtF,KAAK,eAEH,QAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY;GAAC;EACtF,KAAK,cAEH,QAAO,CAAC,WAAW,cAAc;EACnC,QACE,QAAO,CAAC,MAAM,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAAC;;;AAIhE,eAAe,OAAO,KAAiC;CACrD,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,WAAW,IAAI,SACf,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,OACJ,EAAE,UAAU,SAAS,CACtB;AAED,SAAM,sDAAsD,WAAW;AAGvE,OAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,YAAY,EACnB,WACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,SAAM,4CAA4C;AAIlD,QAAA,GAAA,YAAA,KAAA,GAAA,KAAA,MAD6B,YAAY,eAAe,EAC9B;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAI3D,QAAA,GAAA,YAAA,KAAA,GAAA,KAAA,MAD2B,YAAY,cAAc,EAC7B;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAEzD,SAAM,2CAA2C;CAGjD,MAAM,SAAS,UAAU,IAAI;AAC7B,SAAM,eAAe,OAAO;CAC5B,MAAM,OAAO,MAAM,IAAI,QAAQ,KAAK,EAAE,KAAK,YAAY,EAAE,GAAG,OAAO;AAGnE,KAAI,IAAI,QAAQ,SAAS,OAAO;AAI9B,UAAM,qBADS,KAAK,SAAS,KAAK,OACA;AAClC,SAAA,QAAO,GAAG,MAAM,gCAAgC;QAC3C;AACL,UAAM,oCAAoC,IAAI,QAAQ,KAAK;AAC3D,SAAA,QAAO,GAAG,MAAM,yCAAyC,IAAI,QAAQ,OAAO;;;AAIhF,IAAa,SAAyB;CACpC,MAAM;CACN,UAAU,CAAC,UAAU;CACrB,KAAK;CACN"}
1
+ {"version":3,"file":"ci.cjs","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';\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-classic':\n // `yarn install --frozen-lockfile`\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 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 { 'is-odd': '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":";;;;;;;;AAOA,IAAM,WAAA,GAAA,MAAA,SAAmB,4BAA4B;;;;;;;;;;;;;;;AAiBrD,SAAS,UAAU,KAA4B;AAC7C,SAAQ,IAAI,QAAQ,MAApB;EACE,KAAK,MAEH,QAAO,CAAC,MAAM,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAAC;EAC5D,KAAK,OAEH,QAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY;GAAC;EACtF,KAAK,eAEH,QAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY;GAAC;EACtF,KAAK,cAEH,QAAO,CAAC,WAAW,cAAc;EACnC,KAAK,MAEH,QAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY;GAAC;EACtF,QACE,QAAO,CAAC,MAAM,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAAC;;;AAIhE,eAAe,OAAO,KAAiC;AAErD,KAAI,IAAI,QAAQ,SAAS,QAAQ;AAC/B,UAAM,4CAA4C;AAClD;;CAGF,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,WAAW,IAAI,SACf,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,OACJ,EAAE,UAAU,SAAS,CACtB;AAED,SAAM,sDAAsD,WAAW;AAGvE,OAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,YAAY,EACnB,WACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,SAAM,4CAA4C;AAIlD,QAAA,GAAA,YAAA,KAAA,GAAA,KAAA,MAD6B,YAAY,eAAe,EAC9B;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAI3D,QAAA,GAAA,YAAA,KAAA,GAAA,KAAA,MAD2B,YAAY,cAAc,EAC7B;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAEzD,SAAM,2CAA2C;CAGjD,MAAM,SAAS,UAAU,IAAI;AAC7B,SAAM,eAAe,OAAO;CAC5B,MAAM,OAAO,MAAM,IAAI,QAAQ,KAAK,EAAE,KAAK,YAAY,EAAE,GAAG,OAAO;AAGnE,KAAI,IAAI,QAAQ,SAAS,OAAO;AAI9B,UAAM,qBADS,KAAK,SAAS,KAAK,OACA;AAClC,SAAA,QAAO,GAAG,MAAM,gCAAgC;QAC3C;AACL,UAAM,oCAAoC,IAAI,QAAQ,KAAK;AAC3D,SAAA,QAAO,GAAG,MAAM,yCAAyC,IAAI,QAAQ,OAAO;;;AAIhF,IAAa,SAAyB;CACpC,MAAM;CACN,UAAU,CAAC,UAAU;CACrB,KAAK;CACN"}
@@ -21,6 +21,9 @@ async function testInfo(ctx) {
21
21
  }
22
22
  });
23
23
  assert.default.ok(dataLine, "Expected yarn info NDJSON to contain an \"inspect\" entry");
24
+ } else if (ctx.adapter.type === "deno") {
25
+ const output = resp.stdout + resp.stderr;
26
+ assert.default.ok(output.includes("verdaccio"), "Expected deno info output to reference verdaccio");
24
27
  } else {
25
28
  const parsedBody = JSON.parse(resp.stdout);
26
29
  assert.default.strictEqual(parsedBody.name, "verdaccio", "Expected package name \"verdaccio\"");
@@ -1 +1 @@
1
- {"version":3,"file":"info.cjs","names":[],"sources":["../../../src/tests/info.ts"],"sourcesContent":["import assert from 'assert';\n\nimport { TestContext, TestDefinition } from '../types';\nimport { createTempFolder } from '../utils/project';\nimport { writeFile } from 'fs/promises';\nimport { join } from 'path';\n\nasync function testInfo(ctx: TestContext): Promise<void> {\n // Create a minimal temp project so yarn modern has a project context\n // and yarn classic doesn't pick up the repo's packageManager field\n const tempFolder = await createTempFolder('info-test');\n await writeFile(join(tempFolder, 'package.json'), JSON.stringify({ name: 'info-test', version: '1.0.0' }));\n\n const resp = await ctx.adapter.exec(\n { cwd: tempFolder },\n 'info',\n 'verdaccio',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n if (ctx.adapter.type === 'yarn-classic') {\n const lines = resp.stdout.split('\\n').filter(Boolean);\n const dataLine = lines.find((l) => {\n try {\n const obj = JSON.parse(l);\n return obj.type === 'inspect';\n } catch {\n return false;\n }\n });\n assert.ok(dataLine, 'Expected yarn info NDJSON to contain an \"inspect\" entry');\n } else {\n const parsedBody = JSON.parse(resp.stdout);\n assert.strictEqual(parsedBody.name, 'verdaccio', 'Expected package name \"verdaccio\"');\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":";;;;;;;AAOA,eAAe,SAAS,KAAiC;CAGvD,MAAM,aAAa,MAAM,gBAAA,iBAAiB,YAAY;AACtD,QAAA,GAAA,YAAA,YAAA,GAAA,KAAA,MAAqB,YAAY,eAAe,EAAE,KAAK,UAAU;EAAE,MAAM;EAAa,SAAS;EAAS,CAAC,CAAC;CAE1G,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,QACA,aACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,KAAI,IAAI,QAAQ,SAAS,gBAAgB;EAEvC,MAAM,WADQ,KAAK,OAAO,MAAM,KAAK,CAAC,OAAO,QAAQ,CAC9B,MAAM,MAAM;AACjC,OAAI;AAEF,WADY,KAAK,MAAM,EAAE,CACd,SAAS;WACd;AACN,WAAO;;IAET;AACF,SAAA,QAAO,GAAG,UAAU,4DAA0D;QACzE;EACL,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,SAAA,QAAO,YAAY,WAAW,MAAM,aAAa,sCAAoC;AACrF,SAAA,QAAO,GAAG,WAAW,iBAAiB,KAAA,GAAW,0CAAwC;;;AAI7F,IAAa,WAA2B;CACtC,MAAM;CACN,UAAU,CAAC,OAAO;CAClB,KAAK;CACN"}
1
+ {"version":3,"file":"info.cjs","names":[],"sources":["../../../src/tests/info.ts"],"sourcesContent":["import assert from 'assert';\n\nimport { TestContext, TestDefinition } from '../types';\nimport { createTempFolder } from '../utils/project';\nimport { writeFile } from 'fs/promises';\nimport { join } from 'path';\n\nasync function testInfo(ctx: TestContext): Promise<void> {\n // Create a minimal temp project so yarn modern has a project context\n // and yarn classic doesn't pick up the repo's packageManager field\n const tempFolder = await createTempFolder('info-test');\n await writeFile(join(tempFolder, 'package.json'), JSON.stringify({ name: 'info-test', version: '1.0.0' }));\n\n const resp = await ctx.adapter.exec(\n { cwd: tempFolder },\n 'info',\n 'verdaccio',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n if (ctx.adapter.type === 'yarn-classic') {\n const lines = resp.stdout.split('\\n').filter(Boolean);\n const dataLine = lines.find((l) => {\n try {\n const obj = JSON.parse(l);\n return obj.type === 'inspect';\n } catch {\n return false;\n }\n });\n assert.ok(dataLine, 'Expected yarn info NDJSON to contain an \"inspect\" entry');\n } else 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('verdaccio'), 'Expected deno info output to reference verdaccio');\n } else {\n const parsedBody = JSON.parse(resp.stdout);\n assert.strictEqual(parsedBody.name, 'verdaccio', 'Expected package name \"verdaccio\"');\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":";;;;;;;AAOA,eAAe,SAAS,KAAiC;CAGvD,MAAM,aAAa,MAAM,gBAAA,iBAAiB,YAAY;AACtD,QAAA,GAAA,YAAA,YAAA,GAAA,KAAA,MAAqB,YAAY,eAAe,EAAE,KAAK,UAAU;EAAE,MAAM;EAAa,SAAS;EAAS,CAAC,CAAC;CAE1G,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,QACA,aACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,KAAI,IAAI,QAAQ,SAAS,gBAAgB;EAEvC,MAAM,WADQ,KAAK,OAAO,MAAM,KAAK,CAAC,OAAO,QAAQ,CAC9B,MAAM,MAAM;AACjC,OAAI;AAEF,WADY,KAAK,MAAM,EAAE,CACd,SAAS;WACd;AACN,WAAO;;IAET;AACF,SAAA,QAAO,GAAG,UAAU,4DAA0D;YACrE,IAAI,QAAQ,SAAS,QAAQ;EAEtC,MAAM,SAAS,KAAK,SAAS,KAAK;AAClC,SAAA,QAAO,GAAG,OAAO,SAAS,YAAY,EAAE,mDAAmD;QACtF;EACL,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,SAAA,QAAO,YAAY,WAAW,MAAM,aAAa,sCAAoC;AACrF,SAAA,QAAO,GAAG,WAAW,iBAAiB,KAAA,GAAW,0CAAwC;;;AAI7F,IAAa,WAA2B;CACtC,MAAM;CACN,UAAU,CAAC,OAAO;CAClB,KAAK;CACN"}
@@ -16,6 +16,7 @@ async function testPublish(ctx) {
16
16
  const resp = await ctx.adapter.exec({ cwd: tempFolder }, "publish", "--json", ...ctx.adapter.registryArg(ctx.registryUrl));
17
17
  if (type === "yarn-modern") assert.default.ok(resp.stdout.match(/Package archive published/), `Expected "Package archive published" for ${pkgName} but got "${resp.stdout}"`);
18
18
  else if (type === "yarn-classic") assert.default.ok(resp.stdout.length > 0, `Expected publish output for ${pkgName}`);
19
+ else if (type === "bun") assert.default.ok(true, `Publish succeeded for ${pkgName}`);
19
20
  else try {
20
21
  const parsedBody = JSON.parse(resp.stdout);
21
22
  assert.default.strictEqual(parsedBody.name, pkgName, `Expected package name "${pkgName}" but got "${parsedBody.name}"`);
@@ -1 +1 @@
1
- {"version":3,"file":"publish.cjs","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 === 'yarn-classic') {\n // yarn classic --json outputs NDJSON — just verify no error exit (exit code 0 is enough)\n assert.ok(resp.stdout.length > 0, `Expected publish output for ${pkgName}`);\n } else {\n // npm / pnpm\n try {\n const parsedBody = JSON.parse(resp.stdout);\n assert.strictEqual(parsedBody.name, pkgName, `Expected package name \"${pkgName}\" but got \"${parsedBody.name}\"`);\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;EAC5B;CAED,MAAM,OAAO,IAAI,QAAQ;AAEzB,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,SACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,MACL;AAGD,MAAI,SAAS,cACX,OAAM,IAAI,QAAQ,KAAK,EAAE,KAAK,YAAY,EAAE,UAAU;EAGxD,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,WACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,MAAI,SAAS,cACX,QAAA,QAAO,GACL,KAAK,OAAO,MAAM,4BAA4B,EAC9C,4CAA4C,QAAQ,YAAY,KAAK,OAAO,GAC7E;WACQ,SAAS,eAElB,QAAA,QAAO,GAAG,KAAK,OAAO,SAAS,GAAG,+BAA+B,UAAU;MAG3E,KAAI;GACF,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,UAAA,QAAO,YAAY,WAAW,MAAM,SAAS,0BAA0B,QAAQ,aAAa,WAAW,KAAK,GAAG;AAC/G,UAAA,QAAO,GAAG,WAAW,OAAO,oCAAoC,UAAU;UACpE;AAEN,UAAA,QAAO,GAAG,MAAM,yBAAyB,UAAU;;;;AAM3D,IAAa,cAA8B;CACzC,MAAM;CACN,UAAU,CAAC,UAAU;CACrB,KAAK;CACN"}
1
+ {"version":3,"file":"publish.cjs","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 === 'yarn-classic') {\n // yarn classic --json outputs NDJSON — just verify no error exit (exit code 0 is enough)\n assert.ok(resp.stdout.length > 0, `Expected publish output for ${pkgName}`);\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(parsedBody.name, pkgName, `Expected package name \"${pkgName}\" but got \"${parsedBody.name}\"`);\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;EAC5B;CAED,MAAM,OAAO,IAAI,QAAQ;AAEzB,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,SACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,MACL;AAGD,MAAI,SAAS,cACX,OAAM,IAAI,QAAQ,KAAK,EAAE,KAAK,YAAY,EAAE,UAAU;EAGxD,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,WACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,MAAI,SAAS,cACX,QAAA,QAAO,GACL,KAAK,OAAO,MAAM,4BAA4B,EAC9C,4CAA4C,QAAQ,YAAY,KAAK,OAAO,GAC7E;WACQ,SAAS,eAElB,QAAA,QAAO,GAAG,KAAK,OAAO,SAAS,GAAG,+BAA+B,UAAU;WAClE,SAAS,MAElB,QAAA,QAAO,GAAG,MAAM,yBAAyB,UAAU;MAGnD,KAAI;GACF,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,UAAA,QAAO,YAAY,WAAW,MAAM,SAAS,0BAA0B,QAAQ,aAAa,WAAW,KAAK,GAAG;AAC/G,UAAA,QAAO,GAAG,WAAW,OAAO,oCAAoC,UAAU;UACpE;AAEN,UAAA,QAAO,GAAG,MAAM,yBAAyB,UAAU;;;;AAM3D,IAAa,cAA8B;CACzC,MAAM;CACN,UAAU,CAAC,UAAU;CACrB,KAAK;CACN"}
@@ -0,0 +1,61 @@
1
+ import { exec } from "../utils/process.js";
2
+ import { prepareGenericEmptyProject } from "../utils/project.js";
3
+ import buildDebug from "debug";
4
+ import { execSync } from "child_process";
5
+ //#region src/adapters/bun.ts
6
+ var debug = buildDebug("verdaccio:e2e-cli:bun");
7
+ var BUN_SUPPORTED_COMMANDS = new Set([
8
+ "publish",
9
+ "install",
10
+ "info",
11
+ "audit"
12
+ ]);
13
+ function detectVersion(bin) {
14
+ try {
15
+ return execSync(`${bin} --version`, {
16
+ encoding: "utf8",
17
+ timeout: 5e3
18
+ }).trim();
19
+ } catch {
20
+ return "unknown";
21
+ }
22
+ }
23
+ function resolveBunBin(binPath) {
24
+ if (binPath) return binPath;
25
+ return "bun";
26
+ }
27
+ function createBunAdapter(binPath, _version) {
28
+ const bin = resolveBunBin(binPath);
29
+ const resolved = detectVersion(bin);
30
+ debug("creating bun adapter with bin: %s (%s)", bin, resolved);
31
+ return {
32
+ name: `bun@${resolved}`,
33
+ type: "bun",
34
+ bin,
35
+ supports: BUN_SUPPORTED_COMMANDS,
36
+ registryArg(url) {
37
+ return ["--registry", url];
38
+ },
39
+ prefixArg(folder) {
40
+ return ["--cwd", folder];
41
+ },
42
+ exec(options, ...args) {
43
+ if (args[0] === "info") {
44
+ const pkgName = args[1];
45
+ return exec(options, bin, [
46
+ "info",
47
+ pkgName,
48
+ ...args.slice(2).filter((a) => a !== "--registry").filter((a) => !a.startsWith("http"))
49
+ ]);
50
+ }
51
+ return exec(options, bin, args);
52
+ },
53
+ async prepareProject(packageName, version, registryUrl, port, token, dependencies = {}, devDependencies = {}) {
54
+ return prepareGenericEmptyProject(packageName, version, port, token, registryUrl, dependencies, devDependencies);
55
+ }
56
+ };
57
+ }
58
+ //#endregion
59
+ export { createBunAdapter };
60
+
61
+ //# sourceMappingURL=bun.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun.js","names":[],"sources":["../../../src/adapters/bun.ts"],"sourcesContent":["import { SpawnOptions, execSync } from 'child_process';\nimport buildDebug from 'debug';\n\nimport { ExecOutput, PackageManagerAdapter } from '../types';\nimport { exec } from '../utils/process';\nimport { prepareGenericEmptyProject } from '../utils/project';\n\nconst debug = buildDebug('verdaccio:e2e-cli:bun');\n\nconst BUN_SUPPORTED_COMMANDS = new Set([\n 'publish',\n 'install',\n 'info',\n 'audit',\n]);\n\nfunction detectVersion(bin: string): string {\n try {\n return execSync(`${bin} --version`, { encoding: 'utf8', timeout: 5000 }).trim();\n } catch {\n return 'unknown';\n }\n}\n\nfunction resolveBunBin(binPath?: string): string {\n if (binPath) return binPath;\n return 'bun';\n}\n\nexport function createBunAdapter(binPath?: string, _version?: string): PackageManagerAdapter {\n const bin = resolveBunBin(binPath);\n const resolved = detectVersion(bin);\n debug('creating bun adapter with bin: %s (%s)', bin, resolved);\n\n const adapter: PackageManagerAdapter = {\n name: `bun@${resolved}`,\n type: 'bun',\n bin,\n supports: BUN_SUPPORTED_COMMANDS,\n\n registryArg(url: string): string[] {\n return ['--registry', url];\n },\n\n prefixArg(folder: string): string[] {\n return ['--cwd', folder];\n },\n\n exec(options: SpawnOptions, ...args: string[]): Promise<ExecOutput> {\n const cmd = args[0];\n\n if (cmd === 'info') {\n // bun info <pkg> reads registry from .npmrc, strip --registry <url>\n const pkgName = args[1];\n const filteredArgs = args.slice(2).filter((a) => a !== '--registry');\n // also remove the URL that follows --registry\n const cleaned = filteredArgs.filter((a) => !a.startsWith('http'));\n return exec(options, bin, ['info', pkgName, ...cleaned]);\n }\n\n return exec(options, bin, args);\n },\n\n async prepareProject(\n packageName: string,\n version: string,\n registryUrl: string,\n port: number,\n token: string,\n dependencies: Record<string, string> = {},\n devDependencies: Record<string, string> = {}\n ): Promise<{ tempFolder: string }> {\n return prepareGenericEmptyProject(\n packageName,\n version,\n port,\n token,\n registryUrl,\n dependencies,\n devDependencies\n );\n },\n };\n\n return adapter;\n}\n"],"mappings":";;;;;AAOA,IAAM,QAAQ,WAAW,wBAAwB;AAEjD,IAAM,yBAAyB,IAAI,IAAI;CACrC;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,cAAc,KAAqB;AAC1C,KAAI;AACF,SAAO,SAAS,GAAG,IAAI,aAAa;GAAE,UAAU;GAAQ,SAAS;GAAM,CAAC,CAAC,MAAM;SACzE;AACN,SAAO;;;AAIX,SAAS,cAAc,SAA0B;AAC/C,KAAI,QAAS,QAAO;AACpB,QAAO;;AAGT,SAAgB,iBAAiB,SAAkB,UAA0C;CAC3F,MAAM,MAAM,cAAc,QAAQ;CAClC,MAAM,WAAW,cAAc,IAAI;AACnC,OAAM,0CAA0C,KAAK,SAAS;AAoD9D,QAlDuC;EACrC,MAAM,OAAO;EACb,MAAM;EACN;EACA,UAAU;EAEV,YAAY,KAAuB;AACjC,UAAO,CAAC,cAAc,IAAI;;EAG5B,UAAU,QAA0B;AAClC,UAAO,CAAC,SAAS,OAAO;;EAG1B,KAAK,SAAuB,GAAG,MAAqC;AAGlE,OAFY,KAAK,OAEL,QAAQ;IAElB,MAAM,UAAU,KAAK;AAIrB,WAAO,KAAK,SAAS,KAAK;KAAC;KAAQ;KAAS,GAHvB,KAAK,MAAM,EAAE,CAAC,QAAQ,MAAM,MAAM,aAAa,CAEvC,QAAQ,MAAM,CAAC,EAAE,WAAW,OAAO,CAAC;KACV,CAAC;;AAG1D,UAAO,KAAK,SAAS,KAAK,KAAK;;EAGjC,MAAM,eACJ,aACA,SACA,aACA,MACA,OACA,eAAuC,EAAE,EACzC,kBAA0C,EAAE,EACX;AACjC,UAAO,2BACL,aACA,SACA,MACA,OACA,aACA,cACA,gBACD;;EAEJ"}
@@ -0,0 +1,56 @@
1
+ import { exec } from "../utils/process.js";
2
+ import { prepareGenericEmptyProject } from "../utils/project.js";
3
+ import buildDebug from "debug";
4
+ import { execSync } from "child_process";
5
+ //#region src/adapters/deno.ts
6
+ var debug = buildDebug("verdaccio:e2e-cli:deno");
7
+ var DENO_SUPPORTED_COMMANDS = new Set(["install", "info"]);
8
+ function detectVersion(bin) {
9
+ try {
10
+ const match = execSync(`${bin} --version`, {
11
+ encoding: "utf8",
12
+ timeout: 5e3
13
+ }).match(/deno (\S+)/);
14
+ return match ? match[1] : "unknown";
15
+ } catch {
16
+ return "unknown";
17
+ }
18
+ }
19
+ function resolveDenoBin(binPath) {
20
+ if (binPath) return binPath;
21
+ return "deno";
22
+ }
23
+ function createDenoAdapter(binPath, _version) {
24
+ const bin = resolveDenoBin(binPath);
25
+ const resolved = detectVersion(bin);
26
+ debug("creating deno adapter with bin: %s (%s)", bin, resolved);
27
+ return {
28
+ name: `deno@${resolved}`,
29
+ type: "deno",
30
+ bin,
31
+ supports: DENO_SUPPORTED_COMMANDS,
32
+ registryArg(_url) {
33
+ return [];
34
+ },
35
+ prefixArg(folder) {
36
+ return ["--root", folder];
37
+ },
38
+ exec(options, ...args) {
39
+ const cmd = args[0];
40
+ if (cmd === "info") return exec(options, bin, [
41
+ "info",
42
+ `npm:${args[1]}`,
43
+ "--node-modules-dir=auto"
44
+ ].concat(args.slice(2).filter((a) => a !== "--json")));
45
+ if (cmd === "install") return exec(options, bin, ["install"]);
46
+ return exec(options, bin, args);
47
+ },
48
+ async prepareProject(packageName, version, registryUrl, port, token, dependencies = {}, devDependencies = {}) {
49
+ return prepareGenericEmptyProject(packageName, version, port, token, registryUrl, dependencies, devDependencies);
50
+ }
51
+ };
52
+ }
53
+ //#endregion
54
+ export { createDenoAdapter };
55
+
56
+ //# sourceMappingURL=deno.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deno.js","names":[],"sources":["../../../src/adapters/deno.ts"],"sourcesContent":["import { SpawnOptions, execSync } from 'child_process';\nimport buildDebug from 'debug';\n\nimport { ExecOutput, PackageManagerAdapter } from '../types';\nimport { exec } from '../utils/process';\nimport { prepareGenericEmptyProject } from '../utils/project';\n\nconst debug = buildDebug('verdaccio:e2e-cli:deno');\n\nconst DENO_SUPPORTED_COMMANDS = new Set(['install', 'info']);\n\nfunction detectVersion(bin: string): string {\n try {\n const output = execSync(`${bin} --version`, { encoding: 'utf8', timeout: 5000 });\n const match = output.match(/deno (\\S+)/);\n return match ? match[1] : 'unknown';\n } catch {\n return 'unknown';\n }\n}\n\nfunction resolveDenoBin(binPath?: string): string {\n if (binPath) return binPath;\n return 'deno';\n}\n\nexport function createDenoAdapter(binPath?: string, _version?: string): PackageManagerAdapter {\n const bin = resolveDenoBin(binPath);\n const resolved = detectVersion(bin);\n debug('creating deno adapter with bin: %s (%s)', bin, resolved);\n\n const adapter: PackageManagerAdapter = {\n name: `deno@${resolved}`,\n type: 'deno',\n bin,\n supports: DENO_SUPPORTED_COMMANDS,\n\n registryArg(_url: string): string[] {\n // deno reads the registry from .npmrc (written by prepareProject), no CLI flag needed\n return [];\n },\n\n prefixArg(folder: string): string[] {\n return ['--root', folder];\n },\n\n exec(options: SpawnOptions, ...args: string[]): Promise<ExecOutput> {\n const cmd = args[0];\n\n if (cmd === 'info') {\n // deno info npm:<pkg> --node-modules-dir=auto\n const pkgName = args[1];\n const filteredArgs = ['info', `npm:${pkgName}`, '--node-modules-dir=auto'].concat(\n args.slice(2).filter((a) => a !== '--json')\n );\n return exec(options, bin, filteredArgs);\n }\n\n if (cmd === 'install') {\n // deno install — reads registry from .npmrc, no extra flags needed\n return exec(options, bin, ['install']);\n }\n\n return exec(options, bin, args);\n },\n\n async prepareProject(\n packageName: string,\n version: string,\n registryUrl: string,\n port: number,\n token: string,\n dependencies: Record<string, string> = {},\n devDependencies: Record<string, string> = {}\n ): Promise<{ tempFolder: string }> {\n return prepareGenericEmptyProject(\n packageName,\n version,\n port,\n token,\n registryUrl,\n dependencies,\n devDependencies\n );\n },\n };\n\n return adapter;\n}\n"],"mappings":";;;;;AAOA,IAAM,QAAQ,WAAW,yBAAyB;AAElD,IAAM,0BAA0B,IAAI,IAAI,CAAC,WAAW,OAAO,CAAC;AAE5D,SAAS,cAAc,KAAqB;AAC1C,KAAI;EAEF,MAAM,QADS,SAAS,GAAG,IAAI,aAAa;GAAE,UAAU;GAAQ,SAAS;GAAM,CAAC,CAC3D,MAAM,aAAa;AACxC,SAAO,QAAQ,MAAM,KAAK;SACpB;AACN,SAAO;;;AAIX,SAAS,eAAe,SAA0B;AAChD,KAAI,QAAS,QAAO;AACpB,QAAO;;AAGT,SAAgB,kBAAkB,SAAkB,UAA0C;CAC5F,MAAM,MAAM,eAAe,QAAQ;CACnC,MAAM,WAAW,cAAc,IAAI;AACnC,OAAM,2CAA2C,KAAK,SAAS;AA0D/D,QAxDuC;EACrC,MAAM,QAAQ;EACd,MAAM;EACN;EACA,UAAU;EAEV,YAAY,MAAwB;AAElC,UAAO,EAAE;;EAGX,UAAU,QAA0B;AAClC,UAAO,CAAC,UAAU,OAAO;;EAG3B,KAAK,SAAuB,GAAG,MAAqC;GAClE,MAAM,MAAM,KAAK;AAEjB,OAAI,QAAQ,OAMV,QAAO,KAAK,SAAS,KAHA;IAAC;IAAQ,OADd,KAAK;IAC2B;IAA0B,CAAC,OACzE,KAAK,MAAM,EAAE,CAAC,QAAQ,MAAM,MAAM,SAAS,CAC5C,CACsC;AAGzC,OAAI,QAAQ,UAEV,QAAO,KAAK,SAAS,KAAK,CAAC,UAAU,CAAC;AAGxC,UAAO,KAAK,SAAS,KAAK,KAAK;;EAGjC,MAAM,eACJ,aACA,SACA,aACA,MACA,OACA,eAAuC,EAAE,EACzC,kBAA0C,EAAE,EACX;AACjC,UAAO,2BACL,aACA,SACA,MACA,OACA,aACA,cACA,gBACD;;EAEJ"}
@@ -1,3 +1,5 @@
1
+ import "./bun.js";
2
+ import "./deno.js";
1
3
  import "./npm.js";
2
4
  import "./pnpm.js";
3
5
  import "./yarn-classic.js";
@@ -1,3 +1,5 @@
1
+ import { createBunAdapter } from "./adapters/bun.js";
2
+ import { createDenoAdapter } from "./adapters/deno.js";
1
3
  import { createNpmAdapter } from "./adapters/npm.js";
2
4
  import { createPnpmAdapter } from "./adapters/pnpm.js";
3
5
  import { createYarnClassicAdapter } from "./adapters/yarn-classic.js";
@@ -32,7 +34,9 @@ function parseAdapters(pmFilters) {
32
34
  else if (name === "pnpm") adapters.push(createPnpmAdapter(binPath, version));
33
35
  else if (name === "yarn-classic" || name === "yarn1") adapters.push(createYarnClassicAdapter(binPath, version));
34
36
  else if (name === "yarn-modern" || name === "yarn") adapters.push(createYarnModernAdapter(binPath, version));
35
- else throw new Error(`Unknown package manager: "${name}". Supported: npm, pnpm, yarn-classic, yarn-modern[@version]`);
37
+ else if (name === "bun") adapters.push(createBunAdapter(binPath, version));
38
+ else if (name === "deno") adapters.push(createDenoAdapter(binPath, version));
39
+ else throw new Error(`Unknown package manager: "${name}". Supported: npm, pnpm, yarn-classic, yarn-modern, bun, deno`);
36
40
  }
37
41
  return adapters;
38
42
  }
@@ -82,11 +86,12 @@ function printHelp() {
82
86
 
83
87
  Options:
84
88
  --pm <name[@version]> Package manager to test (can be repeated)
85
- Supported: npm, pnpm, yarn-classic, yarn-modern (or yarn)
89
+ Supported: npm, pnpm, yarn-classic, yarn-modern (or yarn), bun, deno
86
90
  Examples: --pm npm@10 --pm pnpm@9
87
91
  --pm yarn-modern@4
88
92
  --pm yarn-modern@3
89
93
  --pm yarn-classic
94
+ --pm bun
90
95
  --pm npm --pm pnpm (uses system version)
91
96
  Auto-installs the requested yarn version if needed
92
97
  Default: npm
@@ -142,6 +147,6 @@ async function main(argv = process.argv) {
142
147
  process.exit(exitCode);
143
148
  }
144
149
  //#endregion
145
- export { allScenarios, allTests, createNpmAdapter, createPnpmAdapter, createYarnClassicAdapter, createYarnModernAdapter, main, runAll, runSuite };
150
+ export { allScenarios, allTests, createBunAdapter, createDenoAdapter, createNpmAdapter, createPnpmAdapter, createYarnClassicAdapter, createYarnModernAdapter, main, runAll, runSuite };
146
151
 
147
152
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport {\n createNpmAdapter,\n createPnpmAdapter,\n createYarnClassicAdapter,\n createYarnModernAdapter,\n} from './adapters';\nimport { allTests } from './tests';\nimport { CliOptions, PackageManagerAdapter } from './types';\nimport { createUser, pingRegistry } from './utils/registry-client';\nimport { runAll } from './runner';\n\nconst debug = buildDebug('verdaccio:e2e-cli');\n\nfunction parsePmSpec(filter: string): { name: string; version?: string; binPath?: string } {\n // --pm yarn-modern@3, --pm yarn-classic@1.22.22, --pm npm=/path/to/bin\n const eqIdx = filter.indexOf('=');\n if (eqIdx !== -1) {\n return { name: filter.slice(0, eqIdx).toLowerCase(), binPath: filter.slice(eqIdx + 1) };\n }\n const atIdx = filter.indexOf('@');\n if (atIdx !== -1) {\n return { name: filter.slice(0, atIdx).toLowerCase(), version: filter.slice(atIdx + 1) };\n }\n return { name: filter.toLowerCase() };\n}\n\nfunction parseAdapters(pmFilters?: string[]): PackageManagerAdapter[] {\n if (!pmFilters || pmFilters.length === 0) {\n return [createNpmAdapter()];\n }\n\n const adapters: PackageManagerAdapter[] = [];\n\n for (const filter of pmFilters) {\n const { name, version, binPath } = parsePmSpec(filter);\n\n if (name === 'npm') {\n adapters.push(createNpmAdapter(binPath, version));\n } else if (name === 'pnpm') {\n adapters.push(createPnpmAdapter(binPath, version));\n } else if (name === 'yarn-classic' || name === 'yarn1') {\n adapters.push(createYarnClassicAdapter(binPath, version));\n } else if (name === 'yarn-modern' || name === 'yarn') {\n adapters.push(createYarnModernAdapter(binPath, version));\n } else {\n throw new Error(\n `Unknown package manager: \"${name}\". Supported: npm, pnpm, yarn-classic, yarn-modern[@version]`\n );\n }\n }\n\n return adapters;\n}\n\nfunction parseArgs(argv: string[]): CliOptions {\n const options: CliOptions = {\n registry: '',\n pm: [],\n test: [],\n concurrency: 1,\n timeout: 50000,\n verbose: false,\n };\n\n for (let i = 2; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg === '--registry' || arg === '-r') {\n options.registry = argv[++i];\n } else if (arg === '--pm') {\n options.pm!.push(argv[++i]);\n } else if (arg === '--test' || arg === '-t') {\n options.test!.push(argv[++i]);\n } else if (arg === '--concurrency' || arg === '-c') {\n options.concurrency = parseInt(argv[++i], 10);\n } else if (arg === '--timeout') {\n options.timeout = parseInt(argv[++i], 10);\n } else if (arg === '--token') {\n options.token = argv[++i];\n } else if (arg === '--verbose' || arg === '-v') {\n options.verbose = true;\n } else if (arg === '--help' || arg === '-h') {\n printHelp();\n process.exit(0);\n } else if (arg.startsWith('--registry=')) {\n options.registry = arg.split('=')[1];\n } else if (arg.startsWith('--pm=')) {\n options.pm!.push(arg.split('=')[1]);\n } else if (arg.startsWith('--test=')) {\n options.test!.push(arg.split('=')[1]);\n } else if (arg.startsWith('--token=')) {\n options.token = arg.split('=')[1];\n } else if (arg.startsWith('--timeout=')) {\n options.timeout = parseInt(arg.split('=')[1], 10);\n } else {\n console.error(`Unknown argument: ${arg}`);\n printHelp();\n process.exit(1);\n }\n }\n\n return options;\n}\n\nfunction printHelp(): void {\n console.log(`\n @verdaccio/e2e-cli - Run Verdaccio e2e tests against any running registry\n\n Usage:\n verdaccio-e2e --registry <url> [options]\n\n Required:\n -r, --registry <url> Verdaccio registry URL (e.g. http://localhost:4873)\n\n Options:\n --pm <name[@version]> Package manager to test (can be repeated)\n Supported: npm, pnpm, yarn-classic, yarn-modern (or yarn)\n Examples: --pm npm@10 --pm pnpm@9\n --pm yarn-modern@4\n --pm yarn-modern@3\n --pm yarn-classic\n --pm npm --pm pnpm (uses system version)\n Auto-installs the requested yarn version if needed\n Default: npm\n\n -t, --test <name> Filter tests by name (can be repeated)\n Available: publish, install, ci, audit, info, deprecate,\n dist-tags, ping, search, star, unpublish\n Scenarios: scenario:install-multiple-deps\n Default: all supported by the PM\n\n --token <token> Auth token (skips user creation)\n --timeout <ms> Per-test timeout (default: 50000)\n -v, --verbose Enable debug output\n -h, --help Show this help\n `);\n}\n\nexport async function main(argv: string[] = process.argv): Promise<void> {\n const options = parseArgs(argv);\n\n if (!options.registry) {\n console.error('Error: --registry is required\\n');\n printHelp();\n process.exit(1);\n }\n\n // Run from a temp dir to isolate from the host project's packageManager, .yarnrc.yml, etc.\n const { createTempFolder } = await import('./utils/project');\n const runDir = await createTempFolder('e2e-run');\n process.chdir(runDir);\n\n if (options.verbose) {\n const { setVerbose } = await import('./utils/process');\n setVerbose(true);\n }\n\n // Ensure registry is reachable\n console.log(`Checking registry at ${options.registry}...`);\n const alive = await pingRegistry(options.registry);\n if (!alive) {\n console.error(`Error: Registry at ${options.registry} is not reachable`);\n process.exit(1);\n }\n console.log(`Registry is alive.`);\n\n // Get auth token\n let token = options.token;\n if (!token) {\n console.log('Creating test user...');\n const auth = await createUser(options.registry);\n token = auth.token;\n console.log(`User \"${auth.user}\" created.`);\n }\n\n // Build adapter list\n const adapters = parseAdapters(options.pm);\n console.log(`Adapters: ${adapters.map((a) => a.name).join(', ')}`);\n\n // Filter tests\n const tests = options.test && options.test.length > 0\n ? allTests.filter((t) => options.test!.includes(t.name))\n : allTests;\n\n console.log(`Tests: ${tests.map((t) => t.name).join(', ')}`);\n\n // Run\n const { exitCode } = await runAll(adapters, tests, options.registry, token, {\n timeout: options.timeout,\n concurrency: options.concurrency,\n testFilter: options.test,\n });\n\n process.exit(exitCode);\n}\n\n// Re-export for programmatic usage\nexport { allTests } from './tests';\nexport { allScenarios } from './scenarios';\nexport { createNpmAdapter, createPnpmAdapter, createYarnClassicAdapter, createYarnModernAdapter } from './adapters';\nexport { runAll, runSuite } from './runner';\nexport type { PackageManagerAdapter, TestDefinition, TestContext, CliOptions } from './types';\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import buildDebug from 'debug';\n\nimport {\n createBunAdapter,\n createDenoAdapter,\n createNpmAdapter,\n createPnpmAdapter,\n createYarnClassicAdapter,\n createYarnModernAdapter,\n} from './adapters';\nimport { allTests } from './tests';\nimport { CliOptions, PackageManagerAdapter } from './types';\nimport { createUser, pingRegistry } from './utils/registry-client';\nimport { runAll } from './runner';\n\nconst debug = buildDebug('verdaccio:e2e-cli');\n\nfunction parsePmSpec(filter: string): { name: string; version?: string; binPath?: string } {\n // --pm yarn-modern@3, --pm yarn-classic@1.22.22, --pm npm=/path/to/bin\n const eqIdx = filter.indexOf('=');\n if (eqIdx !== -1) {\n return { name: filter.slice(0, eqIdx).toLowerCase(), binPath: filter.slice(eqIdx + 1) };\n }\n const atIdx = filter.indexOf('@');\n if (atIdx !== -1) {\n return { name: filter.slice(0, atIdx).toLowerCase(), version: filter.slice(atIdx + 1) };\n }\n return { name: filter.toLowerCase() };\n}\n\nfunction parseAdapters(pmFilters?: string[]): PackageManagerAdapter[] {\n if (!pmFilters || pmFilters.length === 0) {\n return [createNpmAdapter()];\n }\n\n const adapters: PackageManagerAdapter[] = [];\n\n for (const filter of pmFilters) {\n const { name, version, binPath } = parsePmSpec(filter);\n\n if (name === 'npm') {\n adapters.push(createNpmAdapter(binPath, version));\n } else if (name === 'pnpm') {\n adapters.push(createPnpmAdapter(binPath, version));\n } else if (name === 'yarn-classic' || name === 'yarn1') {\n adapters.push(createYarnClassicAdapter(binPath, version));\n } else if (name === 'yarn-modern' || name === 'yarn') {\n adapters.push(createYarnModernAdapter(binPath, version));\n } else if (name === 'bun') {\n adapters.push(createBunAdapter(binPath, version));\n } else if (name === 'deno') {\n adapters.push(createDenoAdapter(binPath, version));\n } else {\n throw new Error(\n `Unknown package manager: \"${name}\". Supported: npm, pnpm, yarn-classic, yarn-modern, bun, deno`\n );\n }\n }\n\n return adapters;\n}\n\nfunction parseArgs(argv: string[]): CliOptions {\n const options: CliOptions = {\n registry: '',\n pm: [],\n test: [],\n concurrency: 1,\n timeout: 50000,\n verbose: false,\n };\n\n for (let i = 2; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg === '--registry' || arg === '-r') {\n options.registry = argv[++i];\n } else if (arg === '--pm') {\n options.pm!.push(argv[++i]);\n } else if (arg === '--test' || arg === '-t') {\n options.test!.push(argv[++i]);\n } else if (arg === '--concurrency' || arg === '-c') {\n options.concurrency = parseInt(argv[++i], 10);\n } else if (arg === '--timeout') {\n options.timeout = parseInt(argv[++i], 10);\n } else if (arg === '--token') {\n options.token = argv[++i];\n } else if (arg === '--verbose' || arg === '-v') {\n options.verbose = true;\n } else if (arg === '--help' || arg === '-h') {\n printHelp();\n process.exit(0);\n } else if (arg.startsWith('--registry=')) {\n options.registry = arg.split('=')[1];\n } else if (arg.startsWith('--pm=')) {\n options.pm!.push(arg.split('=')[1]);\n } else if (arg.startsWith('--test=')) {\n options.test!.push(arg.split('=')[1]);\n } else if (arg.startsWith('--token=')) {\n options.token = arg.split('=')[1];\n } else if (arg.startsWith('--timeout=')) {\n options.timeout = parseInt(arg.split('=')[1], 10);\n } else {\n console.error(`Unknown argument: ${arg}`);\n printHelp();\n process.exit(1);\n }\n }\n\n return options;\n}\n\nfunction printHelp(): void {\n console.log(`\n @verdaccio/e2e-cli - Run Verdaccio e2e tests against any running registry\n\n Usage:\n verdaccio-e2e --registry <url> [options]\n\n Required:\n -r, --registry <url> Verdaccio registry URL (e.g. http://localhost:4873)\n\n Options:\n --pm <name[@version]> Package manager to test (can be repeated)\n Supported: npm, pnpm, yarn-classic, yarn-modern (or yarn), bun, deno\n Examples: --pm npm@10 --pm pnpm@9\n --pm yarn-modern@4\n --pm yarn-modern@3\n --pm yarn-classic\n --pm bun\n --pm npm --pm pnpm (uses system version)\n Auto-installs the requested yarn version if needed\n Default: npm\n\n -t, --test <name> Filter tests by name (can be repeated)\n Available: publish, install, ci, audit, info, deprecate,\n dist-tags, ping, search, star, unpublish\n Scenarios: scenario:install-multiple-deps\n Default: all supported by the PM\n\n --token <token> Auth token (skips user creation)\n --timeout <ms> Per-test timeout (default: 50000)\n -v, --verbose Enable debug output\n -h, --help Show this help\n `);\n}\n\nexport async function main(argv: string[] = process.argv): Promise<void> {\n const options = parseArgs(argv);\n\n if (!options.registry) {\n console.error('Error: --registry is required\\n');\n printHelp();\n process.exit(1);\n }\n\n // Run from a temp dir to isolate from the host project's packageManager, .yarnrc.yml, etc.\n const { createTempFolder } = await import('./utils/project');\n const runDir = await createTempFolder('e2e-run');\n process.chdir(runDir);\n\n if (options.verbose) {\n const { setVerbose } = await import('./utils/process');\n setVerbose(true);\n }\n\n // Ensure registry is reachable\n console.log(`Checking registry at ${options.registry}...`);\n const alive = await pingRegistry(options.registry);\n if (!alive) {\n console.error(`Error: Registry at ${options.registry} is not reachable`);\n process.exit(1);\n }\n console.log(`Registry is alive.`);\n\n // Get auth token\n let token = options.token;\n if (!token) {\n console.log('Creating test user...');\n const auth = await createUser(options.registry);\n token = auth.token;\n console.log(`User \"${auth.user}\" created.`);\n }\n\n // Build adapter list\n const adapters = parseAdapters(options.pm);\n console.log(`Adapters: ${adapters.map((a) => a.name).join(', ')}`);\n\n // Filter tests\n const tests = options.test && options.test.length > 0\n ? allTests.filter((t) => options.test!.includes(t.name))\n : allTests;\n\n console.log(`Tests: ${tests.map((t) => t.name).join(', ')}`);\n\n // Run\n const { exitCode } = await runAll(adapters, tests, options.registry, token, {\n timeout: options.timeout,\n concurrency: options.concurrency,\n testFilter: options.test,\n });\n\n process.exit(exitCode);\n}\n\n// Re-export for programmatic usage\nexport { allTests } from './tests';\nexport { allScenarios } from './scenarios';\nexport { createBunAdapter, createDenoAdapter, createNpmAdapter, createPnpmAdapter, createYarnClassicAdapter, createYarnModernAdapter } from './adapters';\nexport { runAll, runSuite } from './runner';\nexport type { PackageManagerAdapter, TestDefinition, TestContext, CliOptions } from './types';\n"],"mappings":"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"}
@@ -3,8 +3,8 @@ import assert from "assert";
3
3
  //#region src/tests/audit.ts
4
4
  var debug = buildDebug("verdaccio:e2e-cli:test:audit");
5
5
  async function testAudit(ctx) {
6
- if (ctx.adapter.type !== "npm") {
7
- debug("skipping audit test for %s (npm only)", ctx.adapter.type);
6
+ if (ctx.adapter.type !== "npm" && ctx.adapter.type !== "bun") {
7
+ debug("skipping audit test for %s (npm/bun only)", ctx.adapter.type);
8
8
  return;
9
9
  }
10
10
  const packages = [`verdaccio-audit-${ctx.runId}`, `@verdaccio/audit-${ctx.runId}`];
@@ -25,9 +25,12 @@ async function testAudit(ctx) {
25
25
  return;
26
26
  }
27
27
  const resp = await ctx.adapter.exec({ cwd: tempFolder }, "audit", "--json", ...ctx.adapter.registryArg(ctx.registryUrl));
28
- const parsedBody = JSON.parse(resp.stdout);
29
- assert.ok(parsedBody.auditReportVersion !== void 0, "Expected \"auditReportVersion\" in audit response");
30
- assert.ok(parsedBody.vulnerabilities !== void 0, "Expected \"vulnerabilities\" in audit response");
28
+ if (ctx.adapter.type === "bun") assert.ok(resp.stdout.length > 0 || resp.stderr.length > 0, "Expected audit output");
29
+ else {
30
+ const parsedBody = JSON.parse(resp.stdout);
31
+ assert.ok(parsedBody.auditReportVersion !== void 0, "Expected \"auditReportVersion\" in audit response");
32
+ assert.ok(parsedBody.vulnerabilities !== void 0, "Expected \"vulnerabilities\" in audit response");
33
+ }
31
34
  }
32
35
  }
33
36
  var auditTest = {
@@ -1 +1 @@
1
- {"version":3,"file":"audit.js","names":[],"sources":["../../../src/tests/audit.ts"],"sourcesContent":["import assert from 'assert';\nimport buildDebug from 'debug';\n\nimport { TestContext, TestDefinition } from '../types';\n\nconst debug = buildDebug('verdaccio:e2e-cli:test:audit');\n\nasync function testAudit(ctx: TestContext): Promise<void> {\n // Audit is only reliable with npm — pnpm/yarn audit output varies too much\n if (ctx.adapter.type !== 'npm') {\n debug('skipping audit test for %s (npm only)', ctx.adapter.type);\n return;\n }\n\n const packages = [`verdaccio-audit-${ctx.runId}`, `@verdaccio/audit-${ctx.runId}`];\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 { jquery: '3.6.1' }\n );\n\n // install is required to create package lock file\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'install',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n // npm audit exits with code 1 both when vulnerabilities are found AND when\n // the endpoint is unavailable. We need to distinguish between the two.\n // Probe the audit endpoint first to avoid false failures on registries\n // that don't support it (e.g. verdaccio next-7+).\n try {\n const probe = await fetch(`${ctx.registryUrl}/-/npm/v1/security/audits/quick`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: '{}',\n });\n if (probe.status === 404) {\n debug('audit endpoint not supported by this registry (404), skipping');\n return;\n }\n } catch {\n debug('audit endpoint probe failed, skipping');\n return;\n }\n\n const resp = await ctx.adapter.exec(\n { cwd: tempFolder },\n 'audit',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n const parsedBody = JSON.parse(resp.stdout);\n assert.ok(parsedBody.auditReportVersion !== undefined, 'Expected \"auditReportVersion\" in audit response');\n assert.ok(parsedBody.vulnerabilities !== undefined, 'Expected \"vulnerabilities\" in audit response');\n }\n}\n\nexport const auditTest: TestDefinition = {\n name: 'audit',\n requires: ['audit'],\n run: testAudit,\n};\n"],"mappings":";;;AAKA,IAAM,QAAQ,WAAW,+BAA+B;AAExD,eAAe,UAAU,KAAiC;AAExD,KAAI,IAAI,QAAQ,SAAS,OAAO;AAC9B,QAAM,yCAAyC,IAAI,QAAQ,KAAK;AAChE;;CAGF,MAAM,WAAW,CAAC,mBAAmB,IAAI,SAAS,oBAAoB,IAAI,QAAQ;AAElF,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,SACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,OACJ,EAAE,QAAQ,SAAS,CACpB;AAGD,QAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,YAAY,EACnB,WACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAMD,MAAI;AAMF,QALc,MAAM,MAAM,GAAG,IAAI,YAAY,kCAAkC;IAC7E,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,MAAM;IACP,CAAC,EACQ,WAAW,KAAK;AACxB,UAAM,gEAAgE;AACtE;;UAEI;AACN,SAAM,wCAAwC;AAC9C;;EAGF,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,SACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;EAED,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,SAAO,GAAG,WAAW,uBAAuB,KAAA,GAAW,oDAAkD;AACzG,SAAO,GAAG,WAAW,oBAAoB,KAAA,GAAW,iDAA+C;;;AAIvG,IAAa,YAA4B;CACvC,MAAM;CACN,UAAU,CAAC,QAAQ;CACnB,KAAK;CACN"}
1
+ {"version":3,"file":"audit.js","names":[],"sources":["../../../src/tests/audit.ts"],"sourcesContent":["import assert from 'assert';\nimport buildDebug from 'debug';\n\nimport { TestContext, TestDefinition } from '../types';\n\nconst debug = buildDebug('verdaccio:e2e-cli:test:audit');\n\nasync function testAudit(ctx: TestContext): Promise<void> {\n // Audit is only reliable with npm and bun — pnpm/yarn audit output varies too much\n if (ctx.adapter.type !== 'npm' && ctx.adapter.type !== 'bun') {\n debug('skipping audit test for %s (npm/bun only)', ctx.adapter.type);\n return;\n }\n\n const packages = [`verdaccio-audit-${ctx.runId}`, `@verdaccio/audit-${ctx.runId}`];\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 { jquery: '3.6.1' }\n );\n\n // install is required to create package lock file\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'install',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n // npm audit exits with code 1 both when vulnerabilities are found AND when\n // the endpoint is unavailable. We need to distinguish between the two.\n // Probe the audit endpoint first to avoid false failures on registries\n // that don't support it (e.g. verdaccio next-7+).\n try {\n const probe = await fetch(`${ctx.registryUrl}/-/npm/v1/security/audits/quick`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: '{}',\n });\n if (probe.status === 404) {\n debug('audit endpoint not supported by this registry (404), skipping');\n return;\n }\n } catch {\n debug('audit endpoint probe failed, skipping');\n return;\n }\n\n const resp = await ctx.adapter.exec(\n { cwd: tempFolder },\n 'audit',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n if (ctx.adapter.type === 'bun') {\n // bun audit output may differ — exit code 0 is sufficient for basic validation\n assert.ok(resp.stdout.length > 0 || resp.stderr.length > 0, 'Expected audit output');\n } else {\n const parsedBody = JSON.parse(resp.stdout);\n assert.ok(parsedBody.auditReportVersion !== undefined, 'Expected \"auditReportVersion\" in audit response');\n assert.ok(parsedBody.vulnerabilities !== undefined, 'Expected \"vulnerabilities\" in audit response');\n }\n }\n}\n\nexport const auditTest: TestDefinition = {\n name: 'audit',\n requires: ['audit'],\n run: testAudit,\n};\n"],"mappings":";;;AAKA,IAAM,QAAQ,WAAW,+BAA+B;AAExD,eAAe,UAAU,KAAiC;AAExD,KAAI,IAAI,QAAQ,SAAS,SAAS,IAAI,QAAQ,SAAS,OAAO;AAC5D,QAAM,6CAA6C,IAAI,QAAQ,KAAK;AACpE;;CAGF,MAAM,WAAW,CAAC,mBAAmB,IAAI,SAAS,oBAAoB,IAAI,QAAQ;AAElF,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,SACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,OACJ,EAAE,QAAQ,SAAS,CACpB;AAGD,QAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,YAAY,EACnB,WACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAMD,MAAI;AAMF,QALc,MAAM,MAAM,GAAG,IAAI,YAAY,kCAAkC;IAC7E,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,MAAM;IACP,CAAC,EACQ,WAAW,KAAK;AACxB,UAAM,gEAAgE;AACtE;;UAEI;AACN,SAAM,wCAAwC;AAC9C;;EAGF,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,SACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,MAAI,IAAI,QAAQ,SAAS,MAEvB,QAAO,GAAG,KAAK,OAAO,SAAS,KAAK,KAAK,OAAO,SAAS,GAAG,wBAAwB;OAC/E;GACL,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,UAAO,GAAG,WAAW,uBAAuB,KAAA,GAAW,oDAAkD;AACzG,UAAO,GAAG,WAAW,oBAAoB,KAAA,GAAW,iDAA+C;;;;AAKzG,IAAa,YAA4B;CACvC,MAAM;CACN,UAAU,CAAC,QAAQ;CACnB,KAAK;CACN"}
@@ -32,10 +32,19 @@ function getCiArgs(ctx) {
32
32
  ...ctx.adapter.registryArg(ctx.registryUrl)
33
33
  ];
34
34
  case "yarn-modern": return ["install", "--immutable"];
35
+ case "bun": return [
36
+ "install",
37
+ "--frozen-lockfile",
38
+ ...ctx.adapter.registryArg(ctx.registryUrl)
39
+ ];
35
40
  default: return ["ci", ...ctx.adapter.registryArg(ctx.registryUrl)];
36
41
  }
37
42
  }
38
43
  async function testCi(ctx) {
44
+ if (ctx.adapter.type === "deno") {
45
+ debug("skipping ci test for deno (no ci command)");
46
+ return;
47
+ }
39
48
  const { tempFolder } = await ctx.adapter.prepareProject(`ci-test-${ctx.runId}`, "1.0.0", ctx.registryUrl, ctx.port, ctx.token, { "is-odd": "1.0.0" });
40
49
  debug("running initial install to generate lockfile in %s", tempFolder);
41
50
  await ctx.adapter.exec({ cwd: tempFolder }, "install", ...ctx.adapter.registryArg(ctx.registryUrl));
@@ -1 +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';\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-classic':\n // `yarn install --frozen-lockfile`\n return ['install', '--frozen-lockfile', ...ctx.adapter.registryArg(ctx.registryUrl)];\n case 'yarn-modern':\n // `yarn install --immutable`\n return ['install', '--immutable'];\n default:\n return ['ci', ...ctx.adapter.registryArg(ctx.registryUrl)];\n }\n}\n\nasync function testCi(ctx: TestContext): Promise<void> {\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 { 'is-odd': '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":";;;;;AAOA,IAAM,QAAQ,WAAW,4BAA4B;;;;;;;;;;;;;;;AAiBrD,SAAS,UAAU,KAA4B;AAC7C,SAAQ,IAAI,QAAQ,MAApB;EACE,KAAK,MAEH,QAAO,CAAC,MAAM,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAAC;EAC5D,KAAK,OAEH,QAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY;GAAC;EACtF,KAAK,eAEH,QAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY;GAAC;EACtF,KAAK,cAEH,QAAO,CAAC,WAAW,cAAc;EACnC,QACE,QAAO,CAAC,MAAM,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAAC;;;AAIhE,eAAe,OAAO,KAAiC;CACrD,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,WAAW,IAAI,SACf,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,OACJ,EAAE,UAAU,SAAS,CACtB;AAED,OAAM,sDAAsD,WAAW;AAGvE,OAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,YAAY,EACnB,WACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,OAAM,4CAA4C;AAIlD,OAAM,GADkB,KAAK,YAAY,eAAe,EAC9B;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAI3D,OAAM,GADgB,KAAK,YAAY,cAAc,EAC7B;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAEzD,OAAM,2CAA2C;CAGjD,MAAM,SAAS,UAAU,IAAI;AAC7B,OAAM,eAAe,OAAO;CAC5B,MAAM,OAAO,MAAM,IAAI,QAAQ,KAAK,EAAE,KAAK,YAAY,EAAE,GAAG,OAAO;AAGnE,KAAI,IAAI,QAAQ,SAAS,OAAO;AAI9B,QAAM,qBADS,KAAK,SAAS,KAAK,OACA;AAClC,SAAO,GAAG,MAAM,gCAAgC;QAC3C;AACL,QAAM,oCAAoC,IAAI,QAAQ,KAAK;AAC3D,SAAO,GAAG,MAAM,yCAAyC,IAAI,QAAQ,OAAO;;;AAIhF,IAAa,SAAyB;CACpC,MAAM;CACN,UAAU,CAAC,UAAU;CACrB,KAAK;CACN"}
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';\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-classic':\n // `yarn install --frozen-lockfile`\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 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 { 'is-odd': '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":";;;;;AAOA,IAAM,QAAQ,WAAW,4BAA4B;;;;;;;;;;;;;;;AAiBrD,SAAS,UAAU,KAA4B;AAC7C,SAAQ,IAAI,QAAQ,MAApB;EACE,KAAK,MAEH,QAAO,CAAC,MAAM,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAAC;EAC5D,KAAK,OAEH,QAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY;GAAC;EACtF,KAAK,eAEH,QAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY;GAAC;EACtF,KAAK,cAEH,QAAO,CAAC,WAAW,cAAc;EACnC,KAAK,MAEH,QAAO;GAAC;GAAW;GAAqB,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY;GAAC;EACtF,QACE,QAAO,CAAC,MAAM,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAAC;;;AAIhE,eAAe,OAAO,KAAiC;AAErD,KAAI,IAAI,QAAQ,SAAS,QAAQ;AAC/B,QAAM,4CAA4C;AAClD;;CAGF,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,WAAW,IAAI,SACf,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,OACJ,EAAE,UAAU,SAAS,CACtB;AAED,OAAM,sDAAsD,WAAW;AAGvE,OAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,YAAY,EACnB,WACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,OAAM,4CAA4C;AAIlD,OAAM,GADkB,KAAK,YAAY,eAAe,EAC9B;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAI3D,OAAM,GADgB,KAAK,YAAY,cAAc,EAC7B;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAEzD,OAAM,2CAA2C;CAGjD,MAAM,SAAS,UAAU,IAAI;AAC7B,OAAM,eAAe,OAAO;CAC5B,MAAM,OAAO,MAAM,IAAI,QAAQ,KAAK,EAAE,KAAK,YAAY,EAAE,GAAG,OAAO;AAGnE,KAAI,IAAI,QAAQ,SAAS,OAAO;AAI9B,QAAM,qBADS,KAAK,SAAS,KAAK,OACA;AAClC,SAAO,GAAG,MAAM,gCAAgC;QAC3C;AACL,QAAM,oCAAoC,IAAI,QAAQ,KAAK;AAC3D,SAAO,GAAG,MAAM,yCAAyC,IAAI,QAAQ,OAAO;;;AAIhF,IAAa,SAAyB;CACpC,MAAM;CACN,UAAU,CAAC,UAAU;CACrB,KAAK;CACN"}
@@ -19,6 +19,9 @@ async function testInfo(ctx) {
19
19
  }
20
20
  });
21
21
  assert.ok(dataLine, "Expected yarn info NDJSON to contain an \"inspect\" entry");
22
+ } else if (ctx.adapter.type === "deno") {
23
+ const output = resp.stdout + resp.stderr;
24
+ assert.ok(output.includes("verdaccio"), "Expected deno info output to reference verdaccio");
22
25
  } else {
23
26
  const parsedBody = JSON.parse(resp.stdout);
24
27
  assert.strictEqual(parsedBody.name, "verdaccio", "Expected package name \"verdaccio\"");
@@ -1 +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 { createTempFolder } from '../utils/project';\nimport { writeFile } from 'fs/promises';\nimport { join } from 'path';\n\nasync function testInfo(ctx: TestContext): Promise<void> {\n // Create a minimal temp project so yarn modern has a project context\n // and yarn classic doesn't pick up the repo's packageManager field\n const tempFolder = await createTempFolder('info-test');\n await writeFile(join(tempFolder, 'package.json'), JSON.stringify({ name: 'info-test', version: '1.0.0' }));\n\n const resp = await ctx.adapter.exec(\n { cwd: tempFolder },\n 'info',\n 'verdaccio',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n if (ctx.adapter.type === 'yarn-classic') {\n const lines = resp.stdout.split('\\n').filter(Boolean);\n const dataLine = lines.find((l) => {\n try {\n const obj = JSON.parse(l);\n return obj.type === 'inspect';\n } catch {\n return false;\n }\n });\n assert.ok(dataLine, 'Expected yarn info NDJSON to contain an \"inspect\" entry');\n } else {\n const parsedBody = JSON.parse(resp.stdout);\n assert.strictEqual(parsedBody.name, 'verdaccio', 'Expected package name \"verdaccio\"');\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":";;;;;AAOA,eAAe,SAAS,KAAiC;CAGvD,MAAM,aAAa,MAAM,iBAAiB,YAAY;AACtD,OAAM,UAAU,KAAK,YAAY,eAAe,EAAE,KAAK,UAAU;EAAE,MAAM;EAAa,SAAS;EAAS,CAAC,CAAC;CAE1G,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,QACA,aACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,KAAI,IAAI,QAAQ,SAAS,gBAAgB;EAEvC,MAAM,WADQ,KAAK,OAAO,MAAM,KAAK,CAAC,OAAO,QAAQ,CAC9B,MAAM,MAAM;AACjC,OAAI;AAEF,WADY,KAAK,MAAM,EAAE,CACd,SAAS;WACd;AACN,WAAO;;IAET;AACF,SAAO,GAAG,UAAU,4DAA0D;QACzE;EACL,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,SAAO,YAAY,WAAW,MAAM,aAAa,sCAAoC;AACrF,SAAO,GAAG,WAAW,iBAAiB,KAAA,GAAW,0CAAwC;;;AAI7F,IAAa,WAA2B;CACtC,MAAM;CACN,UAAU,CAAC,OAAO;CAClB,KAAK;CACN"}
1
+ {"version":3,"file":"info.js","names":[],"sources":["../../../src/tests/info.ts"],"sourcesContent":["import assert from 'assert';\n\nimport { TestContext, TestDefinition } from '../types';\nimport { createTempFolder } from '../utils/project';\nimport { writeFile } from 'fs/promises';\nimport { join } from 'path';\n\nasync function testInfo(ctx: TestContext): Promise<void> {\n // Create a minimal temp project so yarn modern has a project context\n // and yarn classic doesn't pick up the repo's packageManager field\n const tempFolder = await createTempFolder('info-test');\n await writeFile(join(tempFolder, 'package.json'), JSON.stringify({ name: 'info-test', version: '1.0.0' }));\n\n const resp = await ctx.adapter.exec(\n { cwd: tempFolder },\n 'info',\n 'verdaccio',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n\n if (ctx.adapter.type === 'yarn-classic') {\n const lines = resp.stdout.split('\\n').filter(Boolean);\n const dataLine = lines.find((l) => {\n try {\n const obj = JSON.parse(l);\n return obj.type === 'inspect';\n } catch {\n return false;\n }\n });\n assert.ok(dataLine, 'Expected yarn info NDJSON to contain an \"inspect\" entry');\n } else 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('verdaccio'), 'Expected deno info output to reference verdaccio');\n } else {\n const parsedBody = JSON.parse(resp.stdout);\n assert.strictEqual(parsedBody.name, 'verdaccio', 'Expected package name \"verdaccio\"');\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":";;;;;AAOA,eAAe,SAAS,KAAiC;CAGvD,MAAM,aAAa,MAAM,iBAAiB,YAAY;AACtD,OAAM,UAAU,KAAK,YAAY,eAAe,EAAE,KAAK,UAAU;EAAE,MAAM;EAAa,SAAS;EAAS,CAAC,CAAC;CAE1G,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,QACA,aACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,KAAI,IAAI,QAAQ,SAAS,gBAAgB;EAEvC,MAAM,WADQ,KAAK,OAAO,MAAM,KAAK,CAAC,OAAO,QAAQ,CAC9B,MAAM,MAAM;AACjC,OAAI;AAEF,WADY,KAAK,MAAM,EAAE,CACd,SAAS;WACd;AACN,WAAO;;IAET;AACF,SAAO,GAAG,UAAU,4DAA0D;YACrE,IAAI,QAAQ,SAAS,QAAQ;EAEtC,MAAM,SAAS,KAAK,SAAS,KAAK;AAClC,SAAO,GAAG,OAAO,SAAS,YAAY,EAAE,mDAAmD;QACtF;EACL,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,SAAO,YAAY,WAAW,MAAM,aAAa,sCAAoC;AACrF,SAAO,GAAG,WAAW,iBAAiB,KAAA,GAAW,0CAAwC;;;AAI7F,IAAa,WAA2B;CACtC,MAAM;CACN,UAAU,CAAC,OAAO;CAClB,KAAK;CACN"}
@@ -14,6 +14,7 @@ async function testPublish(ctx) {
14
14
  const resp = await ctx.adapter.exec({ cwd: tempFolder }, "publish", "--json", ...ctx.adapter.registryArg(ctx.registryUrl));
15
15
  if (type === "yarn-modern") assert.ok(resp.stdout.match(/Package archive published/), `Expected "Package archive published" for ${pkgName} but got "${resp.stdout}"`);
16
16
  else if (type === "yarn-classic") assert.ok(resp.stdout.length > 0, `Expected publish output for ${pkgName}`);
17
+ else if (type === "bun") assert.ok(true, `Publish succeeded for ${pkgName}`);
17
18
  else try {
18
19
  const parsedBody = JSON.parse(resp.stdout);
19
20
  assert.strictEqual(parsedBody.name, pkgName, `Expected package name "${pkgName}" but got "${parsedBody.name}"`);
@@ -1 +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 === 'yarn-classic') {\n // yarn classic --json outputs NDJSON — just verify no error exit (exit code 0 is enough)\n assert.ok(resp.stdout.length > 0, `Expected publish output for ${pkgName}`);\n } else {\n // npm / pnpm\n try {\n const parsedBody = JSON.parse(resp.stdout);\n assert.strictEqual(parsedBody.name, pkgName, `Expected package name \"${pkgName}\" but got \"${parsedBody.name}\"`);\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;EAC5B;CAED,MAAM,OAAO,IAAI,QAAQ;AAEzB,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,SACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,MACL;AAGD,MAAI,SAAS,cACX,OAAM,IAAI,QAAQ,KAAK,EAAE,KAAK,YAAY,EAAE,UAAU;EAGxD,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,WACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,MAAI,SAAS,cACX,QAAO,GACL,KAAK,OAAO,MAAM,4BAA4B,EAC9C,4CAA4C,QAAQ,YAAY,KAAK,OAAO,GAC7E;WACQ,SAAS,eAElB,QAAO,GAAG,KAAK,OAAO,SAAS,GAAG,+BAA+B,UAAU;MAG3E,KAAI;GACF,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,UAAO,YAAY,WAAW,MAAM,SAAS,0BAA0B,QAAQ,aAAa,WAAW,KAAK,GAAG;AAC/G,UAAO,GAAG,WAAW,OAAO,oCAAoC,UAAU;UACpE;AAEN,UAAO,GAAG,MAAM,yBAAyB,UAAU;;;;AAM3D,IAAa,cAA8B;CACzC,MAAM;CACN,UAAU,CAAC,UAAU;CACrB,KAAK;CACN"}
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 === 'yarn-classic') {\n // yarn classic --json outputs NDJSON — just verify no error exit (exit code 0 is enough)\n assert.ok(resp.stdout.length > 0, `Expected publish output for ${pkgName}`);\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(parsedBody.name, pkgName, `Expected package name \"${pkgName}\" but got \"${parsedBody.name}\"`);\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;EAC5B;CAED,MAAM,OAAO,IAAI,QAAQ;AAEzB,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,EAAE,eAAe,MAAM,IAAI,QAAQ,eACvC,SACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,MACL;AAGD,MAAI,SAAS,cACX,OAAM,IAAI,QAAQ,KAAK,EAAE,KAAK,YAAY,EAAE,UAAU;EAGxD,MAAM,OAAO,MAAM,IAAI,QAAQ,KAC7B,EAAE,KAAK,YAAY,EACnB,WACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,YAAY,CAC5C;AAED,MAAI,SAAS,cACX,QAAO,GACL,KAAK,OAAO,MAAM,4BAA4B,EAC9C,4CAA4C,QAAQ,YAAY,KAAK,OAAO,GAC7E;WACQ,SAAS,eAElB,QAAO,GAAG,KAAK,OAAO,SAAS,GAAG,+BAA+B,UAAU;WAClE,SAAS,MAElB,QAAO,GAAG,MAAM,yBAAyB,UAAU;MAGnD,KAAI;GACF,MAAM,aAAa,KAAK,MAAM,KAAK,OAAO;AAC1C,UAAO,YAAY,WAAW,MAAM,SAAS,0BAA0B,QAAQ,aAAa,WAAW,KAAK,GAAG;AAC/G,UAAO,GAAG,WAAW,OAAO,oCAAoC,UAAU;UACpE;AAEN,UAAO,GAAG,MAAM,yBAAyB,UAAU;;;;AAM3D,IAAa,cAA8B;CACzC,MAAM;CACN,UAAU,CAAC,UAAU;CACrB,KAAK;CACN"}
package/build/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export declare function main(argv?: string[]): Promise<void>;
2
2
  export { allTests } from './tests';
3
3
  export { allScenarios } from './scenarios';
4
- export { createNpmAdapter, createPnpmAdapter, createYarnClassicAdapter, createYarnModernAdapter } from './adapters';
4
+ export { createBunAdapter, createDenoAdapter, createNpmAdapter, createPnpmAdapter, createYarnClassicAdapter, createYarnModernAdapter } from './adapters';
5
5
  export { runAll, runSuite } from './runner';
6
6
  export type { PackageManagerAdapter, TestDefinition, TestContext, CliOptions } from './types';
package/build/types.d.ts CHANGED
@@ -46,8 +46,8 @@ export type TestDefinition = {
46
46
  export interface PackageManagerAdapter {
47
47
  /** Display name, e.g. "npm@10" */
48
48
  name: string;
49
- /** Package manager type: npm, pnpm, yarn-classic, yarn-modern */
50
- type: 'npm' | 'pnpm' | 'yarn-classic' | 'yarn-modern';
49
+ /** Package manager type: npm, pnpm, yarn-classic, yarn-modern, bun, deno */
50
+ type: 'npm' | 'pnpm' | 'yarn-classic' | 'yarn-modern' | 'bun' | 'deno';
51
51
  /** Resolved path to the binary */
52
52
  bin: string;
53
53
  /** Commands this PM supports */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/e2e-cli",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "CLI tool to run Verdaccio e2e tests against any running registry",