Files
web-app-launcher/src/lib/server/services/__tests__/permissionService.test.ts
T
alexei.dolgolyov e6b50fb4f1 feat(mvp): phase 8 - integration, testing & deployment
Fix all build/type/lint errors (zod 3.25 compat wrapper, Svelte 5 fixes),
write 115 unit tests across 10 test files, expand seed script with demo
data, update Docker config with migration on startup.
2026-03-24 22:09:17 +03:00

152 lines
4.0 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest';
vi.mock('../../prisma.js', () => ({
prisma: {
user: { findUnique: vi.fn() },
permission: {
findFirst: vi.fn(),
findMany: vi.fn(),
upsert: vi.fn(),
deleteMany: vi.fn()
},
userGroup: { findMany: vi.fn() }
}
}));
import { prisma } from '../../prisma.js';
import * as permissionService from '../permissionService.js';
const mockUser = prisma.user as unknown as Record<string, ReturnType<typeof vi.fn>>;
const mockPermission = prisma.permission as unknown as Record<string, ReturnType<typeof vi.fn>>;
const mockUserGroup = prisma.userGroup as unknown as Record<string, ReturnType<typeof vi.fn>>;
describe('permissionService', () => {
beforeEach(() => {
vi.clearAllMocks();
});
describe('checkPermission', () => {
it('grants full access to admins', async () => {
mockUser.findUnique.mockResolvedValue({ role: 'admin' });
const result = await permissionService.checkPermission(
'board',
'b1',
'admin-user',
'edit'
);
expect(result.hasPermission).toBe(true);
expect(result.effectiveLevel).toBe('admin');
expect(result.source).toBe('admin');
});
it('checks direct user permission', async () => {
mockUser.findUnique.mockResolvedValue({ role: 'user' });
mockPermission.findFirst.mockResolvedValue({ level: 'edit' });
const result = await permissionService.checkPermission(
'board',
'b1',
'user1',
'view'
);
expect(result.hasPermission).toBe(true);
expect(result.effectiveLevel).toBe('edit');
expect(result.source).toBe('user');
});
it('denies when user permission is insufficient', async () => {
mockUser.findUnique.mockResolvedValue({ role: 'user' });
mockPermission.findFirst.mockResolvedValue({ level: 'view' });
const result = await permissionService.checkPermission(
'board',
'b1',
'user1',
'admin'
);
expect(result.hasPermission).toBe(false);
});
it('falls back to group permissions', async () => {
mockUser.findUnique.mockResolvedValue({ role: 'user' });
mockPermission.findFirst.mockResolvedValue(null);
mockUserGroup.findMany.mockResolvedValue([{ groupId: 'g1' }]);
mockPermission.findMany.mockResolvedValue([{ level: 'edit' }]);
const result = await permissionService.checkPermission(
'board',
'b1',
'user1',
'view'
);
expect(result.hasPermission).toBe(true);
expect(result.source).toBe('group');
});
it('denies when no permission found', async () => {
mockUser.findUnique.mockResolvedValue({ role: 'user' });
mockPermission.findFirst.mockResolvedValue(null);
mockUserGroup.findMany.mockResolvedValue([]);
const result = await permissionService.checkPermission(
'board',
'b1',
'user1',
'view'
);
expect(result.hasPermission).toBe(false);
expect(result.effectiveLevel).toBeNull();
expect(result.source).toBeNull();
});
});
describe('grantPermission', () => {
it('upserts a permission', async () => {
const perm = {
entityType: 'board' as const,
entityId: 'b1',
targetType: 'user' as const,
targetId: 'u1',
level: 'edit' as const
};
mockPermission.upsert.mockResolvedValue({ id: 'p1', ...perm });
const result = await permissionService.grantPermission(perm);
expect(result.level).toBe('edit');
});
});
describe('revokePermission', () => {
it('deletes matching permissions', async () => {
mockPermission.deleteMany.mockResolvedValue({ count: 1 });
await permissionService.revokePermission('board', 'b1', 'user', 'u1');
expect(mockPermission.deleteMany).toHaveBeenCalledWith({
where: {
entityType: 'board',
entityId: 'b1',
targetType: 'user',
targetId: 'u1'
}
});
});
});
describe('getPermissionsForEntity', () => {
it('returns permissions for an entity', async () => {
const perms = [{ id: 'p1', level: 'view' }];
mockPermission.findMany.mockResolvedValue(perms);
const result = await permissionService.getPermissionsForEntity('board', 'b1');
expect(result).toEqual(perms);
});
});
});