import { OtpDispatcher } from './otp-dispatcher.service'; import { OtpProvider } from './otp-provider.interface'; function provider(name: string, result: boolean | (() => boolean)): OtpProvider { return { name, supports: () => true, send: jest.fn(async () => (typeof result === 'function' ? result() : result)), }; } describe('OtpDispatcher — توجيه حسب الدولة + failover (docs/17 D5)', () => { it('مصر تجرّب Kazumi أولاً', async () => { const kazumi = provider('kazumi', true); const nabeh = provider('nabeh', true); const d = new OtpDispatcher([kazumi, nabeh]); expect(await d.send('201012345678', '1234', { countryPack: 'eg' })).toBe(true); expect(kazumi.send).toHaveBeenCalledTimes(1); expect(nabeh.send).not.toHaveBeenCalled(); // نجح الأول فلا failover }); it('مصر: فشل Kazumi → يتحوّل إلى Nabeh', async () => { const kazumi = provider('kazumi', false); const nabeh = provider('nabeh', true); const d = new OtpDispatcher([kazumi, nabeh]); expect(await d.send('201012345678', '1234', { countryPack: 'eg' })).toBe(true); expect(kazumi.send).toHaveBeenCalledTimes(1); expect(nabeh.send).toHaveBeenCalledTimes(1); // جرّب البديل }); it('الأردن يستعمل Nabeh فقط — لا يلمس Kazumi', async () => { const kazumi = provider('kazumi', true); const nabeh = provider('nabeh', true); const d = new OtpDispatcher([kazumi, nabeh]); expect(await d.send('962790000000', '1234', { countryPack: 'jo' })).toBe(true); expect(nabeh.send).toHaveBeenCalledTimes(1); expect(kazumi.send).not.toHaveBeenCalled(); }); it('سوريا تستعمل Nabeh', async () => { const nabeh = provider('nabeh', true); const d = new OtpDispatcher([nabeh]); expect(await d.send('963944000000', '1234', { countryPack: 'sy' })).toBe(true); }); it('فشل السلسلة كاملة يرجع false — المُستدعي يُفشل الطلب', async () => { const kazumi = provider('kazumi', false); const nabeh = provider('nabeh', false); const d = new OtpDispatcher([kazumi, nabeh]); expect(await d.send('201012345678', '1234', { countryPack: 'eg' })).toBe(false); expect(kazumi.send).toHaveBeenCalledTimes(1); expect(nabeh.send).toHaveBeenCalledTimes(1); }); it('دولة غير معروفة تسقط لـNabeh (السلسلة الافتراضية)', async () => { const nabeh = provider('nabeh', true); const d = new OtpDispatcher([nabeh]); expect(await d.send('491234567', '1234', { countryPack: 'de' })).toBe(true); expect(nabeh.send).toHaveBeenCalledTimes(1); }); it('مزوّد مفقود من التسجيل لا يُسقط السلسلة — يتخطّاه', async () => { // Kazumi غير مسجَّل، فمصر تسقط لـNabeh وحده. const nabeh = provider('nabeh', true); const d = new OtpDispatcher([nabeh]); expect(await d.send('201012345678', '1234', { countryPack: 'eg' })).toBe(true); expect(nabeh.send).toHaveBeenCalledTimes(1); }); });