diff --git a/src/auth.spec.ts b/src/auth.spec.ts index b891fa3d..fab670b3 100644 --- a/src/auth.spec.ts +++ b/src/auth.spec.ts @@ -105,14 +105,16 @@ export const embedConfig: any = { const originalWindow = window; export const mockSessionInfoApiResponse = { - userGUID: '1234', - releaseVersion: 'test', - configInfo: { - isPublicUser: false, - mixpanelConfig: { - production: true, - devSdkKey: 'devKey', - prodSdkKey: 'prodKey', + info: { + userGUID: '1234', + releaseVersion: 'test', + configInfo: { + isPublicUser: false, + mixpanelConfig: { + production: true, + devSdkKey: 'devKey', + prodSdkKey: 'prodKey', + }, }, }, }; diff --git a/src/utils/authService/tokenizedAuthService.spec.ts b/src/utils/authService/tokenizedAuthService.spec.ts index 780b1497..b0671b80 100644 --- a/src/utils/authService/tokenizedAuthService.spec.ts +++ b/src/utils/authService/tokenizedAuthService.spec.ts @@ -1,9 +1,17 @@ import * as tokenizedFetchModule from '../../tokenizedFetch'; -import { isActiveService } from './tokenizedAuthService'; +import { isActiveService, fetchSessionInfoService } from './tokenizedAuthService'; +import { EndPoints } from './authService'; import { logger } from '../logger'; +const thoughtspotHost = 'http://thoughtspotHost'; + describe('tokenizedAuthService', () => { - test('isActiveService is fetch returns ok', async () => { + afterEach(() => { + jest.clearAllMocks(); + jest.restoreAllMocks(); + }); + + test('isActiveService if fetch returns ok', async () => { jest.spyOn(tokenizedFetchModule, 'tokenizedFetch').mockResolvedValueOnce({ ok: true, }); @@ -34,3 +42,116 @@ describe('tokenizedAuthService', () => { expect(logger.warn).toHaveBeenCalled(); }); }); + +describe('fetchSessionInfoService', () => { + afterEach(() => { + jest.clearAllMocks(); + jest.restoreAllMocks(); + }); + + test('fetchSessionInfoService should return a V2 info response containing the info key', async () => { + jest.spyOn(tokenizedFetchModule, 'tokenizedFetch').mockResolvedValueOnce({ + ok: true, + headers: new Headers({ 'content-type': 'application/json' }), // Mock headers correctly + json: async () => ({ + info: { + configInfo: { + mixpanelConfig: { + devSdkKey: 'devSdkKey', + }, + }, + userGUID: 'userGUID', + }, + }), // Mock JSON response + }); + + let sessionInfoResp; + try { + sessionInfoResp = await fetchSessionInfoService('http://thoughtspotHost'); + } catch (e) { + // + } + + // Check if the returned data contains the 'info' key + expect(sessionInfoResp).toHaveProperty('info'); + }); + + it('should handle a 404 error from fetchPreauthInfoService and call fetchV1InfoService', async () => { + const mockFetch = jest.spyOn(tokenizedFetchModule, 'tokenizedFetch'); + + // Mock for fetchPreauthInfoService + mockFetch + .mockResolvedValueOnce({ + ok: false, + status: 404, + statusText: 'Not Found', + message: 'Not Found', + json: jest.fn().mockResolvedValue({}), + text: jest.fn().mockResolvedValue('Not Found'), + }) + // Mock for fetchV1InfoService + .mockResolvedValueOnce({ + ok: true, + status: 200, + json: jest.fn().mockResolvedValue({ data: 'mocked session info' }), + }); + + const result = await fetchSessionInfoService(thoughtspotHost); + + expect(mockFetch).toHaveBeenCalledTimes(2); + expect(mockFetch).toHaveBeenNthCalledWith(1, `${thoughtspotHost}${EndPoints.PREAUTH_INFO}`, {}); + expect(mockFetch).toHaveBeenNthCalledWith(2, `${thoughtspotHost}${EndPoints.SESSION_INFO}`, {}); + expect(result).toEqual({ data: 'mocked session info' }); + }); + + it('should handle a error from both fetchPreauthInfoService and call fetchV1InfoService', async () => { + const mockFetch = jest.spyOn(tokenizedFetchModule, 'tokenizedFetch'); + + // Mock for fetchPreauthInfoService + mockFetch + .mockResolvedValueOnce({ + ok: false, + status: 404, + statusText: 'Not Found', + json: jest.fn().mockResolvedValue({}), + text: jest.fn().mockResolvedValue('Not Found'), + }) + // Mock for fetchV1InfoService + .mockResolvedValueOnce({ + ok: false, + status: 404, + statusText: 'Something went wrong', + text: jest.fn().mockResolvedValue('Internal Server Error'), + json: jest.fn().mockResolvedValue({ data: 'mocked session info' }), + }); + + try { + await fetchSessionInfoService(thoughtspotHost); + } catch (e) { + expect(e.message).toContain('Failed to fetch session info: Something went wrong'); + } + + expect(mockFetch).toHaveBeenCalledTimes(2); + expect(mockFetch).toHaveBeenNthCalledWith(1, `${thoughtspotHost}${EndPoints.PREAUTH_INFO}`, {}); + expect(mockFetch).toHaveBeenNthCalledWith(2, `${thoughtspotHost}${EndPoints.SESSION_INFO}`, {}); + }); + + it('should return an empty object if an error other than 404 occurs', async () => { + const mockFetch = jest.spyOn(tokenizedFetchModule, 'tokenizedFetch'); + + // Mock for fetchPreauthInfoService + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 500, + statusText: 'Internal Server Error', + json: jest.fn().mockResolvedValue({}), + text: jest.fn().mockResolvedValue('Internal Server Error'), + }); + + const result = await fetchSessionInfoService(thoughtspotHost); + + expect(mockFetch).toHaveBeenCalledTimes(1); + expect(mockFetch).toHaveBeenCalledWith(`${thoughtspotHost}${EndPoints.PREAUTH_INFO}`, {}); + expect(result).toEqual({}); + }); +}); diff --git a/src/utils/authService/tokenizedAuthService.ts b/src/utils/authService/tokenizedAuthService.ts index 95f9eeb7..b063dd73 100644 --- a/src/utils/authService/tokenizedAuthService.ts +++ b/src/utils/authService/tokenizedAuthService.ts @@ -10,7 +10,11 @@ import { EndPoints } from './authService'; function tokenizedFailureLoggedFetch(url: string, options: RequestInit = {}): Promise { return tokenizedFetch(url, options).then(async (r) => { if (!r.ok && r.type !== 'opaqueredirect' && r.type !== 'opaque') { - logger.error(`Failed to fetch ${url}`, await r.text?.()); + if (r.status === 404) { + logger.warn(`Failed to fetch ${url}`, await r.text?.()); + } else { + logger.error(`Failed to fetch ${url}`, await r.text?.()); + } } return r; }); @@ -29,7 +33,9 @@ export async function fetchPreauthInfoService(thoughtspotHost: string): Promise< const sessionInfoPath = `${thoughtspotHost}${EndPoints.PREAUTH_INFO}`; const response = await tokenizedFailureLoggedFetch(sessionInfoPath); if (!response.ok) { - throw new Error(`Failed to fetch auth info: ${response.statusText}`); + const error: any = new Error(`Failed to fetch auth info: ${response.statusText}`); + error.status = response.status; // Attach the status code to the error object + throw error; } return response; @@ -48,7 +54,9 @@ export async function fetchV1InfoService(thoughtspotHost: string): Promise const sessionInfoPath = `${thoughtspotHost}${EndPoints.SESSION_INFO}`; const response = await tokenizedFailureLoggedFetch(sessionInfoPath); if (!response.ok) { - throw new Error(`Failed to fetch session info: ${response.statusText}`); + const error: any = new Error(`Failed to fetch session info: ${response.statusText}`); + error.status = response.status; // Attach the status code to the error object + throw error; } return response;