Skip to content

Commit

Permalink
Spotter Embed components (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
ashubham authored Oct 8, 2024
1 parent ba1bf4b commit 03ba61b
Show file tree
Hide file tree
Showing 37 changed files with 22,606 additions and 5,796 deletions.
8 changes: 8 additions & 0 deletions jest-setup.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const fetchMock = require('jest-fetch-mock');
const crypto = require('crypto');

fetchMock.enableMocks();

Expand Down Expand Up @@ -32,3 +33,10 @@ global.MessageChannel = jest.fn().mockImplementation(() => {
},
};
});

Object.defineProperty(global, 'crypto', {
value: {
getRandomValues: (arr) => crypto.randomBytes(arr.length),
randomUUID: () => crypto.randomBytes(16).toString('hex'),
},
});
26,325 changes: 20,770 additions & 5,555 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 8 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@thoughtspot/visual-embed-sdk",
"version": "1.33.0",
"version": "1.33.1",
"description": "ThoughtSpot Embed SDK",
"module": "lib/src/index.js",
"main": "dist/tsembed.js",
Expand Down Expand Up @@ -37,8 +37,8 @@
},
"size-limit": [
{
"path": "dist/tsembed.js",
"limit": "49 kB"
"path": "dist/es/index.js",
"limit": "30 kB"
}
],
"scripts": {
Expand Down Expand Up @@ -80,7 +80,8 @@
"mixpanel-browser": "2.47.0",
"ts-deepmerge": "^6.0.2",
"tslib": "^2.5.3",
"use-deep-compare-effect": "^1.8.1"
"use-deep-compare-effect": "^1.8.1",
"yaml": "^2.5.1"
},
"devDependencies": {
"@mdx-js/mdx": "^1.6.22",
Expand All @@ -96,8 +97,8 @@
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^13.1.8",
"@types/jest": "^22.2.3",
"@types/mixpanel-browser": "^2.35.6",
"@types/lodash": "^4.17.0",
"@types/mixpanel-browser": "^2.35.6",
"@types/react-test-renderer": "^17.0.1",
"@typescript-eslint/eslint-plugin": "^4.6.0",
"@typescript-eslint/parser": "^4.6.0",
Expand All @@ -106,6 +107,7 @@
"babel-preset-gatsby": "^1.10.0",
"command-line-args": "^5.1.1",
"coveralls": "^3.1.0",
"crypto": "^1.0.1",
"current-git-branch": "^1.1.0",
"dts-bundle": "^0.7.3",
"eslint": "^7.12.1",
Expand All @@ -132,7 +134,7 @@
"react-resize-detector": "^6.6.0",
"react-test-renderer": "^17.0.2",
"react-use-flexsearch": "^0.1.1",
"rollup": "2.30.0",
"rollup": "4.24.0",
"rollup-plugin-typescript2": "0.27.3",
"ts-jest": "^26.5.5",
"ts-loader": "8.0.4",
Expand Down
33 changes: 17 additions & 16 deletions rollup.config.js → rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* Copyright (c) 2020
*
* Rollup configuration for building ThoughtSpot Embed UI SDK module
*
* @summary Rollup config
* @author Ayon Ghosh <[email protected]>
*/
Expand All @@ -13,31 +12,31 @@ import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import replace from '@rollup/plugin-replace';

import pkg from './package.json';
import pkg from './package.json' assert {type: "json"};

const plugins = [
typescript({
typescript: require('typescript'),
}),
nodeResolve(),
commonjs(),
json({
compact: true
}),
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
})
];
typescript(),
nodeResolve(),
commonjs(),
json({
compact: true,
}),
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
];

