import { requestWidgetUrl, buildRequestParams } from '../services/WidgetBootstrapService'; import { WidgetData } from '../domain'; // Mock das dependĂȘncias jest.mock('../constants/Constants', () => ({ SDK_NAME: 'rn-widget-sdk', SDK_VERSION: '0.1.16', })); jest.mock('../hooks/useClientVersionCollector', () => ({ getClientVersion: jest.fn(() => '1.0.0'), })); jest.mock('../hooks/useDeviceInfoCollector', () => ({ getDeviceInfo: jest.fn(() => ({ platform: 'ios', osVersion: '16.0', deviceType: 'phone', model: 'iPhone 14 Pro', })), })); // Mock global do fetch const originalFetch = global.fetch; describe('WidgetBootstrapService', () => { beforeEach(() => { jest.clearAllMocks(); global.fetch = jest.fn(); }); afterEach(() => { global.fetch = originalFetch; }); describe('buildRequestParams', () => { it('should build URL parameters from widget data', () => { const data: WidgetData = { customer_id: 'cust-123', email: 'test@example.com', journey: 'checkout', }; const params = buildRequestParams(data); expect(params.get('customer_id')).toBe('cust-123'); expect(params.get('email')).toBe('test@example.com'); expect(params.get('journey')).toBe('checkout'); expect(params.get('transactionId')).toBeNull(); expect(params.get('attemptId')).toBeNull(); }); it('should skip undefined and null values', () => { const data: WidgetData = { customer_id: 'cust-123', email: undefined, name: null as any, }; const params = buildRequestParams(data); expect(params.has('customer_id')).toBe(true); expect(params.has('email')).toBe(false); expect(params.has('name')).toBe(false); }); it('should convert numbers to strings', () => { const data: WidgetData = { amount: 100.50, score: 5, }; const params = buildRequestParams(data); expect(params.get('amount')).toBe('100.5'); expect(params.get('score')).toBe('5'); }); }); describe('requestWidgetUrl', () => { it('should send request with correct Sec-CH-UA headers', async () => { const mockResponse = { ok: true, json: jest.fn().mockResolvedValue({ url: 'https://widget.url' }), }; (global.fetch as jest.Mock).mockResolvedValue(mockResponse); const data: WidgetData = { customer_id: 'cust-123', journey: 'test', }; await requestWidgetUrl('api-key-123', data, 'user-id-456'); expect(global.fetch).toHaveBeenCalledWith( expect.stringContaining('customer_id=cust-123'), expect.objectContaining({ method: 'GET', headers: expect.objectContaining({ 'x-solucx-api-key': 'api-key-123', 'x-solucx-device-id': 'user-id-456', 'Sec-CH-UA': '"rn-widget-sdk";v="0.1.16", "app";v="1.0.0"', 'Sec-CH-UA-Platform': '"ios"', 'Sec-CH-UA-Mobile': '?1', 'Sec-CH-UA-Platform-Version': '"16.0"', 'Sec-CH-UA-Model': '"iPhone 14 Pro"', 'User-Agent': 'rn-widget-sdk/0.1.16 (ios; OS 16.0; iPhone 14 Pro) App/1.0.0', }), }) ); }); it('should set Sec-CH-UA-Mobile to ?0 for tablets', async () => { const { getDeviceInfo } = require('../hooks/useDeviceInfoCollector'); getDeviceInfo.mockReturnValueOnce({ platform: 'android', osVersion: '13.0', deviceType: 'tablet', model: 'Samsung Galaxy Tab S8', }); const mockResponse = { ok: true, json: jest.fn().mockResolvedValue({ url: 'https://widget.url' }), }; (global.fetch as jest.Mock).mockResolvedValue(mockResponse); const data: WidgetData = { customer_id: 'cust-123' }; await requestWidgetUrl('api-key-123', data, 'user-id-456'); expect(global.fetch).toHaveBeenCalledWith( expect.any(String), expect.objectContaining({ headers: expect.objectContaining({ 'Sec-CH-UA-Mobile': '?0', 'Sec-CH-UA-Platform': '"android"', }), }) ); }); it('should return widget URL on success', async () => { const mockResponse = { ok: true, json: jest.fn().mockResolvedValue({ url: 'https://widget.url/test' }), }; (global.fetch as jest.Mock).mockResolvedValue(mockResponse); const result = await requestWidgetUrl( 'api-key', { customer_id: 'cust' }, 'user-id' ); expect(result).toEqual({ url: 'https://widget.url/test' }); }); it('should throw error when response is not ok', async () => { const mockResponse = { ok: false, status: 404, statusText: 'Not Found', }; (global.fetch as jest.Mock).mockResolvedValue(mockResponse); await expect( requestWidgetUrl('api-key', { customer_id: 'cust' }, 'user-id') ).rejects.toThrow('Failed to get error response: 404 Not Found'); }); it('should throw error with status 500', async () => { const mockResponse = { ok: false, status: 500, statusText: 'Internal Server Error', }; (global.fetch as jest.Mock).mockResolvedValue(mockResponse); await expect( requestWidgetUrl('api-key', { customer_id: 'cust' }, 'user-id') ).rejects.toThrow('Failed to get error response: 500 Internal Server Error'); }); it('should throw error when fetch is not available', async () => { (global as any).fetch = undefined; await expect( requestWidgetUrl('api-key', { customer_id: 'cust' }, 'user-id') ).rejects.toThrow('Fetch is not available'); }); it('should return payload without url when response does not contain url', async () => { const mockResponse = { ok: true, json: jest.fn().mockResolvedValue({ available: false, reason: 'No survey available' }), }; (global.fetch as jest.Mock).mockResolvedValue(mockResponse); const result = await requestWidgetUrl('api-key', { customer_id: 'cust' }, 'user-id'); expect(result).toEqual({ available: false, reason: 'No survey available' }); }); it('should return payload when url is null', async () => { const mockResponse = { ok: true, json: jest.fn().mockResolvedValue({ available: true, url: null }), }; (global.fetch as jest.Mock).mockResolvedValue(mockResponse); const result = await requestWidgetUrl('api-key', { customer_id: 'cust' }, 'user-id'); expect(result).toEqual({ available: true, url: null }); }); }); });