Jobber/orchestrator/src/server/api/routes/settings.test.ts
Shaheer Sarfaraz fe0aebe01a
Small bits and bobs, codebase quality (#129)
* initial change

* nav highlighting

* icon change

* deeeedoooop

* text

* show version number on all pages

* icon

* remove unused code

* add knip

* formatting

* remove unused code

* types fix

* remove notion completely from the codebase.

* update test for new url structure

* clean up the fucking shop boys

* make a "create job" factory and use that

* moar factories

* formatting
2026-02-10 20:01:58 +00:00

122 lines
4.2 KiB
TypeScript

import type { Server } from "node:http";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { startServer, stopServer } from "./test-utils";
describe.sequential("Settings API routes", () => {
let server: Server;
let baseUrl: string;
let closeDb: () => void;
let tempDir: string;
beforeEach(async () => {
({ server, baseUrl, closeDb, tempDir } = await startServer({
env: {
LLM_API_KEY: "secret-key",
RXRESUME_EMAIL: "resume@example.com",
},
}));
});
afterEach(async () => {
await stopServer({ server, closeDb, tempDir });
});
it("returns settings with defaults", async () => {
const res = await fetch(`${baseUrl}/api/settings`);
const body = await res.json();
expect(body.ok).toBe(true);
expect(body.data.defaultModel).toBe("test-model");
expect(Array.isArray(body.data.searchTerms)).toBe(true);
expect(body.data.rxresumeEmail).toBe("resume@example.com");
expect(body.data.llmApiKeyHint).toBe("secr");
expect(body.data.basicAuthActive).toBe(false);
});
it("rejects invalid settings updates and persists overrides", async () => {
const badPatch = await fetch(`${baseUrl}/api/settings`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ jobspyResultsWanted: 9999 }),
});
expect(badPatch.status).toBe(400);
const patchRes = await fetch(`${baseUrl}/api/settings`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
searchTerms: ["engineer"],
rxresumeEmail: "updated@example.com",
llmApiKey: "updated-secret",
}),
});
const patchBody = await patchRes.json();
expect(patchBody.ok).toBe(true);
expect(patchBody.data.searchTerms).toEqual(["engineer"]);
expect(patchBody.data.overrideSearchTerms).toEqual(["engineer"]);
expect(patchBody.data.rxresumeEmail).toBe("updated@example.com");
expect(patchBody.data.llmApiKeyHint).toBe("upda");
});
it("validates basic auth requirements", async () => {
const res = await fetch(`${baseUrl}/api/settings`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
enableBasicAuth: true,
basicAuthUser: "",
}),
});
expect(res.status).toBe(400);
const body = await res.json();
expect(body.ok).toBe(false);
expect(body.error.message).toContain("Username is required");
});
it("handles salary penalty settings with validation", async () => {
// Get initial settings
const initialRes = await fetch(`${baseUrl}/api/settings`);
const initialBody = await initialRes.json();
expect(initialBody.ok).toBe(true);
expect(initialBody.data.penalizeMissingSalary).toBe(false);
expect(initialBody.data.missingSalaryPenalty).toBe(10);
// Test invalid penalty values
const invalidRes = await fetch(`${baseUrl}/api/settings`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ missingSalaryPenalty: 150 }),
});
expect(invalidRes.status).toBe(400);
const negativeRes = await fetch(`${baseUrl}/api/settings`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ missingSalaryPenalty: -10 }),
});
expect(negativeRes.status).toBe(400);
// Test valid settings update
const validRes = await fetch(`${baseUrl}/api/settings`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
penalizeMissingSalary: true,
missingSalaryPenalty: 20,
}),
});
const validBody = await validRes.json();
expect(validBody.ok).toBe(true);
expect(validBody.data.penalizeMissingSalary).toBe(true);
expect(validBody.data.overridePenalizeMissingSalary).toBe(true);
expect(validBody.data.missingSalaryPenalty).toBe(20);
expect(validBody.data.overrideMissingSalaryPenalty).toBe(20);
// Verify persistence
const getRes = await fetch(`${baseUrl}/api/settings`);
const getBody = await getRes.json();
expect(getBody.ok).toBe(true);
expect(getBody.data.penalizeMissingSalary).toBe(true);
expect(getBody.data.missingSalaryPenalty).toBe(20);
});
});