Remove dead signup router, unused verification functions, and legacy cleanup query
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 18m37s
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 18m37s
- Delete src/routes/signup.ts (dead code, 410 handler in index.ts remains) - Remove isEmailVerified() and getVerifiedApiKey() from verification.ts (only used by signup) - Remove stale-key cleanup from cleanupStaleData() that queried legacy verifications table - Update usage middleware message: 'Free tier limit' → 'Account limit' - TDD: 8 new tests, removed signup.test.ts (dead), net 556 tests passing
This commit is contained in:
parent
921562750f
commit
7206cb518d
11 changed files with 79 additions and 308 deletions
16
src/__tests__/cleanup-no-verifications-table.test.ts
Normal file
16
src/__tests__/cleanup-no-verifications-table.test.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
describe("cleanupStaleData should not reference legacy verifications table", () => {
|
||||
it("should not query verifications table (legacy, no longer written to)", () => {
|
||||
const dbSrc = readFileSync(join(__dirname, "../services/db.ts"), "utf8");
|
||||
// Extract just the cleanupStaleData function body
|
||||
const funcStart = dbSrc.indexOf("async function cleanupStaleData");
|
||||
const funcEnd = dbSrc.indexOf("export { pool }");
|
||||
const funcBody = dbSrc.slice(funcStart, funcEnd);
|
||||
// Should not reference 'verifications' table (only pending_verifications is active)
|
||||
// The old query checked: email NOT IN (SELECT ... FROM verifications WHERE verified_at IS NOT NULL)
|
||||
expect(funcBody).not.toContain("FROM verifications WHERE verified_at");
|
||||
});
|
||||
});
|
||||
44
src/__tests__/dead-signup-removal.test.ts
Normal file
44
src/__tests__/dead-signup-removal.test.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
import { readFileSync, existsSync } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
describe("Dead Signup Router Removal", () => {
|
||||
describe("Signup router module removed", () => {
|
||||
it("should not have src/routes/signup.ts file", () => {
|
||||
const signupPath = join(__dirname, "../routes/signup.ts");
|
||||
expect(existsSync(signupPath)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Dead verification functions removed from source", () => {
|
||||
it("should not export isEmailVerified from verification.ts source", () => {
|
||||
const src = readFileSync(join(__dirname, "../services/verification.ts"), "utf8");
|
||||
expect(src).not.toContain("export async function isEmailVerified");
|
||||
});
|
||||
|
||||
it("should not export getVerifiedApiKey from verification.ts source", () => {
|
||||
const src = readFileSync(join(__dirname, "../services/verification.ts"), "utf8");
|
||||
expect(src).not.toContain("export async function getVerifiedApiKey");
|
||||
});
|
||||
|
||||
it("should still export createPendingVerification", () => {
|
||||
const src = readFileSync(join(__dirname, "../services/verification.ts"), "utf8");
|
||||
expect(src).toContain("export async function createPendingVerification");
|
||||
});
|
||||
|
||||
it("should still export verifyCode", () => {
|
||||
const src = readFileSync(join(__dirname, "../services/verification.ts"), "utf8");
|
||||
expect(src).toContain("export async function verifyCode");
|
||||
});
|
||||
});
|
||||
|
||||
describe("410 signup handler still works", () => {
|
||||
it("should still have signup 410 handler working", async () => {
|
||||
const request = (await import("supertest")).default;
|
||||
const { app } = await import("../index.js");
|
||||
const res = await request(app).post("/v1/signup/free");
|
||||
expect(res.status).toBe(410);
|
||||
expect(res.body.error).toContain("discontinued");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -80,17 +80,7 @@ describe("Dead Token Verification System Removal", () => {
|
|||
expect(typeof verification.verifyCode).toBe("function");
|
||||
});
|
||||
|
||||
it("should export isEmailVerified", async () => {
|
||||
const verification = await import("../services/verification.js");
|
||||
expect(verification).toHaveProperty("isEmailVerified");
|
||||
expect(typeof verification.isEmailVerified).toBe("function");
|
||||
});
|
||||
|
||||
it("should export getVerifiedApiKey", async () => {
|
||||
const verification = await import("../services/verification.js");
|
||||
expect(verification).toHaveProperty("getVerifiedApiKey");
|
||||
expect(typeof verification.getVerifiedApiKey).toBe("function");
|
||||
});
|
||||
// isEmailVerified and getVerifiedApiKey removed — only used by dead signup router
|
||||
|
||||
it("should export PendingVerification interface", async () => {
|
||||
// TypeScript interface test - if compilation passes, the interface exists
|
||||
|
|
|
|||
|
|
@ -74,8 +74,7 @@ vi.mock("../services/browser.js", () => ({
|
|||
vi.mock("../services/verification.js", () => ({
|
||||
createPendingVerification: vi.fn().mockResolvedValue({ email: "test@test.com", code: "123456" }),
|
||||
verifyCode: vi.fn().mockResolvedValue({ status: "ok" }),
|
||||
isEmailVerified: vi.fn().mockResolvedValue(false),
|
||||
getVerifiedApiKey: vi.fn().mockResolvedValue(null),
|
||||
|
||||
}));
|
||||
|
||||
// Mock email service
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import express from "express";
|
||||
import request from "supertest";
|
||||
|
||||
let app: express.Express;
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
vi.resetModules();
|
||||
|
||||
const { isEmailVerified, createPendingVerification, verifyCode } = await import("../services/verification.js");
|
||||
const { sendVerificationEmail } = await import("../services/email.js");
|
||||
const { createFreeKey } = await import("../services/keys.js");
|
||||
|
||||
vi.mocked(isEmailVerified).mockResolvedValue(false);
|
||||
vi.mocked(createPendingVerification).mockResolvedValue({ email: "test@test.com", code: "123456", createdAt: "", expiresAt: "", attempts: 0 });
|
||||
vi.mocked(verifyCode).mockResolvedValue({ status: "ok" });
|
||||
vi.mocked(createFreeKey).mockResolvedValue({ key: "free-key-123", tier: "free", email: "test@test.com", createdAt: "" });
|
||||
|
||||
vi.mocked(sendVerificationEmail).mockResolvedValue(true);
|
||||
|
||||
const { signupRouter } = await import("../routes/signup.js");
|
||||
app = express();
|
||||
app.use(express.json());
|
||||
app.use("/signup", signupRouter);
|
||||
});
|
||||
|
||||
describe("POST /signup/free", () => {
|
||||
it("returns 400 for missing email", async () => {
|
||||
const res = await request(app).post("/signup/free").send({});
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
|
||||
it("returns 400 for invalid email format", async () => {
|
||||
const res = await request(app).post("/signup/free").send({ email: "not-email" });
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
|
||||
it("returns 409 for already verified email", async () => {
|
||||
const { isEmailVerified } = await import("../services/verification.js");
|
||||
vi.mocked(isEmailVerified).mockResolvedValue(true);
|
||||
const res = await request(app).post("/signup/free").send({ email: "dup@test.com" });
|
||||
expect(res.status).toBe(409);
|
||||
});
|
||||
|
||||
it("returns 200 with verification_required for valid email", async () => {
|
||||
const res = await request(app).post("/signup/free").send({ email: "new@test.com" });
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.status).toBe("verification_required");
|
||||
});
|
||||
|
||||
it("sends verification email asynchronously", async () => {
|
||||
const { sendVerificationEmail } = await import("../services/email.js");
|
||||
await request(app).post("/signup/free").send({ email: "new@test.com" });
|
||||
await new Promise(r => setTimeout(r, 50));
|
||||
expect(sendVerificationEmail).toHaveBeenCalledWith("new@test.com", "123456");
|
||||
});
|
||||
});
|
||||
|
||||
describe("POST /signup/verify", () => {
|
||||
it("returns 400 for missing email/code", async () => {
|
||||
const res = await request(app).post("/signup/verify").send({ email: "a@b.com" });
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
|
||||
it("returns 409 for already verified email", async () => {
|
||||
const { isEmailVerified } = await import("../services/verification.js");
|
||||
vi.mocked(isEmailVerified).mockResolvedValue(true);
|
||||
const res = await request(app).post("/signup/verify").send({ email: "dup@test.com", code: "123456" });
|
||||
expect(res.status).toBe(409);
|
||||
});
|
||||
|
||||
it("returns 410 for expired code", async () => {
|
||||
const { verifyCode } = await import("../services/verification.js");
|
||||
vi.mocked(verifyCode).mockResolvedValue({ status: "expired" });
|
||||
const res = await request(app).post("/signup/verify").send({ email: "a@b.com", code: "123456" });
|
||||
expect(res.status).toBe(410);
|
||||
});
|
||||
|
||||
it("returns 429 for max attempts", async () => {
|
||||
const { verifyCode } = await import("../services/verification.js");
|
||||
vi.mocked(verifyCode).mockResolvedValue({ status: "max_attempts" });
|
||||
const res = await request(app).post("/signup/verify").send({ email: "a@b.com", code: "123456" });
|
||||
expect(res.status).toBe(429);
|
||||
});
|
||||
|
||||
it("returns 400 for invalid code", async () => {
|
||||
const { verifyCode } = await import("../services/verification.js");
|
||||
vi.mocked(verifyCode).mockResolvedValue({ status: "invalid" });
|
||||
const res = await request(app).post("/signup/verify").send({ email: "a@b.com", code: "999999" });
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
|
||||
it("returns 200 with apiKey for valid code", async () => {
|
||||
const res = await request(app).post("/signup/verify").send({ email: "a@b.com", code: "123456" });
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body).toMatchObject({ status: "verified", apiKey: "free-key-123" });
|
||||
});
|
||||
});
|
||||
11
src/__tests__/usage-free-tier-message.test.ts
Normal file
11
src/__tests__/usage-free-tier-message.test.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
describe("Usage middleware messaging", () => {
|
||||
it("should not reference 'Free tier' in limit message", () => {
|
||||
const usageSrc = readFileSync(join(__dirname, "../middleware/usage.ts"), "utf8");
|
||||
// The rate limit message should say "Account limit" not "Free tier limit"
|
||||
expect(usageSrc).not.toContain("Free tier limit");
|
||||
});
|
||||
});
|
||||
|
|
@ -132,7 +132,7 @@ describe("usage middleware", () => {
|
|||
|
||||
expect(mockStatus).toHaveBeenCalledWith(429);
|
||||
expect(mockJson).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ error: expect.stringContaining("Free tier limit") })
|
||||
expect.objectContaining({ error: expect.stringContaining("Account limit") })
|
||||
);
|
||||
expect(mockNext).not.toHaveBeenCalled();
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue