test: add recover/email-change branch coverage tests (TDD)
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 21m29s

This commit is contained in:
OpenClaw Subagent 2026-03-21 17:09:39 +01:00
parent 20e6c8ce8c
commit e0c4214e53
2 changed files with 122 additions and 0 deletions

View file

@ -0,0 +1,44 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import express from "express";
import request from "supertest";
vi.mock("../services/db.js");
vi.mock("../services/logger.js", () => ({
default: { info: vi.fn(), error: vi.fn(), warn: vi.fn(), debug: vi.fn() },
}));
let app: express.Express;
beforeEach(async () => {
vi.clearAllMocks();
vi.resetModules();
const { queryWithRetry } = await import("../services/db.js");
vi.mocked(queryWithRetry).mockResolvedValue({ rows: [], rowCount: 0 } as any);
const { emailChangeRouter } = await import("../routes/email-change.js");
app = express();
app.use(express.json());
app.use("/email-change", emailChangeRouter);
});
describe("email-change branch coverage", () => {
// Line 16: req.body being falsy in rate limiter keyGenerator — covered implicitly
// Line 75: req.body being falsy in POST / handler
it("POST /email-change with no body returns 400", async () => {
const res = await request(app)
.post("/email-change")
.set("Content-Type", "application/json")
.send("null");
expect(res.status).toBe(400);
});
// Line 171: req.body being falsy in POST /verify handler
it("POST /email-change/verify with no body returns 400", async () => {
const res = await request(app)
.post("/email-change/verify")
.set("Content-Type", "application/json")
.send("null");
expect(res.status).toBe(400);
});
});

View file

@ -0,0 +1,78 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import express from "express";
import request from "supertest";
vi.mock("../services/db.js");
vi.mock("../services/logger.js", () => ({
default: { info: vi.fn(), error: vi.fn(), warn: vi.fn(), debug: vi.fn() },
}));
let app: express.Express;
beforeEach(async () => {
vi.clearAllMocks();
vi.resetModules();
const { createPendingVerification, verifyCode } = await import("../services/verification.js");
const { sendVerificationEmail } = await import("../services/email.js");
const { getAllKeys } = await import("../services/keys.js");
const { queryWithRetry } = await import("../services/db.js");
vi.mocked(createPendingVerification).mockResolvedValue({ email: "test@test.com", code: "654321", createdAt: "", expiresAt: "", attempts: 0 });
vi.mocked(verifyCode).mockResolvedValue({ status: "ok" });
vi.mocked(sendVerificationEmail).mockResolvedValue(true);
vi.mocked(getAllKeys).mockReturnValue([]);
vi.mocked(queryWithRetry).mockResolvedValue({ rows: [], rowCount: 0 } as any);
const { recoverRouter } = await import("../routes/recover.js");
app = express();
app.use(express.json());
app.use("/recover", recoverRouter);
});
describe("recover branch coverage", () => {
// Line 61: req.body being falsy (no body sent) — hits `req.body || {}` fallback
it("POST /recover with no body returns 400", async () => {
const res = await request(app)
.post("/recover")
.set("Content-Type", "application/json")
.send("null");
expect(res.status).toBe(400);
});
// Line 151: req.body being falsy in verify endpoint
it("POST /recover/verify with no body returns 400", async () => {
const res = await request(app)
.post("/recover/verify")
.set("Content-Type", "application/json")
.send("null");
expect(res.status).toBe(400);
});
// Line 181: row.created_at instanceof Date — when DB returns a Date object
it("POST /recover/verify handles Date object for created_at in DB fallback", async () => {
const { verifyCode } = await import("../services/verification.js");
const { getAllKeys } = await import("../services/keys.js");
const { queryWithRetry } = await import("../services/db.js");
vi.mocked(verifyCode).mockResolvedValue({ status: "ok" });
vi.mocked(getAllKeys).mockReturnValue([]); // Force DB fallback
vi.mocked(queryWithRetry).mockResolvedValue({
rows: [{
key: "recovered-key",
tier: "pro",
email: "found@test.com",
created_at: new Date("2026-01-15T10:00:00Z"), // Date object, not string
stripe_customer_id: null,
}],
rowCount: 1,
} as any);
const res = await request(app)
.post("/recover/verify")
.send({ email: "found@test.com", code: "654321" });
expect(res.status).toBe(200);
expect(res.body.apiKey).toBe("recovered-key");
});
});