/** * access-classify — pure-layer tests (derived `partial` label + subset verdicts). */ import { describe, it, expect } from 'vitest'; import { deriveAccessLabel, classifySubsetVisibility, classifyEmptyList, subsetVisibleForRole, } from '../access-classify.js'; import type { AccessVerdict, Route, Subset } from '../plantest-schema.js'; function subset(visibleFor: string[]): Subset { return { id: 'btn', type: 'action', kind: 'button', action_kind: 'click', selector: 'button', is_destructive: false, visible_for: visibleFor, expect: 'ok', } as Subset; } function route(access: Record, subsets: Subset[]): Route { return { id: 'R', route: '/r', navigation_strategy: 'menu_click', expect: { access_by_role: true, no_console_error: true }, access, subsets, } as Route; } describe('deriveAccessLabel', () => { it('passes denied / redirect_login through unchanged', () => { expect(deriveAccessLabel(route({ viewer: 'denied' }, []), 'viewer')).toBe('denied'); expect(deriveAccessLabel(route({ anonymous: 'redirect_login' }, []), 'anonymous')).toBe('redirect_login'); }); it('allowed with full subset visibility stays allowed', () => { const r = route({ admin: 'allowed' }, [subset(['admin']), subset(['admin'])]); expect(deriveAccessLabel(r, 'admin')).toBe('allowed'); }); it('allowed but a subset legitimately hidden becomes partial', () => { const r = route({ admin: 'allowed', manager: 'allowed' }, [subset(['admin'])]); expect(deriveAccessLabel(r, 'manager')).toBe('partial'); // manager not in visible_for expect(deriveAccessLabel(r, 'admin')).toBe('allowed'); }); it('a role missing from the access map defaults to denied', () => { expect(deriveAccessLabel(route({ admin: 'allowed' }, []), 'ghost')).toBe('denied'); }); }); describe('classifySubsetVisibility', () => { const sub = subset(['admin']); it('role may see it: present => PASS RBAC-OK, absent => FAIL BUG-MISSING-ELEMENT', () => { expect(classifySubsetVisibility(sub, 'admin', 1)).toEqual({ pass: true, category: 'RBAC-OK' }); expect(classifySubsetVisibility(sub, 'admin', 0)).toEqual({ pass: false, category: 'BUG-MISSING-ELEMENT' }); }); it('role may NOT see it: present => FAIL BUG-OVEREXPOSED, absent => PASS CONFIG-LEGITIME', () => { expect(classifySubsetVisibility(sub, 'viewer', 1)).toEqual({ pass: false, category: 'BUG-OVEREXPOSED' }); expect(classifySubsetVisibility(sub, 'viewer', 0)).toEqual({ pass: true, category: 'CONFIG-LEGITIME' }); }); }); describe('classifyEmptyList / subsetVisibleForRole', () => { it('empty parent list is INDETERMINATE, never denied', () => { expect(classifyEmptyList()).toEqual({ pass: true, category: 'INDETERMINATE' }); }); it('subsetVisibleForRole reflects visible_for membership', () => { expect(subsetVisibleForRole(subset(['admin']), 'admin')).toBe(true); expect(subsetVisibleForRole(subset(['admin']), 'viewer')).toBe(false); }); });