test: admin seed ve kimlik doğrulama entegrasyon testleri
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
// Testlerde "server-only" paketinin yerine geçer (paket React Server ortamı dışında hata fırlatır).
|
||||
export {};
|
||||
Reference in New Issue
Block a user