diff --git a/src/controllers/getPackagesPackageName.js b/src/controllers/getPackagesPackageName.js index 7e220310..60d88ba3 100644 --- a/src/controllers/getPackagesPackageName.js +++ b/src/controllers/getPackagesPackageName.js @@ -4,7 +4,15 @@ module.exports = { docs: { - summary: "Show package details." + summary: "Show package details.", + responses: { + 200: { + description: "A 'Package Object Full' of the requested package.", + content: { + "application/json": "$packageObjectFull" + } + } + } }, endpoint: { method: "GET", @@ -54,6 +62,6 @@ module.exports = { const sso = new context.sso(); - return sso.isOk().addcontent(pack); + return sso.isOk().addContent(pack); } }; diff --git a/src/database.js b/src/database.js index f5e28e7d..ea216b1d 100644 --- a/src/database.js +++ b/src/database.js @@ -605,14 +605,13 @@ async function getPackageByName(name, user = false) { : { ok: false, content: `package ${name} not found.`, - short: "Not Found", + short: "not_found", }; } catch (err) { return { ok: false, - content: "Generic Error", - short: "Server Error", - error: err, + content: err, + short: "server_error" }; } } diff --git a/src/utils.js b/src/utils.js index 5c2eb011..960f0034 100644 --- a/src/utils.js +++ b/src/utils.js @@ -52,7 +52,7 @@ async function constructPackageObjectFull(pack) { for (const v of vers) { retVer[v.semver] = v.meta; retVer[v.semver].license = v.license; - retVer[v.semver].engine = v.engine; + retVer[v.semver].engines = v.engines; retVer[v.semver].dist = { tarball: `${server_url}/api/packages/${pack.name}/versions/${v.semver}/tarball`, }; @@ -182,7 +182,7 @@ async function constructPackageObjectJSON(pack) { } newPack.dist ??= {}; newPack.dist.tarball = `${server_url}/api/packages/${v.meta.name}/versions/${v.semver}/tarball`; - newPack.engines = v.engine; + newPack.engines = v.engines; logger.generic(6, "Single Package Object JSON finished without Error"); return newPack; }; diff --git a/tests/helpers/global.setup.jest.js b/tests/helpers/global.setup.jest.js index 604ac7ad..de08a48a 100644 --- a/tests/helpers/global.setup.jest.js +++ b/tests/helpers/global.setup.jest.js @@ -1,5 +1,8 @@ // Add `expect().toMatchSchema()` to Jest, for matching against Joi Schemas - +const Joi = require("joi"); +global.Joi = Joi; +// We add Joi to the global context so that the `models/* .test` object doesn't need +// to worry about `require`ing the module. const jestJoi = require("jest-joi"); expect.extend(jestJoi.matchers); @@ -61,7 +64,7 @@ expect.extend({ obj = require(`../models/${obj.replace("$","")}.js`); } - expect(sso.content).toMatchObject(obj.test); + expect(sso.content).toMatchSchema(obj.test); done = true; break; } diff --git a/tests/http/getPackagesPackageName.test.js b/tests/http/getPackagesPackageName.test.js new file mode 100644 index 00000000..148c4ab4 --- /dev/null +++ b/tests/http/getPackagesPackageName.test.js @@ -0,0 +1,72 @@ +const endpoint = require("../../src/controllers/getPackagesPackageName.js"); +const database = require("../../src/database.js"); +const context = require("../../src/context.js"); + +describe("Behaves as expected", () => { + test("Calls the correct function", async () => { + const localContext = context; + const spy = jest.spyOn(localContext.database, "getPackageByName"); + + await endpoint.logic({}, localContext); + + expect(spy).toBeCalledTimes(1); + + spy.mockClear(); + }); + + test("Returns 'not_found' when package doesn't exist", async () => { + const sso = await endpoint.logic({ + engine: false, + packageName: "anything" + }, context); + + expect(sso.ok).toBe(false); + expect(sso.content.short).toBe("not_found"); + }); + + test("Returns package on success", async () => { + await database.insertNewPackage({ + name: "get-package-test", + repository: { + url: "https://github.com/confused-Techie/package-backend", + type: "git" + }, + creation_method: "Test Package", + releases: { + latest: "1.1.0" + }, + readme: "This is a readme!", + metadata: { + name: "get-package-test" + }, + versions: { + "1.1.0": { + dist: { + tarball: "download-url", + sha: "1234" + }, + name: "get-package-test" + }, + "1.0.0": { + dist: { + tarball: "download-url", + sha: "1234" + }, + name: "get-package-test" + } + } + }); + + const sso = await endpoint.logic({ + engine: false, + packageName: "get-package-test" + }, context); + + expect(sso.ok).toBe(true); + expect(sso.content.name).toBe("get-package-test"); + expect(sso).toMatchEndpointSuccessObject(endpoint); + await database.removePackageByName("get-package-test", true); + }); + + +}); diff --git a/tests/http/getThemesSearch.test.js b/tests/http/getThemesSearch.test.js index 5a47d5d5..4d854332 100644 --- a/tests/http/getThemesSearch.test.js +++ b/tests/http/getThemesSearch.test.js @@ -35,7 +35,7 @@ describe("Behaves as expected", () => { releases: { latest: "1.1.0" }, - reamde: "This is a readme!", + readme: "This is a readme!", metadata: { name: "atom-material-syntax", theme: "ui" diff --git a/tests/http/getUsersLogin.test.js b/tests/http/getUsersLogin.test.js index 6e83a5e3..19012752 100644 --- a/tests/http/getUsersLogin.test.js +++ b/tests/http/getUsersLogin.test.js @@ -41,7 +41,6 @@ describe("Behaves as expected", () => { expect(res.ok).toBe(true); // First make sure the user object matches expectations broadly, then specifically - expect(res.content).toMatchObject(userObject.test); expect(res.content.username).toBe(userObj.username); expect(res.content.avatar).toBe(userObj.avatar); expect(res).toMatchEndpointSuccessObject(endpoint); diff --git a/tests/models/message.js b/tests/models/message.js index c658ca51..eba46891 100644 --- a/tests/models/message.js +++ b/tests/models/message.js @@ -14,7 +14,8 @@ module.exports = { example: { message: "This is some message content." }, - test: { - message: expect.toBeTypeof("string") - } + test: + Joi.object({ + message: Joi.string().required() + }) }; diff --git a/tests/models/packageObjectFull.js b/tests/models/packageObjectFull.js new file mode 100644 index 00000000..51e02947 --- /dev/null +++ b/tests/models/packageObjectFull.js @@ -0,0 +1,111 @@ +module.exports = { + schema: { + description: "A 'Package Object Full' of a package on the PPR.", + type: "object", + required: [ + "name", "readme", "metadata", "releases", "versions", + "repository", "creation_method", "downloads", "stargazers_count", "badges" + ], + properties: { + name: { type: "string" }, + readme: { type: "string" }, + metadata: { type: "object" }, + releases: { type: "object" }, + versions: { type: "object" }, + repository: { type: "object" }, + creation_method: { type: "string" }, + downloads: { type: "string" }, + stargazers_count: { type: "string" }, + badges: { type: "array" } + } + }, + example: { + // This is nearly the full return of `language-powershell-revised` + name: "language-powershell-revised", + readme: "This is the full content of a readme file!", + metadata: { + // The metadata field is the `package.json` of the most recent version + // With the `dist` object added + dist: { + sha: "604a047247ded9df50e7325345405c93871868e5", + tarball: "https://api.github.com/repos/confused-Techie/language-powershell-revised/tarball/refs/tags/v1.0.0" + }, + name: "language-powershell-revised", + engines: { + atom: ">=1.0.0 <2.0.0" + }, + license: "MIT", + version: "1.0.0", + keywords: [], + // This may be a repository object + repository: "https://github.com/confused-Techie/language-powershell-revised", + description: "Updated, revised PowerShell Syntax Highlighting Support in Pulsar." + }, + releases: { + latest: "1.0.0" + }, + versions: { + "1.0.0": { + // This is the `package.json` of every version + // With a `dist` key added + dist: { + tarball: "https://api.pulsar-edit.dev/api/packages/language-powershell-revised/versions/1.0.0/tarball" + }, + name: "language-powershell-revised", + engines: { + atom: ">=1.0.0 <2.0.0" + }, + license: "MIT", + version: "1.0.0", + keywords: [], + repository: "https://github.com/confsued-Techie/language-powershell-revised", + description: "Updated, revised PowerShell Syntax Highlighting Support in Pulsar" + } + }, + repository: { + // This is the repo object for the VCS Service + url: "https://github.com/confsued-Techie/langauge-powershell-revised", + type: "git" + }, + // This can be either `User Made Package` or `Migrated Package` + creation_method: "User Made Package", + // Note how some fields here are strings not numbers + downloads: "54", + stargazers_count: "0", + badges: [ + // Some badges are baked in, some are applied at render time. + { + title: "Made for Pulsar!", + type: "success" + } + ] + }, + test: + Joi.object({ + name: Joi.string().required(), + readme: Joi.string().required(), + metadata: Joi.object().required(), + releases: Joi.object().required(), + versions: Joi.object().required(), + repository: Joi.object().required(), + creation_method: Joi.string().required(), + downloads: Joi.string().required(), + stargazers_count: Joi.string().required(), + badges: Joi.array().items( + Joi.object({ + title: Joi.string().valid( + "Outdated", + "Made for Pulsar!", + "Broken", + "Archived", + "Deprecated" + ).required(), + type: Joi.string().valid( + "warn", "info", "success" + ).required(), + text: Joi.string(), + link: Joi.string() + }) + ).required() + }) +}; diff --git a/tests/models/userObjectPrivate.js b/tests/models/userObjectPrivate.js index ab182ee9..744b77b2 100644 --- a/tests/models/userObjectPrivate.js +++ b/tests/models/userObjectPrivate.js @@ -38,13 +38,14 @@ module.exports = { created_at: "2023-09-16T00:58:36.755Z", packages: [] }, - test: { - username: expect.toBeTypeof("string"), - avatar: expect.toBeTypeof("string"), - data: {}, - node_id: expect.toBeTypeof("string"), - token: expect.toBeTypeof("string"), - created_at: expect.toBeTypeof("string"), - packages: expect.toBeArray() - } + test: + Joi.object({ + username: Joi.string().required(), + avatar: Joi.string().required(), + data: Joi.object().required(), + node_id: Joi.string().required(), + token: Joi.string().required(), + created_at: Joi.string().required(), + packages: Joi.array().required() + }) }; diff --git a/tests/models/userObjectPublic.js b/tests/models/userObjectPublic.js index 04346a47..1b0f97a3 100644 --- a/tests/models/userObjectPublic.js +++ b/tests/models/userObjectPublic.js @@ -30,11 +30,12 @@ module.exports = { created_at: "2023-09-16T00:58:36.755Z", packages: [] }, - test: { - username: expect.toBeTypeof("string"), - avatar: expect.toBeTypeof("string"), - data: {}, - created_at: expect.toBeTypeof("string"), - packages: expect.toBeArray() - } + test: + Joi.object({ + username: Joi.string().required(), + avatar: Joi.string().required(), + data: Joi.object().required(), + created_at: Joi.string().required(), + packages: Joi.array().required() + }) };