import { applyDirectionScope, scopedDirections } from './trade-scope.util'; /** * The scope decides what a restricted user may see, so the cases that matter * are the ones where a wrong answer widens access: an unrestricted fallback * where a restriction was configured, or an out-of-scope explicit filter * being honoured instead of denied. */ describe('scopedDirections', () => { it('leaves an unrestricted user unfiltered', () => { expect(scopedDirections(null)).toBeNull(); }); it('honours an explicit filter for an unrestricted user', () => { expect(scopedDirections(null, 'EXPORT')).toEqual(['EXPORT']); }); it('falls back to the full scope when no filter is requested', () => { expect(scopedDirections(['EXPORT'])).toEqual(['EXPORT']); }); it('narrows to the intersection when the filter is in scope', () => { expect(scopedDirections(['IMPORT', 'EXPORT'], 'EXPORT')).toEqual(['EXPORT']); }); it('denies an out-of-scope filter instead of widening access', () => { expect(scopedDirections(['EXPORT'], 'IMPORT')).toEqual([]); }); }); describe('applyDirectionScope', () => { const makeQb = () => { const calls: { sql: string; params?: object }[] = []; const qb = { calls, andWhere(sql: string, params?: object) { calls.push({ sql, params }); return qb; }, }; return qb; }; it('does not touch the query when unrestricted', () => { const qb = makeQb(); applyDirectionScope(qb as never, 'booking.trade_direction', null); expect(qb.calls).toHaveLength(0); }); it('matches nothing on an empty scope rather than everything', () => { const qb = makeQb(); applyDirectionScope(qb as never, 'booking.trade_direction', []); expect(qb.calls[0].sql).toBe('1 = 0'); }); it('filters to the allowed directions', () => { const qb = makeQb(); applyDirectionScope(qb as never, 'booking.trade_direction', ['EXPORT']); expect(qb.calls[0].sql).toContain('booking.trade_direction IN'); expect(qb.calls[0].params).toEqual({ scopeDirs_booking_trade_direction: ['EXPORT'], }); }); });