import { describe, expect, it } from 'vitest'; import { buildVisibilityWhere, canUserSeeTask } from './visibility.js'; function makeUser(overrides: Partial = {}): Express.User { return { id: 'user-1', email: 'u@x.com', name: 'u', avatarUrl: null, role: 'user', status: 'active', orgIds: [], defaultVisibility: 'private', defaultVisibilityOrgId: null, ...overrides, }; } describe('buildVisibilityWhere', () => { it('admin sees everything (1=1)', () => { const w = buildVisibilityWhere(makeUser({ role: 'admin' }), 'lt'); expect(w.clause).toBe('1=1'); expect(w.params).toEqual([]); }); it('user with no orgs: owner or public only', () => { const w = buildVisibilityWhere(makeUser(), 'lt'); expect(w.clause).toContain('lt.owner_id = ?'); expect(w.clause).toContain("lt.visibility = 'public'"); expect(w.clause).toContain('IN (NULL)'); // empty orgs → never matches expect(w.params).toEqual(['user-1']); }); it('user with orgs: owner or public or same-org', () => { const w = buildVisibilityWhere(makeUser({ orgIds: ['10', '20'] }), 'lt'); expect(w.clause).toMatch(/lt\.visibility_scope_org_id IN \(\?,\?\)/); expect(w.params).toEqual(['user-1', '10', '20']); }); it('respects custom table alias', () => { const w = buildVisibilityWhere(makeUser(), 'j'); expect(w.clause).toContain('j.owner_id'); expect(w.clause).not.toContain('lt.'); }); }); describe('canUserSeeTask', () => { const adminUser = makeUser({ role: 'admin' }); const aliceNoOrg = makeUser({ id: 'alice' }); const bobOrg10 = makeUser({ id: 'bob', orgIds: ['10'] }); it('admin sees private tasks of others', () => { const t = { ownerId: 'someone-else', visibility: 'private' as const, visibilityScopeOrgId: null }; expect(canUserSeeTask(adminUser, t)).toBe(true); }); it('owner sees own private task', () => { const t = { ownerId: 'alice', visibility: 'private' as const, visibilityScopeOrgId: null }; expect(canUserSeeTask(aliceNoOrg, t)).toBe(true); }); it('non-owner cannot see another user\'s private task', () => { const t = { ownerId: 'someone-else', visibility: 'private' as const, visibilityScopeOrgId: null }; expect(canUserSeeTask(aliceNoOrg, t)).toBe(false); }); it('public task is visible to anyone', () => { const t = { ownerId: 'someone-else', visibility: 'public' as const, visibilityScopeOrgId: null }; expect(canUserSeeTask(aliceNoOrg, t)).toBe(true); }); it('org task: same org member can see', () => { const t = { ownerId: 'someone-else', visibility: 'org' as const, visibilityScopeOrgId: '10' }; expect(canUserSeeTask(bobOrg10, t)).toBe(true); }); it('org task: different org member cannot see', () => { const t = { ownerId: 'someone-else', visibility: 'org' as const, visibilityScopeOrgId: '99' }; expect(canUserSeeTask(bobOrg10, t)).toBe(false); }); it('org task with null scope: only owner can see', () => { const t = { ownerId: 'alice', visibility: 'org' as const, visibilityScopeOrgId: null }; expect(canUserSeeTask(aliceNoOrg, t)).toBe(true); expect(canUserSeeTask(bobOrg10, t)).toBe(false); }); it('owner with null ownerId: not matched (null !== null check skipped)', () => { const t = { ownerId: null, visibility: 'private' as const, visibilityScopeOrgId: null }; expect(canUserSeeTask(aliceNoOrg, t)).toBe(false); }); });