Skip to content

Commit

Permalink
test(api): add test for user service
Browse files Browse the repository at this point in the history
  • Loading branch information
cuixiaorui committed Jul 20, 2024
1 parent 026c996 commit 98863df
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 3 deletions.
179 changes: 179 additions & 0 deletions apps/api/src/user/tests/user.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import { Test, TestingModule } from "@nestjs/testing";

import { insertCourse, insertCoursePack } from "../../../test/fixture/db";
import { cleanDB, testImportModules } from "../../../test/helper/utils";
import { endDB } from "../../common/db";
import { DB, DbType } from "../../global/providers/db.provider";
import { LogtoService } from "../../logto/logto.service";
import { MembershipService } from "../../membership/membership.service";
import { UserCourseProgressService } from "../../user-course-progress/user-course-progress.service";
import { UserService } from "../user.service";

describe("UserService", () => {
let db: DbType;
let userService: UserService;
let logtoServiceMock: jest.Mocked<LogtoService>;
let membershipServiceMock: jest.Mocked<MembershipService>;
let userCourseProgressServiceMock: jest.Mocked<UserCourseProgressService>;

beforeAll(async () => {
const testHelper = await setupTesting();
db = testHelper.db;
userService = testHelper.userService;
logtoServiceMock = testHelper.logtoService as jest.Mocked<LogtoService>;
membershipServiceMock = testHelper.membershipService as jest.Mocked<MembershipService>;
userCourseProgressServiceMock =
testHelper.userCourseProgressService as jest.Mocked<UserCourseProgressService>;
});

afterAll(async () => {
await cleanDB(db);
await endDB();
});

beforeEach(async () => {
await cleanDB(db);
jest.clearAllMocks();
});

describe("findUser", () => {
it("should return user info with membership details when user is a member", async () => {
const userId = "testUserId";
const logtoUserInfo = { id: userId, name: "Test User" };
const membershipDetails = {
type: "founder",
startDate: new Date(),
endDate: new Date(),
isActive: true,
};
(logtoServiceMock.logtoApi.get as jest.Mock).mockResolvedValue({ data: logtoUserInfo });
membershipServiceMock.isMember.mockResolvedValue(true);
membershipServiceMock.getMembershipDetails.mockResolvedValue(membershipDetails);

const result = await userService.findUser(userId);

expect(result).toEqual({
...logtoUserInfo,
membership: {
isMember: true,
details: membershipDetails,
},
});
});

it("should return user info without membership details when user is not a member", async () => {
const userId = "testUserId";
const logtoUserInfo = { id: userId, name: "Test User" };

(logtoServiceMock.logtoApi.get as jest.Mock).mockResolvedValue({ data: logtoUserInfo });
membershipServiceMock.isMember.mockResolvedValue(false);

const result = await userService.findUser(userId);

expect(result).toEqual({
...logtoUserInfo,
membership: {
isMember: false,
details: null,
},
});
});

it("should return undefined when there's an error fetching user info", async () => {
const userId = "testUserId";

(logtoServiceMock.logtoApi.get as jest.Mock).mockRejectedValue(new Error("API Error"));

const result = await userService.findUser(userId);

expect(result).toBeUndefined();
});
});

describe("setupNewUser", () => {
it("should setup a new user with provided username and avatar", async () => {
const user = { userId: "newUserId" };
const dto = { username: "newUser", avatar: "custom-avatar.png" };
jest.spyOn(userService as any, "updateUser").mockResolvedValue({});

const coursePackEntity = await insertCoursePack(db);
const courseEntity = await insertCourse(db, coursePackEntity.id);

const result = await userService.setupNewUser(user, dto);

expect(result).toEqual({
avatar: dto.avatar,
username: dto.username,
});
expect(userService.updateUser).toHaveBeenCalledWith(user, dto);
expect(userCourseProgressServiceMock.upsert).toHaveBeenCalledWith(
user.userId,
coursePackEntity.id,
courseEntity.id,
0,
);
});

it("should use default avatar if not provided", async () => {
const user = { userId: "newUserId" };
const dto = { username: "newUser", avatar: "" };
jest.spyOn(userService as any, "updateUser").mockResolvedValue({});
jest.spyOn(userService as any, "getRandomNumber").mockReturnValue(5); // 模拟随机数
const coursePackEntity = await insertCoursePack(db);
const courseEntity = await insertCourse(db, coursePackEntity.id);
const result = await userService.setupNewUser(user, dto);

const expectedAvatar =
"https://earthworm-prod-1312884695.cos.ap-beijing.myqcloud.com/avatars/avatar5.png";
expect(result).toEqual({
avatar: expectedAvatar,
username: dto.username,
});
expect(userService.updateUser).toHaveBeenCalledWith(user, {
username: dto.username,
avatar: expectedAvatar,
});
expect(userCourseProgressServiceMock.upsert).toHaveBeenCalledWith(
user.userId,
coursePackEntity.id,
courseEntity.id,
0,
);
});
});
});

async function setupTesting() {
const logtoServiceMock = {
logtoApi: {
get: jest.fn(),
patch: jest.fn(),
},
};

const membershipServiceMock = {
isMember: jest.fn(),
getMembershipDetails: jest.fn(),
};
const userCourseProgressServiceMock = {
upsert: jest.fn(),
};

const moduleRef: TestingModule = await Test.createTestingModule({
imports: testImportModules,
providers: [
UserService,
{ provide: LogtoService, useValue: logtoServiceMock },
{ provide: MembershipService, useValue: membershipServiceMock },
{ provide: UserCourseProgressService, useValue: userCourseProgressServiceMock },
],
}).compile();

return {
db: moduleRef.get<DbType>(DB),
userService: moduleRef.get<UserService>(UserService),
logtoService: moduleRef.get<LogtoService>(LogtoService),
membershipService: moduleRef.get<MembershipService>(MembershipService),
userCourseProgressService: moduleRef.get<UserCourseProgressService>(UserCourseProgressService),
};
}
5 changes: 2 additions & 3 deletions apps/api/src/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,8 @@ export class UserService {
}

async setupNewUser(user: UserEntity, dto: { username: string; avatar: string }) {
const avatar = this.getAvatarUrl();
if (!dto.avatar) {
dto.avatar = avatar;
dto.avatar = this.getAvatarUrl();
}

await this.updateUser(user, { username: dto.username, avatar: dto.avatar });
Expand All @@ -73,7 +72,7 @@ export class UserService {

await this.userCourseProgressService.upsert(user.userId, id, courses.at(0).id, 0);
return {
avatar,
avatar: dto.avatar,
username: dto.username,
};
}
Expand Down

0 comments on commit 98863df

Please sign in to comment.