UNPKG

@wearesage/schema

Version:

A flexible schema definition and validation system for TypeScript with multi-database support

308 lines (251 loc) 8.5 kB
import "reflect-metadata"; import { UniversalEntityService, EntityContext } from "../../services/UniversalEntityService"; import { Entity, Property, Id, Auth } from "../../core/decorators"; import { MetadataRegistry } from "../../core/MetadataRegistry"; // Test entities @Entity() @Auth({ permissions: ['user'] }) class TestUser { @Id() id: string; @Property({ required: true }) name: string; @Property({ required: true }) email: string; @Property() createdAt: Date; @Property() updatedAt: Date; } @Entity() @Auth({ roles: ['admin'] }) class TestSpace { @Id() id: string; @Property({ required: true }) name: string; @Property() description: string; @Property({ required: true }) spaceType: string; @Property({ required: true }) visibility: string; @Property({ required: true }) ownedByType: string; @Property({ required: true }) ownedById: string; @Property() status: string; @Property() metadata: any; @Property() createdAt: Date; @Property() updatedAt: Date; } describe("UniversalEntityService", () => { let service: UniversalEntityService; let userContext: EntityContext; let adminContext: EntityContext; beforeEach(() => { // Get fresh instance for each test service = UniversalEntityService.getInstance(); // Register test entities service.registerEntities([TestUser, TestSpace]); // Create test contexts userContext = { user: { id: 'user123', username: 'testuser', email: 'test@example.com', role: 0, permissions: ['user'] } }; adminContext = { user: { id: 'admin123', username: 'admin', email: 'admin@example.com', role: 999, permissions: ['user', 'admin'] } }; }); afterAll(async () => { // Close any open database connections if ((service as any).adapter && (service as any).adapter.close) { await (service as any).adapter.close(); } }); describe("Entity Registration", () => { test("should register entities successfully", () => { // This should not throw expect(() => { service.registerEntities([TestUser, TestSpace]); }).not.toThrow(); }); test("should extract metadata from registered entities", () => { // This is tested implicitly by the CRUD operations below expect(true).toBe(true); }); }); describe("Permission Checks", () => { test("should allow user access to TestUser (user permission)", async () => { const userData = { name: 'Test User', email: 'test@example.com' }; // This should not throw await expect( service.create(TestUser, userData, userContext) ).resolves.toBeDefined(); }); test("should deny user access to TestSpace (admin role required)", async () => { const spaceData = { name: 'Test Space', spaceType: 'project', visibility: 'private', ownedByType: 'user', ownedById: 'user123' }; await expect( service.create(TestSpace, spaceData, userContext) ).rejects.toThrow('Insufficient role permissions'); }); test("should allow admin access to TestSpace", async () => { const spaceData = { name: 'Test Space', spaceType: 'project', visibility: 'private', ownedByType: 'user', ownedById: 'admin123' }; await expect( service.create(TestSpace, spaceData, adminContext) ).resolves.toBeDefined(); }); }); describe("Validation", () => { test("should enforce required fields", async () => { const invalidUserData = { name: 'Test User' // Missing required email field }; await expect( service.create(TestUser, invalidUserData, userContext) ).rejects.toThrow("Required field 'email' is missing"); }); test("should allow valid data", async () => { const validUserData = { name: 'Test User', email: 'test@example.com' }; const user = await service.create(TestUser, validUserData, userContext); expect(user.name).toBe('Test User'); expect(user.email).toBe('test@example.com'); expect(user.id).toBeDefined(); expect(user.createdAt).toBeDefined(); expect(user.updatedAt).toBeDefined(); }); }); describe("CRUD Operations", () => { test("should create entity with auto-generated fields", async () => { const userData = { name: 'Test User', email: 'test@example.com' }; const user = await service.create(TestUser, userData, userContext); expect(user.id).toBeDefined(); expect(user.id).toMatch(/^entity_/); expect(user.createdAt).toBeInstanceOf(Date); expect(user.updatedAt).toBeInstanceOf(Date); expect(user.name).toBe('Test User'); expect(user.email).toBe('test@example.com'); }); test("should find entity by ID", async () => { const userData = { name: 'Test User', email: 'test@example.com' }; const createdUser = await service.create(TestUser, userData, userContext); const foundUser = await service.findById(TestUser, createdUser.id, userContext); expect(foundUser).toBeDefined(); expect(foundUser?.id).toBe(createdUser.id); expect(foundUser?.name).toBe('Test User'); }); test("should find all entities", async () => { const userData1 = { name: 'User 1', email: 'user1@example.com' }; const userData2 = { name: 'User 2', email: 'user2@example.com' }; await service.create(TestUser, userData1, userContext); await service.create(TestUser, userData2, userContext); const allUsers = await service.findAll(TestUser, {}, userContext); expect(allUsers.length).toBeGreaterThanOrEqual(2); }); test("should update entity", async () => { const userData = { name: 'Original Name', email: 'test@example.com' }; const createdUser = await service.create(TestUser, userData, userContext); const updatedUser = await service.update( TestUser, createdUser.id, { name: 'Updated Name' }, userContext ); expect(updatedUser?.name).toBe('Updated Name'); expect(updatedUser?.email).toBe('test@example.com'); // Should remain unchanged expect(updatedUser?.updatedAt).toBeInstanceOf(Date); }); test("should delete entity", async () => { const userData = { name: 'Test User', email: 'test@example.com' }; const createdUser = await service.create(TestUser, userData, userContext); const deleteResult = await service.delete(TestUser, createdUser.id, userContext); expect(deleteResult).toBe(true); const foundUser = await service.findById(TestUser, createdUser.id, userContext); expect(foundUser).toBeNull(); }); }); describe("Entity Instance Creation", () => { test("should create proper entity instances", async () => { const userData = { name: 'Test User', email: 'test@example.com' }; const user = await service.create(TestUser, userData, userContext); // Should be an instance of the TestUser class expect(user).toBeInstanceOf(TestUser); expect(user.constructor.name).toBe('TestUser'); }); }); describe("Error Handling", () => { test("should handle non-existent entity IDs gracefully", async () => { const foundUser = await service.findById(TestUser, 'non-existent-id', userContext); expect(foundUser).toBeNull(); }); test("should handle update of non-existent entity", async () => { const updatedUser = await service.update( TestUser, 'non-existent-id', { name: 'New Name' }, userContext ); expect(updatedUser).toBeNull(); }); test("should handle delete of non-existent entity", async () => { const deleteResult = await service.delete(TestUser, 'non-existent-id', userContext); expect(deleteResult).toBe(false); }); }); }); describe("UniversalEntityService Integration", () => { test("should work with real entities from API project", () => { // This test would import actual entities from the API project // and verify they work with the Universal Entity Service expect(true).toBe(true); // Placeholder }); });