import { describe, expect, it } from 'vitest'; import { computeOidcScopes, parseGroupsScopesMap } from '../../src/middleware/scopes.js'; describe('parseGroupsScopesMap', () => { it('retourne {} si vide', () => { expect(parseGroupsScopesMap(undefined)).toEqual({}); expect(parseGroupsScopesMap('')).toEqual({}); }); it('parse un mapping valide', () => { const map = parseGroupsScopesMap('{"g1":["a","b"],"g2":["c"]}'); expect(map).toEqual({ g1: ['a', 'b'], g2: ['c'] }); }); it('throw si JSON invalide', () => { expect(() => parseGroupsScopesMap('{')).toThrow(/JSON/); }); it('throw si pas un objet', () => { expect(() => parseGroupsScopesMap('[1,2]')).toThrow(/objet/); expect(() => parseGroupsScopesMap('"x"')).toThrow(/objet/); }); it('throw si valeur pas array of strings', () => { expect(() => parseGroupsScopesMap('{"g":[1]}')).toThrow(); expect(() => parseGroupsScopesMap('{"g":"x"}')).toThrow(); }); }); describe('computeOidcScopes (R1 generique)', () => { it('union groups + permissions + dedup', () => { const scopes = computeOidcScopes(['group-formateurs'], ['custom:perm', 'read:tables'], { 'group-formateurs': ['read:tables', 'admin:custom'], }); expect(scopes).toContain('read:tables'); expect(scopes).toContain('admin:custom'); expect(scopes).toContain('custom:perm'); // Dedup : read:tables apparait une seule fois expect(scopes.filter((s) => s === 'read:tables')).toHaveLength(1); }); it("group inconnu ignore (pas d'erreur)", () => { const scopes = computeOidcScopes(['unknown-group'], [], {}); expect(scopes).toEqual([]); }); it('aucun group + aucune permission = scopes vides', () => { expect(computeOidcScopes([], [], {})).toEqual([]); }); it('permissions explicites sans group fonctionnent (claim direct du JWT)', () => { const scopes = computeOidcScopes([], ['read:tables', 'write:tables'], {}); expect(scopes).toContain('read:tables'); expect(scopes).toContain('write:tables'); }); it('ignore les permissions non-strings ou vides', () => { const scopes = computeOidcScopes([], ['ok', '', 'also-ok'], {}); expect(scopes).toEqual(['also-ok', 'ok']); }); it('output trie alphabetiquement (stabilite)', () => { const scopes = computeOidcScopes(['g'], ['z', 'a'], { g: ['m', 'b'] }); expect(scopes).toEqual(['a', 'b', 'm', 'z']); }); });