diff --git a/AGENTS.md b/AGENTS.md index 592ce7d..7f19918 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,6 +14,7 @@ ## Tests - Suites live in `src/tests/`. They compile to `dist/tests` and ship in the package, so implementing modules can run them as a conformance suite; `src/tests/codec_helpers.ts` and `src/tests/helpers/` are part of that surface. +- The model tests fetch routes from the `@antelopejs/api` module on `DECORATORS_TEST_API_PORT`, 5010 when unset. A project that runs the suite serves `api` on that same port, so suites that each set their own port run in parallel on one machine. - `pnpm test` builds once, then runs `ajs module test .` with the project in `src/antelope.test.ts`: a MongoDB memory server, `@antelopejs/mongodb` and `@antelopejs/api` from npm, cached in `.antelope/cache`. The first run needs network access to fetch them and the `mongod` binary. - `pnpm run checks` runs this whole suite. The documentation check runs only in CI (the `Check documentation` step of `ci-node.yml`). To run it locally, clone `AntelopeJS/tooling-configs` at `v0.0.9`, run `npm ci --prefix actions/docs --omit=dev`, then from this repository run `node /actions/docs/check.mjs --files $'README.md\ndocs' --typescript-project docs/tsconfig.json`. diff --git a/src/antelope.test.ts b/src/antelope.test.ts index 3aafb44..99a394c 100644 --- a/src/antelope.test.ts +++ b/src/antelope.test.ts @@ -1,7 +1,9 @@ import { MongoMemoryServer } from "mongodb-memory-server-core"; import { defineConfig } from "@antelopejs/interface-core/config"; +import { ApiPort } from "./tests/helpers/api-port"; let mongod: MongoMemoryServer; +const apiPort = ApiPort(); export default defineConfig({ name: "interface-database-decorators-test", @@ -24,8 +26,8 @@ export default defineConfig({ version: "1.6.0", }, config: { - servers: [{ protocol: "http", host: "127.0.0.1", port: 5010 }], - publicBaseUrl: "http://127.0.0.1:5010", + servers: [{ protocol: "http", host: "127.0.0.1", port: apiPort }], + publicBaseUrl: `http://127.0.0.1:${apiPort}`, }, }, }, diff --git a/src/tests/api_port.test.ts b/src/tests/api_port.test.ts new file mode 100644 index 0000000..802f171 --- /dev/null +++ b/src/tests/api_port.test.ts @@ -0,0 +1,20 @@ +import { expect } from "chai"; + +import { API_PORT_VARIABLE, ApiPort } from "./helpers/api-port"; + +describe("ApiPort", () => { + it("serves on 5010 when the variable is unset or empty", () => { + expect(ApiPort({})).to.equal(5010); + expect(ApiPort({ [API_PORT_VARIABLE]: "" })).to.equal(5010); + }); + it("reads the port from the variable", () => { + expect(ApiPort({ [API_PORT_VARIABLE]: "5011" })).to.equal(5011); + }); + it("rejects a value that is not a port", () => { + for (const raw of ["abc", "0", "65536", "50.1", " 5011", "-1"]) { + expect(() => ApiPort({ [API_PORT_VARIABLE]: raw }), raw).to.throw( + API_PORT_VARIABLE, + ); + } + }); +}); diff --git a/src/tests/helpers/api-port.ts b/src/tests/helpers/api-port.ts new file mode 100644 index 0000000..ad1afd8 --- /dev/null +++ b/src/tests/helpers/api-port.ts @@ -0,0 +1,26 @@ +/** The environment variable that sets the port the `@antelopejs/api` module serves the model tests on. */ +export const API_PORT_VARIABLE = "DECORATORS_TEST_API_PORT"; + +const DEFAULT_API_PORT = 5010; +const MAX_PORT = 65_535; + +/** + * The port the model tests fetch their routes from: `DECORATORS_TEST_API_PORT`, or 5010 when it is + * unset or empty. A backend serves `@antelopejs/api` on this port, so two suites on one machine run + * side by side when each sets its own. + * + * @throws When the variable is set to anything but a port number from 1 to 65535. + */ +export function ApiPort(env: NodeJS.ProcessEnv = process.env): number { + const raw = env[API_PORT_VARIABLE]; + if (raw === undefined || raw === "") { + return DEFAULT_API_PORT; + } + const port = Number(raw); + if (!/^\d+$/.test(raw) || port < 1 || port > MAX_PORT) { + throw new Error( + `${API_PORT_VARIABLE} must be a port from 1 to ${MAX_PORT}, got "${raw}"`, + ); + } + return port; +} diff --git a/src/tests/model.test.ts b/src/tests/model.test.ts index db9e3e9..c6dc878 100644 --- a/src/tests/model.test.ts +++ b/src/tests/model.test.ts @@ -11,6 +11,9 @@ import { import { BasicDataModel, GetModel, Model } from "../model"; import { asFieldType, numberCodec, stringCodec } from "./codec_helpers"; +import { ApiPort } from "./helpers/api-port"; + +const apiUrl = `http://localhost:${ApiPort()}`; describe("Model - data operations", () => { it("creates basic data model", async () => { @@ -150,7 +153,7 @@ describe("Model - data operations", () => { } } - const res = await fetch("http://localhost:5010/staticmodel"); + const res = await fetch(`${apiUrl}/staticmodel`); expect(res.status, res.statusText).to.equal(200); }); it("handles model with callback instance id", async () => { @@ -171,9 +174,7 @@ describe("Model - data operations", () => { } } - const res = await fetch( - "http://localhost:5010/dynamicmodel/test-dynamic-model-db", - ); + const res = await fetch(`${apiUrl}/dynamicmodel/test-dynamic-model-db`); expect(res.status, res.statusText).to.equal(200); }); });