|
@@ -0,0 +1,210 @@
|
|
|
|
|
+import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
|
|
|
|
|
+import { DataSource } from 'typeorm';
|
|
|
|
|
+import { UserService } from '../../src/services/user.service';
|
|
|
|
|
+import { RoleService } from '../../src/services/role.service';
|
|
|
|
|
+import { UserEntity } from '../../src/entities/user.entity';
|
|
|
|
|
+import { Role } from '../../src/entities/role.entity';
|
|
|
|
|
+import { getTestDataSource } from '@d8d/shared-utils';
|
|
|
|
|
+
|
|
|
|
|
+describe('User Integration Tests', () => {
|
|
|
|
|
+ let dataSource: DataSource;
|
|
|
|
|
+ let userService: UserService;
|
|
|
|
|
+ let roleService: RoleService;
|
|
|
|
|
+
|
|
|
|
|
+ beforeAll(async () => {
|
|
|
|
|
+ dataSource = await getTestDataSource();
|
|
|
|
|
+ userService = new UserService(dataSource);
|
|
|
|
|
+ roleService = new RoleService(dataSource);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ afterAll(async () => {
|
|
|
|
|
+ if (dataSource.isInitialized) {
|
|
|
|
|
+ await dataSource.destroy();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ beforeEach(async () => {
|
|
|
|
|
+ // Clean up database before each test
|
|
|
|
|
+ await dataSource.getRepository(UserEntity).delete({});
|
|
|
|
|
+ await dataSource.getRepository(Role).delete({});
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('User CRUD Operations', () => {
|
|
|
|
|
+ it('should create and retrieve a user', async () => {
|
|
|
|
|
+ // Create user
|
|
|
|
|
+ const userData = {
|
|
|
|
|
+ username: 'integrationuser',
|
|
|
|
|
+ password: 'password123',
|
|
|
|
|
+ email: 'integration@example.com',
|
|
|
|
|
+ nickname: 'Integration User'
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const createdUser = await userService.createUser(userData);
|
|
|
|
|
+
|
|
|
|
|
+ expect(createdUser.id).toBeDefined();
|
|
|
|
|
+ expect(createdUser.username).toBe(userData.username);
|
|
|
|
|
+ expect(createdUser.email).toBe(userData.email);
|
|
|
|
|
+ expect(createdUser.nickname).toBe(userData.nickname);
|
|
|
|
|
+ expect(createdUser.password).not.toBe(userData.password); // Password should be hashed
|
|
|
|
|
+
|
|
|
|
|
+ // Retrieve user
|
|
|
|
|
+ const retrievedUser = await userService.getUserById(createdUser.id);
|
|
|
|
|
+ expect(retrievedUser).toBeDefined();
|
|
|
|
|
+ expect(retrievedUser?.username).toBe(userData.username);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should update user information', async () => {
|
|
|
|
|
+ // Create user first
|
|
|
|
|
+ const userData = {
|
|
|
|
|
+ username: 'updateuser',
|
|
|
|
|
+ password: 'password123',
|
|
|
|
|
+ email: 'update@example.com'
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const createdUser = await userService.createUser(userData);
|
|
|
|
|
+
|
|
|
|
|
+ // Update user
|
|
|
|
|
+ const updateData = {
|
|
|
|
|
+ email: 'updated@example.com',
|
|
|
|
|
+ nickname: 'Updated User'
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const updatedUser = await userService.updateUser(createdUser.id, updateData);
|
|
|
|
|
+
|
|
|
|
|
+ expect(updatedUser).toBeDefined();
|
|
|
|
|
+ expect(updatedUser?.email).toBe(updateData.email);
|
|
|
|
|
+ expect(updatedUser?.nickname).toBe(updateData.nickname);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should delete user', async () => {
|
|
|
|
|
+ // Create user first
|
|
|
|
|
+ const userData = {
|
|
|
|
|
+ username: 'deleteuser',
|
|
|
|
|
+ password: 'password123'
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const createdUser = await userService.createUser(userData);
|
|
|
|
|
+
|
|
|
|
|
+ // Delete user
|
|
|
|
|
+ const deleteResult = await userService.deleteUser(createdUser.id);
|
|
|
|
|
+ expect(deleteResult).toBe(true);
|
|
|
|
|
+
|
|
|
|
|
+ // Verify user is deleted
|
|
|
|
|
+ const retrievedUser = await userService.getUserById(createdUser.id);
|
|
|
|
|
+ expect(retrievedUser).toBeNull();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should get user by username', async () => {
|
|
|
|
|
+ const userData = {
|
|
|
|
|
+ username: 'usernameuser',
|
|
|
|
|
+ password: 'password123'
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ await userService.createUser(userData);
|
|
|
|
|
+
|
|
|
|
|
+ const foundUser = await userService.getUserByUsername('usernameuser');
|
|
|
|
|
+ expect(foundUser).toBeDefined();
|
|
|
|
|
+ expect(foundUser?.username).toBe('usernameuser');
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should get user by account (username or email)', async () => {
|
|
|
|
|
+ const userData = {
|
|
|
|
|
+ username: 'accountuser',
|
|
|
|
|
+ password: 'password123',
|
|
|
|
|
+ email: 'account@example.com'
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ await userService.createUser(userData);
|
|
|
|
|
+
|
|
|
|
|
+ // Find by username
|
|
|
|
|
+ const byUsername = await userService.getUserByAccount('accountuser');
|
|
|
|
|
+ expect(byUsername).toBeDefined();
|
|
|
|
|
+ expect(byUsername?.username).toBe('accountuser');
|
|
|
|
|
+
|
|
|
|
|
+ // Find by email
|
|
|
|
|
+ const byEmail = await userService.getUserByAccount('account@example.com');
|
|
|
|
|
+ expect(byEmail).toBeDefined();
|
|
|
|
|
+ expect(byEmail?.email).toBe('account@example.com');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('User-Role Relationship', () => {
|
|
|
|
|
+ it('should assign roles to user', async () => {
|
|
|
|
|
+ // Create user
|
|
|
|
|
+ const userData = {
|
|
|
|
|
+ username: 'roleuser',
|
|
|
|
|
+ password: 'password123'
|
|
|
|
|
+ };
|
|
|
|
|
+ const user = await userService.createUser(userData);
|
|
|
|
|
+
|
|
|
|
|
+ // Create roles
|
|
|
|
|
+ const adminRole = await roleService.create({
|
|
|
|
|
+ name: 'admin',
|
|
|
|
|
+ description: 'Administrator role',
|
|
|
|
|
+ permissions: ['user:create', 'user:delete']
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const userRole = await roleService.create({
|
|
|
|
|
+ name: 'user',
|
|
|
|
|
+ description: 'Regular user role',
|
|
|
|
|
+ permissions: ['user:read']
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Assign roles to user
|
|
|
|
|
+ const updatedUser = await userService.assignRoles(user.id, [adminRole.id, userRole.id]);
|
|
|
|
|
+
|
|
|
|
|
+ expect(updatedUser).toBeDefined();
|
|
|
|
|
+ expect(updatedUser?.roles).toHaveLength(2);
|
|
|
|
|
+ expect(updatedUser?.roles.map(r => r.name)).toContain('admin');
|
|
|
|
|
+ expect(updatedUser?.roles.map(r => r.name)).toContain('user');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('User List Operations', () => {
|
|
|
|
|
+ it('should get all users', async () => {
|
|
|
|
|
+ // Create multiple users
|
|
|
|
|
+ const usersData = [
|
|
|
|
|
+ { username: 'user1', password: 'password123' },
|
|
|
|
|
+ { username: 'user2', password: 'password123' },
|
|
|
|
|
+ { username: 'user3', password: 'password123' }
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ for (const userData of usersData) {
|
|
|
|
|
+ await userService.createUser(userData);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const allUsers = await userService.getUsers();
|
|
|
|
|
+
|
|
|
|
|
+ expect(allUsers).toHaveLength(3);
|
|
|
|
|
+ expect(allUsers.map(u => u.username)).toEqual(
|
|
|
|
|
+ expect.arrayContaining(['user1', 'user2', 'user3'])
|
|
|
|
|
+ );
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ describe('Password Verification', () => {
|
|
|
|
|
+ it('should verify correct password', async () => {
|
|
|
|
|
+ const userData = {
|
|
|
|
|
+ username: 'verifyuser',
|
|
|
|
|
+ password: 'correctpassword'
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const user = await userService.createUser(userData);
|
|
|
|
|
+
|
|
|
|
|
+ const isCorrect = await userService.verifyPassword(user, 'correctpassword');
|
|
|
|
|
+ expect(isCorrect).toBe(true);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('should reject incorrect password', async () => {
|
|
|
|
|
+ const userData = {
|
|
|
|
|
+ username: 'verifyuser2',
|
|
|
|
|
+ password: 'correctpassword'
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const user = await userService.createUser(userData);
|
|
|
|
|
+
|
|
|
|
|
+ const isCorrect = await userService.verifyPassword(user, 'wrongpassword');
|
|
|
|
|
+ expect(isCorrect).toBe(false);
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+});
|