Tracer bullet for gitea-axi: runnable npm package on axi-sdk-js with gitea-js as the sole HTTP layer, ESM on Node 20+. - issue list with --state/--limit, default fields, count line from X-Total-Count, type=issues guard, explicit empty state, and next-step suggestions - repo context detection from the git origin remote (SSH/scp/HTTPS), tea credential discovery with the three-way login-matching split, and -R/--repo and --login overrides (flag > env > auto) - token retrieval via tea login helper get: tea's login list JSON carries no token (ADR 0001 amended) - full AxiError classification table with path-based 404 split, TOON errors on stdout, exit codes 0/1/2 - test mode (GITEA_AXI_API_URL/TOKEN/REPO) suppressing subprocesses, fixture server, and vitest suites driving the CLI seam (50 tests)
120 lines
4.1 KiB
TypeScript
120 lines
4.1 KiB
TypeScript
import { afterEach, describe, expect, it } from "vitest";
|
|
import { startFixtureServer, type FixtureServer } from "./fixture-server.js";
|
|
import { runCliTest, testModeEnv } from "./harness.js";
|
|
|
|
let server: FixtureServer | undefined;
|
|
|
|
afterEach(async () => {
|
|
await server?.close();
|
|
server = undefined;
|
|
});
|
|
|
|
describe("context overrides", () => {
|
|
it("prefers the -R flag over GITEA_AXI_REPO", async () => {
|
|
server = await startFixtureServer([
|
|
{ method: "GET", path: "/api/v1/repos/flagowner/flagrepo/issues", body: [] },
|
|
]);
|
|
const { exitCode } = await runCliTest(
|
|
["issue", "list", "-R", "flagowner/flagrepo"],
|
|
{ env: testModeEnv(server.url) },
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(server.requests[0]!.path).toBe("/api/v1/repos/flagowner/flagrepo/issues");
|
|
});
|
|
|
|
it("accepts -R before the command", async () => {
|
|
server = await startFixtureServer([
|
|
{ method: "GET", path: "/api/v1/repos/flagowner/flagrepo/issues", body: [] },
|
|
]);
|
|
const { exitCode } = await runCliTest(
|
|
["-R", "flagowner/flagrepo", "issue", "list"],
|
|
{ env: testModeEnv(server.url) },
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(server.requests[0]!.path).toBe("/api/v1/repos/flagowner/flagrepo/issues");
|
|
});
|
|
|
|
it("accepts the --repo=OWNER/NAME form", async () => {
|
|
server = await startFixtureServer([
|
|
{ method: "GET", path: "/api/v1/repos/flagowner/flagrepo/issues", body: [] },
|
|
]);
|
|
const { exitCode } = await runCliTest(
|
|
["issue", "list", "--repo=flagowner/flagrepo"],
|
|
{ env: testModeEnv(server.url) },
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(server.requests[0]!.path).toBe("/api/v1/repos/flagowner/flagrepo/issues");
|
|
});
|
|
|
|
it("includes the -R override in next-step suggestions when context came from a flag", async () => {
|
|
server = await startFixtureServer([
|
|
{ method: "GET", path: "/api/v1/repos/flagowner/flagrepo/issues", body: [] },
|
|
]);
|
|
const { stdout } = await runCliTest(
|
|
["issue", "list", "-R", "flagowner/flagrepo"],
|
|
{ env: testModeEnv(server.url) },
|
|
);
|
|
|
|
expect(stdout).toContain("-R flagowner/flagrepo");
|
|
});
|
|
|
|
it("includes the -R override in suggestions when context came from the environment", async () => {
|
|
server = await startFixtureServer([
|
|
{ method: "GET", path: "/api/v1/repos/testowner/testrepo/issues", body: [] },
|
|
]);
|
|
const { stdout } = await runCliTest(["issue", "list"], {
|
|
env: testModeEnv(server.url),
|
|
});
|
|
|
|
expect(stdout).toContain("-R testowner/testrepo");
|
|
});
|
|
|
|
it("fails with REPO_NOT_FOUND when test mode has no repository context", async () => {
|
|
server = await startFixtureServer([]);
|
|
const { stdout, exitCode } = await runCliTest(["issue", "list"], {
|
|
env: { GITEA_AXI_API_URL: server.url, GITEA_AXI_TOKEN: "test-token" },
|
|
});
|
|
|
|
expect(exitCode).toBe(1);
|
|
expect(stdout).toContain("code: REPO_NOT_FOUND");
|
|
expect(stdout).toContain("GITEA_AXI_REPO");
|
|
});
|
|
|
|
it("rejects a malformed -R value with exit code 2", async () => {
|
|
server = await startFixtureServer([]);
|
|
const { stdout, exitCode } = await runCliTest(
|
|
["issue", "list", "-R", "not-a-repo"],
|
|
{ env: testModeEnv(server.url) },
|
|
);
|
|
|
|
expect(exitCode).toBe(2);
|
|
expect(stdout).toContain("code: VALIDATION_ERROR");
|
|
expect(stdout).toContain("OWNER/NAME");
|
|
});
|
|
|
|
it("rejects -R without a value with exit code 2", async () => {
|
|
const { stdout, exitCode } = await runCliTest(["issue", "list", "-R"], {
|
|
env: { GITEA_AXI_API_URL: "http://127.0.0.1:1" },
|
|
});
|
|
|
|
expect(exitCode).toBe(2);
|
|
expect(stdout).toContain("code: VALIDATION_ERROR");
|
|
});
|
|
|
|
it("test mode never spawns git or tea", async () => {
|
|
// An empty PATH makes any subprocess spawn fail loudly; success here
|
|
// proves the git and tea subprocesses were suppressed.
|
|
server = await startFixtureServer([
|
|
{ method: "GET", path: "/api/v1/repos/testowner/testrepo/issues", body: [] },
|
|
]);
|
|
const { exitCode } = await runCliTest(["issue", "list"], {
|
|
env: { ...testModeEnv(server.url), PATH: "" },
|
|
});
|
|
|
|
expect(exitCode).toBe(0);
|
|
});
|
|
});
|