Some checks failed
ci/woodpecker/push/api Pipeline failed
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
230 lines
7.6 KiB
TypeScript
230 lines
7.6 KiB
TypeScript
/**
|
|
* TerminalSessionService Tests
|
|
*
|
|
* Unit tests for database-backed terminal session CRUD:
|
|
* create, findByWorkspace, close, and findById.
|
|
* PrismaService is mocked to isolate the service logic.
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
import { NotFoundException } from "@nestjs/common";
|
|
import { TerminalSessionStatus } from "@prisma/client";
|
|
import type { TerminalSession } from "@prisma/client";
|
|
import { TerminalSessionService } from "./terminal-session.service";
|
|
|
|
// ==========================================
|
|
// Helpers
|
|
// ==========================================
|
|
|
|
function makeSession(overrides: Partial<TerminalSession> = {}): TerminalSession {
|
|
return {
|
|
id: "session-uuid-1",
|
|
workspaceId: "workspace-uuid-1",
|
|
name: "Terminal",
|
|
status: TerminalSessionStatus.ACTIVE,
|
|
createdAt: new Date("2026-02-25T00:00:00Z"),
|
|
closedAt: null,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
// ==========================================
|
|
// Mock PrismaService
|
|
// ==========================================
|
|
|
|
function makeMockPrisma() {
|
|
return {
|
|
terminalSession: {
|
|
create: vi.fn(),
|
|
findMany: vi.fn(),
|
|
findUnique: vi.fn(),
|
|
update: vi.fn(),
|
|
},
|
|
};
|
|
}
|
|
|
|
// ==========================================
|
|
// Tests
|
|
// ==========================================
|
|
|
|
describe("TerminalSessionService", () => {
|
|
let service: TerminalSessionService;
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
let mockPrisma: any;
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mockPrisma = makeMockPrisma();
|
|
service = new TerminalSessionService(mockPrisma);
|
|
});
|
|
|
|
// ==========================================
|
|
// create
|
|
// ==========================================
|
|
describe("create", () => {
|
|
it("should call prisma.terminalSession.create with workspaceId only when no name provided", async () => {
|
|
const session = makeSession();
|
|
mockPrisma.terminalSession.create.mockResolvedValueOnce(session);
|
|
|
|
const result = await service.create("workspace-uuid-1");
|
|
|
|
expect(mockPrisma.terminalSession.create).toHaveBeenCalledWith({
|
|
data: { workspaceId: "workspace-uuid-1" },
|
|
});
|
|
expect(result).toEqual(session);
|
|
});
|
|
|
|
it("should include name in create data when name is provided", async () => {
|
|
const session = makeSession({ name: "My Terminal" });
|
|
mockPrisma.terminalSession.create.mockResolvedValueOnce(session);
|
|
|
|
const result = await service.create("workspace-uuid-1", "My Terminal");
|
|
|
|
expect(mockPrisma.terminalSession.create).toHaveBeenCalledWith({
|
|
data: { workspaceId: "workspace-uuid-1", name: "My Terminal" },
|
|
});
|
|
expect(result).toEqual(session);
|
|
});
|
|
|
|
it("should return the created session", async () => {
|
|
const session = makeSession();
|
|
mockPrisma.terminalSession.create.mockResolvedValueOnce(session);
|
|
|
|
const result = await service.create("workspace-uuid-1");
|
|
|
|
expect(result.id).toBe("session-uuid-1");
|
|
expect(result.status).toBe(TerminalSessionStatus.ACTIVE);
|
|
});
|
|
});
|
|
|
|
// ==========================================
|
|
// findByWorkspace
|
|
// ==========================================
|
|
describe("findByWorkspace", () => {
|
|
it("should query for ACTIVE sessions in the given workspace, ordered by createdAt desc", async () => {
|
|
const sessions = [makeSession(), makeSession({ id: "session-uuid-2" })];
|
|
mockPrisma.terminalSession.findMany.mockResolvedValueOnce(sessions);
|
|
|
|
const result = await service.findByWorkspace("workspace-uuid-1");
|
|
|
|
expect(mockPrisma.terminalSession.findMany).toHaveBeenCalledWith({
|
|
where: {
|
|
workspaceId: "workspace-uuid-1",
|
|
status: TerminalSessionStatus.ACTIVE,
|
|
},
|
|
orderBy: { createdAt: "desc" },
|
|
});
|
|
expect(result).toHaveLength(2);
|
|
});
|
|
|
|
it("should return an empty array when no active sessions exist", async () => {
|
|
mockPrisma.terminalSession.findMany.mockResolvedValueOnce([]);
|
|
|
|
const result = await service.findByWorkspace("workspace-uuid-empty");
|
|
|
|
expect(result).toEqual([]);
|
|
});
|
|
|
|
it("should not include CLOSED sessions", async () => {
|
|
// The where clause enforces ACTIVE status — verify it is present
|
|
mockPrisma.terminalSession.findMany.mockResolvedValueOnce([]);
|
|
|
|
await service.findByWorkspace("workspace-uuid-1");
|
|
|
|
const callArgs = mockPrisma.terminalSession.findMany.mock.calls[0][0] as {
|
|
where: { status: TerminalSessionStatus };
|
|
};
|
|
expect(callArgs.where.status).toBe(TerminalSessionStatus.ACTIVE);
|
|
});
|
|
});
|
|
|
|
// ==========================================
|
|
// close
|
|
// ==========================================
|
|
describe("close", () => {
|
|
it("should set status to CLOSED and set closedAt when session exists", async () => {
|
|
const existingSession = makeSession();
|
|
const closedSession = makeSession({
|
|
status: TerminalSessionStatus.CLOSED,
|
|
closedAt: new Date("2026-02-25T01:00:00Z"),
|
|
});
|
|
|
|
mockPrisma.terminalSession.findUnique.mockResolvedValueOnce(existingSession);
|
|
mockPrisma.terminalSession.update.mockResolvedValueOnce(closedSession);
|
|
|
|
const result = await service.close("session-uuid-1");
|
|
|
|
expect(mockPrisma.terminalSession.findUnique).toHaveBeenCalledWith({
|
|
where: { id: "session-uuid-1" },
|
|
});
|
|
expect(mockPrisma.terminalSession.update).toHaveBeenCalledWith({
|
|
where: { id: "session-uuid-1" },
|
|
data: {
|
|
status: TerminalSessionStatus.CLOSED,
|
|
closedAt: expect.any(Date),
|
|
},
|
|
});
|
|
expect(result.status).toBe(TerminalSessionStatus.CLOSED);
|
|
});
|
|
|
|
it("should throw NotFoundException when session does not exist", async () => {
|
|
mockPrisma.terminalSession.findUnique.mockResolvedValueOnce(null);
|
|
|
|
await expect(service.close("nonexistent-id")).rejects.toThrow(NotFoundException);
|
|
expect(mockPrisma.terminalSession.update).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should include a non-null closedAt timestamp on close", async () => {
|
|
const existingSession = makeSession();
|
|
const closedSession = makeSession({
|
|
status: TerminalSessionStatus.CLOSED,
|
|
closedAt: new Date(),
|
|
});
|
|
|
|
mockPrisma.terminalSession.findUnique.mockResolvedValueOnce(existingSession);
|
|
mockPrisma.terminalSession.update.mockResolvedValueOnce(closedSession);
|
|
|
|
const result = await service.close("session-uuid-1");
|
|
|
|
expect(result.closedAt).not.toBeNull();
|
|
});
|
|
});
|
|
|
|
// ==========================================
|
|
// findById
|
|
// ==========================================
|
|
describe("findById", () => {
|
|
it("should return the session when it exists", async () => {
|
|
const session = makeSession();
|
|
mockPrisma.terminalSession.findUnique.mockResolvedValueOnce(session);
|
|
|
|
const result = await service.findById("session-uuid-1");
|
|
|
|
expect(mockPrisma.terminalSession.findUnique).toHaveBeenCalledWith({
|
|
where: { id: "session-uuid-1" },
|
|
});
|
|
expect(result).toEqual(session);
|
|
});
|
|
|
|
it("should return null when session does not exist", async () => {
|
|
mockPrisma.terminalSession.findUnique.mockResolvedValueOnce(null);
|
|
|
|
const result = await service.findById("no-such-id");
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("should find CLOSED sessions as well as ACTIVE ones", async () => {
|
|
const closedSession = makeSession({
|
|
status: TerminalSessionStatus.CLOSED,
|
|
closedAt: new Date(),
|
|
});
|
|
mockPrisma.terminalSession.findUnique.mockResolvedValueOnce(closedSession);
|
|
|
|
const result = await service.findById("session-uuid-1");
|
|
|
|
expect(result?.status).toBe(TerminalSessionStatus.CLOSED);
|
|
});
|
|
});
|
|
});
|