425 lines
11 KiB
TypeScript
425 lines
11 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'vitest'
|
|
import { UserService, AuthService, PermissionService, FileService } from './index'
|
|
import type { Config } from '@fischerx/config'
|
|
import type { User } from '@fischerx/types'
|
|
import { ROLES, PERMISSIONS } from '@fischerx/constants'
|
|
|
|
const mockConfig: Config = {
|
|
app: {
|
|
name: 'TestApp',
|
|
version: '0.1.0',
|
|
description: 'Test',
|
|
},
|
|
server: {
|
|
port: 3001,
|
|
host: 'localhost',
|
|
corsOrigins: ['http://localhost:3000'],
|
|
nodeEnv: 'test',
|
|
},
|
|
database: {
|
|
host: 'localhost',
|
|
port: 5432,
|
|
name: 'test',
|
|
username: 'test',
|
|
password: 'test',
|
|
url: 'postgresql://test:test@localhost:5432/test',
|
|
},
|
|
redis: {
|
|
host: 'localhost',
|
|
port: 6379,
|
|
password: '',
|
|
db: 0,
|
|
url: 'redis://localhost:6379',
|
|
},
|
|
jwt: {
|
|
secret: 'test-secret',
|
|
expiresIn: '15m',
|
|
refreshSecret: 'test-refresh',
|
|
refreshExpiresIn: '7d',
|
|
algorithm: 'HS256',
|
|
},
|
|
}
|
|
|
|
describe('Core Services', () => {
|
|
describe('UserService', () => {
|
|
let userService: UserService
|
|
|
|
beforeEach(async () => {
|
|
userService = new UserService(mockConfig)
|
|
await userService.init()
|
|
})
|
|
|
|
it('should create user', async () => {
|
|
const user = await userService.create({
|
|
email: 'test@example.com',
|
|
name: 'Test User',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
expect(user.email).toBe('test@example.com')
|
|
expect(user.name).toBe('Test User')
|
|
expect(user.role.name).toBe(ROLES.USER)
|
|
})
|
|
|
|
it('should find user by id', async () => {
|
|
const created = await userService.create({
|
|
email: 'test@example.com',
|
|
name: 'Test User',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
const found = await userService.findById(created.id)
|
|
expect(found).not.toBeNull()
|
|
expect(found?.email).toBe('test@example.com')
|
|
})
|
|
|
|
it('should find user by email', async () => {
|
|
await userService.create({
|
|
email: 'test@example.com',
|
|
name: 'Test User',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
const found = await userService.findByEmail('test@example.com')
|
|
expect(found).not.toBeNull()
|
|
expect(found?.name).toBe('Test User')
|
|
})
|
|
|
|
it('should update user', async () => {
|
|
const user = await userService.create({
|
|
email: 'test@example.com',
|
|
name: 'Test User',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
const updated = await userService.update(user.id, {
|
|
name: 'Updated Name',
|
|
})
|
|
|
|
expect(updated.name).toBe('Updated Name')
|
|
})
|
|
|
|
it('should delete user', async () => {
|
|
const user = await userService.create({
|
|
email: 'test@example.com',
|
|
name: 'Test User',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
const deleted = await userService.delete(user.id)
|
|
expect(deleted).toBe(true)
|
|
|
|
const found = await userService.findById(user.id)
|
|
expect(found).toBeNull()
|
|
})
|
|
|
|
it('should list users with pagination', async () => {
|
|
await userService.create({
|
|
email: 'test1@example.com',
|
|
name: 'Test 1',
|
|
password: 'Strong1!password',
|
|
})
|
|
await userService.create({
|
|
email: 'test2@example.com',
|
|
name: 'Test 2',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
const result = await userService.list(1, 10)
|
|
expect(result.success).toBe(true)
|
|
expect(result.data?.length).toBeGreaterThanOrEqual(2)
|
|
expect(result.meta?.total).toBeGreaterThanOrEqual(2)
|
|
})
|
|
|
|
it('should reject invalid email', async () => {
|
|
await expect(
|
|
userService.create({
|
|
email: 'invalid',
|
|
name: 'Test',
|
|
password: 'Strong1!password',
|
|
})
|
|
).rejects.toThrow('Invalid email')
|
|
})
|
|
|
|
it('should reject weak password', async () => {
|
|
await expect(
|
|
userService.create({
|
|
email: 'test@example.com',
|
|
name: 'Test',
|
|
password: 'weak',
|
|
})
|
|
).rejects.toThrow()
|
|
})
|
|
})
|
|
|
|
describe('AuthService', () => {
|
|
let authService: AuthService
|
|
let userService: UserService
|
|
|
|
beforeEach(async () => {
|
|
userService = new UserService(mockConfig)
|
|
await userService.init()
|
|
authService = new AuthService(mockConfig, userService)
|
|
await authService.init()
|
|
})
|
|
|
|
it('should register user', async () => {
|
|
const result = await authService.register({
|
|
email: 'test@example.com',
|
|
name: 'Test User',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
expect(result.accessToken).toBeDefined()
|
|
expect(result.refreshToken).toBeDefined()
|
|
expect(result.user.email).toBe('test@example.com')
|
|
})
|
|
|
|
it('should login user', async () => {
|
|
await userService.create({
|
|
email: 'test@example.com',
|
|
name: 'Test User',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
const result = await authService.login({
|
|
email: 'test@example.com',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
expect(result.accessToken).toBeDefined()
|
|
expect(result.user.email).toBe('test@example.com')
|
|
})
|
|
|
|
it('should reject login with wrong password', async () => {
|
|
await userService.create({
|
|
email: 'test@example.com',
|
|
name: 'Test User',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
const user = await userService.findByEmail('test@example.com')
|
|
expect(user).not.toBeNull()
|
|
})
|
|
|
|
it('should logout user', async () => {
|
|
const result = await authService.register({
|
|
email: 'test@example.com',
|
|
name: 'Test User',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
await authService.logout(result.accessToken)
|
|
|
|
const valid = await authService.validateToken(result.accessToken)
|
|
expect(valid).toBeNull()
|
|
})
|
|
|
|
it('should refresh token', async () => {
|
|
const result = await authService.register({
|
|
email: 'test@example.com',
|
|
name: 'Test User',
|
|
password: 'Strong1!password',
|
|
})
|
|
|
|
const refreshed = await authService.refreshToken(result.refreshToken)
|
|
expect(refreshed).not.toBeNull()
|
|
expect(refreshed?.accessToken).toBeDefined()
|
|
expect(refreshed?.refreshToken).toBeDefined()
|
|
})
|
|
})
|
|
|
|
describe('PermissionService', () => {
|
|
let permissionService: PermissionService
|
|
|
|
beforeEach(async () => {
|
|
permissionService = new PermissionService(mockConfig)
|
|
await permissionService.init()
|
|
})
|
|
|
|
it('should check if user is admin', () => {
|
|
const adminUser: User = {
|
|
id: '1',
|
|
email: 'admin@example.com',
|
|
name: 'Admin',
|
|
role: {
|
|
id: 'admin',
|
|
name: ROLES.ADMIN,
|
|
description: 'Admin',
|
|
permissions: [],
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
},
|
|
permissions: [],
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
}
|
|
|
|
expect(permissionService.isAdmin(adminUser)).toBe(true)
|
|
})
|
|
|
|
it('should check user permissions', () => {
|
|
const user: User = {
|
|
id: '1',
|
|
email: 'user@example.com',
|
|
name: 'User',
|
|
role: {
|
|
id: 'user',
|
|
name: ROLES.USER,
|
|
description: 'User',
|
|
permissions: [],
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
},
|
|
permissions: [
|
|
{
|
|
id: '1',
|
|
name: PERMISSIONS.FILE.READ,
|
|
description: 'Read files',
|
|
resource: 'file',
|
|
action: 'read',
|
|
},
|
|
],
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
}
|
|
|
|
expect(permissionService.hasPermission(user, PERMISSIONS.FILE.READ)).toBe(true)
|
|
expect(permissionService.hasPermission(user, PERMISSIONS.FILE.UPDATE)).toBe(false)
|
|
})
|
|
|
|
it('should check resource access', () => {
|
|
const user: User = {
|
|
id: '1',
|
|
email: 'user@example.com',
|
|
name: 'User',
|
|
role: {
|
|
id: 'user',
|
|
name: ROLES.USER,
|
|
description: 'User',
|
|
permissions: [],
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
},
|
|
permissions: [
|
|
{
|
|
id: '1',
|
|
name: PERMISSIONS.FILE.READ,
|
|
description: 'Read files',
|
|
resource: 'file',
|
|
action: 'read',
|
|
},
|
|
],
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
}
|
|
|
|
expect(permissionService.canAccess(user, 'file', 'read')).toBe(true)
|
|
expect(permissionService.canAccess(user, 'file', 'write')).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('FileService', () => {
|
|
let fileService: FileService
|
|
|
|
beforeEach(async () => {
|
|
fileService = new FileService(mockConfig)
|
|
await fileService.init()
|
|
})
|
|
|
|
it('should create file', async () => {
|
|
const file = await fileService.create({
|
|
name: 'document.pdf',
|
|
originalName: 'my-document.pdf',
|
|
mimeType: 'application/pdf',
|
|
size: 1024,
|
|
url: 'https://example.com/file.pdf',
|
|
ownerId: 'user-1',
|
|
})
|
|
|
|
expect(file.name).toBe('document.pdf')
|
|
expect(file.ownerId).toBe('user-1')
|
|
})
|
|
|
|
it('should find file by id', async () => {
|
|
const created = await fileService.create({
|
|
name: 'document.pdf',
|
|
originalName: 'my-document.pdf',
|
|
mimeType: 'application/pdf',
|
|
size: 1024,
|
|
url: 'https://example.com/file.pdf',
|
|
ownerId: 'user-1',
|
|
})
|
|
|
|
const found = await fileService.findById(created.id)
|
|
expect(found).not.toBeNull()
|
|
expect(found?.name).toBe('document.pdf')
|
|
})
|
|
|
|
it('should find files by owner', async () => {
|
|
await fileService.create({
|
|
name: 'file1.pdf',
|
|
originalName: 'file1.pdf',
|
|
mimeType: 'application/pdf',
|
|
size: 1024,
|
|
url: 'https://example.com/file1.pdf',
|
|
ownerId: 'user-test-1',
|
|
})
|
|
await new Promise(resolve => setTimeout(resolve, 10))
|
|
await fileService.create({
|
|
name: 'file2.pdf',
|
|
originalName: 'file2.pdf',
|
|
mimeType: 'application/pdf',
|
|
size: 2048,
|
|
url: 'https://example.com/file2.pdf',
|
|
ownerId: 'user-test-1',
|
|
})
|
|
|
|
const files = await fileService.findByOwnerId('user-test-1')
|
|
expect(files.length).toBe(2)
|
|
})
|
|
|
|
it('should delete file', async () => {
|
|
const file = await fileService.create({
|
|
name: 'document.pdf',
|
|
originalName: 'my-document.pdf',
|
|
mimeType: 'application/pdf',
|
|
size: 1024,
|
|
url: 'https://example.com/file.pdf',
|
|
ownerId: 'user-1',
|
|
})
|
|
|
|
const deleted = await fileService.delete(file.id)
|
|
expect(deleted).toBe(true)
|
|
|
|
const found = await fileService.findById(file.id)
|
|
expect(found).toBeNull()
|
|
})
|
|
|
|
it('should list files with pagination', async () => {
|
|
await fileService.create({
|
|
name: 'file1.pdf',
|
|
originalName: 'file1.pdf',
|
|
mimeType: 'application/pdf',
|
|
size: 1024,
|
|
url: 'https://example.com/file1.pdf',
|
|
ownerId: 'user-test-2',
|
|
})
|
|
await new Promise(resolve => setTimeout(resolve, 10))
|
|
await fileService.create({
|
|
name: 'file2.pdf',
|
|
originalName: 'file2.pdf',
|
|
mimeType: 'application/pdf',
|
|
size: 2048,
|
|
url: 'https://example.com/file2.pdf',
|
|
ownerId: 'user-test-2',
|
|
})
|
|
|
|
const result = await fileService.list(1, 10)
|
|
expect(result.success).toBe(true)
|
|
expect(result.data?.length).toBe(2)
|
|
expect(result.meta?.total).toBe(2)
|
|
})
|
|
})
|
|
})
|