Files
GMW/services/backend/src/e2e.test.ts
T
DeveloperandClaude Opus 4.8 5802d02e29
Build & Deploy / build-and-push (discord-gateway) (push) Failing after 2m22s
Build & Deploy / build-and-push (backend) (push) Failing after 3m22s
Build & Deploy / build-and-push (proxy) (push) Successful in 1m36s
Build & Deploy / deploy (push) Skipped
refactor: large codebase cleanup - consolidate schemas, migrate to Drizzle ORM, extract frontend components, modernize Docker builds
- Consolidate all DB schema definitions into packages/shared as single source of truth
- Migrate backend from raw SQL to Drizzle ORM across all modules
- Extract frontend inline UI into separate component files
- Refactor discord-gateway circuitBreaker into conversationState + moderationState
- Convert messageStore to Proxy singleton pattern
- Add validateBody/validateQuery middleware + Zod schemas for API endpoints
- Modernize Docker builds with multi-stage + pnpm deploy
- Migrate CI/CD from deployment to image-based pipeline
- Remove 60+ unused/dead files (~15K lines)
- Update color scheme from sky-blue to teal-cyan
- Move DB connection management to @bete/shared/database

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-27 21:54:31 +07:00

83 lines
2.5 KiB
TypeScript

/**
* E2E API tests — runs against a running backend instance.
* Usage: API_BASE=http://localhost:3001 vitest run
*/
import { describe, expect, it } from "vitest";
const BASE = process.env.API_BASE ?? "http://localhost:3001/api";
async function api(path: string, init?: RequestInit) {
const res = await fetch(`${BASE}${path}`, {
...init,
headers: { "Content-Type": "application/json", ...init?.headers },
});
const body = res.status !== 204 ? await res.json().catch(() => null) : null;
return { status: res.status, body };
}
describe("API Health", () => {
it("GET /health returns 200 with status=healthy", async () => {
const { status, body } = await api("/health");
expect(status).toBe(200);
expect(body?.status).toBe("healthy");
});
it("GET /metrics returns prometheus text", async () => {
const res = await fetch(`${BASE.replace("/api", "")}/api/metrics`);
expect(res.status).toBe(200);
const text = await res.text();
expect(text).toContain("nodejs");
});
});
describe("API Dashboard", () => {
it("GET /dashboard/stats returns stats fields", async () => {
const { status, body } = await api("/dashboard/stats");
expect(status).toBe(200);
expect(body).toHaveProperty("total_messages");
expect(body).toHaveProperty("total_flagged");
expect(body).toHaveProperty("active_users_24h");
expect(typeof body.total_messages).toBe("number");
});
});
describe("API Recordings", () => {
it("GET /recordings returns items with pagination", async () => {
const { status, body } = await api("/recordings?limit=5");
expect(status).toBe(200);
expect(body).toHaveProperty("items");
expect(Array.isArray(body.items)).toBe(true);
if (body.items.length > 0) {
expect(body.items[0]).toHaveProperty("id");
expect(body.items[0]).toHaveProperty("username");
expect(body.items[0]).toHaveProperty("created_at");
}
});
});
describe("API Config", () => {
it("GET /config returns 200", async () => {
const { status } = await api("/config");
expect(status).toBe(200);
});
});
describe("API Voice", () => {
it("GET /guilds returns 200", async () => {
const { status } = await api("/guilds");
expect(status).toBe(200);
});
});
describe("API Negative", () => {
it("GET /nonexistent returns 404", async () => {
const { status } = await api("/nonexistent");
expect(status).toBe(404);
});
it("GET /messages without channelId returns 400", async () => {
const { status } = await api("/messages?limit=3");
expect(status).toBe(400);
});
});