103 lines
3.2 KiB
TypeScript
103 lines
3.2 KiB
TypeScript
import { beforeEach, describe, expect, it } from "vitest";
|
|
import type { DecodedIdToken } from "firebase-admin/auth";
|
|
import { firestore } from "../../src/firebase.js";
|
|
import { createMe, getMe } from "../../src/services/userService.js";
|
|
import { HttpError } from "../../src/middleware/errors.js";
|
|
|
|
const uid = "user-1";
|
|
|
|
function fakeToken(overrides: Partial<DecodedIdToken> = {}): DecodedIdToken {
|
|
return {
|
|
uid,
|
|
email: "tester@example.com",
|
|
picture: "https://cdn.example.com/p.png",
|
|
firebase: {
|
|
identities: {},
|
|
sign_in_provider: "google.com",
|
|
},
|
|
aud: "test",
|
|
auth_time: 0,
|
|
exp: 0,
|
|
iat: 0,
|
|
iss: "test",
|
|
sub: uid,
|
|
...overrides,
|
|
} as DecodedIdToken;
|
|
}
|
|
|
|
const validBody = {
|
|
displayName: "유저1",
|
|
favoriteTeamCode: "LG",
|
|
knowledgeLevel: "casual",
|
|
};
|
|
|
|
describe("userService", () => {
|
|
beforeEach(async () => {
|
|
await firestore.recursiveDelete(firestore.collection("users"));
|
|
});
|
|
|
|
describe("getMe", () => {
|
|
it("미존재 유저는 404 + USER_NOT_FOUND", async () => {
|
|
await expect(getMe(uid)).rejects.toMatchObject({
|
|
status: 404,
|
|
code: "USER_NOT_FOUND",
|
|
});
|
|
});
|
|
|
|
it("존재하는 유저를 반환한다", async () => {
|
|
await createMe(fakeToken(), validBody);
|
|
const u = await getMe(uid);
|
|
expect(u.displayName).toBe("유저1");
|
|
expect(u.favoriteTeamCode).toBe("LG");
|
|
expect(u.knowledgeLevel).toBe("casual");
|
|
});
|
|
});
|
|
|
|
describe("createMe", () => {
|
|
it("정상 생성 시 토큰의 email/photo/provider를 사용한다", async () => {
|
|
const u = await createMe(fakeToken(), validBody);
|
|
expect(u.email).toBe("tester@example.com");
|
|
expect(u.photoUrl).toBe("https://cdn.example.com/p.png");
|
|
expect(u.provider).toBe("google");
|
|
expect(u.favoriteTeamCode).toBe("LG");
|
|
expect(u.knowledgeLevel).toBe("casual");
|
|
});
|
|
|
|
it("apple.com 프로바이더 매핑", async () => {
|
|
const t = fakeToken({
|
|
firebase: { identities: {}, sign_in_provider: "apple.com" },
|
|
});
|
|
const u = await createMe(t, validBody);
|
|
expect(u.provider).toBe("apple");
|
|
});
|
|
|
|
it("중복 생성 시 409 + USER_ALREADY_EXISTS", async () => {
|
|
await createMe(fakeToken(), validBody);
|
|
await expect(createMe(fakeToken(), validBody)).rejects.toMatchObject({
|
|
status: 409,
|
|
code: "USER_ALREADY_EXISTS",
|
|
});
|
|
});
|
|
|
|
it.each([
|
|
["빈 displayName", { ...validBody, displayName: "" }],
|
|
["11자 displayName", { ...validBody, displayName: "1234567890X" }],
|
|
["숫자 displayName", { ...validBody, displayName: 123 }],
|
|
["잘못된 팀코드", { ...validBody, favoriteTeamCode: "XX" }],
|
|
["잘못된 레벨", { ...validBody, knowledgeLevel: "master" }],
|
|
])("%s → 400 INVALID_INPUT", async (_label, body) => {
|
|
await expect(createMe(fakeToken(), body as never)).rejects.toMatchObject({
|
|
status: 400,
|
|
code: "INVALID_INPUT",
|
|
});
|
|
});
|
|
|
|
it("지원하지 않는 provider → 400", async () => {
|
|
const t = fakeToken({
|
|
firebase: { identities: {}, sign_in_provider: "password" },
|
|
});
|
|
await expect(createMe(t, validBody)).rejects.toBeInstanceOf(HttpError);
|
|
});
|
|
});
|
|
});
|