diff --git a/lib/ui5Framework/npm/Registry.js b/lib/ui5Framework/npm/Registry.js index 721399cf4..73cc9947b 100644 --- a/lib/ui5Framework/npm/Registry.js +++ b/lib/ui5Framework/npm/Registry.js @@ -41,56 +41,61 @@ class Registry { throw new Error(`Failed to extract package ${pkgName}@${version}: ${err.message}`); } } + async _getPacote() { - return { - pacote: (await import("pacote")).default, - pacoteOptions: await this._getPacoteOptions() - }; - } - async _getPacoteOptions() { - if (!this._npmConfig) { - const {default: libnpmconfig} = await import("libnpmconfig"); - const opts = { - cache: this._cacheDir, + if (this._pGetPacote) { + return this._pGetPacote; + } + return this._pGetPacote = (async () => { + return { + pacote: (await import("pacote")).default, + pacoteOptions: await this._getPacoteOptions() }; - const config = libnpmconfig.read(opts, { - cwd: this._cwd - }).toJSON(); + })(); + } - // Rename https-proxy to httpsProxy so that it is picked up by npm-registry-fetch (via pacote) - if (config["https-proxy"]) { - config.httpsProxy = config["https-proxy"]; - delete config["https-proxy"]; - } + async _getPacoteOptions() { + const {default: Config} = await import("@npmcli/config"); + const { + default: {flatten, definitions, shorthands, defaults}, + } = await import("@npmcli/config/lib/definitions/index.js"); - if (!config.proxy && !config.httpsProxy) { - // Disable usage of shared keep-alive agents unless a proxy is configured - // which only works with agents. + const configuration = new Config({ + cwd: this._cwd, + npmPath: this._cwd, + definitions, + flatten, + shorthands, + defaults + }); - // make-fetch-happen uses a hard-coded 15 seconds freeSocketTimeout - // that can be easily reached (Error: Socket timeout) and there doesn't - // seem to be another way to disable or increase it. - // Also see: https://github.com/node-modules/agentkeepalive/issues/106 - config.agent = false; - } + await configuration.load(); // Reads through the configurations + const config = configuration.flat; // JSON. Formatted via "flatten" - log.verbose(`Using npm configuration (extract):`); - // Do not log full configuration as it may contain authentication tokens - logConfig(config, "registry"); - logConfig(config, "@sapui5:registry"); - logConfig(config, "@openui5:registry"); - logConfig(config, "proxy"); - logConfig(config, "httpsProxy"); - logConfig(config, "globalconfig"); - logConfig(config, "userconfig"); - logConfig(config, "cache"); - logConfig(config, "cwd"); + if (!config.proxy && !config.httpsProxy) { + // Disable usage of shared keep-alive agents unless a proxy is configured + // which only works with agents. - this._npmConfig = config; + // make-fetch-happen uses a hard-coded 15 seconds freeSocketTimeout + // that can be easily reached (Error: Socket timeout) and there doesn't + // seem to be another way to disable or increase it. + // Also see: https://github.com/node-modules/agentkeepalive/issues/106 + config.agent = false; } - // Use cached config - return this._npmConfig; + log.verbose(`Using npm configuration (extract):`); + // Do not log full configuration as it may contain authentication tokens + logConfig(config, "registry"); + logConfig(config, "@sapui5:registry"); + logConfig(config, "@openui5:registry"); + logConfig(config, "proxy"); + logConfig(config, "httpsProxy"); + logConfig(config, "globalconfig"); + logConfig(config, "userconfig"); + logConfig(config, "cache"); + logConfig(config, "cwd"); + + return config; } } diff --git a/package-lock.json b/package-lock.json index aeb07db30..23935c3c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "3.4.0", "license": "Apache-2.0", "dependencies": { + "@npmcli/config": "^6.2.1", "@ui5/builder": "^3.0.6", "@ui5/fs": "^3.0.4", "@ui5/logger": "^3.0.0", @@ -19,7 +20,6 @@ "globby": "^13.2.0", "graceful-fs": "^4.2.11", "js-yaml": "^4.1.0", - "libnpmconfig": "^1.2.1", "lockfile": "^1.0.4", "make-fetch-happen": "^11.1.1", "node-stream-zip": "^1.15.0", @@ -833,6 +833,54 @@ "node": ">= 8" } }, + "node_modules/@npmcli/config": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/config/-/config-6.2.1.tgz", + "integrity": "sha512-Cj/OrSbrLvnwWuzquFCDTwFN8QmR+SWH6qLNCBttUreDkKM5D5p36SeSMbcEUiCGdwjUrVy2yd8C0REwwwDPEw==", + "dependencies": { + "@npmcli/map-workspaces": "^3.0.2", + "ci-info": "^3.8.0", + "ini": "^4.1.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.5", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/config/node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/config/node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/config/node_modules/nopt": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.1.0.tgz", + "integrity": "sha512-ZFPLe9Iu0tnx7oWhFxAo4s7QTn8+NNDDxYNaKLjE7Dp0tbakQ3M1QhQzsnzXHQBTUO3K9BmwaxnyO8Ayn2I95Q==", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@npmcli/fs": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", @@ -899,6 +947,75 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@npmcli/map-workspaces": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-3.0.4.tgz", + "integrity": "sha512-Z0TbvXkRbacjFFLpVpV0e2mheCh+WzQpcqL+4xp49uNJOxOnIAPZyXtUxZ5Qn3QBTGKA11Exjd9a5411rBrhDg==", + "dependencies": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/glob": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.6.tgz", + "integrity": "sha512-U/rnDpXJGF414QQQZv5uVsabTVxMSwzS5CH0p3DRCIV6ownl4f7PzGnkGmvlum2wB+9RlJWJZ6ACU1INnBqiPA==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2", + "path-scurry": "^1.7.0" + }, + "bin": { + "glob": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/signal-exit": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", + "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/name-from-folder": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz", + "integrity": "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@npmcli/node-gyp": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", @@ -2221,7 +2338,6 @@ "version": "3.8.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, "funding": [ { "type": "github", @@ -3758,11 +3874,6 @@ "reusify": "^1.0.4" } }, - "node_modules/figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" - }, "node_modules/figures": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", @@ -4454,7 +4565,8 @@ "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true }, "node_modules/invariant": { "version": "2.2.4", @@ -5131,59 +5243,6 @@ "node": ">= 0.8.0" } }, - "node_modules/libnpmconfig": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/libnpmconfig/-/libnpmconfig-1.2.1.tgz", - "integrity": "sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==", - "deprecated": "This module is not used anymore. npm config is parsed by npm itself and by @npmcli/config", - "dependencies": { - "figgy-pudding": "^3.5.1", - "find-up": "^3.0.0", - "ini": "^1.3.5" - } - }, - "node_modules/libnpmconfig/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/libnpmconfig/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/libnpmconfig/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/libnpmconfig/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "engines": { - "node": ">=4" - } - }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -6638,6 +6697,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "dependencies": { "p-try": "^2.0.0" }, @@ -6691,6 +6751,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, "engines": { "node": ">=6" } @@ -9243,6 +9304,11 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/walk-up-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", + "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==" + }, "node_modules/well-known-symbols": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", diff --git a/package.json b/package.json index 8acf5dc44..b0b66aff3 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "globby": "^13.2.0", "graceful-fs": "^4.2.11", "js-yaml": "^4.1.0", - "libnpmconfig": "^1.2.1", + "@npmcli/config": "^6.2.1", "lockfile": "^1.0.4", "make-fetch-happen": "^11.1.1", "node-stream-zip": "^1.15.0", diff --git a/test/lib/graph/helpers/ui5Framework.integration.js b/test/lib/graph/helpers/ui5Framework.integration.js index 43452effb..0c7c5a9ef 100644 --- a/test/lib/graph/helpers/ui5Framework.integration.js +++ b/test/lib/graph/helpers/ui5Framework.integration.js @@ -32,20 +32,29 @@ test.beforeEach(async (t) => { manifest: sinon.stub() }; + class Config { + static get typeDefs() { + return {}; + } + + async load() {} + + get flat() { + return {}; + } + } + sinon.stub(Config.prototype, "flat").value({ + registry: "https://registry.fake", + cache: path.join(ui5FrameworkBaseDir, "cacache"), + proxy: "" + }); + t.context.Registry = await esmock.p("../../../../lib/ui5Framework/npm/Registry.js", { "@ui5/logger": ui5Logger, "pacote": t.context.pacote, - "libnpmconfig": { - read: sinon.stub().returns({ - toJSON: () => { - return { - registry: "https://registry.fake", - cache: path.join(ui5FrameworkBaseDir, "cacache"), - proxy: "" - }; - } - }) - }, + "@npmcli/config": { + "default": Config + } }); const AbstractInstaller = await esmock.p("../../../../lib/ui5Framework/AbstractInstaller.js", { diff --git a/test/lib/ui5framework/npm/Registry.js b/test/lib/ui5framework/npm/Registry.js index 5467271e7..6fb430244 100644 --- a/test/lib/ui5framework/npm/Registry.js +++ b/test/lib/ui5framework/npm/Registry.js @@ -3,7 +3,7 @@ import sinonGlobal from "sinon"; import esmock from "esmock"; test.beforeEach(async (t) => { - const sinon = t.context.sinon = sinonGlobal.createSandbox(); + const sinon = (t.context.sinon = sinonGlobal.createSandbox()); t.context.pacote = { packument: sinon.stub(), @@ -11,18 +11,39 @@ test.beforeEach(async (t) => { extract: sinon.stub(), }; - t.context.libnpmconfigReadToJSON = sinon.stub(); - t.context.libnpmconfig = { - read: sinon.stub().returns({ - toJSON: t.context.libnpmconfigReadToJSON - }) - }; + class Config { + constructor(...args) { + t.context.npmConfigConstructor(...args); + } + + static get typeDefs() { + return {path: "string"}; + } + + async load() {} + get flat() { + return {}; + } + } + + t.context.npmConfigConstructor = sinon.stub(); + t.context.npmConfigFlat = sinon.stub(Config.prototype, "flat"); t.context.Registry = await esmock.p("../../../../lib/ui5Framework/npm/Registry.js", { "pacote": { - default: t.context.pacote + "default": t.context.pacote + }, + "@npmcli/config": { + "default": Config }, - "libnpmconfig": t.context.libnpmconfig + "@npmcli/config/lib/definitions/index.js": { + default: { + flatten: "flatten", + definitions: "definitions", + shorthands: "shorthands", + defaults: "defaults", + } + } }); }); @@ -43,7 +64,7 @@ test.serial("Constructor", (t) => { }); test.serial("_getPacoteOptions", async (t) => { - const {Registry, libnpmconfig, libnpmconfigReadToJSON} = t.context; + const {Registry, npmConfigFlat, npmConfigConstructor} = t.context; const registry = new Registry({ cwd: "cwd", @@ -58,31 +79,25 @@ test.serial("_getPacoteOptions", async (t) => { fake: "config", agent: false }; - - libnpmconfigReadToJSON.returns(npmConfig); + npmConfigFlat.value(npmConfig); const pacoteOptions = await registry._getPacoteOptions(); - t.is(libnpmconfigReadToJSON.callCount, 1); - t.is(libnpmconfig.read.callCount, 1); - t.deepEqual(libnpmconfig.read.getCall(0).args, [{ - cache: "cacheDir", - }, { - cwd: "cwd" - }]); + t.is(npmConfigConstructor.callCount, 1); + t.deepEqual(npmConfigConstructor.firstCall.firstArg, { + cwd: "cwd", + npmPath: "cwd", + flatten: "flatten", + definitions: "definitions", + shorthands: "shorthands", + defaults: "defaults", + }); t.deepEqual(pacoteOptions, expectedPacoteOptions); - - const cachedPacoteOptions = await registry._getPacoteOptions(); - - t.is(libnpmconfigReadToJSON.callCount, 1); - t.is(libnpmconfig.read.callCount, 1); - - t.deepEqual(cachedPacoteOptions, expectedPacoteOptions); }); test.serial("_getPacoteOptions (proxy config set)", async (t) => { - const {Registry, libnpmconfig, libnpmconfigReadToJSON} = t.context; + const {Registry, npmConfigFlat, npmConfigConstructor} = t.context; const registry = new Registry({ cwd: "cwd", @@ -97,30 +112,17 @@ test.serial("_getPacoteOptions (proxy config set)", async (t) => { proxy: "http://localhost:9999" }; - libnpmconfigReadToJSON.returns(npmConfig); + npmConfigFlat.value(npmConfig); const pacoteOptions = await registry._getPacoteOptions(); - t.is(libnpmconfigReadToJSON.callCount, 1); - t.is(libnpmconfig.read.callCount, 1); - t.deepEqual(libnpmconfig.read.getCall(0).args, [{ - cache: "cacheDir", - }, { - cwd: "cwd" - }]); + t.is(npmConfigConstructor.callCount, 1); t.deepEqual(pacoteOptions, expectedPacoteOptions); - - const cachedPacoteOptions = await registry._getPacoteOptions(); - - t.is(libnpmconfigReadToJSON.callCount, 1); - t.is(libnpmconfig.read.callCount, 1); - - t.deepEqual(cachedPacoteOptions, expectedPacoteOptions); }); test.serial("_getPacoteOptions (https-proxy config set)", async (t) => { - const {Registry, libnpmconfig, libnpmconfigReadToJSON} = t.context; + const {Registry, npmConfigFlat, npmConfigConstructor} = t.context; const registry = new Registry({ cwd: "cwd", @@ -128,36 +130,41 @@ test.serial("_getPacoteOptions (https-proxy config set)", async (t) => { }); const npmConfig = { - "https-proxy": "http://localhost:9999" + "httpsProxy": "http://localhost:9999" }; const expectedPacoteOptions = { httpsProxy: "http://localhost:9999" }; - libnpmconfigReadToJSON.returns(npmConfig); + npmConfigFlat.value(npmConfig); const pacoteOptions = await registry._getPacoteOptions(); - t.is(libnpmconfigReadToJSON.callCount, 1); - t.is(libnpmconfig.read.callCount, 1); - t.deepEqual(libnpmconfig.read.getCall(0).args, [{ - cache: "cacheDir", - }, { - cwd: "cwd" - }]); + t.is(npmConfigConstructor.callCount, 1); t.deepEqual(pacoteOptions, expectedPacoteOptions); +}); - const cachedPacoteOptions = await registry._getPacoteOptions(); +test.serial("_getPacote", async (t) => { + const {Registry, sinon} = t.context; - t.is(libnpmconfigReadToJSON.callCount, 1); - t.is(libnpmconfig.read.callCount, 1); + const registry = new Registry({ + cwd: "cwd", + cacheDir: "cacheDir" + }); + + const expectedPacoteOptions = {"fake": "options"}; + + sinon.stub(registry, "_getPacoteOptions").resolves(expectedPacoteOptions); - t.deepEqual(cachedPacoteOptions, expectedPacoteOptions); + const {pacote, pacoteOptions} = await registry._getPacote(); + + t.is(pacote, t.context.pacote); + t.is(pacoteOptions, expectedPacoteOptions); }); -test.serial("_getPacote", async (t) => { +test.serial("_getPacote caching", async (t) => { const {Registry, sinon} = t.context; const registry = new Registry({ @@ -167,10 +174,15 @@ test.serial("_getPacote", async (t) => { const expectedPacoteOptions = {"fake": "options"}; - sinon.stub(registry, "_getPacoteOptions").resolves(expectedPacoteOptions); + const getPacoteOptionsStub = sinon.stub(registry, "_getPacoteOptions").resolves(expectedPacoteOptions); const {pacote, pacoteOptions} = await registry._getPacote(); t.is(pacote, t.context.pacote); t.is(pacoteOptions, expectedPacoteOptions); + + await registry._getPacote(); + await registry._getPacote(); + + t.is(getPacoteOptionsStub.callCount, 1, "_getPacoteOptions got called once"); });