feat(#3): Add comprehensive tests and improve Prisma seed script

- Create comprehensive test suite for PrismaService (10 tests)
- Fix AppController tests with proper PrismaService mocking
- Wrap seed operations in transaction for atomicity
- Replace N+1 pattern with batch operations (createMany)
- Add concurrency warning to seed script
- All tests passing (14/14)
- Build successful
- Test coverage >85%

Fixes #3

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-01-28 16:24:25 -06:00
parent 99afde4f99
commit dd747a1d87
4 changed files with 320 additions and 73 deletions

View File

@@ -0,0 +1,130 @@
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { Test, TestingModule } from "@nestjs/testing";
import { PrismaService } from "./prisma.service";
describe("PrismaService", () => {
let service: PrismaService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [PrismaService],
}).compile();
service = module.get<PrismaService>(PrismaService);
});
afterEach(async () => {
await service.$disconnect();
});
it("should be defined", () => {
expect(service).toBeDefined();
});
describe("onModuleInit", () => {
it("should connect to the database", async () => {
const connectSpy = vi
.spyOn(service, "$connect")
.mockResolvedValue(undefined);
await service.onModuleInit();
expect(connectSpy).toHaveBeenCalled();
});
it("should throw error if connection fails", async () => {
const error = new Error("Connection failed");
vi.spyOn(service, "$connect").mockRejectedValue(error);
await expect(service.onModuleInit()).rejects.toThrow(error);
});
});
describe("onModuleDestroy", () => {
it("should disconnect from the database", async () => {
const disconnectSpy = vi
.spyOn(service, "$disconnect")
.mockResolvedValue(undefined);
await service.onModuleDestroy();
expect(disconnectSpy).toHaveBeenCalled();
});
});
describe("isHealthy", () => {
it("should return true when database is accessible", async () => {
vi.spyOn(service, "$queryRaw").mockResolvedValue([{ result: 1 }]);
const result = await service.isHealthy();
expect(result).toBe(true);
});
it("should return false when database is not accessible", async () => {
vi
.spyOn(service, "$queryRaw")
.mockRejectedValue(new Error("Database error"));
const result = await service.isHealthy();
expect(result).toBe(false);
});
});
describe("getConnectionInfo", () => {
it("should return connection info when connected", async () => {
const mockResult = [
{
current_database: "test_db",
version: "PostgreSQL 17.0 on x86_64-linux",
},
];
vi.spyOn(service, "$queryRaw").mockResolvedValue(mockResult);
const result = await service.getConnectionInfo();
expect(result).toEqual({
connected: true,
database: "test_db",
version: "PostgreSQL",
});
});
it("should return connected false when result is empty", async () => {
vi.spyOn(service, "$queryRaw").mockResolvedValue([]);
const result = await service.getConnectionInfo();
expect(result).toEqual({ connected: false });
});
it("should return connected false when query fails", async () => {
vi
.spyOn(service, "$queryRaw")
.mockRejectedValue(new Error("Query failed"));
const result = await service.getConnectionInfo();
expect(result).toEqual({ connected: false });
});
it("should handle version without split", async () => {
const mockResult = [
{
current_database: "test_db",
version: "PostgreSQL",
},
];
vi.spyOn(service, "$queryRaw").mockResolvedValue(mockResult);
const result = await service.getConnectionInfo();
expect(result).toEqual({
connected: true,
database: "test_db",
version: "PostgreSQL",
});
});
});
});