aboutsummaryrefslogtreecommitdiffstats
path: root/test/api.test.ts
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-03-15 21:53:52 -0700
committerAdam Soltys <[email protected]>2026-03-15 21:53:52 -0700
commitddfe2e3279706f6476364cecfe23427dcabcfd3e (patch)
treef37a2ea3d8e904214c7d8b695c3d87dca7c56466 /test/api.test.ts
parentfddfe10f84908c058e239b93985dfe02ba37df04 (diff)
downloadcoinos-server-ddfe2e3279706f6476364cecfe23427dcabcfd3e.tar.gz
coinos-server-ddfe2e3279706f6476364cecfe23427dcabcfd3e.zip
tests
Diffstat (limited to 'test/api.test.ts')
-rw-r--r--test/api.test.ts126
1 files changed, 126 insertions, 0 deletions
diff --git a/test/api.test.ts b/test/api.test.ts
new file mode 100644
index 00000000..92e506f3
--- /dev/null
+++ b/test/api.test.ts
@@ -0,0 +1,126 @@
+import { describe, test, expect, beforeAll } from "bun:test";
+import app from "$lib/app";
+import { auth, optional } from "$lib/auth";
+import users from "$routes/users";
+import info from "$routes/info";
+import invoices from "$routes/invoices";
+
+// Register routes (subset of index.ts — no side effects, no Bun.serve)
+app.get("/health", info.health);
+app.post("/register", users.create);
+app.post("/login", users.login);
+app.get("/me", auth, users.me);
+app.get("/users/:key", users.get);
+app.post("/invoice", optional, invoices.create);
+app.get("/invoice/:id", invoices.get);
+
+const post = (path: string, body: any) =>
+ app.request(path, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(body),
+ });
+
+// Use unique username to avoid collisions with other test files
+const USERNAME = `apiuser${Date.now()}`;
+const PASSWORD = "testpass123";
+
+beforeAll(() => {
+ // Clear any leftover state from other test files
+ const store = globalThis.__testStore;
+ for (const k of Object.keys(store.kvStore)) delete store.kvStore[k];
+ for (const k of Object.keys(store.listStore)) delete store.listStore[k];
+ for (const k of Object.keys(store.setStore)) delete store.setStore[k];
+});
+
+describe("Health", () => {
+ test("GET /health returns 200", async () => {
+ const res = await app.request("/health");
+ expect(res.status).toBe(200);
+ const body = await res.json();
+ expect(body.healthy).toBe(true);
+ });
+});
+
+describe("Registration", () => {
+ test("creates user with valid credentials", async () => {
+ const res = await post("/register", {
+ user: { username: USERNAME, password: PASSWORD },
+ });
+ expect(res.status).toBe(200);
+ const body = await res.json();
+ expect(body.token).toBeDefined();
+ expect(body.username).toBe(USERNAME);
+ });
+
+ test("rejects duplicate username", async () => {
+ const res = await post("/register", {
+ user: { username: USERNAME, password: PASSWORD },
+ });
+ expect(res.status).toBe(500);
+ });
+
+ test("rejects missing user object", async () => {
+ const res = await post("/register", { password: PASSWORD });
+ expect(res.status).toBe(500);
+ });
+
+ test("rejects invalid username", async () => {
+ const res = await post("/register", {
+ user: { username: "ab!@#", password: PASSWORD },
+ });
+ expect(res.status).toBe(500);
+ });
+});
+
+describe("Login", () => {
+ test("succeeds with valid credentials", async () => {
+ const res = await post("/login", {
+ username: USERNAME,
+ password: PASSWORD,
+ });
+ expect(res.status).toBe(200);
+ const body = await res.json();
+ expect(body.token).toBeDefined();
+ expect(body.user).toBeDefined();
+ });
+
+ test("fails with wrong password", async () => {
+ const res = await post("/login", {
+ username: USERNAME,
+ password: "wrongpass",
+ });
+ expect(res.status).toBe(401);
+ });
+
+ test("fails with nonexistent user", async () => {
+ const res = await post("/login", {
+ username: "noone",
+ password: PASSWORD,
+ });
+ expect(res.status).toBe(401);
+ });
+});
+
+describe("Authenticated endpoints", () => {
+ test("GET /me returns user data", async () => {
+ const res = await app.request("/me");
+ expect(res.status).toBe(200);
+ const body = await res.json();
+ expect(body.username).toBeDefined();
+ });
+});
+
+describe("User lookup", () => {
+ test("GET /users/:key finds registered user", async () => {
+ const res = await app.request(`/users/${USERNAME}`);
+ expect(res.status).toBe(200);
+ });
+});
+
+describe("Routing", () => {
+ test("unknown route returns 404", async () => {
+ const res = await app.request("/nonexistent");
+ expect(res.status).toBe(404);
+ });
+});