test: admin seed ve kimlik doğrulama entegrasyon testleri

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-05 02:02:00 +03:00
parent 97e7ebe9aa
commit fc3e0ae21b
6 changed files with 305 additions and 13 deletions
+191
View File
@@ -0,0 +1,191 @@
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { getAuth } from "@/lib/auth";
import { authErrorCode } from "@/lib/auth-errors";
import { getDb, getMongoClient } from "@/lib/db/mongo";
import { placeholderEmail } from "@/shared/account-email";
/**
* Better Auth yapılandırmasının güvenlik sözleşmesi (gerçek MongoDB, butcem_test veritabanı).
*/
const auth = getAuth();
const PASSWORD = "Gizli-Sifre-123";
/** Giriş yapıp oturum cookie'sini içeren istek başlıklarını döner. */
async function signIn(username: string, password = PASSWORD): Promise<Headers> {
const { headers } = await auth.api.signInUsername({
body: { username, password },
returnHeaders: true,
});
const cookie = headers
.getSetCookie()
.map((c) => c.split(";")[0])
.join("; ");
return new Headers({ cookie });
}
async function expectAuthError(promise: Promise<unknown>, code: string) {
const error = await promise.then(
() => null,
(e: unknown) => e,
);
expect(error, `beklenen hata: ${code}`).not.toBeNull();
expect(authErrorCode(error)).toBe(code);
}
beforeAll(async () => {
const db = getDb();
expect(db.databaseName).toBe("butcem_test");
await db.dropDatabase();
await auth.api.createUser({
body: {
email: "admin@test.local",
password: PASSWORD,
name: "Admin",
role: "admin",
data: { username: "admin" },
},
});
await auth.api.createUser({
body: {
email: placeholderEmail("emre"),
password: PASSWORD,
name: "Emre",
role: "user",
data: { username: "Emre" },
},
});
});
afterAll(async () => {
await getDb().dropDatabase();
await getMongoClient().close();
});
describe("kayıt kapalı", () => {
it("sign-up/email uç noktası reddedilir ve kullanıcı oluşmaz", async () => {
const res = await auth.handler(
new Request("http://localhost:3000/api/auth/sign-up/email", {
method: "POST",
headers: { "content-type": "application/json", origin: "http://localhost:3000" },
body: JSON.stringify({ email: "yeni@test.local", password: PASSWORD, name: "Yeni" }),
}),
);
expect(res.ok).toBe(false);
expect(await getDb().collection("user").countDocuments({ email: "yeni@test.local" })).toBe(0);
});
});
describe("giriş", () => {
it("kullanıcı adı küçük harfe normalize edilir ve kullanıcı adıyla giriş yapılır", async () => {
const stored = await getDb()
.collection("user")
.findOne({ email: placeholderEmail("emre") });
expect(stored?.username).toBe("emre");
const headers = await signIn("EMRE");
const session = await auth.api.getSession({ headers });
expect(session?.user.name).toBe("Emre");
expect(session?.user.role).toBe("user");
});
it("HTTP üzerinden büyük harfli (I içeren) kullanıcı adıyla giriş yapılır", async () => {
const res = await auth.handler(
new Request("http://localhost:3000/api/auth/sign-in/username", {
method: "POST",
headers: {
"content-type": "application/json",
origin: "http://localhost:3000",
"x-forwarded-for": "198.51.100.1",
},
// "I" içeren büyük harfli giriş (tr-TR'de "ADMIN" → "admın" tuzağı)
body: JSON.stringify({ username: "ADMIN", password: PASSWORD }),
}),
);
expect(res.status).toBe(200);
expect(res.headers.getSetCookie().some((c) => c.includes("session_token"))).toBe(true);
});
it("e-posta ile giriş yapılır", async () => {
const result = await auth.api.signInEmail({
body: { email: "admin@test.local", password: PASSWORD },
});
expect(result.user.email).toBe("admin@test.local");
});
it("yanlış şifre reddedilir", async () => {
await expectAuthError(
auth.api.signInUsername({ body: { username: "emre", password: "yanlis-sifre" } }),
"INVALID_USERNAME_OR_PASSWORD",
);
});
it("aynı kullanıcı adı ikinci kez kullanılamaz", async () => {
await expectAuthError(
auth.api.createUser({
body: {
email: "baska@test.local",
password: PASSWORD,
name: "Kopya",
data: { username: "emre" },
},
}),
"USERNAME_IS_ALREADY_TAKEN",
);
});
});
describe("admin yetkileri", () => {
it("admin olmayan kullanıcı admin API'sini çağıramaz", async () => {
const headers = await signIn("emre");
const res = await auth.api
.listUsers({ headers, query: { limit: 10 } })
.then(() => "ok")
.catch((e: unknown) => authErrorCode(e) ?? "error");
expect(res).not.toBe("ok");
});
it("askıya alınan kullanıcı giriş yapamaz, askı kaldırılınca yapabilir", async () => {
const adminHeaders = await signIn("admin");
const emre = await getDb().collection("user").findOne({ username: "emre" });
const userId = String(emre?._id);
await auth.api.banUser({ headers: adminHeaders, body: { userId, banReason: "test" } });
await expectAuthError(
auth.api.signInUsername({ body: { username: "emre", password: PASSWORD } }),
"BANNED_USER",
);
await auth.api.unbanUser({ headers: adminHeaders, body: { userId } });
await expect(signIn("emre")).resolves.toBeInstanceOf(Headers);
});
it("admin kendini askıya alamaz", async () => {
const adminHeaders = await signIn("admin");
const self = await auth.api.getSession({ headers: adminHeaders });
await expectAuthError(
auth.api.banUser({ headers: adminHeaders, body: { userId: self!.user.id } }),
"YOU_CANNOT_BAN_YOURSELF",
);
});
});
describe("rate limit", () => {
it("giriş denemeleri dakikada 5 ile sınırlıdır", async () => {
const attempt = () =>
auth.handler(
new Request("http://localhost:3000/api/auth/sign-in/username", {
method: "POST",
headers: {
"content-type": "application/json",
origin: "http://localhost:3000",
"x-forwarded-for": "203.0.113.7",
},
body: JSON.stringify({ username: "emre", password: "yanlis-sifre" }),
}),
);
const statuses: number[] = [];
for (let i = 0; i < 6; i++) statuses.push((await attempt()).status);
expect(statuses.slice(0, 5).every((s) => s !== 429)).toBe(true);
expect(statuses[5]).toBe(429);
});
});
+2
View File
@@ -0,0 +1,2 @@
// Testlerde "server-only" paketinin yerine geçer (paket React Server ortamı dışında hata fırlatır).
export {};