import { describe, it, expect } from "vitest"; import { validate } from "class-validator"; import { plainToInstance } from "class-transformer"; import { CreateActivityLogDto } from "./create-activity-log.dto"; import { ActivityAction, EntityType } from "@prisma/client"; describe("CreateActivityLogDto", () => { describe("required fields validation", () => { it("should pass with all required fields valid", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors).toHaveLength(0); }); it("should fail when workspaceId is missing", async () => { const dto = plainToInstance(CreateActivityLogDto, { userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const workspaceIdError = errors.find((e) => e.property === "workspaceId"); expect(workspaceIdError).toBeDefined(); }); it("should fail when userId is missing", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const userIdError = errors.find((e) => e.property === "userId"); expect(userIdError).toBeDefined(); }); it("should fail when action is missing", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const actionError = errors.find((e) => e.property === "action"); expect(actionError).toBeDefined(); }); it("should fail when entityType is missing", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const entityTypeError = errors.find((e) => e.property === "entityType"); expect(entityTypeError).toBeDefined(); }); it("should fail when entityId is missing", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: EntityType.TASK, }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const entityIdError = errors.find((e) => e.property === "entityId"); expect(entityIdError).toBeDefined(); }); }); describe("UUID validation", () => { it("should fail with invalid workspaceId UUID", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "invalid-uuid", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); expect(errors[0].property).toBe("workspaceId"); }); it("should fail with invalid userId UUID", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "not-a-uuid", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const userIdError = errors.find((e) => e.property === "userId"); expect(userIdError).toBeDefined(); }); it("should fail with invalid entityId UUID", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "bad-entity-id", }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const entityIdError = errors.find((e) => e.property === "entityId"); expect(entityIdError).toBeDefined(); }); }); describe("enum validation", () => { it("should pass with all valid ActivityAction values", async () => { const actions = Object.values(ActivityAction); for (const action of actions) { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors).toHaveLength(0); } }); it("should fail with invalid action value", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: "INVALID_ACTION", entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const actionError = errors.find((e) => e.property === "action"); expect(actionError?.constraints?.isEnum).toBeDefined(); }); it("should pass with all valid EntityType values", async () => { const entityTypes = Object.values(EntityType); for (const entityType of entityTypes) { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType, entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors).toHaveLength(0); } }); it("should fail with invalid entityType value", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: "INVALID_TYPE", entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const entityTypeError = errors.find((e) => e.property === "entityType"); expect(entityTypeError?.constraints?.isEnum).toBeDefined(); }); }); describe("optional fields validation", () => { it("should pass with valid details object", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.UPDATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", details: { field: "status", oldValue: "TODO", newValue: "IN_PROGRESS", }, }); const errors = await validate(dto); expect(errors).toHaveLength(0); }); it("should fail with non-object details", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.UPDATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", details: "not an object", }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const detailsError = errors.find((e) => e.property === "details"); expect(detailsError?.constraints?.isObject).toBeDefined(); }); it("should pass with valid ipAddress", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", ipAddress: "192.168.1.1", }); const errors = await validate(dto); expect(errors).toHaveLength(0); }); it("should pass with valid IPv6 address", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", ipAddress: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", }); const errors = await validate(dto); expect(errors).toHaveLength(0); }); it("should fail when ipAddress exceeds max length", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", ipAddress: "a".repeat(46), }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const ipError = errors.find((e) => e.property === "ipAddress"); expect(ipError?.constraints?.maxLength).toBeDefined(); }); it("should pass with valid userAgent", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", }); const errors = await validate(dto); expect(errors).toHaveLength(0); }); it("should fail when userAgent exceeds max length", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", userAgent: "a".repeat(501), }); const errors = await validate(dto); expect(errors.length).toBeGreaterThan(0); const userAgentError = errors.find((e) => e.property === "userAgent"); expect(userAgentError?.constraints?.maxLength).toBeDefined(); }); it("should pass when optional fields are not provided", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "550e8400-e29b-41d4-a716-446655440002", }); const errors = await validate(dto); expect(errors).toHaveLength(0); }); }); describe("complete validation", () => { it("should pass with all fields valid", async () => { const dto = plainToInstance(CreateActivityLogDto, { workspaceId: "550e8400-e29b-41d4-a716-446655440000", userId: "550e8400-e29b-41d4-a716-446655440001", action: ActivityAction.UPDATED, entityType: EntityType.PROJECT, entityId: "550e8400-e29b-41d4-a716-446655440002", details: { changes: ["status", "priority"], metadata: { source: "web-app" }, }, ipAddress: "10.0.0.1", userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", }); const errors = await validate(dto); expect(errors).toHaveLength(0); }); }); });