feat: add initial unit tests for user service and configure bun test script.

This commit is contained in:
syntaxbullet
2025-12-19 10:59:06 +01:00
parent acaca46298
commit bdb8456f34
2 changed files with 101 additions and 1 deletions

View File

@@ -18,7 +18,8 @@
"db:push:local": "drizzle-kit push", "db:push:local": "drizzle-kit push",
"dev": "bun --watch src/index.ts", "dev": "bun --watch src/index.ts",
"db:studio": "drizzle-kit studio --host 0.0.0.0", "db:studio": "drizzle-kit studio --host 0.0.0.0",
"studio:remote": "bash scripts/remote-studio.sh" "studio:remote": "bash scripts/remote-studio.sh",
"test": "bun test"
}, },
"dependencies": { "dependencies": {
"@napi-rs/canvas": "^0.1.84", "@napi-rs/canvas": "^0.1.84",

View File

@@ -0,0 +1,99 @@
import { describe, it, expect, mock, beforeEach, afterEach } from "bun:test";
import { userService } from "./user.service";
// Define mock functions outside so we can control them in tests
const mockFindFirst = mock();
const mockInsert = mock();
const mockUpdate = mock();
const mockDelete = mock();
const mockValues = mock();
const mockReturning = mock();
const mockSet = mock();
const mockWhere = mock();
// Chainable mock setup
mockInsert.mockReturnValue({ values: mockValues });
mockValues.mockReturnValue({ returning: mockReturning });
mockUpdate.mockReturnValue({ set: mockSet });
mockSet.mockReturnValue({ where: mockWhere });
mockWhere.mockReturnValue({ returning: mockReturning });
// Mock DrizzleClient
mock.module("@/lib/DrizzleClient", () => {
return {
DrizzleClient: {
query: {
users: {
findFirst: mockFindFirst,
},
},
insert: mockInsert,
update: mockUpdate,
delete: mockDelete,
transaction: async (cb: any) => {
// Pass the mock client itself as the transaction object
// This simplifies things as we use the same structure for tx and client
return cb({
query: {
users: {
findFirst: mockFindFirst,
},
},
insert: mockInsert,
update: mockUpdate,
delete: mockDelete,
});
}
},
};
});
describe("userService", () => {
beforeEach(() => {
mockFindFirst.mockReset();
mockInsert.mockClear();
mockValues.mockClear();
mockReturning.mockClear();
});
describe("getUserById", () => {
it("should return a user when found", async () => {
const mockUser = { id: 123n, username: "testuser", class: null };
mockFindFirst.mockResolvedValue(mockUser);
const result = await userService.getUserById("123");
expect(result).toEqual(mockUser as any);
expect(mockFindFirst).toHaveBeenCalledTimes(1);
});
it("should return undefined when user not found", async () => {
mockFindFirst.mockResolvedValue(undefined);
const result = await userService.getUserById("999");
expect(result).toBeUndefined();
expect(mockFindFirst).toHaveBeenCalledTimes(1);
});
});
describe("createUser", () => {
it("should create and return a new user", async () => {
const newUser = { id: 456n, username: "newuser", classId: null };
mockReturning.mockResolvedValue([newUser]);
const result = await userService.createUser("456", "newuser");
expect(result).toEqual(newUser as any);
expect(mockInsert).toHaveBeenCalledTimes(1);
expect(mockValues).toHaveBeenCalledWith({
id: 456n,
username: "newuser",
classId: undefined
});
});
});
});