e6b50fb4f1
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.
152 lines
4.0 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
});
|