@verdaccio/e2e-cli 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/adapters/index.d.ts +2 -0
- package/build/adapters/nub.d.ts +2 -0
- package/build/adapters/upm.d.ts +2 -0
- package/build/cjs/adapters/index.cjs +4 -0
- package/build/cjs/adapters/nub.cjs +67 -0
- package/build/cjs/adapters/nub.cjs.map +1 -0
- package/build/cjs/adapters/upm.cjs +65 -0
- package/build/cjs/adapters/upm.cjs.map +1 -0
- package/build/cjs/index.cjs +9 -2
- package/build/cjs/index.cjs.map +1 -1
- package/build/cjs/scenarios/index.cjs +4 -1
- package/build/cjs/scenarios/index.cjs.map +1 -1
- package/build/cjs/scenarios/reserved-names.cjs +88 -0
- package/build/cjs/scenarios/reserved-names.cjs.map +1 -0
- package/build/cjs/tests/dist-tags.cjs +12 -0
- package/build/cjs/tests/dist-tags.cjs.map +1 -1
- package/build/cjs/tests/index.cjs +4 -0
- package/build/cjs/tests/index.cjs.map +1 -1
- package/build/cjs/tests/package-names.cjs +47 -0
- package/build/cjs/tests/package-names.cjs.map +1 -0
- package/build/cjs/utils/e2e-config.cjs +9 -2
- package/build/cjs/utils/e2e-config.cjs.map +1 -1
- package/build/cjs/utils/mock-uplink.cjs +4 -3
- package/build/cjs/utils/mock-uplink.cjs.map +1 -1
- package/build/esm/adapters/index.js +3 -1
- package/build/esm/adapters/nub.js +65 -0
- package/build/esm/adapters/nub.js.map +1 -0
- package/build/esm/adapters/upm.js +63 -0
- package/build/esm/adapters/upm.js.map +1 -0
- package/build/esm/index.js +8 -3
- package/build/esm/index.js.map +1 -1
- package/build/esm/scenarios/index.js +4 -2
- package/build/esm/scenarios/index.js.map +1 -1
- package/build/esm/scenarios/reserved-names.js +86 -0
- package/build/esm/scenarios/reserved-names.js.map +1 -0
- package/build/esm/tests/dist-tags.js +12 -0
- package/build/esm/tests/dist-tags.js.map +1 -1
- package/build/esm/tests/index.js +4 -1
- package/build/esm/tests/index.js.map +1 -1
- package/build/esm/tests/package-names.js +45 -0
- package/build/esm/tests/package-names.js.map +1 -0
- package/build/esm/utils/e2e-config.js +9 -2
- package/build/esm/utils/e2e-config.js.map +1 -1
- package/build/esm/utils/mock-uplink.js +4 -3
- package/build/esm/utils/mock-uplink.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/scenarios/index.d.ts +2 -1
- package/build/scenarios/reserved-names.d.ts +2 -0
- package/build/tests/index.d.ts +3 -2
- package/build/tests/package-names.d.ts +2 -0
- package/build/types.d.ts +2 -2
- package/build/utils/e2e-config.d.ts +3 -2
- package/build/utils/mock-uplink.d.ts +2 -2
- package/package.json +1 -1
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
*
|
|
7
7
|
* - max_body_size raised so scenario:tarballs can publish ~30 MB packages
|
|
8
8
|
* (Verdaccio's default is 10mb)
|
|
9
|
-
* - an `e2emock` uplink + `e2e-uplink
|
|
10
|
-
* uplink server that scenario:uplink-failure
|
|
9
|
+
* - an `e2emock` uplink + `e2e-uplink-*`, `nul.*` and `@e2e-uplink/*` package
|
|
10
|
+
* patterns wired to the mock uplink server that scenario:uplink-failure and
|
|
11
|
+
* scenario:reserved-names start on E2E_UPLINK_PORT
|
|
11
12
|
* (short timeout so the "slow uplink" case completes quickly; high
|
|
12
13
|
* max_fails so simulated failures don't trip the circuit breaker for
|
|
13
14
|
* later sub-tests)
|
|
@@ -41,6 +42,12 @@ packages:
|
|
|
41
42
|
'e2e-uplink-*':
|
|
42
43
|
access: $all
|
|
43
44
|
proxy: e2emock
|
|
45
|
+
'nul.*':
|
|
46
|
+
access: $all
|
|
47
|
+
proxy: e2emock
|
|
48
|
+
'@e2e-uplink/*':
|
|
49
|
+
access: $all
|
|
50
|
+
proxy: e2emock
|
|
44
51
|
'@*/*':
|
|
45
52
|
access: $all
|
|
46
53
|
publish: $authenticated
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"e2e-config.cjs","names":[],"sources":["../../../src/utils/e2e-config.ts"],"sourcesContent":["/**\n * Recommended Verdaccio config for running the full e2e-cli battery,\n * printed by `verdaccio-e2e --print-config`. It is what the consuming repos'\n * CI jobs and scripts/run-e2e.sh feed to `verdaccio --config`:\n *\n * - max_body_size raised so scenario:tarballs can publish ~30 MB packages\n * (Verdaccio's default is 10mb)\n * - an `e2emock` uplink + `e2e-uplink
|
|
1
|
+
{"version":3,"file":"e2e-config.cjs","names":[],"sources":["../../../src/utils/e2e-config.ts"],"sourcesContent":["/**\n * Recommended Verdaccio config for running the full e2e-cli battery,\n * printed by `verdaccio-e2e --print-config`. It is what the consuming repos'\n * CI jobs and scripts/run-e2e.sh feed to `verdaccio --config`:\n *\n * - max_body_size raised so scenario:tarballs can publish ~30 MB packages\n * (Verdaccio's default is 10mb)\n * - an `e2emock` uplink + `e2e-uplink-*`, `nul.*` and `@e2e-uplink/*` package\n * patterns wired to the mock uplink server that scenario:uplink-failure and\n * scenario:reserved-names start on E2E_UPLINK_PORT\n * (short timeout so the \"slow uplink\" case completes quickly; high\n * max_fails so simulated failures don't trip the circuit breaker for\n * later sub-tests)\n * - NO npmjs uplink: the whole suite publishes every package it consumes,\n * so the registry under test never talks to the outside world and the\n * battery runs fully offline (and deterministically in CI)\n *\n * Relative paths (storage/htpasswd) resolve next to the config file, so write\n * it into a disposable directory.\n */\nexport const DEFAULT_UPLINK_PORT = 4874;\n\nexport function buildE2EConfig(uplinkPort: number = DEFAULT_UPLINK_PORT): string {\n return `# Generated by @verdaccio/e2e-cli --print-config\nstorage: ./storage\nauth:\n htpasswd:\n file: ./htpasswd\n max_users: 1000\nweb:\n enable: true\n title: Verdaccio E2E\nmax_body_size: 100mb\nuplinks:\n e2emock:\n url: http://localhost:${uplinkPort}/\n timeout: 3s\n retry: 0\n max_fails: 100\n fail_timeout: 1s\npackages:\n 'e2e-uplink-*':\n access: $all\n proxy: e2emock\n 'nul.*':\n access: $all\n proxy: e2emock\n '@e2e-uplink/*':\n access: $all\n proxy: e2emock\n '@*/*':\n access: $all\n publish: $authenticated\n unpublish: $authenticated\n '**':\n access: $all\n publish: $authenticated\n unpublish: $authenticated\nlog: { type: stdout, format: pretty, level: warn }\n`;\n}\n\n/**\n * Recommended pnpr config for the same battery, printed by\n * `verdaccio-e2e --print-config --server pnpr`. pnpr's config is\n * verdaccio-shaped but routes through a `registries:` block instead of a\n * global `packages:` map (which pnpr rejects loudly):\n *\n * - one hosted registry claiming every name (`**`), publish open to\n * authenticated users (pnpr's default) and unpublish loosened to match\n * the verdaccio battery config\n * - no `e2emock` uplink: pnpr registry namespaces only accept exact\n * names, scope wildcards or `**`, so the unscoped dynamic\n * `e2e-uplink-*` names can't be routed to the mock uplink. Run pnpr\n * without --uplink-port and scenario:uplink-failure (plus the uplink\n * search sub-tests) skip, exactly like docker mode.\n * - no max_body_size knob: pnpr's publish body limit is a fixed 100 MB,\n * already above what scenario:tarballs needs\n */\nexport function buildPnprE2EConfig(): string {\n return `# Generated by @verdaccio/e2e-cli --print-config --server pnpr\nstorage: ./storage\nauth:\n htpasswd:\n file: ./htpasswd\n max_users: 1000\nregistries:\n local:\n type: hosted\n access: $all\n packages:\n '**': { unpublish: $authenticated }\ndefaultRegistry: local\nlog: { type: stdout, format: pretty, level: warn }\n`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,sBAAsB;AAEnC,SAAgB,eAAe,aAAqB,qBAA6B;CAC/E,OAAO;;;;;;;;;;;;4BAYmB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;AAyBvC;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,qBAA6B;CAC3C,OAAO;;;;;;;;;;;;;;;AAeT"}
|
|
@@ -23,9 +23,9 @@ var MockUplink = class {
|
|
|
23
23
|
constructor(port) {
|
|
24
24
|
this.port = port;
|
|
25
25
|
}
|
|
26
|
-
/** Register a package served by this uplink; tarball is random (incompressible) bytes. */
|
|
26
|
+
/** Register a package served by this uplink; tarball is random (incompressible) bytes unless one is given. */
|
|
27
27
|
addPackage(name, tarballBytes = 65536) {
|
|
28
|
-
const tarball = (0, crypto.randomBytes)(tarballBytes);
|
|
28
|
+
const tarball = Buffer.isBuffer(tarballBytes) ? tarballBytes : (0, crypto.randomBytes)(tarballBytes);
|
|
29
29
|
const { shasum, integrity } = require_http_client.computeDist(tarball);
|
|
30
30
|
const pkg = {
|
|
31
31
|
name,
|
|
@@ -85,7 +85,8 @@ var MockUplink = class {
|
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
87
|
packument(pkg) {
|
|
88
|
-
const
|
|
88
|
+
const filename = `${pkg.name.split("/").pop()}-${pkg.version}.tgz`;
|
|
89
|
+
const tarballUrl = `http://localhost:${this.port}/${pkg.name}/-/${filename}`;
|
|
89
90
|
return JSON.stringify({
|
|
90
91
|
name: pkg.name,
|
|
91
92
|
"dist-tags": { latest: pkg.version },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-uplink.cjs","names":[],"sources":["../../../src/utils/mock-uplink.ts"],"sourcesContent":["import { randomBytes } from 'crypto';\nimport buildDebug from 'debug';\nimport { Server, createServer } from 'http';\n\nimport { computeDist } from './http-client';\n\nconst debug = buildDebug('verdaccio:e2e-cli:mock-uplink');\n\nexport type UplinkMode =\n /** Serve packuments and tarballs normally */\n | 'ok'\n /** Send tarball headers + half the body, then destroy the socket */\n | 'drop-mid-stream'\n /** Delay every response long enough to trip the registry's uplink timeout */\n | 'slow'\n /** Respond 500 to everything */\n | 'error-500';\n\ntype MockPackage = {\n name: string;\n version: string;\n tarball: Buffer;\n shasum: string;\n integrity: string;\n};\n\n/**\n * Minimal controllable npm uplink used by scenario:uplink-failure.\n *\n * The registry under test is configured (see --print-config) to proxy the\n * `e2e-uplink-*` package pattern to this server, so the scenario can flip the\n * uplink between healthy, dropping connections mid-tarball, slow, and down.\n */\nexport class MockUplink {\n public mode: UplinkMode = 'ok';\n public requests: string[] = [];\n private server?: Server;\n private packages = new Map<string, MockPackage>();\n private searchResults: { name: string; version: string }[] = [];\n\n constructor(public readonly port: number) {}\n\n /** Register a package served by this uplink; tarball is random (incompressible) bytes. */\n addPackage(name: string, tarballBytes = 64 * 1024): MockPackage {\n const tarball = randomBytes(tarballBytes);\n const { shasum, integrity } = computeDist(tarball);\n const pkg: MockPackage = { name, version: '1.0.0', tarball, shasum, integrity };\n this.packages.set(name, pkg);\n return pkg;\n }\n\n /** Register a result served by the /-/v1/search endpoint. */\n addSearchResult(name: string, version = '1.0.0'): void {\n this.searchResults.push({ name, version });\n }\n\n /**\n * npmjs-faithful /-/v1/search: filters by `text` substring, applies\n * `from`/`size` itself (like registry.npmjs.org does) and reports the real\n * `total` of matches. Mimicking the upstream offsetting is what exposes\n * double pagination in the registry under test.\n */\n private searchResponse(url: URL): string {\n const text = url.searchParams.get('text') ?? '';\n const from = Math.max(0, parseInt(url.searchParams.get('from') ?? '0', 10) || 0);\n const size = Math.max(0, parseInt(url.searchParams.get('size') ?? '20', 10) || 20);\n const matches = this.searchResults.filter((r) => r.name.includes(text));\n const page = matches.slice(from, from + size);\n return JSON.stringify({\n objects: page.map((r) => ({\n package: {\n name: r.name,\n version: r.version,\n description: 'mock uplink search result',\n date: '2020-01-01T00:00:00.000Z',\n maintainers: [{ username: 'mock-uplink', email: 'mock@example.org' }],\n links: { npm: `http://localhost:${this.port}/${r.name}` },\n },\n score: { final: 1, detail: { quality: 1, popularity: 1, maintenance: 1 } },\n searchScore: 1,\n flags: {},\n })),\n total: matches.length,\n time: new Date('2020-01-01T00:00:00.000Z').toISOString(),\n });\n }\n\n private packument(pkg: MockPackage): string {\n const tarballUrl = `http://localhost:${this.port}/${pkg.name}/-/${pkg.name}-${pkg.version}.tgz`;\n return JSON.stringify({\n name: pkg.name,\n 'dist-tags': { latest: pkg.version },\n versions: {\n [pkg.version]: {\n name: pkg.name,\n version: pkg.version,\n description: 'mock uplink package',\n dist: { tarball: tarballUrl, shasum: pkg.shasum, integrity: pkg.integrity },\n },\n },\n time: {\n created: '2020-01-01T00:00:00.000Z',\n modified: '2020-01-01T00:00:00.000Z',\n [pkg.version]: '2020-01-01T00:00:00.000Z',\n },\n });\n }\n\n start(): Promise<void> {\n this.server = createServer((req, res) => {\n const url = req.url || '';\n this.requests.push(url);\n debug('mock uplink %s %s (mode: %s)', req.method, url, this.mode);\n\n const respond = () => {\n if (this.mode === 'error-500') {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'mock uplink internal error' }));\n return;\n }\n\n // Search route: /-/v1/search?text=...&from=...&size=...\n if (url.startsWith('/-/v1/search')) {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(this.searchResponse(new URL(url, `http://localhost:${this.port}`)));\n return;\n }\n\n // Tarball route: /<name>/-/<file>.tgz — parsed without a regex to\n // avoid backtracking on untrusted input (CodeQL js/polynomial-redos).\n const tarballSep = url.indexOf('/-/');\n if (tarballSep > 0 && url.endsWith('.tgz')) {\n const pkg = this.packages.get(decodeURIComponent(url.slice(1, tarballSep)));\n if (!pkg) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'not found' }));\n return;\n }\n if (this.mode === 'drop-mid-stream') {\n res.writeHead(200, {\n 'Content-Type': 'application/octet-stream',\n 'Content-Length': String(pkg.tarball.length),\n });\n res.write(pkg.tarball.subarray(0, Math.floor(pkg.tarball.length / 2)));\n // Kill the connection before the body completes.\n setTimeout(() => res.socket?.destroy(), 50);\n return;\n }\n res.writeHead(200, {\n 'Content-Type': 'application/octet-stream',\n 'Content-Length': String(pkg.tarball.length),\n });\n res.end(pkg.tarball);\n return;\n }\n\n // Packument route: /<name>\n const pkg = this.packages.get(decodeURIComponent(url.slice(1)));\n if (!pkg) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'not found' }));\n return;\n }\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(this.packument(pkg));\n };\n\n // The registry (or a stopped server) may have torn the socket down by the\n // time a delayed response fires — never let that crash the mock.\n const safeRespond = () => {\n try {\n respond();\n } catch (err) {\n debug('mock uplink response failed (socket gone?): %s', err);\n }\n };\n\n if (this.mode === 'slow') {\n // Longer than the uplink timeout configured for the e2e registry (3s).\n const timer = setTimeout(safeRespond, 10_000);\n res.socket?.once('close', () => clearTimeout(timer));\n } else {\n safeRespond();\n }\n });\n\n return new Promise((resolve, reject) => {\n this.server!.once('error', reject);\n this.server!.listen(this.port, () => {\n debug('mock uplink listening on %d', this.port);\n resolve();\n });\n });\n }\n\n stop(): Promise<void> {\n return new Promise((resolve) => {\n if (!this.server) {\n resolve();\n return;\n }\n // closeAllConnections drops keep-alive sockets so close() completes.\n this.server.closeAllConnections?.();\n this.server.close(() => {\n debug('mock uplink stopped');\n this.server = undefined;\n resolve();\n });\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mock-uplink.cjs","names":[],"sources":["../../../src/utils/mock-uplink.ts"],"sourcesContent":["import { randomBytes } from 'crypto';\nimport buildDebug from 'debug';\nimport { Server, createServer } from 'http';\n\nimport { computeDist } from './http-client';\n\nconst debug = buildDebug('verdaccio:e2e-cli:mock-uplink');\n\nexport type UplinkMode =\n /** Serve packuments and tarballs normally */\n | 'ok'\n /** Send tarball headers + half the body, then destroy the socket */\n | 'drop-mid-stream'\n /** Delay every response long enough to trip the registry's uplink timeout */\n | 'slow'\n /** Respond 500 to everything */\n | 'error-500';\n\ntype MockPackage = {\n name: string;\n version: string;\n tarball: Buffer;\n shasum: string;\n integrity: string;\n};\n\n/**\n * Minimal controllable npm uplink used by scenario:uplink-failure.\n *\n * The registry under test is configured (see --print-config) to proxy the\n * `e2e-uplink-*` package pattern to this server, so the scenario can flip the\n * uplink between healthy, dropping connections mid-tarball, slow, and down.\n */\nexport class MockUplink {\n public mode: UplinkMode = 'ok';\n public requests: string[] = [];\n private server?: Server;\n private packages = new Map<string, MockPackage>();\n private searchResults: { name: string; version: string }[] = [];\n\n constructor(public readonly port: number) {}\n\n /** Register a package served by this uplink; tarball is random (incompressible) bytes unless one is given. */\n addPackage(name: string, tarballBytes: number | Buffer = 64 * 1024): MockPackage {\n const tarball = Buffer.isBuffer(tarballBytes) ? tarballBytes : randomBytes(tarballBytes);\n const { shasum, integrity } = computeDist(tarball);\n const pkg: MockPackage = { name, version: '1.0.0', tarball, shasum, integrity };\n this.packages.set(name, pkg);\n return pkg;\n }\n\n /** Register a result served by the /-/v1/search endpoint. */\n addSearchResult(name: string, version = '1.0.0'): void {\n this.searchResults.push({ name, version });\n }\n\n /**\n * npmjs-faithful /-/v1/search: filters by `text` substring, applies\n * `from`/`size` itself (like registry.npmjs.org does) and reports the real\n * `total` of matches. Mimicking the upstream offsetting is what exposes\n * double pagination in the registry under test.\n */\n private searchResponse(url: URL): string {\n const text = url.searchParams.get('text') ?? '';\n const from = Math.max(0, parseInt(url.searchParams.get('from') ?? '0', 10) || 0);\n const size = Math.max(0, parseInt(url.searchParams.get('size') ?? '20', 10) || 20);\n const matches = this.searchResults.filter((r) => r.name.includes(text));\n const page = matches.slice(from, from + size);\n return JSON.stringify({\n objects: page.map((r) => ({\n package: {\n name: r.name,\n version: r.version,\n description: 'mock uplink search result',\n date: '2020-01-01T00:00:00.000Z',\n maintainers: [{ username: 'mock-uplink', email: 'mock@example.org' }],\n links: { npm: `http://localhost:${this.port}/${r.name}` },\n },\n score: { final: 1, detail: { quality: 1, popularity: 1, maintenance: 1 } },\n searchScore: 1,\n flags: {},\n })),\n total: matches.length,\n time: new Date('2020-01-01T00:00:00.000Z').toISOString(),\n });\n }\n\n private packument(pkg: MockPackage): string {\n const filename = `${pkg.name.split('/').pop()}-${pkg.version}.tgz`;\n const tarballUrl = `http://localhost:${this.port}/${pkg.name}/-/${filename}`;\n return JSON.stringify({\n name: pkg.name,\n 'dist-tags': { latest: pkg.version },\n versions: {\n [pkg.version]: {\n name: pkg.name,\n version: pkg.version,\n description: 'mock uplink package',\n dist: { tarball: tarballUrl, shasum: pkg.shasum, integrity: pkg.integrity },\n },\n },\n time: {\n created: '2020-01-01T00:00:00.000Z',\n modified: '2020-01-01T00:00:00.000Z',\n [pkg.version]: '2020-01-01T00:00:00.000Z',\n },\n });\n }\n\n start(): Promise<void> {\n this.server = createServer((req, res) => {\n const url = req.url || '';\n this.requests.push(url);\n debug('mock uplink %s %s (mode: %s)', req.method, url, this.mode);\n\n const respond = () => {\n if (this.mode === 'error-500') {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'mock uplink internal error' }));\n return;\n }\n\n // Search route: /-/v1/search?text=...&from=...&size=...\n if (url.startsWith('/-/v1/search')) {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(this.searchResponse(new URL(url, `http://localhost:${this.port}`)));\n return;\n }\n\n // Tarball route: /<name>/-/<file>.tgz — parsed without a regex to\n // avoid backtracking on untrusted input (CodeQL js/polynomial-redos).\n const tarballSep = url.indexOf('/-/');\n if (tarballSep > 0 && url.endsWith('.tgz')) {\n const pkg = this.packages.get(decodeURIComponent(url.slice(1, tarballSep)));\n if (!pkg) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'not found' }));\n return;\n }\n if (this.mode === 'drop-mid-stream') {\n res.writeHead(200, {\n 'Content-Type': 'application/octet-stream',\n 'Content-Length': String(pkg.tarball.length),\n });\n res.write(pkg.tarball.subarray(0, Math.floor(pkg.tarball.length / 2)));\n // Kill the connection before the body completes.\n setTimeout(() => res.socket?.destroy(), 50);\n return;\n }\n res.writeHead(200, {\n 'Content-Type': 'application/octet-stream',\n 'Content-Length': String(pkg.tarball.length),\n });\n res.end(pkg.tarball);\n return;\n }\n\n // Packument route: /<name>\n const pkg = this.packages.get(decodeURIComponent(url.slice(1)));\n if (!pkg) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'not found' }));\n return;\n }\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(this.packument(pkg));\n };\n\n // The registry (or a stopped server) may have torn the socket down by the\n // time a delayed response fires — never let that crash the mock.\n const safeRespond = () => {\n try {\n respond();\n } catch (err) {\n debug('mock uplink response failed (socket gone?): %s', err);\n }\n };\n\n if (this.mode === 'slow') {\n // Longer than the uplink timeout configured for the e2e registry (3s).\n const timer = setTimeout(safeRespond, 10_000);\n res.socket?.once('close', () => clearTimeout(timer));\n } else {\n safeRespond();\n }\n });\n\n return new Promise((resolve, reject) => {\n this.server!.once('error', reject);\n this.server!.listen(this.port, () => {\n debug('mock uplink listening on %d', this.port);\n resolve();\n });\n });\n }\n\n stop(): Promise<void> {\n return new Promise((resolve) => {\n if (!this.server) {\n resolve();\n return;\n }\n // closeAllConnections drops keep-alive sockets so close() completes.\n this.server.closeAllConnections?.();\n this.server.close(() => {\n debug('mock uplink stopped');\n this.server = undefined;\n resolve();\n });\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createBunAdapter } from "./bun.js";
|
|
2
2
|
import { createDenoAdapter } from "./deno.js";
|
|
3
3
|
import { createNpmAdapter } from "./npm.js";
|
|
4
|
+
import { createNubAdapter } from "./nub.js";
|
|
4
5
|
import { createPnpmAdapter } from "./pnpm.js";
|
|
6
|
+
import { createUpmAdapter } from "./upm.js";
|
|
5
7
|
import { createYarnModernAdapter } from "./yarn-modern.js";
|
|
6
|
-
export { createBunAdapter, createDenoAdapter, createNpmAdapter, createPnpmAdapter, createYarnModernAdapter };
|
|
8
|
+
export { createBunAdapter, createDenoAdapter, createNpmAdapter, createNubAdapter, createPnpmAdapter, createUpmAdapter, createYarnModernAdapter };
|
|
@@ -0,0 +1,65 @@
|
|
|
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/nub.ts
|
|
6
|
+
var debug = buildDebug("verdaccio:e2e-cli:nub");
|
|
7
|
+
var NUB_SUPPORTED_COMMANDS = /* @__PURE__ */ new Set(["install", "ci"]);
|
|
8
|
+
function detectVersion(bin) {
|
|
9
|
+
try {
|
|
10
|
+
return execSync(`${bin} --version`, {
|
|
11
|
+
encoding: "utf8",
|
|
12
|
+
timeout: 5e3
|
|
13
|
+
}).trim();
|
|
14
|
+
} catch {
|
|
15
|
+
return "unknown";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function installNub(version) {
|
|
19
|
+
const pkg = `@nubjs/nub@${version}`;
|
|
20
|
+
debug("installing %s into temp dir", pkg);
|
|
21
|
+
const tmpDir = execSync("mktemp -d", { encoding: "utf8" }).trim();
|
|
22
|
+
execSync(`npm install --prefix "${tmpDir}" ${pkg} --loglevel=error`, {
|
|
23
|
+
encoding: "utf8",
|
|
24
|
+
timeout: 3e4
|
|
25
|
+
});
|
|
26
|
+
const bin = `${tmpDir}/node_modules/.bin/nub`;
|
|
27
|
+
const installed = detectVersion(bin);
|
|
28
|
+
debug("installed nub %s at %s", installed, bin);
|
|
29
|
+
console.log(` Auto-installed nub ${installed}`);
|
|
30
|
+
return bin;
|
|
31
|
+
}
|
|
32
|
+
function resolveNubBin(binPath, version) {
|
|
33
|
+
if (binPath) return binPath;
|
|
34
|
+
if (version) return installNub(version);
|
|
35
|
+
return "nub";
|
|
36
|
+
}
|
|
37
|
+
function createNubAdapter(binPath, version) {
|
|
38
|
+
const bin = resolveNubBin(binPath, version);
|
|
39
|
+
const resolved = detectVersion(bin);
|
|
40
|
+
debug("creating nub adapter with bin: %s (%s)", bin, resolved);
|
|
41
|
+
return {
|
|
42
|
+
name: `nub@${resolved}`,
|
|
43
|
+
type: "nub",
|
|
44
|
+
bin,
|
|
45
|
+
supports: NUB_SUPPORTED_COMMANDS,
|
|
46
|
+
registryArg(_url) {
|
|
47
|
+
return [];
|
|
48
|
+
},
|
|
49
|
+
prefixArg(folder) {
|
|
50
|
+
return ["--dir", folder];
|
|
51
|
+
},
|
|
52
|
+
exec(options, ...args) {
|
|
53
|
+
const cmd = args[0];
|
|
54
|
+
if (cmd === "install" || cmd === "ci") args = [...args, "--minimum-release-age=0"];
|
|
55
|
+
return exec(options, bin, args);
|
|
56
|
+
},
|
|
57
|
+
async prepareProject(packageName, version, registryUrl, port, token, dependencies = {}, devDependencies = {}) {
|
|
58
|
+
return prepareGenericEmptyProject(packageName, version, port, token, registryUrl, dependencies, devDependencies);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { createNubAdapter };
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=nub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nub.js","names":[],"sources":["../../../src/adapters/nub.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:nub');\n\n// nub (https://nubjs.com, package @nubjs/nub) is an all-in-one Node.js toolkit\n// whose package-manager side only covers the install path (install, ci, add,\n// remove, update, dedupe) — it has no publish/info/audit/etc. So the suite\n// exercises just install and ci.\nconst NUB_SUPPORTED_COMMANDS = new Set(['install', 'ci']);\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 installNub(version: string): string {\n const pkg = `@nubjs/nub@${version}`;\n debug('installing %s into temp dir', pkg);\n const tmpDir = execSync('mktemp -d', { encoding: 'utf8' }).trim();\n execSync(`npm install --prefix \"${tmpDir}\" ${pkg} --loglevel=error`, {\n encoding: 'utf8',\n timeout: 30000,\n });\n const bin = `${tmpDir}/node_modules/.bin/nub`;\n const installed = detectVersion(bin);\n debug('installed nub %s at %s', installed, bin);\n console.log(` Auto-installed nub ${installed}`);\n return bin;\n}\n\nfunction resolveNubBin(binPath?: string, version?: string): string {\n if (binPath) return binPath;\n if (version) return installNub(version);\n return 'nub';\n}\n\nexport function createNubAdapter(binPath?: string, version?: string): PackageManagerAdapter {\n const bin = resolveNubBin(binPath, version);\n const resolved = detectVersion(bin);\n debug('creating nub adapter with bin: %s (%s)', bin, resolved);\n\n const adapter: PackageManagerAdapter = {\n name: `nub@${resolved}`,\n type: 'nub',\n bin,\n supports: NUB_SUPPORTED_COMMANDS,\n\n registryArg(_url: string): string[] {\n // nub reads registry and _authToken from the .npmrc cascade written by\n // prepareProject, so no CLI flag is needed.\n return [];\n },\n\n prefixArg(folder: string): string[] {\n return ['--dir', folder];\n },\n\n exec(options: SpawnOptions, ...args: string[]): Promise<ExecOutput> {\n // nub enforces a strict 24h `minimumReleaseAge` by default and reads it\n // under the pnpm-style key, not npm's `min-release-age` that the harness\n // .npmrc sets. Disable it explicitly on install/ci so the just-published\n // fixtures (age ~0) resolve.\n const cmd = args[0];\n if (cmd === 'install' || cmd === 'ci') {\n args = [...args, '--minimum-release-age=0'];\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,uBAAuB;AAMhD,IAAM,yCAAyB,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC;AAExD,SAAS,cAAc,KAAqB;CAC1C,IAAI;EACF,OAAO,SAAS,GAAG,IAAI,aAAa;GAAE,UAAU;GAAQ,SAAS;EAAK,CAAC,CAAC,CAAC,KAAK;CAChF,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,WAAW,SAAyB;CAC3C,MAAM,MAAM,cAAc;CAC1B,MAAM,+BAA+B,GAAG;CACxC,MAAM,SAAS,SAAS,aAAa,EAAE,UAAU,OAAO,CAAC,CAAC,CAAC,KAAK;CAChE,SAAS,yBAAyB,OAAO,IAAI,IAAI,oBAAoB;EACnE,UAAU;EACV,SAAS;CACX,CAAC;CACD,MAAM,MAAM,GAAG,OAAO;CACtB,MAAM,YAAY,cAAc,GAAG;CACnC,MAAM,0BAA0B,WAAW,GAAG;CAC9C,QAAQ,IAAI,wBAAwB,WAAW;CAC/C,OAAO;AACT;AAEA,SAAS,cAAc,SAAkB,SAA0B;CACjE,IAAI,SAAS,OAAO;CACpB,IAAI,SAAS,OAAO,WAAW,OAAO;CACtC,OAAO;AACT;AAEA,SAAgB,iBAAiB,SAAkB,SAAyC;CAC1F,MAAM,MAAM,cAAc,SAAS,OAAO;CAC1C,MAAM,WAAW,cAAc,GAAG;CAClC,MAAM,0CAA0C,KAAK,QAAQ;CAmD7D,OAAO;EAhDL,MAAM,OAAO;EACb,MAAM;EACN;EACA,UAAU;EAEV,YAAY,MAAwB;GAGlC,OAAO,CAAC;EACV;EAEA,UAAU,QAA0B;GAClC,OAAO,CAAC,SAAS,MAAM;EACzB;EAEA,KAAK,SAAuB,GAAG,MAAqC;GAKlE,MAAM,MAAM,KAAK;GACjB,IAAI,QAAQ,aAAa,QAAQ,MAC/B,OAAO,CAAC,GAAG,MAAM,yBAAyB;GAE5C,OAAO,KAAK,SAAS,KAAK,IAAI;EAChC;EAEA,MAAM,eACJ,aACA,SACA,aACA,MACA,OACA,eAAuC,CAAC,GACxC,kBAA0C,CAAC,GACV;GACjC,OAAO,2BACL,aACA,SACA,MACA,OACA,aACA,cACA,eACF;EACF;CAGK;AACT"}
|
|
@@ -0,0 +1,63 @@
|
|
|
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/upm.ts
|
|
6
|
+
var debug = buildDebug("verdaccio:e2e-cli:upm");
|
|
7
|
+
var UPM_SUPPORTED_COMMANDS = /* @__PURE__ */ new Set(["install", "ci"]);
|
|
8
|
+
function detectVersion(bin) {
|
|
9
|
+
try {
|
|
10
|
+
return execSync(`${bin} --version`, {
|
|
11
|
+
encoding: "utf8",
|
|
12
|
+
timeout: 5e3
|
|
13
|
+
}).trim();
|
|
14
|
+
} catch {
|
|
15
|
+
return "unknown";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function installUpm(version) {
|
|
19
|
+
const pkg = `upm@${version}`;
|
|
20
|
+
debug("installing %s into temp dir", pkg);
|
|
21
|
+
const tmpDir = execSync("mktemp -d", { encoding: "utf8" }).trim();
|
|
22
|
+
execSync(`npm install --prefix "${tmpDir}" ${pkg} --loglevel=error`, {
|
|
23
|
+
encoding: "utf8",
|
|
24
|
+
timeout: 3e4
|
|
25
|
+
});
|
|
26
|
+
const bin = `${tmpDir}/node_modules/.bin/upm`;
|
|
27
|
+
const installed = detectVersion(bin);
|
|
28
|
+
debug("installed upm %s at %s", installed, bin);
|
|
29
|
+
console.log(` Auto-installed upm ${installed}`);
|
|
30
|
+
return bin;
|
|
31
|
+
}
|
|
32
|
+
function resolveUpmBin(binPath, version) {
|
|
33
|
+
if (binPath) return binPath;
|
|
34
|
+
if (version) return installUpm(version);
|
|
35
|
+
return "upm";
|
|
36
|
+
}
|
|
37
|
+
function createUpmAdapter(binPath, version) {
|
|
38
|
+
const bin = resolveUpmBin(binPath, version);
|
|
39
|
+
const resolved = detectVersion(bin);
|
|
40
|
+
debug("creating upm adapter with bin: %s (%s)", bin, resolved);
|
|
41
|
+
return {
|
|
42
|
+
name: `upm@${resolved}`,
|
|
43
|
+
type: "upm",
|
|
44
|
+
bin,
|
|
45
|
+
supports: UPM_SUPPORTED_COMMANDS,
|
|
46
|
+
registryArg(_url) {
|
|
47
|
+
return [];
|
|
48
|
+
},
|
|
49
|
+
prefixArg(folder) {
|
|
50
|
+
return ["--dir", folder];
|
|
51
|
+
},
|
|
52
|
+
exec(options, ...args) {
|
|
53
|
+
return exec(options, bin, args);
|
|
54
|
+
},
|
|
55
|
+
async prepareProject(packageName, version, registryUrl, port, token, dependencies = {}, devDependencies = {}) {
|
|
56
|
+
return prepareGenericEmptyProject(packageName, version, port, token, registryUrl, dependencies, devDependencies);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { createUpmAdapter };
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=upm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upm.js","names":[],"sources":["../../../src/adapters/upm.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:upm');\n\n// upm (https://upm.sh) proxies most commands straight to npm (publish, info,\n// deprecate, dist-tag, ping, search, unpublish…). Only its resolver/installer\n// is upm's own code, so the suite exercises just those native commands.\nconst UPM_SUPPORTED_COMMANDS = new Set(['install', 'ci']);\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 installUpm(version: string): string {\n const pkg = `upm@${version}`;\n debug('installing %s into temp dir', pkg);\n const tmpDir = execSync('mktemp -d', { encoding: 'utf8' }).trim();\n execSync(`npm install --prefix \"${tmpDir}\" ${pkg} --loglevel=error`, {\n encoding: 'utf8',\n timeout: 30000,\n });\n const bin = `${tmpDir}/node_modules/.bin/upm`;\n const installed = detectVersion(bin);\n debug('installed upm %s at %s', installed, bin);\n console.log(` Auto-installed upm ${installed}`);\n return bin;\n}\n\nfunction resolveUpmBin(binPath?: string, version?: string): string {\n if (binPath) return binPath;\n if (version) return installUpm(version);\n return 'upm';\n}\n\nexport function createUpmAdapter(binPath?: string, version?: string): PackageManagerAdapter {\n const bin = resolveUpmBin(binPath, version);\n const resolved = detectVersion(bin);\n debug('creating upm adapter with bin: %s (%s)', bin, resolved);\n\n const adapter: PackageManagerAdapter = {\n name: `upm@${resolved}`,\n type: 'upm',\n bin,\n supports: UPM_SUPPORTED_COMMANDS,\n\n registryArg(_url: string): string[] {\n // upm reads registry, _authToken and min-release-age from .npmrc (written\n // by prepareProject). min-release-age=0 is essential: upm holds back\n // versions younger than a day by default, which would reject the\n // just-published fixtures the suite installs.\n return [];\n },\n\n prefixArg(folder: string): string[] {\n return ['--dir', folder];\n },\n\n exec(options: SpawnOptions, ...args: string[]): Promise<ExecOutput> {\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,uBAAuB;AAKhD,IAAM,yCAAyB,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC;AAExD,SAAS,cAAc,KAAqB;CAC1C,IAAI;EACF,OAAO,SAAS,GAAG,IAAI,aAAa;GAAE,UAAU;GAAQ,SAAS;EAAK,CAAC,CAAC,CAAC,KAAK;CAChF,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,WAAW,SAAyB;CAC3C,MAAM,MAAM,OAAO;CACnB,MAAM,+BAA+B,GAAG;CACxC,MAAM,SAAS,SAAS,aAAa,EAAE,UAAU,OAAO,CAAC,CAAC,CAAC,KAAK;CAChE,SAAS,yBAAyB,OAAO,IAAI,IAAI,oBAAoB;EACnE,UAAU;EACV,SAAS;CACX,CAAC;CACD,MAAM,MAAM,GAAG,OAAO;CACtB,MAAM,YAAY,cAAc,GAAG;CACnC,MAAM,0BAA0B,WAAW,GAAG;CAC9C,QAAQ,IAAI,wBAAwB,WAAW;CAC/C,OAAO;AACT;AAEA,SAAS,cAAc,SAAkB,SAA0B;CACjE,IAAI,SAAS,OAAO;CACpB,IAAI,SAAS,OAAO,WAAW,OAAO;CACtC,OAAO;AACT;AAEA,SAAgB,iBAAiB,SAAkB,SAAyC;CAC1F,MAAM,MAAM,cAAc,SAAS,OAAO;CAC1C,MAAM,WAAW,cAAc,GAAG;CAClC,MAAM,0CAA0C,KAAK,QAAQ;CA6C7D,OAAO;EA1CL,MAAM,OAAO;EACb,MAAM;EACN;EACA,UAAU;EAEV,YAAY,MAAwB;GAKlC,OAAO,CAAC;EACV;EAEA,UAAU,QAA0B;GAClC,OAAO,CAAC,SAAS,MAAM;EACzB;EAEA,KAAK,SAAuB,GAAG,MAAqC;GAClE,OAAO,KAAK,SAAS,KAAK,IAAI;EAChC;EAEA,MAAM,eACJ,aACA,SACA,aACA,MACA,OACA,eAAuC,CAAC,GACxC,kBAA0C,CAAC,GACV;GACjC,OAAO,2BACL,aACA,SACA,MACA,OACA,aACA,cACA,eACF;EACF;CAGK;AACT"}
|
package/build/esm/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createBunAdapter } from "./adapters/bun.js";
|
|
2
2
|
import { createDenoAdapter } from "./adapters/deno.js";
|
|
3
3
|
import { createNpmAdapter } from "./adapters/npm.js";
|
|
4
|
+
import { createNubAdapter } from "./adapters/nub.js";
|
|
4
5
|
import { createPnpmAdapter } from "./adapters/pnpm.js";
|
|
6
|
+
import { createUpmAdapter } from "./adapters/upm.js";
|
|
5
7
|
import { createYarnModernAdapter } from "./adapters/yarn-modern.js";
|
|
6
8
|
import "./adapters/index.js";
|
|
7
9
|
import { runAll, runSuite } from "./runner.js";
|
|
@@ -35,7 +37,9 @@ function parseAdapters(pmFilters) {
|
|
|
35
37
|
else if (name === "yarn-modern" || name === "yarn") adapters.push(createYarnModernAdapter(binPath, version));
|
|
36
38
|
else if (name === "bun") adapters.push(createBunAdapter(binPath, version));
|
|
37
39
|
else if (name === "deno") adapters.push(createDenoAdapter(binPath, version));
|
|
38
|
-
else
|
|
40
|
+
else if (name === "upm") adapters.push(createUpmAdapter(binPath, version));
|
|
41
|
+
else if (name === "nub") adapters.push(createNubAdapter(binPath, version));
|
|
42
|
+
else throw new Error(`Unknown package manager: "${name}". Supported: npm, pnpm, yarn-modern, bun, deno, upm, nub`);
|
|
39
43
|
}
|
|
40
44
|
return adapters;
|
|
41
45
|
}
|
|
@@ -94,7 +98,8 @@ function printHelp() {
|
|
|
94
98
|
Options:
|
|
95
99
|
--pm <name[@version]> Package manager to test (can be repeated)
|
|
96
100
|
Supported: npm (10-12), pnpm (10+),
|
|
97
|
-
yarn-modern (or yarn, Yarn 3+), bun, deno
|
|
101
|
+
yarn-modern (or yarn, Yarn 3+), bun, deno,
|
|
102
|
+
upm (install/ci only), nub (install/ci only)
|
|
98
103
|
Examples: --pm npm@10 --pm pnpm@11
|
|
99
104
|
--pm yarn-modern@4
|
|
100
105
|
--pm yarn-modern@3
|
|
@@ -191,6 +196,6 @@ async function main(argv = process.argv) {
|
|
|
191
196
|
process.exit(exitCode);
|
|
192
197
|
}
|
|
193
198
|
//#endregion
|
|
194
|
-
export { allScenarios, allTests, createBunAdapter, createDenoAdapter, createNpmAdapter, createPnpmAdapter, createYarnModernAdapter, main, runAll, runSuite };
|
|
199
|
+
export { allScenarios, allTests, createBunAdapter, createDenoAdapter, createNpmAdapter, createNubAdapter, createPnpmAdapter, createUpmAdapter, createYarnModernAdapter, main, runAll, runSuite };
|
|
195
200
|
|
|
196
201
|
//# sourceMappingURL=index.js.map
|
package/build/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 createYarnModernAdapter,\n} from './adapters';\nimport { runAll } from './runner';\nimport { allTests } from './tests';\nimport { CliOptions, PackageManagerAdapter } from './types';\nimport { createUser, pingRegistry } from './utils/registry-client';\n\nconst debug = buildDebug('verdaccio:e2e-cli');\n\nfunction parsePmSpec(filter: string): { name: string; version?: string; binPath?: string } {\n // --pm yarn-modern@3, --pm npm@10, --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 throw new Error(\n 'yarn classic (v1) is no longer supported. Use yarn-modern (Yarn 3+) instead.'\n );\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-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 skipTest: [],\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 === '--uplink-port') {\n options.uplinkPort = parseInt(argv[++i], 10);\n } else if (arg === '--print-config') {\n options.printConfig = true;\n } else if (arg === '--server') {\n options.server = argv[++i];\n } else if (arg.startsWith('--server=')) {\n options.server = arg.split('=')[1];\n } else if (arg === '--skip-test') {\n options.skipTest!.push(argv[++i]);\n } else if (arg.startsWith('--skip-test=')) {\n options.skipTest!.push(arg.split('=')[1]);\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 if (arg.startsWith('--uplink-port=')) {\n options.uplinkPort = 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 (10-12), pnpm (10+),\n yarn-modern (or yarn, Yarn 3+), bun, deno\n Examples: --pm npm@10 --pm pnpm@11\n --pm yarn-modern@4\n --pm yarn-modern@3\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, unpublish\n Scenarios: scenario:install-multiple-deps,\n scenario:minimum-release-age (pnpm 11.1+),\n scenario:tarballs (npm adapter),\n scenario:metadata (npm adapter),\n scenario:search (npm adapter; the\n uplink sub-tests also need\n --uplink-port / E2E_UPLINK_PORT),\n scenario:uplink-failure (npm adapter,\n needs --uplink-port / E2E_UPLINK_PORT\n and a registry started with the config\n from --print-config)\n Default: all supported by the PM\n\n --skip-test <name> Skip a test by name (can be repeated). Unlike\n --test, the rest of the battery still runs and\n the skipped tests are reported as SKIP\n\n --token <token> Auth token (skips user creation)\n --timeout <ms> Per-test timeout (default: 50000)\n --uplink-port <port> Port for the mock uplink used by\n scenario:uplink-failure (default: $E2E_UPLINK_PORT)\n --print-config Print the recommended registry config for the full\n battery (max_body_size, mock uplink) and exit\n --server <name> Registry server the printed config targets:\n verdaccio (default) or pnpr. pnpr's config has no\n mock uplink (its registry namespaces can't claim\n the unscoped dynamic e2e-uplink-* names), so run\n it without --uplink-port and the uplink tests skip\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.printConfig) {\n const { buildE2EConfig, buildPnprE2EConfig, DEFAULT_UPLINK_PORT } =\n await import('./utils/e2e-config');\n const server = options.server ?? 'verdaccio';\n if (server === 'pnpr') {\n process.stdout.write(buildPnprE2EConfig());\n } else if (server === 'verdaccio') {\n process.stdout.write(buildE2EConfig(options.uplinkPort ?? DEFAULT_UPLINK_PORT));\n } else {\n console.error(`Unknown --server: \"${server}\". Supported: verdaccio, pnpr`);\n process.exit(1);\n }\n process.exit(0);\n }\n\n // Expose the mock uplink port to scenarios (scenario:uplink-failure gates on it).\n if (options.uplinkPort) {\n process.env.E2E_UPLINK_PORT = String(options.uplinkPort);\n }\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 =\n 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 if (options.skipTest && options.skipTest.length > 0) {\n console.log(`Skipping tests: ${options.skipTest.join(', ')}`);\n }\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 skipTests: options.skipTest,\n });\n\n process.exit(exitCode);\n}\n\n// Re-export for programmatic usage\nexport { allTests } from './tests';\nexport { allScenarios } from './scenarios';\nexport {\n createBunAdapter,\n createDenoAdapter,\n createNpmAdapter,\n createPnpmAdapter,\n createYarnModernAdapter,\n} 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 createNubAdapter,\n createPnpmAdapter,\n createUpmAdapter,\n createYarnModernAdapter,\n} from './adapters';\nimport { runAll } from './runner';\nimport { allTests } from './tests';\nimport { CliOptions, PackageManagerAdapter } from './types';\nimport { createUser, pingRegistry } from './utils/registry-client';\n\nconst debug = buildDebug('verdaccio:e2e-cli');\n\nfunction parsePmSpec(filter: string): { name: string; version?: string; binPath?: string } {\n // --pm yarn-modern@3, --pm npm@10, --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 throw new Error(\n 'yarn classic (v1) is no longer supported. Use yarn-modern (Yarn 3+) instead.'\n );\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 if (name === 'upm') {\n adapters.push(createUpmAdapter(binPath, version));\n } else if (name === 'nub') {\n adapters.push(createNubAdapter(binPath, version));\n } else {\n throw new Error(\n `Unknown package manager: \"${name}\". Supported: npm, pnpm, yarn-modern, bun, deno, upm, nub`\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 skipTest: [],\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 === '--uplink-port') {\n options.uplinkPort = parseInt(argv[++i], 10);\n } else if (arg === '--print-config') {\n options.printConfig = true;\n } else if (arg === '--server') {\n options.server = argv[++i];\n } else if (arg.startsWith('--server=')) {\n options.server = arg.split('=')[1];\n } else if (arg === '--skip-test') {\n options.skipTest!.push(argv[++i]);\n } else if (arg.startsWith('--skip-test=')) {\n options.skipTest!.push(arg.split('=')[1]);\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 if (arg.startsWith('--uplink-port=')) {\n options.uplinkPort = 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 (10-12), pnpm (10+),\n yarn-modern (or yarn, Yarn 3+), bun, deno,\n upm (install/ci only), nub (install/ci only)\n Examples: --pm npm@10 --pm pnpm@11\n --pm yarn-modern@4\n --pm yarn-modern@3\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, unpublish\n Scenarios: scenario:install-multiple-deps,\n scenario:minimum-release-age (pnpm 11.1+),\n scenario:tarballs (npm adapter),\n scenario:metadata (npm adapter),\n scenario:search (npm adapter; the\n uplink sub-tests also need\n --uplink-port / E2E_UPLINK_PORT),\n scenario:uplink-failure (npm adapter,\n needs --uplink-port / E2E_UPLINK_PORT\n and a registry started with the config\n from --print-config)\n Default: all supported by the PM\n\n --skip-test <name> Skip a test by name (can be repeated). Unlike\n --test, the rest of the battery still runs and\n the skipped tests are reported as SKIP\n\n --token <token> Auth token (skips user creation)\n --timeout <ms> Per-test timeout (default: 50000)\n --uplink-port <port> Port for the mock uplink used by\n scenario:uplink-failure (default: $E2E_UPLINK_PORT)\n --print-config Print the recommended registry config for the full\n battery (max_body_size, mock uplink) and exit\n --server <name> Registry server the printed config targets:\n verdaccio (default) or pnpr. pnpr's config has no\n mock uplink (its registry namespaces can't claim\n the unscoped dynamic e2e-uplink-* names), so run\n it without --uplink-port and the uplink tests skip\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.printConfig) {\n const { buildE2EConfig, buildPnprE2EConfig, DEFAULT_UPLINK_PORT } =\n await import('./utils/e2e-config');\n const server = options.server ?? 'verdaccio';\n if (server === 'pnpr') {\n process.stdout.write(buildPnprE2EConfig());\n } else if (server === 'verdaccio') {\n process.stdout.write(buildE2EConfig(options.uplinkPort ?? DEFAULT_UPLINK_PORT));\n } else {\n console.error(`Unknown --server: \"${server}\". Supported: verdaccio, pnpr`);\n process.exit(1);\n }\n process.exit(0);\n }\n\n // Expose the mock uplink port to scenarios (scenario:uplink-failure gates on it).\n if (options.uplinkPort) {\n process.env.E2E_UPLINK_PORT = String(options.uplinkPort);\n }\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 =\n 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 if (options.skipTest && options.skipTest.length > 0) {\n console.log(`Skipping tests: ${options.skipTest.join(', ')}`);\n }\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 skipTests: options.skipTest,\n });\n\n process.exit(exitCode);\n}\n\n// Re-export for programmatic usage\nexport { allTests } from './tests';\nexport { allScenarios } from './scenarios';\nexport {\n createBunAdapter,\n createDenoAdapter,\n createNpmAdapter,\n createNubAdapter,\n createPnpmAdapter,\n createUpmAdapter,\n createYarnModernAdapter,\n} from './adapters';\nexport { runAll, runSuite } from './runner';\nexport type { PackageManagerAdapter, TestDefinition, TestContext, CliOptions } from './types';\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { installMultipleDepsScenario } from "./install-multiple-deps.js";
|
|
2
2
|
import { metadataScenario } from "./metadata.js";
|
|
3
3
|
import { minimumReleaseAgeScenario } from "./minimum-release-age.js";
|
|
4
|
+
import { reservedNamesScenario } from "./reserved-names.js";
|
|
4
5
|
import { searchScenario } from "./search.js";
|
|
5
6
|
import { tarballsScenario } from "./tarballs.js";
|
|
6
7
|
import { uplinkFailureScenario } from "./uplink-failure.js";
|
|
@@ -11,9 +12,10 @@ var allScenarios = [
|
|
|
11
12
|
tarballsScenario,
|
|
12
13
|
metadataScenario,
|
|
13
14
|
searchScenario,
|
|
14
|
-
uplinkFailureScenario
|
|
15
|
+
uplinkFailureScenario,
|
|
16
|
+
reservedNamesScenario
|
|
15
17
|
];
|
|
16
18
|
//#endregion
|
|
17
|
-
export { allScenarios, installMultipleDepsScenario, metadataScenario, minimumReleaseAgeScenario, searchScenario, tarballsScenario, uplinkFailureScenario };
|
|
19
|
+
export { allScenarios, installMultipleDepsScenario, metadataScenario, minimumReleaseAgeScenario, reservedNamesScenario, searchScenario, tarballsScenario, uplinkFailureScenario };
|
|
18
20
|
|
|
19
21
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/scenarios/index.ts"],"sourcesContent":["import { TestDefinition } from '../types';\nimport { installMultipleDepsScenario } from './install-multiple-deps';\nimport { metadataScenario } from './metadata';\nimport { minimumReleaseAgeScenario } from './minimum-release-age';\nimport { searchScenario } from './search';\nimport { tarballsScenario } from './tarballs';\nimport { uplinkFailureScenario } from './uplink-failure';\n\nexport const allScenarios: TestDefinition[] = [\n installMultipleDepsScenario,\n minimumReleaseAgeScenario,\n tarballsScenario,\n metadataScenario,\n searchScenario,\n uplinkFailureScenario,\n];\n\nexport {\n installMultipleDepsScenario,\n minimumReleaseAgeScenario,\n searchScenario,\n tarballsScenario,\n metadataScenario,\n uplinkFailureScenario,\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/scenarios/index.ts"],"sourcesContent":["import { TestDefinition } from '../types';\nimport { installMultipleDepsScenario } from './install-multiple-deps';\nimport { metadataScenario } from './metadata';\nimport { minimumReleaseAgeScenario } from './minimum-release-age';\nimport { reservedNamesScenario } from './reserved-names';\nimport { searchScenario } from './search';\nimport { tarballsScenario } from './tarballs';\nimport { uplinkFailureScenario } from './uplink-failure';\n\nexport const allScenarios: TestDefinition[] = [\n installMultipleDepsScenario,\n minimumReleaseAgeScenario,\n tarballsScenario,\n metadataScenario,\n searchScenario,\n uplinkFailureScenario,\n reservedNamesScenario,\n];\n\nexport {\n installMultipleDepsScenario,\n minimumReleaseAgeScenario,\n searchScenario,\n tarballsScenario,\n metadataScenario,\n uplinkFailureScenario,\n reservedNamesScenario,\n};\n"],"mappings":";;;;;;;;AASA,IAAa,eAAiC;CAC5C;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { downloadTarball, fetchPackument } from "../utils/http-client.js";
|
|
2
|
+
import { MockUplink } from "../utils/mock-uplink.js";
|
|
3
|
+
import { pendingContractChecksEnabled } from "../utils/pending-checks.js";
|
|
4
|
+
import { buildPackageTarball, publishViaHttp } from "../utils/publish.js";
|
|
5
|
+
import assert from "assert";
|
|
6
|
+
//#region src/scenarios/reserved-names.ts
|
|
7
|
+
/**
|
|
8
|
+
* Scenario: reserved-names
|
|
9
|
+
*
|
|
10
|
+
* Packages named like Windows device names (`nul`, `con`, `aux`, with or without
|
|
11
|
+
* an extension) exist on npmjs. The registry must proxy and install them, and stay
|
|
12
|
+
* healthy when they are requested with the uplink down or published locally. Uses
|
|
13
|
+
* the `nul.*` and `@e2e-uplink/*` patterns of the battery config (see `--print-config`).
|
|
14
|
+
*/
|
|
15
|
+
function uplinkPort() {
|
|
16
|
+
return parseInt(process.env.E2E_UPLINK_PORT || "", 10);
|
|
17
|
+
}
|
|
18
|
+
async function expectRegistryAlive(ctx) {
|
|
19
|
+
const ping = await fetch(`${ctx.registryUrl}/-/ping`);
|
|
20
|
+
assert.strictEqual(ping.status, 200, "Registry stopped responding");
|
|
21
|
+
}
|
|
22
|
+
async function testReservedNames(ctx) {
|
|
23
|
+
const id = ctx.runId;
|
|
24
|
+
const proxied = [`nul.${id}`, `@e2e-uplink/con.${id}`];
|
|
25
|
+
const mock = new MockUplink(uplinkPort());
|
|
26
|
+
const packages = proxied.map((name) => mock.addPackage(name, buildPackageTarball(name, "1.0.0")));
|
|
27
|
+
await mock.start();
|
|
28
|
+
try {
|
|
29
|
+
await ctx.subTest("reserved device names are proxied from the uplink", async () => {
|
|
30
|
+
for (const pkg of packages) {
|
|
31
|
+
const { status, body } = await fetchPackument(ctx.registryUrl, pkg.name);
|
|
32
|
+
assert.strictEqual(status, 200, `Expected 200 proxying ${pkg.name}, got ${status}`);
|
|
33
|
+
assert.strictEqual(body.name, pkg.name, `Proxied packument name mismatch for ${pkg.name}`);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
if (pendingContractChecksEnabled("reserved-names")) {
|
|
37
|
+
await ctx.subTest("reserved device name tarballs are proxied", async () => {
|
|
38
|
+
for (const pkg of packages) {
|
|
39
|
+
const { body } = await fetchPackument(ctx.registryUrl, pkg.name);
|
|
40
|
+
const download = await downloadTarball(body.versions["1.0.0"].dist.tarball);
|
|
41
|
+
assert.strictEqual(download.status, 200, `Proxied tarball failed for ${pkg.name}`);
|
|
42
|
+
assert.strictEqual(download.sha1, pkg.shasum, `Proxied tarball bytes mismatch for ${pkg.name}`);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
await ctx.subTest("reserved device names install with the client", async () => {
|
|
46
|
+
const { tempFolder } = await ctx.adapter.prepareProject(`e2e-reserved-consumer-${id}`, "1.0.0", ctx.registryUrl, ctx.port, ctx.token, Object.fromEntries(proxied.map((name) => [name, "1.0.0"])));
|
|
47
|
+
await ctx.adapter.exec({ cwd: tempFolder }, "install", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
} finally {
|
|
51
|
+
await mock.stop();
|
|
52
|
+
}
|
|
53
|
+
await ctx.subTest("uplink down: reserved device names fail cleanly", async () => {
|
|
54
|
+
for (const name of proxied) {
|
|
55
|
+
const { status } = await fetchPackument(ctx.registryUrl, name);
|
|
56
|
+
assert.ok([200, 404].includes(status), `Expected 200 or 404 for ${name}, got ${status}`);
|
|
57
|
+
}
|
|
58
|
+
await expectRegistryAlive(ctx);
|
|
59
|
+
});
|
|
60
|
+
if (pendingContractChecksEnabled("reserved-names")) await ctx.subTest("publishing a reserved device name keeps the registry healthy", async () => {
|
|
61
|
+
const name = `aux.${id}`;
|
|
62
|
+
let published = true;
|
|
63
|
+
try {
|
|
64
|
+
await publishViaHttp(ctx, name);
|
|
65
|
+
} catch (err) {
|
|
66
|
+
published = false;
|
|
67
|
+
assert.match(String(err), / 404 /, `Expected a 404 refusal for ${name}, got ${err}`);
|
|
68
|
+
}
|
|
69
|
+
if (published) {
|
|
70
|
+
const { status, body } = await fetchPackument(ctx.registryUrl, name);
|
|
71
|
+
assert.strictEqual(status, 200, `Expected 200 for published ${name}, got ${status}`);
|
|
72
|
+
assert.strictEqual(body.name, name, `Packument name mismatch for ${name}`);
|
|
73
|
+
}
|
|
74
|
+
await expectRegistryAlive(ctx);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
var reservedNamesScenario = {
|
|
78
|
+
name: "scenario:reserved-names",
|
|
79
|
+
appliesTo: (adapter) => adapter.type === "npm" && Number.isFinite(uplinkPort()),
|
|
80
|
+
timeout: 6e4,
|
|
81
|
+
run: testReservedNames
|
|
82
|
+
};
|
|
83
|
+
//#endregion
|
|
84
|
+
export { reservedNamesScenario };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=reserved-names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reserved-names.js","names":[],"sources":["../../../src/scenarios/reserved-names.ts"],"sourcesContent":["import assert from 'assert';\n\nimport { TestContext, TestDefinition } from '../types';\nimport { downloadTarball, fetchPackument } from '../utils/http-client';\nimport { MockUplink } from '../utils/mock-uplink';\nimport { pendingContractChecksEnabled } from '../utils/pending-checks';\nimport { buildPackageTarball, publishViaHttp } from '../utils/publish';\n\n/**\n * Scenario: reserved-names\n *\n * Packages named like Windows device names (`nul`, `con`, `aux`, with or without\n * an extension) exist on npmjs. The registry must proxy and install them, and stay\n * healthy when they are requested with the uplink down or published locally. Uses\n * the `nul.*` and `@e2e-uplink/*` patterns of the battery config (see `--print-config`).\n */\nfunction uplinkPort(): number {\n return parseInt(process.env.E2E_UPLINK_PORT || '', 10);\n}\n\nasync function expectRegistryAlive(ctx: TestContext): Promise<void> {\n const ping = await fetch(`${ctx.registryUrl}/-/ping`);\n assert.strictEqual(ping.status, 200, 'Registry stopped responding');\n}\n\nasync function testReservedNames(ctx: TestContext): Promise<void> {\n const id = ctx.runId;\n const proxied = [`nul.${id}`, `@e2e-uplink/con.${id}`];\n const mock = new MockUplink(uplinkPort());\n const packages = proxied.map((name) => mock.addPackage(name, buildPackageTarball(name, '1.0.0')));\n\n await mock.start();\n try {\n await ctx.subTest('reserved device names are proxied from the uplink', async () => {\n for (const pkg of packages) {\n const { status, body } = await fetchPackument(ctx.registryUrl, pkg.name);\n assert.strictEqual(status, 200, `Expected 200 proxying ${pkg.name}, got ${status}`);\n assert.strictEqual(body.name, pkg.name, `Proxied packument name mismatch for ${pkg.name}`);\n }\n });\n\n if (pendingContractChecksEnabled('reserved-names')) {\n await ctx.subTest('reserved device name tarballs are proxied', async () => {\n for (const pkg of packages) {\n const { body } = await fetchPackument(ctx.registryUrl, pkg.name);\n const download = await downloadTarball(body.versions['1.0.0'].dist.tarball);\n assert.strictEqual(download.status, 200, `Proxied tarball failed for ${pkg.name}`);\n assert.strictEqual(\n download.sha1,\n pkg.shasum,\n `Proxied tarball bytes mismatch for ${pkg.name}`\n );\n }\n });\n\n await ctx.subTest('reserved device names install with the client', async () => {\n const { tempFolder } = await ctx.adapter.prepareProject(\n `e2e-reserved-consumer-${id}`,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token,\n Object.fromEntries(proxied.map((name) => [name, '1.0.0']))\n );\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'install',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n });\n }\n } finally {\n await mock.stop();\n }\n\n await ctx.subTest('uplink down: reserved device names fail cleanly', async () => {\n // Served from the local cache (200) or not cached for these names (404), never a 5xx.\n for (const name of proxied) {\n const { status } = await fetchPackument(ctx.registryUrl, name);\n assert.ok([200, 404].includes(status), `Expected 200 or 404 for ${name}, got ${status}`);\n }\n await expectRegistryAlive(ctx);\n });\n\n if (pendingContractChecksEnabled('reserved-names')) {\n await ctx.subTest('publishing a reserved device name keeps the registry healthy', async () => {\n const name = `aux.${id}`;\n let published = true;\n try {\n await publishViaHttp(ctx, name);\n } catch (err) {\n // Registries whose storage has no folder for such a name refuse it with a 404.\n published = false;\n assert.match(String(err), / 404 /, `Expected a 404 refusal for ${name}, got ${err}`);\n }\n if (published) {\n const { status, body } = await fetchPackument(ctx.registryUrl, name);\n assert.strictEqual(status, 200, `Expected 200 for published ${name}, got ${status}`);\n assert.strictEqual(body.name, name, `Packument name mismatch for ${name}`);\n }\n await expectRegistryAlive(ctx);\n });\n }\n}\n\nexport const reservedNamesScenario: TestDefinition = {\n name: 'scenario:reserved-names',\n // Needs the harness-provided uplink config; skipped cleanly otherwise.\n appliesTo: (adapter) => adapter.type === 'npm' && Number.isFinite(uplinkPort()),\n timeout: 60_000,\n run: testReservedNames,\n};\n"],"mappings":"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"}
|
|
@@ -29,6 +29,18 @@ async function testDistTags(ctx) {
|
|
|
29
29
|
await publishPkg(ctx, tf3);
|
|
30
30
|
const resp3 = await ctx.adapter.exec({ cwd: tf3 }, "dist-tag", "add", `${pkgName3}@1.1.0`, "alfa", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
31
31
|
assert.strictEqual(resp3.stdout, `+alfa: ${pkgName3}@1.1.0`);
|
|
32
|
+
const pkgName4 = `@verdaccio/dt4-${id}`;
|
|
33
|
+
const { tempFolder: tf4 } = await ctx.adapter.prepareProject(pkgName4, "1.0.0", ctx.registryUrl, ctx.port, ctx.token);
|
|
34
|
+
await publishPkg(ctx, tf4);
|
|
35
|
+
for (const tag of ["aux", "con"]) {
|
|
36
|
+
const added = await ctx.adapter.exec({ cwd: tf4 }, "dist-tag", "add", `${pkgName4}@1.0.0`, tag, ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
37
|
+
assert.strictEqual(added.stdout, `+${tag}: ${pkgName4}@1.0.0`);
|
|
38
|
+
}
|
|
39
|
+
const listed = await ctx.adapter.exec({ cwd: tf4 }, "dist-tag", "ls", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
40
|
+
assert.ok(listed.stdout.includes("aux: 1.0.0"), `Expected aux tag in: ${listed.stdout}`);
|
|
41
|
+
assert.ok(listed.stdout.includes("con: 1.0.0"), `Expected con tag in: ${listed.stdout}`);
|
|
42
|
+
const removed = await ctx.adapter.exec({ cwd: tf4 }, "dist-tag", "rm", pkgName4, "aux", ...ctx.adapter.registryArg(ctx.registryUrl));
|
|
43
|
+
assert.strictEqual(removed.stdout, `-aux: ${pkgName4}@1.0.0`);
|
|
32
44
|
}
|
|
33
45
|
var distTagsTest = {
|
|
34
46
|
name: "dist-tags",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dist-tags.js","names":[],"sources":["../../../src/tests/dist-tags.ts"],"sourcesContent":["import assert from 'assert';\n\nimport { TestContext, TestDefinition } from '../types';\n\nasync function publishPkg(ctx: TestContext, tempFolder: string, extraArgs: string[] = []) {\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'publish',\n ...extraArgs,\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n}\n\nasync function bumpVersion(ctx: TestContext, tempFolder: string) {\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'version',\n 'minor',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n}\n\nasync function testDistTags(ctx: TestContext): Promise<void> {\n const id = ctx.runId;\n\n // Test 1: list dist-tags\n const pkgName1 = `@foo/dt1-${id}`;\n const { tempFolder: tf1 } = await ctx.adapter.prepareProject(\n pkgName1,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n await publishPkg(ctx, tf1);\n await bumpVersion(ctx, tf1);\n await publishPkg(ctx, tf1, ['--tag', 'beta']);\n const resp1 = await ctx.adapter.exec(\n { cwd: tf1 },\n 'dist-tag',\n 'ls',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.strictEqual(resp1.stdout, 'beta: 1.1.0latest: 1.0.0');\n\n // Test 2: remove tag\n const pkgName2 = `@verdaccio/dt2-${id}`;\n const { tempFolder: tf2 } = await ctx.adapter.prepareProject(\n pkgName2,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n await publishPkg(ctx, tf2);\n await bumpVersion(ctx, tf2);\n await publishPkg(ctx, tf2, ['--tag', 'beta']);\n const resp2 = await ctx.adapter.exec(\n { cwd: tf2 },\n 'dist-tag',\n 'rm',\n `${pkgName2}@1.1.0`,\n 'beta',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.strictEqual(resp2.stdout, `-beta: ${pkgName2}@1.1.0`);\n\n // Test 3: add tag\n const pkgName3 = `@verdaccio/dt3-${id}`;\n const { tempFolder: tf3 } = await ctx.adapter.prepareProject(\n pkgName3,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n await publishPkg(ctx, tf3);\n await bumpVersion(ctx, tf3);\n await publishPkg(ctx, tf3);\n const resp3 = await ctx.adapter.exec(\n { cwd: tf3 },\n 'dist-tag',\n 'add',\n `${pkgName3}@1.1.0`,\n 'alfa',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.strictEqual(resp3.stdout, `+alfa: ${pkgName3}@1.1.0`);\n}\n\nexport const distTagsTest: TestDefinition = {\n name: 'dist-tags',\n requires: ['dist-tag'],\n run: testDistTags,\n};\n"],"mappings":";;AAIA,eAAe,WAAW,KAAkB,YAAoB,YAAsB,CAAC,GAAG;CACxF,MAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,WAAW,GAClB,WACA,GAAG,WACH,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;AACF;AAEA,eAAe,YAAY,KAAkB,YAAoB;CAC/D,MAAM,IAAI,QAAQ,KAChB,EAAE,KAAK,WAAW,GAClB,WACA,SACA,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;AACF;AAEA,eAAe,aAAa,KAAiC;CAC3D,MAAM,KAAK,IAAI;CAGf,MAAM,WAAW,YAAY;CAC7B,MAAM,EAAE,YAAY,QAAQ,MAAM,IAAI,QAAQ,eAC5C,UACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,KACN;CACA,MAAM,WAAW,KAAK,GAAG;CACzB,MAAM,YAAY,KAAK,GAAG;CAC1B,MAAM,WAAW,KAAK,KAAK,CAAC,SAAS,MAAM,CAAC;CAC5C,MAAM,QAAQ,MAAM,IAAI,QAAQ,KAC9B,EAAE,KAAK,IAAI,GACX,YACA,MACA,UACA,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;CACA,OAAO,YAAY,MAAM,QAAQ,0BAA0B;CAG3D,MAAM,WAAW,kBAAkB;CACnC,MAAM,EAAE,YAAY,QAAQ,MAAM,IAAI,QAAQ,eAC5C,UACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,KACN;CACA,MAAM,WAAW,KAAK,GAAG;CACzB,MAAM,YAAY,KAAK,GAAG;CAC1B,MAAM,WAAW,KAAK,KAAK,CAAC,SAAS,MAAM,CAAC;CAC5C,MAAM,QAAQ,MAAM,IAAI,QAAQ,KAC9B,EAAE,KAAK,IAAI,GACX,YACA,MACA,GAAG,SAAS,SACZ,QACA,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;CACA,OAAO,YAAY,MAAM,QAAQ,UAAU,SAAS,OAAO;CAG3D,MAAM,WAAW,kBAAkB;CACnC,MAAM,EAAE,YAAY,QAAQ,MAAM,IAAI,QAAQ,eAC5C,UACA,SACA,IAAI,aACJ,IAAI,MACJ,IAAI,KACN;CACA,MAAM,WAAW,KAAK,GAAG;CACzB,MAAM,YAAY,KAAK,GAAG;CAC1B,MAAM,WAAW,KAAK,GAAG;CACzB,MAAM,QAAQ,MAAM,IAAI,QAAQ,KAC9B,EAAE,KAAK,IAAI,GACX,YACA,OACA,GAAG,SAAS,SACZ,QACA,GAAG,IAAI,QAAQ,YAAY,IAAI,WAAW,CAC5C;CACA,OAAO,YAAY,MAAM,QAAQ,UAAU,SAAS,OAAO;
|
|
1
|
+
{"version":3,"file":"dist-tags.js","names":[],"sources":["../../../src/tests/dist-tags.ts"],"sourcesContent":["import assert from 'assert';\n\nimport { TestContext, TestDefinition } from '../types';\n\nasync function publishPkg(ctx: TestContext, tempFolder: string, extraArgs: string[] = []) {\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'publish',\n ...extraArgs,\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n}\n\nasync function bumpVersion(ctx: TestContext, tempFolder: string) {\n await ctx.adapter.exec(\n { cwd: tempFolder },\n 'version',\n 'minor',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n}\n\nasync function testDistTags(ctx: TestContext): Promise<void> {\n const id = ctx.runId;\n\n // Test 1: list dist-tags\n const pkgName1 = `@foo/dt1-${id}`;\n const { tempFolder: tf1 } = await ctx.adapter.prepareProject(\n pkgName1,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n await publishPkg(ctx, tf1);\n await bumpVersion(ctx, tf1);\n await publishPkg(ctx, tf1, ['--tag', 'beta']);\n const resp1 = await ctx.adapter.exec(\n { cwd: tf1 },\n 'dist-tag',\n 'ls',\n '--json',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.strictEqual(resp1.stdout, 'beta: 1.1.0latest: 1.0.0');\n\n // Test 2: remove tag\n const pkgName2 = `@verdaccio/dt2-${id}`;\n const { tempFolder: tf2 } = await ctx.adapter.prepareProject(\n pkgName2,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n await publishPkg(ctx, tf2);\n await bumpVersion(ctx, tf2);\n await publishPkg(ctx, tf2, ['--tag', 'beta']);\n const resp2 = await ctx.adapter.exec(\n { cwd: tf2 },\n 'dist-tag',\n 'rm',\n `${pkgName2}@1.1.0`,\n 'beta',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.strictEqual(resp2.stdout, `-beta: ${pkgName2}@1.1.0`);\n\n // Test 3: add tag\n const pkgName3 = `@verdaccio/dt3-${id}`;\n const { tempFolder: tf3 } = await ctx.adapter.prepareProject(\n pkgName3,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n await publishPkg(ctx, tf3);\n await bumpVersion(ctx, tf3);\n await publishPkg(ctx, tf3);\n const resp3 = await ctx.adapter.exec(\n { cwd: tf3 },\n 'dist-tag',\n 'add',\n `${pkgName3}@1.1.0`,\n 'alfa',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.strictEqual(resp3.stdout, `+alfa: ${pkgName3}@1.1.0`);\n\n // Test 4: tags named like Windows device names are plain metadata keys\n const pkgName4 = `@verdaccio/dt4-${id}`;\n const { tempFolder: tf4 } = await ctx.adapter.prepareProject(\n pkgName4,\n '1.0.0',\n ctx.registryUrl,\n ctx.port,\n ctx.token\n );\n await publishPkg(ctx, tf4);\n for (const tag of ['aux', 'con']) {\n const added = await ctx.adapter.exec(\n { cwd: tf4 },\n 'dist-tag',\n 'add',\n `${pkgName4}@1.0.0`,\n tag,\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.strictEqual(added.stdout, `+${tag}: ${pkgName4}@1.0.0`);\n }\n const listed = await ctx.adapter.exec(\n { cwd: tf4 },\n 'dist-tag',\n 'ls',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.ok(listed.stdout.includes('aux: 1.0.0'), `Expected aux tag in: ${listed.stdout}`);\n assert.ok(listed.stdout.includes('con: 1.0.0'), `Expected con tag in: ${listed.stdout}`);\n const removed = await ctx.adapter.exec(\n { cwd: tf4 },\n 'dist-tag',\n 'rm',\n pkgName4,\n 'aux',\n ...ctx.adapter.registryArg(ctx.registryUrl)\n );\n assert.strictEqual(removed.stdout, `-aux: ${pkgName4}@1.0.0`);\n}\n\nexport const distTagsTest: TestDefinition = {\n name: 'dist-tags',\n requires: ['dist-tag'],\n run: testDistTags,\n};\n"],"mappings":"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"}
|
package/build/esm/tests/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "../scenarios/install-multiple-deps.js";
|
|
2
2
|
import "../scenarios/metadata.js";
|
|
3
3
|
import "../scenarios/minimum-release-age.js";
|
|
4
|
+
import "../scenarios/reserved-names.js";
|
|
4
5
|
import "../scenarios/search.js";
|
|
5
6
|
import "../scenarios/tarballs.js";
|
|
6
7
|
import "../scenarios/uplink-failure.js";
|
|
@@ -12,6 +13,7 @@ import { distTagsTest } from "./dist-tags.js";
|
|
|
12
13
|
import { infoTest } from "./info.js";
|
|
13
14
|
import { installTest } from "./install.js";
|
|
14
15
|
import { loginTest } from "./login.js";
|
|
16
|
+
import { packageNamesTest } from "./package-names.js";
|
|
15
17
|
import { pingTest } from "./ping.js";
|
|
16
18
|
import { publishTest } from "./publish.js";
|
|
17
19
|
import { searchTest } from "./search.js";
|
|
@@ -25,6 +27,7 @@ var allTests = [
|
|
|
25
27
|
infoTest,
|
|
26
28
|
deprecateTest,
|
|
27
29
|
distTagsTest,
|
|
30
|
+
packageNamesTest,
|
|
28
31
|
loginTest,
|
|
29
32
|
pingTest,
|
|
30
33
|
searchTest,
|
|
@@ -32,6 +35,6 @@ var allTests = [
|
|
|
32
35
|
...allScenarios
|
|
33
36
|
];
|
|
34
37
|
//#endregion
|
|
35
|
-
export { allScenarios, allTests, auditTest, ciTest, deprecateTest, distTagsTest, infoTest, installTest, loginTest, pingTest, publishTest, searchTest, unpublishTest };
|
|
38
|
+
export { allScenarios, allTests, auditTest, ciTest, deprecateTest, distTagsTest, infoTest, installTest, loginTest, packageNamesTest, pingTest, publishTest, searchTest, unpublishTest };
|
|
36
39
|
|
|
37
40
|
//# sourceMappingURL=index.js.map
|