export default [{
input: 'src/index.ts',
output: [
{
file: 'dist/tsembed.js',
format: 'umd',
inlineDynamicImports: true,
name: 'tsembed',
},
{
file: 'dist/tsembed.es.js',
dir: 'dist/es',
format: 'es',
},
],
Expand All @@ -51,10 +50,12 @@ export default [{
{
file: 'dist/tsembed-react.js',
format: 'umd',
inlineDynamicImports: true,
name: 'tsembed',
},
{
file: 'dist/tsembed-react.es.js',
dir: 'dist/es/react',
inlineDynamicImports: true,
format: 'es',
},
],
Expand Down
15 changes: 3 additions & 12 deletions src/auth.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import 'jest-fetch-mock';
import * as authInstance from './auth';
import * as authTokenService from './authToken';
import * as EmbedConfig from './embed/embedConfig';
import * as mixPanelService from './mixpanel-service';
import { executeAfterWait } from './test/test-utils';
import { executeAfterWait, mockSessionInfo } from './test/test-utils';
import { AuthType, EmbedEvent } from './types';
import * as checkReleaseVersionInBetaInstance from './utils';
import * as authService from './utils/authService/authService';
Expand Down Expand Up @@ -102,17 +103,6 @@ export const embedConfig: any = {
};

const originalWindow = window;
export const mockSessionInfo = {
userGUID: '1234',
mixpanelToken: 'abc123',
isPublicUser: false,
sessionId: '6588e7d9-710c-453e-a7b4-535fb3a8cbb2',
genNo: 3,
acSession: {
sessionId: 'cb202c48-b14b-4466-8a70-899ea666d46q',
genNo: 5,
},
};

export const mockSessionInfoApiResponse = {
userGUID: '1234',
Expand Down Expand Up @@ -205,6 +195,7 @@ describe('Unit test for auth', () => {
});

test('doTokenAuth: when user is not loggedIn & getAuthToken not present, isLoggedIn should called', async () => {
fetchMock.mockResponse(JSON.stringify({ mixpanelAccessToken: '' }));
jest.spyOn(tokenAuthService, 'isActiveService').mockImplementation(async () => false);
jest.spyOn(authService, 'fetchAuthTokenService').mockImplementation(() => ({
text: () => Promise.resolve('abc'),
Expand Down
3 changes: 1 addition & 2 deletions src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,6 @@ async function isLoggedIn(thoughtSpotHost: string): Promise<boolean> {
* Services to be called after the login is successful,
* This should be called after the cookie is set for cookie auth or
* after the token is set for cookieless.
*
* @return {Promise<void>}
* @example
* ```js
Expand All @@ -231,7 +230,7 @@ export async function postLoginService(): Promise<void> {
initMixpanel(sessionInfo);
}
} catch (e) {
logger.error('Post login services failed.', e.message);
logger.error('Post login services failed.', e.message, e);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/authToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { logger } from './utils/logger';
let cachedAuthToken: string | null = null;

// This method can be used to get the authToken using the embedConfig
/**
*
* @param embedConfig
*/
export async function getAuthenticationToken(embedConfig: EmbedConfig): Promise<string> {
// Since we don't have token validation enabled , we cannot tell if the
// cached token is valid or not. So we will always fetch a new token.
Expand Down
141 changes: 141 additions & 0 deletions src/embed/bodyless-conversation.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import 'jest-fetch-mock';
import { BodylessConversation, BodylessConversationViewConfig } from './bodyless-conversation';
import * as authInstance from '../auth';
import { init } from '../index';
import { Action, AuthType, RuntimeFilterOp } from '../types';
import {
executeAfterWait,
getDocumentBody,
getIFrameSrc,
getRootEl,
fixedEncodeURI,
defaultParamsWithoutHiddenActions as defaultParams,
expectUrlMatchesWithParams,
expectUrlToHaveParamsWithValues,
} from '../test/test-utils';

describe('BodylessConversation', () => {
const thoughtSpotHost = 'tshost';

beforeAll(() => {
init({
thoughtSpotHost,
authType: AuthType.None,
});
jest.spyOn(authInstance, 'postLoginService').mockImplementation(() => Promise.resolve({}));
spyOn(window, 'alert');
document.body.innerHTML = getDocumentBody();
});

beforeEach(() => {
fetchMock.resetMocks();
});

test('should render the bodyless conversation embed', async () => {
fetchMock.mockResponses(
JSON.stringify({
data: {
ConvAssist__createConversation: {
convId: 'conversationId',
initialCtx: {
type: 'TS_ANSWER',
tsAnsCtx: {
sessionId: 'sessionId',
genNo: 1,
stateKey: {
transactionId: 'transactionId',
generationNumber: 1,
},
worksheet: {
worksheetId: 'worksheetId',
worksheetName: 'GTM',
},
},
},
},
},
}),
JSON.stringify({
data: {
ConvAssist__sendMessage: {
responses: [
{
msgId: 'msgId',
data: {
asstRespData: {
tool: 'TS_NLS',
asstRespText: '',
nlsAnsData: {
sageQuerySuggestions: [
{
llmReasoning: {
assumptions: 'You want the total [COL|sales] for [COL|item_type] [VAL|jackets] for [VAL|this year].',
clarifications: '',
interpretation: '',
__typename: 'eureka_SageQuerySuggestion_LLMReasoning',
},
tokens: [
'sum sales',
"item type = 'jackets'",
"date = 'this year'",
],
tmlTokens: [
'sum [sales]',
"[date] = [date].'this year'",
"[item type] = [item type].'jackets'",
],
worksheetId: 'worksheetId',
description: '',
title: '',
cached: false,
sqlQuery: "SELECT SUM(sales) FROM __Sample_Retail_Apparel WHERE item_type = 'jackets' AND date = _this_year();",
sessionId: 'sessionId',
genNo: 2,
formulaInfo: [],
tmlPhrases: [],
stateKey: {
transactionId: 'transactionId',
generationNumber: 1,
__typename: 'sage_auto_complete_v2_ACStateKey',
},
__typename: 'eureka_SageQuerySuggestion',
},
],
responseType: 'ANSWER',
__typename: 'convassist_nls_tool_NLSToolAsstRespData',
},
__typename: 'convassist_AsstResponseData',
},
__typename: 'convassist_MessageData',
},
type: 'ASST_RESPONSE',
__typename: 'convassist_MessagePayload',
},
],
__typename: 'convassist_SendMessageResponse',
},
},
}),
);
const viewConfig: BodylessConversationViewConfig = {
worksheetId: 'worksheetId',
};

const conversationEmbed = new BodylessConversation(viewConfig);
const result = await conversationEmbed.sendMessage('userMessage');
console.log(result.container);
const iframeSrc = getIFrameSrc(result.container);
expectUrlToHaveParamsWithValues(iframeSrc, {
sessionId: 'sessionId',
genNo: 2,
acSessionId: 'transactionId',
acGenNo: 1,
});

fetchMock.mockRejectOnce(
new Error('error'),
);
const errorResult = await conversationEmbed.sendMessage('userMessage');
expect(errorResult.error instanceof Error).toBeTruthy();
});
});
Loading

0 comments on commit 03ba61b

Please sign in to comment.