diff --git a/package.json b/package.json index 51479b90..5409ba4a 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ }, "main": "out/node/entry.js", "devDependencies": { + "@schemastore/package": "^0.0.6", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express": "^4.17.8", @@ -62,8 +63,8 @@ "stylelint": "^13.0.0", "stylelint-config-recommended": "^3.0.0", "ts-node": "^9.0.0", - "wtfnode": "^0.8.4", - "typescript": "^4.1.3" + "typescript": "^4.1.3", + "wtfnode": "^0.8.4" }, "resolutions": { "@types/node": "^12.12.7", diff --git a/src/node/constants.ts b/src/node/constants.ts index d6ba953e..c39beb05 100644 --- a/src/node/constants.ts +++ b/src/node/constants.ts @@ -1,13 +1,20 @@ import { logger } from "@coder/logger" +import { JSONSchemaForNPMPackageJsonFiles } from "@schemastore/package" import * as path from "path" -let pkg: { version?: string; commit?: string } = {} -try { - pkg = require("../../package.json") -} catch (error) { - logger.warn(error.message) +export function getPackageJson(relativePath: string): JSONSchemaForNPMPackageJsonFiles { + let pkg = {} + try { + pkg = require(relativePath) + } catch (error) { + logger.warn(error.message) + } + + return pkg } +const pkg = getPackageJson("../../package.json") + export const version = pkg.version || "development" export const commit = pkg.commit || "development" export const rootPath = path.resolve(__dirname, "../..") diff --git a/test/constants.test.ts b/test/constants.test.ts new file mode 100644 index 00000000..457f57fa --- /dev/null +++ b/test/constants.test.ts @@ -0,0 +1,58 @@ +// Note: we need to import logger from the root +// because this is the logger used in logError in ../src/common/util +import { logger } from "../node_modules/@coder/logger" +import { commit, getPackageJson, version } from "../src/node/constants" + +describe("constants", () => { + describe("getPackageJson", () => { + let spy: jest.SpyInstance + + beforeEach(() => { + spy = jest.spyOn(logger, "warn") + }) + + afterEach(() => { + jest.clearAllMocks() + }) + + afterAll(() => { + jest.restoreAllMocks() + }) + + it("should log a warning if package.json not found", () => { + const expectedErrorMessage = "Cannot find module './package.json' from 'src/node/constants.ts'" + + getPackageJson("./package.json") + + expect(spy).toHaveBeenCalled() + expect(spy).toHaveBeenCalledWith(expectedErrorMessage) + }) + + it("should find the package.json", () => { + // the function calls require from src/node/constants + // so to get the root package.json we need to use ../../ + const packageJson = getPackageJson("../../package.json") + expect(Object.keys(packageJson).length).toBeGreaterThan(0) + expect(packageJson.name).toBe("code-server") + expect(packageJson.description).toBe("Run VS Code on a remote server.") + expect(packageJson.repository).toBe("https://github.com/cdr/code-server") + }) + }) + describe("version", () => { + it("should return the package.json version", () => { + // Source: https://gist.github.com/jhorsman/62eeea161a13b80e39f5249281e17c39#gistcomment-2896416 + const validSemVar = new RegExp("^(0|[1-9]d*).(0|[1-9]d*).(0|[1-9]d*)") + const isValidSemVar = validSemVar.test(version) + expect(version).not.toBe(null) + expect(isValidSemVar).toBe(true) + }) + }) + + describe("commit", () => { + it("should return 'development' if commit is undefined", () => { + // In development, the commit is not stored in our package.json + // But when we build code-server and release it, it is + expect(commit).toBe("development") + }) + }) +}) diff --git a/test/http.test.ts b/test/http.test.ts new file mode 100644 index 00000000..234fca0d --- /dev/null +++ b/test/http.test.ts @@ -0,0 +1,35 @@ +import { HttpCode, HttpError } from "../src/common/http" + +describe("http", () => { + describe("HttpCode", () => { + it("should return the correct HTTP codes", () => { + expect(HttpCode.Ok).toBe(200) + expect(HttpCode.Redirect).toBe(302) + expect(HttpCode.NotFound).toBe(404) + expect(HttpCode.BadRequest).toBe(400) + expect(HttpCode.Unauthorized).toBe(401) + expect(HttpCode.LargePayload).toBe(413) + expect(HttpCode.ServerError).toBe(500) + }) + }) + + describe("HttpError", () => { + it("should work as expected", () => { + const message = "Bad request from client" + const httpError = new HttpError(message, HttpCode.BadRequest) + + expect(httpError.message).toBe(message) + expect(httpError.status).toBe(400) + expect(httpError.details).toBeUndefined() + }) + it("should have details if provided", () => { + const details = { + message: "User needs to be signed-in in order to perform action", + } + const message = "Unauthorized" + const httpError = new HttpError(message, HttpCode.BadRequest, details) + + expect(httpError.details).toStrictEqual(details) + }) + }) +}) diff --git a/test/util.test.ts b/test/util.test.ts index 418756a5..78985554 100644 --- a/test/util.test.ts +++ b/test/util.test.ts @@ -125,10 +125,6 @@ describe("util", () => { }) describe("getOptions", () => { - // Things to mock - // logger - // location - // document beforeEach(() => { const location: LocationLike = { pathname: "/healthz", diff --git a/yarn.lock b/yarn.lock index cb51b991..93173db8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -980,6 +980,11 @@ "@parcel/utils" "^1.11.0" physical-cpu-count "^2.0.0" +"@schemastore/package@^0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@schemastore/package/-/package-0.0.6.tgz#9a76713da1c7551293b7e72e4f387f802bfd5d81" + integrity sha512-uNloNHoyHttSSdeuEkkSC+mdxJXMKlcUPOMb//qhQbIQijXg8x54VmAw3jm6GJZQ5DBtIqGBd66zEQCDCChQVA== + "@stylelint/postcss-css-in-js@^0.37.2": version "0.37.2" resolved "https://registry.yarnpkg.com/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz#7e5a84ad181f4234a2480803422a47b8749af3d2"