UNPKG

@thoughtspot/visual-embed-sdk

Version:
563 lines (533 loc) 20.3 kB
import 'jest-fetch-mock'; import { AuthType, RuntimeFilterOp, VizPoint } from '../../../types'; import { AnswerService } from './answerService'; import { getAnswerData, removeColumns, addFilter, addColumns, getSQLQuery, } from './answer-queries'; import * as queries from './answer-queries'; import * as authTokenInstance from '../../../authToken'; import * as tokenizedFetch from '../../../tokenizedFetch'; import * as embedConfigInstance from '../../../embed/embedConfig'; const defaultSession = { sessionId: 'id', genNo: 1, acSession: { sessionId: 'ac', genNo: 0, }, }; /** * * @param answer * @param point */ function createAnswerService(answer = {}, point?: VizPoint[]) { return new AnswerService( defaultSession, answer, 'https://tshost', point, ); } describe('Answer service tests', () => { beforeEach(() => { fetchMock.resetMocks(); }); test('should call executeQuery with correct parameters to add columns', async () => { const service = createAnswerService(); const executeQuerySpy = jest.spyOn(service, 'executeQuery').mockResolvedValue({ id: { genNo: 2 }, }); const columnIds = ['col1', 'col2']; const result = await service.addColumns(columnIds); expect(executeQuerySpy).toHaveBeenCalledWith(queries.addColumns, { columns: columnIds.map((colId) => ({ logicalColumnId: colId })), }); expect(result.id.genNo).toBe(2); }); test('Execute query should execute the supplied graphql on the session', async () => { fetchMock.mockResponseOnce(JSON.stringify({ data: { Bla: { id: {}, }, }, })); const answerService = createAnswerService(); answerService.executeQuery( 'query Bla {}', { a: 1 }, ); expect(fetchMock).toBeCalledWith('https://tshost/prism/?op=Bla', expect.objectContaining({ body: JSON.stringify({ operationName: 'Bla', query: 'query Bla {}', variables: { session: defaultSession, a: 1, }, }), })); }); test('Should return error when failure', async () => { fetchMock.mockRejectOnce(new Error('testError')); const answerService = createAnswerService(); const data = await answerService.executeQuery( 'query Bla {}', { a: 1 }, ); expect(data.message).toBe('testError'); }); test('fetchData should call the right graphql, and return data', async () => { fetchMock.mockResponseOnce(JSON.stringify({ data: { getAnswer: { id: {}, answer: { visualizations: [{ id: 'vizId', }, { columns: [{ column: { id: 'id1', }, }], data: { foo: 1, }, }], }, }, }, })); const answerService = createAnswerService(); const data = await answerService.fetchData(20, 10); expect(fetchMock).toHaveBeenCalledWith( 'https://tshost/prism/?op=GetTableWithHeadlineData', expect.objectContaining({ body: JSON.stringify({ operationName: 'GetTableWithHeadlineData', query: getAnswerData, variables: { session: defaultSession, deadline: 0, dataPaginationParams: { isClientPaginated: true, offset: 20, size: 10, }, }, }), }), ); expect(data.columns[0].column.id).toBe('id1'); expect(data.data.foo).toBe(1); }); test('fetchCSVBlob should call the right API', () => { fetchMock.once('Bla'); const answerService = createAnswerService(); const mockEmbedConfig = { thougthspotHost: '/test', authType: AuthType.TrustedAuthTokenCookieless, }; jest.spyOn(embedConfigInstance, 'getEmbedConfig').mockReturnValueOnce(mockEmbedConfig); jest.spyOn(authTokenInstance, 'getAuthenticationToken').mockReturnValueOnce(Promise.resolve('token')); const mockTokenizedFetch = jest.spyOn(tokenizedFetch, 'tokenizedFetch'); answerService.fetchCSVBlob(undefined, true); expect(mockTokenizedFetch).toHaveBeenCalledWith( `https://tshost/prism/download/answer/csv?sessionId=${defaultSession.sessionId}&genNo=${defaultSession.genNo}&userLocale=en-us&exportFileName=data&hideCsvHeader=false`, expect.objectContaining({}), ); answerService.fetchCSVBlob('en-uk', true); expect(mockTokenizedFetch).toHaveBeenCalledWith( `https://tshost/prism/download/answer/csv?sessionId=${defaultSession.sessionId}&genNo=${defaultSession.genNo}&userLocale=en-uk&exportFileName=data&hideCsvHeader=false`, expect.objectContaining({}), ); answerService.fetchCSVBlob(undefined, false); expect(mockTokenizedFetch).toHaveBeenCalledWith( `https://tshost/prism/download/answer/csv?sessionId=${defaultSession.sessionId}&genNo=${defaultSession.genNo}&userLocale=en-us&exportFileName=data&hideCsvHeader=true`, expect.objectContaining({}), ); }); test('fetchPNGBlob should call the right API', () => { const answerService = createAnswerService(); const mockEmbedConfig = { thougthspotHost: '/test', authType: AuthType.TrustedAuthTokenCookieless, }; jest.spyOn(embedConfigInstance, 'getEmbedConfig').mockReturnValueOnce(mockEmbedConfig); jest.spyOn(authTokenInstance, 'getAuthenticationToken').mockReturnValueOnce(Promise.resolve('token')); const mockTokenizedFetch = jest.spyOn(tokenizedFetch, 'tokenizedFetch'); answerService.fetchPNGBlob(undefined, true); expect(mockTokenizedFetch).toHaveBeenCalledWith(`https://tshost/prism/download/answer/png?sessionId=${defaultSession.sessionId}&deviceScaleFactor=2&omitBackground=true&genNo=${defaultSession.genNo}&userLocale=en-us&exportFileName=data`, expect.objectContaining({})); answerService.fetchPNGBlob('en-uk', true); expect(mockTokenizedFetch).toHaveBeenCalledWith(`https://tshost/prism/download/answer/png?sessionId=${defaultSession.sessionId}&deviceScaleFactor=2&omitBackground=true&genNo=${defaultSession.genNo}&userLocale=en-uk&exportFileName=data`, expect.objectContaining({})); answerService.fetchPNGBlob(undefined, false); expect(mockTokenizedFetch).toHaveBeenCalledWith(`https://tshost/prism/download/answer/png?sessionId=${defaultSession.sessionId}&deviceScaleFactor=2&omitBackground=false&genNo=${defaultSession.genNo}&userLocale=en-us&exportFileName=data`, expect.objectContaining({})); answerService.fetchPNGBlob(undefined, true, 3); expect(mockTokenizedFetch).toHaveBeenCalledWith(`https://tshost/prism/download/answer/png?sessionId=${defaultSession.sessionId}&deviceScaleFactor=3&omitBackground=true&genNo=${defaultSession.genNo}&userLocale=en-us&exportFileName=data`, expect.objectContaining({})); }); test('getUnderlyingDataForPoint should call the right APIs', async () => { fetchMock.mockResponses( JSON.stringify({ data: { getSourceDetailById: [{ columns: [{ id: 'id1', name: 'col1', }, { id: 'id2', name: 'col2', }, { id: 'id3', name: 'col3', }], }], }, }), JSON.stringify({ data: { Answer__getUnaggregatedAnswer: { id: { ...defaultSession, }, answer: { visualizations: [{ columns: [{ column: { id: 'oid1', name: 'col1', referencedColumns: [{ guid: 'id1', }], }, }], }], }, }, }, }), JSON.stringify({ data: { Answer__addColumn: { id: { genNo: 2, }, }, }, }), JSON.stringify({ data: { Answer__removeColumns: { id: { genNo: 3, }, }, }, }), ); const answerService = createAnswerService({ sources: [{ header: { guid: 'source1', }, }], }, [{ selectedAttributes: [{ column: { id: 'oid1', // output column id name: 'col1', dataType: 'CHAR', }, value: '1', }, { column: { id: 'oid3', name: 'col3', dataType: 'DATE', }, value: 12345, }, { column: { id: 'oid4', name: 'col4', dataType: 'DATE', }, value: { v: { s: 12345, e: 54321, }, }, }], selectedMeasures: [], }]); const underlying = await answerService.getUnderlyingDataForPoint(['col2']); expect(fetchMock).toHaveBeenCalledTimes(4); expect(underlying.getSession().genNo).toBe(3); expect(fetchMock).toHaveBeenCalledWith( 'https://tshost/prism/?op=RemoveColumns', expect.objectContaining({ body: JSON.stringify({ operationName: 'RemoveColumns', query: removeColumns, variables: { session: { ...defaultSession, genNo: 2, }, logicalColumnIds: [ 'id1', ], }, }), }), ); }); test('getUnderlyingDataForPoint should throw when no point is selected', async () => { const answerService = createAnswerService({}, null); await expect(answerService.getUnderlyingDataForPoint(['col2'])).rejects.toThrow(); }); test('addFilter should call the right API', async () => { fetchMock.mockResponses( JSON.stringify({ data: { getSourceDetailById: [{ columns: [{ id: 'id1', name: 'col1', }], }], }, }), JSON.stringify({ data: { Answer__addUpdateFilter: { id: { genNo: 2, }, }, }, }), ); const answerService = createAnswerService({ sources: [{ header: { guid: 'source1', }, }], }); const session = await answerService.addFilter('col1', RuntimeFilterOp.IN, [2]); expect(fetchMock).toHaveBeenCalledWith( 'https://tshost/prism/?op=AddUpdateFilter', expect.objectContaining({ body: JSON.stringify({ operationName: 'AddUpdateFilter', query: addFilter, variables: { session: defaultSession, params: { filterContent: [{ filterType: 'IN', value: [{ type: 'DOUBLE', doubleValue: 2, }], }], filterGroupId: { logicalColumnId: 'id1', }, }, }, }), }), ); }); test('Should fetch answer if not passed', async () => { fetchMock.mockResponses(JSON.stringify({ data: { getAnswer: { id: {}, answer: { visualizations: [{ columns: [{ column: { id: 'id1', name: 'col1', }, }], }], sources: [{ header: { guid: 'source1', displayName: 'source1', }, }], filterGroups: [], }, }, }, })); const answerService = new AnswerService(defaultSession, null, 'https://tshost'); const answer = await answerService.getAnswer(); expect(answer.sources[0].header.guid).toBe('source1'); }); test('Add columns by name should call the right API', async () => { fetchMock.mockResponses( JSON.stringify({ data: { getSourceDetailById: [{ columns: [{ id: 'id1', name: 'col1', }, { id: 'id2', name: 'col2', }], }], }, }), JSON.stringify({ data: { Answer__addColumn: { id: { genNo: 2, }, }, }, }), ); const answerService = createAnswerService({ sources: [{ header: { guid: 'source1', }, }], }); const session = await answerService.addColumnsByName(['col1']); expect(fetchMock).toHaveBeenCalledWith( 'https://tshost/prism/?op=AddColumns', expect.objectContaining({ body: JSON.stringify({ operationName: 'AddColumns', query: addColumns, variables: { session: defaultSession, columns: [{ logicalColumnId: 'id1', }], }, }), }), ); }); test('Get SQL query should call the right API', async () => { fetchMock.mockResponseOnce(JSON.stringify({ data: { Answer__getQuery: { id: {}, sql: 'SELECT * FROM table', }, }, })); const answerService = createAnswerService(); const sql = await answerService.getSQLQuery(); expect(fetchMock).toHaveBeenCalledWith( 'https://tshost/prism/?op=GetSQLQuery', expect.objectContaining({ body: JSON.stringify({ operationName: 'GetSQLQuery', query: getSQLQuery, variables: { session: defaultSession, }, }), }), ); expect(sql).toBe('SELECT * FROM table'); }); test('Add displayed Viz should call the right API', async () => { fetchMock.mockResponseOnce(JSON.stringify({ data: { Answer__addDisplayedViz: { id: { genNo: 2, }, }, }, })); const answer = { displayMode: 'CHART_MODE', visualizations: [{ id: 'table1', __typename: 'TableViz', }, { id: 'chart1', __typename: 'ChartViz', }], }; const answerService = createAnswerService(answer); await answerService.addDisplayedVizToLiveboard('lbId'); expect(fetchMock).toHaveBeenCalledWith( 'https://tshost/prism/?op=AddVizToLiveboard', expect.objectContaining({ body: JSON.stringify({ operationName: 'AddVizToLiveboard', query: queries.addVizToLiveboard, variables: { session: defaultSession, liveboardId: 'lbId', vizId: 'chart1', }, }), }), ); answer.displayMode = 'TABLE_MODE'; const answerService2 = createAnswerService(answer); await answerService2.addDisplayedVizToLiveboard('lbId'); expect(fetchMock).toHaveBeenCalledWith( 'https://tshost/prism/?op=AddVizToLiveboard', expect.objectContaining({ body: JSON.stringify({ operationName: 'AddVizToLiveboard', query: queries.addVizToLiveboard, variables: { session: defaultSession, liveboardId: 'lbId', vizId: 'table1', }, }), }), ); }); test('GetTML should call the right API', async () => { fetchMock.mockResponseOnce(JSON.stringify({ data: { UnsavedAnswer_getTML: { object: [{ edoc: `answer: id: bar`, }], }, }, })); const answerService = createAnswerService(); answerService.setTMLOverride({ name: 'name' }); const { answer } = await answerService.getTML(); expect(fetchMock).toHaveBeenCalledWith( 'https://tshost/prism/?op=GetUnsavedAnswerTML', expect.objectContaining({ body: JSON.stringify({ operationName: 'GetUnsavedAnswerTML', query: queries.getAnswerTML, variables: { session: defaultSession, }, }), }), ); expect(answer.name).toBe('name'); expect(answer.id).toBe('bar'); }); });