@thoughtspot/visual-embed-sdk 1.46.4 → 1.46.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/cjs/package.json +3 -3
  2. package/cjs/src/auth.d.ts +2 -1
  3. package/cjs/src/auth.d.ts.map +1 -1
  4. package/cjs/src/auth.js +2 -1
  5. package/cjs/src/auth.js.map +1 -1
  6. package/cjs/src/authToken.d.ts.map +1 -1
  7. package/cjs/src/authToken.js.map +1 -1
  8. package/cjs/src/css-variables.d.ts +87 -17
  9. package/cjs/src/css-variables.d.ts.map +1 -1
  10. package/cjs/src/embed/app.d.ts +41 -1
  11. package/cjs/src/embed/app.d.ts.map +1 -1
  12. package/cjs/src/embed/app.js +25 -36
  13. package/cjs/src/embed/app.js.map +1 -1
  14. package/cjs/src/embed/app.spec.js +35 -23
  15. package/cjs/src/embed/app.spec.js.map +1 -1
  16. package/cjs/src/embed/base.d.ts.map +1 -1
  17. package/cjs/src/embed/base.js.map +1 -1
  18. package/cjs/src/embed/base.spec.js.map +1 -1
  19. package/cjs/src/embed/conversation.d.ts +23 -1
  20. package/cjs/src/embed/conversation.d.ts.map +1 -1
  21. package/cjs/src/embed/conversation.js +18 -33
  22. package/cjs/src/embed/conversation.js.map +1 -1
  23. package/cjs/src/embed/conversation.spec.js +129 -97
  24. package/cjs/src/embed/conversation.spec.js.map +1 -1
  25. package/cjs/src/embed/events.spec.js +72 -0
  26. package/cjs/src/embed/events.spec.js.map +1 -1
  27. package/cjs/src/embed/hostEventClient/contracts.d.ts +105 -3
  28. package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  29. package/cjs/src/embed/hostEventClient/contracts.js +9 -0
  30. package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
  31. package/cjs/src/embed/hostEventClient/host-event-client.d.ts +28 -0
  32. package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  33. package/cjs/src/embed/hostEventClient/host-event-client.js +106 -9
  34. package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
  35. package/cjs/src/embed/hostEventClient/host-event-client.spec.js +327 -6
  36. package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  37. package/cjs/src/embed/hostEventClient/utils.d.ts +22 -0
  38. package/cjs/src/embed/hostEventClient/utils.d.ts.map +1 -0
  39. package/cjs/src/embed/hostEventClient/utils.js +51 -0
  40. package/cjs/src/embed/hostEventClient/utils.js.map +1 -0
  41. package/cjs/src/embed/hostEventClient/utils.spec.d.ts +2 -0
  42. package/cjs/src/embed/hostEventClient/utils.spec.d.ts.map +1 -0
  43. package/cjs/src/embed/hostEventClient/utils.spec.js +115 -0
  44. package/cjs/src/embed/hostEventClient/utils.spec.js.map +1 -0
  45. package/cjs/src/embed/liveboard.d.ts +18 -0
  46. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  47. package/cjs/src/embed/liveboard.js +10 -3
  48. package/cjs/src/embed/liveboard.js.map +1 -1
  49. package/cjs/src/embed/liveboard.spec.js +54 -2
  50. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  51. package/cjs/src/embed/sage.d.ts.map +1 -1
  52. package/cjs/src/embed/sage.js.map +1 -1
  53. package/cjs/src/embed/search.spec.js.map +1 -1
  54. package/cjs/src/embed/spotter-utils.d.ts +20 -0
  55. package/cjs/src/embed/spotter-utils.d.ts.map +1 -0
  56. package/cjs/src/embed/spotter-utils.js +52 -0
  57. package/cjs/src/embed/spotter-utils.js.map +1 -0
  58. package/cjs/src/embed/spotter-utils.spec.d.ts +2 -0
  59. package/cjs/src/embed/spotter-utils.spec.d.ts.map +1 -0
  60. package/cjs/src/embed/spotter-utils.spec.js +54 -0
  61. package/cjs/src/embed/spotter-utils.spec.js.map +1 -0
  62. package/cjs/src/embed/ts-embed.d.ts +41 -2
  63. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  64. package/cjs/src/embed/ts-embed.js +54 -3
  65. package/cjs/src/embed/ts-embed.js.map +1 -1
  66. package/cjs/src/errors.d.ts +2 -0
  67. package/cjs/src/errors.d.ts.map +1 -1
  68. package/cjs/src/errors.js +2 -0
  69. package/cjs/src/errors.js.map +1 -1
  70. package/cjs/src/react/index.d.ts.map +1 -1
  71. package/cjs/src/react/index.js +58 -53
  72. package/cjs/src/react/index.js.map +1 -1
  73. package/cjs/src/types.d.ts +832 -33
  74. package/cjs/src/types.d.ts.map +1 -1
  75. package/cjs/src/types.js +835 -3
  76. package/cjs/src/types.js.map +1 -1
  77. package/cjs/src/utils/graphql/answerService/answerService.d.ts +4 -2
  78. package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  79. package/cjs/src/utils/graphql/answerService/answerService.js +4 -2
  80. package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
  81. package/cjs/src/utils/graphql/preview-service.d.ts.map +1 -1
  82. package/cjs/src/utils/graphql/preview-service.js.map +1 -1
  83. package/cjs/src/utils/processData.d.ts.map +1 -1
  84. package/cjs/src/utils/processData.js.map +1 -1
  85. package/cjs/src/utils.d.ts +0 -9
  86. package/cjs/src/utils.d.ts.map +1 -1
  87. package/cjs/src/utils.js +1 -10
  88. package/cjs/src/utils.js.map +1 -1
  89. package/dist/index-ChNydfIz.js +7371 -0
  90. package/dist/index-DW2wEHqy.js +7371 -0
  91. package/dist/src/auth.d.ts +2 -1
  92. package/dist/src/auth.d.ts.map +1 -1
  93. package/dist/src/authToken.d.ts.map +1 -1
  94. package/dist/src/css-variables.d.ts +87 -17
  95. package/dist/src/css-variables.d.ts.map +1 -1
  96. package/dist/src/embed/app.d.ts +41 -1
  97. package/dist/src/embed/app.d.ts.map +1 -1
  98. package/dist/src/embed/base.d.ts.map +1 -1
  99. package/dist/src/embed/conversation.d.ts +23 -1
  100. package/dist/src/embed/conversation.d.ts.map +1 -1
  101. package/dist/src/embed/hostEventClient/contracts.d.ts +105 -3
  102. package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  103. package/dist/src/embed/hostEventClient/host-event-client.d.ts +28 -0
  104. package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  105. package/dist/src/embed/hostEventClient/utils.d.ts +22 -0
  106. package/dist/src/embed/hostEventClient/utils.d.ts.map +1 -0
  107. package/dist/src/embed/hostEventClient/utils.spec.d.ts +2 -0
  108. package/dist/src/embed/hostEventClient/utils.spec.d.ts.map +1 -0
  109. package/dist/src/embed/liveboard.d.ts +18 -0
  110. package/dist/src/embed/liveboard.d.ts.map +1 -1
  111. package/dist/src/embed/sage.d.ts.map +1 -1
  112. package/dist/src/embed/spotter-utils.d.ts +20 -0
  113. package/dist/src/embed/spotter-utils.d.ts.map +1 -0
  114. package/dist/src/embed/spotter-utils.spec.d.ts +2 -0
  115. package/dist/src/embed/spotter-utils.spec.d.ts.map +1 -0
  116. package/dist/src/embed/ts-embed.d.ts +41 -2
  117. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  118. package/dist/src/errors.d.ts +2 -0
  119. package/dist/src/errors.d.ts.map +1 -1
  120. package/dist/src/react/index.d.ts.map +1 -1
  121. package/dist/src/types.d.ts +832 -33
  122. package/dist/src/types.d.ts.map +1 -1
  123. package/dist/src/utils/graphql/answerService/answerService.d.ts +4 -2
  124. package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  125. package/dist/src/utils/graphql/preview-service.d.ts.map +1 -1
  126. package/dist/src/utils/processData.d.ts.map +1 -1
  127. package/dist/src/utils.d.ts +0 -9
  128. package/dist/src/utils.d.ts.map +1 -1
  129. package/dist/tsembed-react.es.js +1208 -154
  130. package/dist/tsembed-react.js +1206 -152
  131. package/dist/tsembed.es.js +1150 -101
  132. package/dist/tsembed.js +1148 -99
  133. package/dist/visual-embed-sdk-react-full.d.ts +1156 -55
  134. package/dist/visual-embed-sdk-react.d.ts +1156 -55
  135. package/dist/visual-embed-sdk.d.ts +1179 -60
  136. package/lib/package.json +3 -3
  137. package/lib/src/auth.d.ts +2 -1
  138. package/lib/src/auth.d.ts.map +1 -1
  139. package/lib/src/auth.js +2 -1
  140. package/lib/src/auth.js.map +1 -1
  141. package/lib/src/authToken.d.ts.map +1 -1
  142. package/lib/src/authToken.js.map +1 -1
  143. package/lib/src/css-variables.d.ts +87 -17
  144. package/lib/src/css-variables.d.ts.map +1 -1
  145. package/lib/src/embed/app.d.ts +41 -1
  146. package/lib/src/embed/app.d.ts.map +1 -1
  147. package/lib/src/embed/app.js +27 -38
  148. package/lib/src/embed/app.js.map +1 -1
  149. package/lib/src/embed/app.spec.js +35 -23
  150. package/lib/src/embed/app.spec.js.map +1 -1
  151. package/lib/src/embed/base.d.ts.map +1 -1
  152. package/lib/src/embed/base.js.map +1 -1
  153. package/lib/src/embed/base.spec.js.map +1 -1
  154. package/lib/src/embed/conversation.d.ts +23 -1
  155. package/lib/src/embed/conversation.d.ts.map +1 -1
  156. package/lib/src/embed/conversation.js +19 -34
  157. package/lib/src/embed/conversation.js.map +1 -1
  158. package/lib/src/embed/conversation.spec.js +131 -99
  159. package/lib/src/embed/conversation.spec.js.map +1 -1
  160. package/lib/src/embed/events.spec.js +73 -1
  161. package/lib/src/embed/events.spec.js.map +1 -1
  162. package/lib/src/embed/hostEventClient/contracts.d.ts +105 -3
  163. package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  164. package/lib/src/embed/hostEventClient/contracts.js +9 -0
  165. package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
  166. package/lib/src/embed/hostEventClient/host-event-client.d.ts +28 -0
  167. package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  168. package/lib/src/embed/hostEventClient/host-event-client.js +106 -9
  169. package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
  170. package/lib/src/embed/hostEventClient/host-event-client.spec.js +327 -6
  171. package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  172. package/lib/src/embed/hostEventClient/utils.d.ts +22 -0
  173. package/lib/src/embed/hostEventClient/utils.d.ts.map +1 -0
  174. package/lib/src/embed/hostEventClient/utils.js +43 -0
  175. package/lib/src/embed/hostEventClient/utils.js.map +1 -0
  176. package/lib/src/embed/hostEventClient/utils.spec.d.ts +2 -0
  177. package/lib/src/embed/hostEventClient/utils.spec.d.ts.map +1 -0
  178. package/lib/src/embed/hostEventClient/utils.spec.js +113 -0
  179. package/lib/src/embed/hostEventClient/utils.spec.js.map +1 -0
  180. package/lib/src/embed/liveboard.d.ts +18 -0
  181. package/lib/src/embed/liveboard.d.ts.map +1 -1
  182. package/lib/src/embed/liveboard.js +10 -3
  183. package/lib/src/embed/liveboard.js.map +1 -1
  184. package/lib/src/embed/liveboard.spec.js +54 -2
  185. package/lib/src/embed/liveboard.spec.js.map +1 -1
  186. package/lib/src/embed/sage.d.ts.map +1 -1
  187. package/lib/src/embed/sage.js.map +1 -1
  188. package/lib/src/embed/search.spec.js.map +1 -1
  189. package/lib/src/embed/spotter-utils.d.ts +20 -0
  190. package/lib/src/embed/spotter-utils.d.ts.map +1 -0
  191. package/lib/src/embed/spotter-utils.js +47 -0
  192. package/lib/src/embed/spotter-utils.js.map +1 -0
  193. package/lib/src/embed/spotter-utils.spec.d.ts +2 -0
  194. package/lib/src/embed/spotter-utils.spec.d.ts.map +1 -0
  195. package/lib/src/embed/spotter-utils.spec.js +52 -0
  196. package/lib/src/embed/spotter-utils.spec.js.map +1 -0
  197. package/lib/src/embed/ts-embed.d.ts +41 -2
  198. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  199. package/lib/src/embed/ts-embed.js +55 -4
  200. package/lib/src/embed/ts-embed.js.map +1 -1
  201. package/lib/src/errors.d.ts +2 -0
  202. package/lib/src/errors.d.ts.map +1 -1
  203. package/lib/src/errors.js +2 -0
  204. package/lib/src/errors.js.map +1 -1
  205. package/lib/src/react/index.d.ts.map +1 -1
  206. package/lib/src/react/index.js +58 -53
  207. package/lib/src/react/index.js.map +1 -1
  208. package/lib/src/types.d.ts +832 -33
  209. package/lib/src/types.d.ts.map +1 -1
  210. package/lib/src/types.js +835 -3
  211. package/lib/src/types.js.map +1 -1
  212. package/lib/src/utils/graphql/answerService/answerService.d.ts +4 -2
  213. package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  214. package/lib/src/utils/graphql/answerService/answerService.js +4 -2
  215. package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
  216. package/lib/src/utils/graphql/preview-service.d.ts.map +1 -1
  217. package/lib/src/utils/graphql/preview-service.js.map +1 -1
  218. package/lib/src/utils/processData.d.ts.map +1 -1
  219. package/lib/src/utils/processData.js.map +1 -1
  220. package/lib/src/utils.d.ts +0 -9
  221. package/lib/src/utils.d.ts.map +1 -1
  222. package/lib/src/utils.js +0 -8
  223. package/lib/src/utils.js.map +1 -1
  224. package/lib/src/visual-embed-sdk.d.ts +1179 -60
  225. package/package.json +3 -3
  226. package/src/auth.spec.ts +1 -1
  227. package/src/auth.ts +2 -1
  228. package/src/authToken.ts +0 -1
  229. package/src/css-variables.ts +96 -17
  230. package/src/embed/app.spec.ts +48 -30
  231. package/src/embed/app.ts +59 -54
  232. package/src/embed/base.spec.ts +1 -2
  233. package/src/embed/base.ts +1 -4
  234. package/src/embed/conversation.spec.ts +150 -119
  235. package/src/embed/conversation.ts +30 -54
  236. package/src/embed/events.spec.ts +88 -0
  237. package/src/embed/hostEventClient/contracts.ts +105 -2
  238. package/src/embed/hostEventClient/host-event-client.spec.ts +504 -6
  239. package/src/embed/hostEventClient/host-event-client.ts +146 -15
  240. package/src/embed/hostEventClient/utils.spec.ts +137 -0
  241. package/src/embed/hostEventClient/utils.ts +61 -0
  242. package/src/embed/liveboard.spec.ts +71 -2
  243. package/src/embed/liveboard.ts +29 -2
  244. package/src/embed/sage.ts +0 -1
  245. package/src/embed/search.spec.ts +0 -2
  246. package/src/embed/spotter-utils.spec.ts +56 -0
  247. package/src/embed/spotter-utils.ts +65 -0
  248. package/src/embed/ts-embed.ts +58 -4
  249. package/src/errors.ts +2 -0
  250. package/src/react/index.tsx +76 -72
  251. package/src/types.ts +843 -31
  252. package/src/utils/graphql/answerService/answerService.ts +4 -5
  253. package/src/utils/graphql/preview-service.ts +0 -1
  254. package/src/utils/processData.ts +0 -5
  255. package/src/utils.ts +0 -14
@@ -125,6 +125,8 @@ describe('HostEventClient', () => {
125
125
  });
126
126
 
127
127
  describe('executeHostEvent', () => {
128
+ const mockGetAvailablePassthroughs = () => [{ value: { keys: Object.values(UIPassthroughEvent) } }];
129
+
128
130
  it('should call handleUIPassthroughForHostEvent for Pin event', async () => {
129
131
  const { client, mockIframe } = createHostEventClient();
130
132
  const hostEvent = HostEvent.Pin;
@@ -140,7 +142,9 @@ describe('HostEventClient', () => {
140
142
  },
141
143
  };
142
144
 
143
- mockProcessTrigger.mockResolvedValue([mockResponse]);
145
+ mockProcessTrigger
146
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
147
+ .mockResolvedValueOnce([mockResponse]);
144
148
 
145
149
  const result = await client.triggerHostEvent(hostEvent, payload);
146
150
 
@@ -176,7 +180,9 @@ describe('HostEventClient', () => {
176
180
  },
177
181
  refId: 'testVizId',
178
182
  }];
179
- mockProcessTrigger.mockResolvedValue(mockResponse);
183
+ mockProcessTrigger
184
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
185
+ .mockResolvedValueOnce(mockResponse);
180
186
  const result = await client.triggerHostEvent(hostEvent, payload);
181
187
 
182
188
  expect(mockProcessTrigger).toHaveBeenCalledWith(
@@ -192,6 +198,168 @@ describe('HostEventClient', () => {
192
198
  expect(result).toEqual({ answerId: 'newAnswer', ...mockResponse[0].value });
193
199
  });
194
200
 
201
+ it('should call handleHostEventWithParam for UpdateFilters event', async () => {
202
+ const { client, mockIframe } = createHostEventClient();
203
+ const hostEvent = HostEvent.UpdateFilters;
204
+ const payload: HostEventRequest<typeof hostEvent> = {
205
+ vizId: 'viz-123',
206
+ filter: {
207
+ column: 'region',
208
+ oper: 'EQ',
209
+ values: ['North'],
210
+ },
211
+ } as any;
212
+ const mockResponse = [{ value: { success: true } }];
213
+ mockProcessTrigger
214
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
215
+ .mockResolvedValueOnce(mockResponse);
216
+
217
+ const result = await client.triggerHostEvent(hostEvent, payload);
218
+
219
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
220
+ mockIframe,
221
+ HostEvent.UIPassthrough,
222
+ mockThoughtSpotHost,
223
+ {
224
+ type: UIPassthroughEvent.UpdateFilters,
225
+ parameters: payload,
226
+ },
227
+ undefined,
228
+ );
229
+ expect(result).toEqual({ success: true });
230
+ });
231
+
232
+ it('should call handleHostEventWithParam for DrillDown event', async () => {
233
+ const { client, mockIframe } = createHostEventClient();
234
+ const hostEvent = HostEvent.DrillDown;
235
+ const payload: HostEventRequest<typeof hostEvent> = {
236
+ points: { clickedPoint: 'point-1', selectedPoints: ['sel-1'] },
237
+ autoDrillDown: true,
238
+ } as any;
239
+ const mockResponse = [{ value: { drillDownApplied: true } }];
240
+ mockProcessTrigger
241
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
242
+ .mockResolvedValueOnce(mockResponse);
243
+
244
+ const result = await client.triggerHostEvent(hostEvent, payload);
245
+
246
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
247
+ mockIframe,
248
+ HostEvent.UIPassthrough,
249
+ mockThoughtSpotHost,
250
+ {
251
+ type: UIPassthroughEvent.Drilldown,
252
+ parameters: payload,
253
+ },
254
+ undefined,
255
+ );
256
+ expect(result).toEqual({ drillDownApplied: true });
257
+ });
258
+
259
+ it('should accept UpdateFilters with filters array', async () => {
260
+ const { client, mockIframe } = createHostEventClient();
261
+ const payload = {
262
+ filters: [
263
+ { column: '(Sample) Retail - Apparel::city', oper: 'IN', values: ['atlanta'] },
264
+ { column: '(Sample) Retail - Apparel::Region', oper: 'IN', values: ['West', 'Midwest'] },
265
+ ],
266
+ } as any;
267
+ const mockResponse = [{ value: { success: true } }];
268
+ mockProcessTrigger
269
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
270
+ .mockResolvedValueOnce(mockResponse);
271
+
272
+ const result = await client.triggerHostEvent(HostEvent.UpdateFilters, payload);
273
+
274
+ expect(mockProcessTrigger).toHaveBeenNthCalledWith(
275
+ 2,
276
+ mockIframe,
277
+ HostEvent.UIPassthrough,
278
+ mockThoughtSpotHost,
279
+ { type: UIPassthroughEvent.UpdateFilters, parameters: payload },
280
+ undefined,
281
+ );
282
+ expect(result).toEqual({ success: true });
283
+ });
284
+
285
+ it('should throw when UpdateFilters payload has no valid filter', async () => {
286
+ const { client } = createHostEventClient();
287
+ const invalidPayload = {} as any;
288
+ mockProcessTrigger.mockResolvedValueOnce(mockGetAvailablePassthroughs());
289
+
290
+ await expect(client.triggerHostEvent(HostEvent.UpdateFilters, invalidPayload))
291
+ .rejects.toThrow('UpdateFilters requires a valid filter or filters array');
292
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
293
+ });
294
+
295
+ it('should pass context to UpdateFilters event', async () => {
296
+ const { client, mockIframe } = createHostEventClient();
297
+ const payload = { vizId: 'viz-1', filter: { column: 'x', oper: 'EQ', values: ['a'] } } as any;
298
+ const context = { answerId: 'ans-1' } as any;
299
+ mockProcessTrigger
300
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
301
+ .mockResolvedValueOnce([{ value: {} }]);
302
+
303
+ await client.triggerHostEvent(HostEvent.UpdateFilters, payload, context);
304
+
305
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
306
+ mockIframe,
307
+ HostEvent.UIPassthrough,
308
+ mockThoughtSpotHost,
309
+ { type: UIPassthroughEvent.UpdateFilters, parameters: payload },
310
+ context,
311
+ );
312
+ });
313
+
314
+ it('should throw when DrillDown payload has no valid points', async () => {
315
+ const { client } = createHostEventClient();
316
+ const invalidPayload = {} as any;
317
+ mockProcessTrigger.mockResolvedValueOnce(mockGetAvailablePassthroughs());
318
+
319
+ await expect(client.triggerHostEvent(HostEvent.DrillDown, invalidPayload))
320
+ .rejects.toThrow('DrillDown requires a valid points object');
321
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
322
+ });
323
+
324
+ it('should pass context to DrillDown event', async () => {
325
+ const { client, mockIframe } = createHostEventClient();
326
+ const payload = { points: { clickedPoint: 'point-1' }, vizId: 'viz-2' } as any;
327
+ const context = { liveboardId: 'lb-1' } as any;
328
+ mockProcessTrigger
329
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
330
+ .mockResolvedValueOnce([{ value: {} }]);
331
+
332
+ await client.triggerHostEvent(HostEvent.DrillDown, payload, context);
333
+
334
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
335
+ mockIframe,
336
+ HostEvent.UIPassthrough,
337
+ mockThoughtSpotHost,
338
+ { type: UIPassthroughEvent.Drilldown, parameters: payload },
339
+ context,
340
+ );
341
+ });
342
+
343
+ it('should skip to fallback when passthrough is not in available keys', async () => {
344
+ const { client, mockIframe } = createHostEventClient();
345
+ mockProcessTrigger
346
+ .mockResolvedValueOnce([{ value: { keys: ['getFilters'] } }])
347
+ .mockResolvedValueOnce({ session: 'legacySession' });
348
+
349
+ const result = await client.triggerHostEvent(HostEvent.GetAnswerSession, { vizId: '123' });
350
+
351
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
352
+ expect(mockProcessTrigger).toHaveBeenNthCalledWith(
353
+ 2,
354
+ mockIframe,
355
+ HostEvent.GetAnswerSession,
356
+ mockThoughtSpotHost,
357
+ { vizId: '123' },
358
+ undefined,
359
+ );
360
+ expect(result).toEqual({ session: 'legacySession' });
361
+ });
362
+
195
363
  it('should call hostEventFallback for unmapped events', async () => {
196
364
  const { client } = createHostEventClient();
197
365
  const hostEvent = 'testEvent' as HostEvent;
@@ -205,6 +373,147 @@ describe('HostEventClient', () => {
205
373
  expect(result).toEqual(mockResponse);
206
374
  });
207
375
 
376
+ it('should route GetAnswerSession through passthrough and return data', async () => {
377
+ const { client, mockIframe } = createHostEventClient();
378
+ const mockResponse = [{ value: { session: 'testSession', embedAnswerData: { id: '1' } } }];
379
+ mockProcessTrigger
380
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
381
+ .mockResolvedValueOnce(mockResponse);
382
+
383
+ const result = await client.triggerHostEvent(HostEvent.GetAnswerSession, { vizId: '123' });
384
+
385
+ expect(mockProcessTrigger).toHaveBeenNthCalledWith(
386
+ 2,
387
+ mockIframe,
388
+ HostEvent.UIPassthrough,
389
+ mockThoughtSpotHost,
390
+ { type: UIPassthroughEvent.GetAnswerSession, parameters: { vizId: '123' } },
391
+ undefined,
392
+ );
393
+ expect(result).toEqual({ session: 'testSession', embedAnswerData: { id: '1' } });
394
+ });
395
+
396
+ it('should fall back to legacy host event when passthrough returns no data for GetAnswerSession', async () => {
397
+ const { client } = createHostEventClient();
398
+ mockProcessTrigger
399
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
400
+ .mockResolvedValueOnce([])
401
+ .mockResolvedValueOnce({ session: 'fallbackSession' });
402
+
403
+ const result = await client.triggerHostEvent(HostEvent.GetAnswerSession, { vizId: '123' });
404
+
405
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(3);
406
+ expect(mockProcessTrigger).toHaveBeenNthCalledWith(
407
+ 3,
408
+ expect.anything(),
409
+ HostEvent.GetAnswerSession,
410
+ mockThoughtSpotHost,
411
+ { vizId: '123' },
412
+ undefined,
413
+ );
414
+ expect(result).toEqual({ session: 'fallbackSession' });
415
+ });
416
+
417
+ it('should throw real errors from passthrough without falling back', async () => {
418
+ const { client } = createHostEventClient();
419
+ mockProcessTrigger
420
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
421
+ .mockResolvedValueOnce([{ error: 'Permission denied' }]);
422
+
423
+ await expect(client.triggerHostEvent(HostEvent.GetAnswerSession, {}))
424
+ .rejects.toThrow('Permission denied');
425
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
426
+ });
427
+
428
+ it('should route GetFilters through passthrough and return data', async () => {
429
+ const { client, mockIframe } = createHostEventClient();
430
+ const mockResponse = [{ value: { liveboardFilters: [{ id: 'f1' }], runtimeFilters: [] as any[] } }];
431
+ mockProcessTrigger
432
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
433
+ .mockResolvedValueOnce(mockResponse);
434
+
435
+ const result = await client.triggerHostEvent(HostEvent.GetFilters, {});
436
+
437
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
438
+ mockIframe,
439
+ HostEvent.UIPassthrough,
440
+ mockThoughtSpotHost,
441
+ { type: UIPassthroughEvent.GetFilters, parameters: {} },
442
+ undefined,
443
+ );
444
+ expect(result).toEqual({ liveboardFilters: [{ id: 'f1' }], runtimeFilters: [] });
445
+ });
446
+
447
+ it('should route GetTabs through passthrough and return data', async () => {
448
+ const { client } = createHostEventClient();
449
+ const mockResponse = [{ value: { orderedTabIds: ['t1', 't2'], numberOfTabs: 2, Tabs: [] as any[] } }];
450
+ mockProcessTrigger
451
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
452
+ .mockResolvedValueOnce(mockResponse);
453
+
454
+ const result = await client.triggerHostEvent(HostEvent.GetTabs, {});
455
+
456
+ expect(result).toEqual({ orderedTabIds: ['t1', 't2'], numberOfTabs: 2, Tabs: [] });
457
+ });
458
+
459
+ it('should route GetTML through passthrough and return data', async () => {
460
+ const { client } = createHostEventClient();
461
+ const tmlData = { answer: { search_query: 'revenue by region' } };
462
+ mockProcessTrigger
463
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
464
+ .mockResolvedValueOnce([{ value: tmlData }]);
465
+
466
+ const result = await client.triggerHostEvent(HostEvent.GetTML, {});
467
+
468
+ expect(result).toEqual(tmlData);
469
+ });
470
+
471
+ it('should route GetIframeUrl through passthrough and return data', async () => {
472
+ const { client } = createHostEventClient();
473
+ mockProcessTrigger
474
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
475
+ .mockResolvedValueOnce([{ value: { iframeUrl: 'https://ts.example.com/embed' } }]);
476
+
477
+ const result = await client.triggerHostEvent(HostEvent.GetIframeUrl, {});
478
+
479
+ expect(result).toEqual({ iframeUrl: 'https://ts.example.com/embed' });
480
+ });
481
+
482
+ it('should route GetParameters through passthrough and return data', async () => {
483
+ const { client } = createHostEventClient();
484
+ mockProcessTrigger
485
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
486
+ .mockResolvedValueOnce([{ value: { parameters: [{ name: 'p1' }] } }]);
487
+
488
+ const result = await client.triggerHostEvent(HostEvent.GetParameters, {});
489
+
490
+ expect(result).toEqual({ parameters: [{ name: 'p1' }] });
491
+ });
492
+
493
+ it('should route getExportRequestForCurrentPinboard through passthrough and return data', async () => {
494
+ const { client } = createHostEventClient();
495
+ mockProcessTrigger
496
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
497
+ .mockResolvedValueOnce([{ value: { v2Content: 'exportData' } }]);
498
+
499
+ const result = await client.triggerHostEvent(HostEvent.getExportRequestForCurrentPinboard, {});
500
+
501
+ expect(result).toEqual({ v2Content: 'exportData' });
502
+ });
503
+
504
+ it('should fall back to legacy for GetFilters when passthrough returns null', async () => {
505
+ const { client } = createHostEventClient();
506
+ mockProcessTrigger
507
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
508
+ .mockResolvedValueOnce(null)
509
+ .mockResolvedValueOnce({ liveboardFilters: [], runtimeFilters: [] });
510
+
511
+ const result = await client.triggerHostEvent(HostEvent.GetFilters, {});
512
+
513
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(3);
514
+ expect(result).toEqual({ liveboardFilters: [], runtimeFilters: [] });
515
+ });
516
+
208
517
  it('should call fallback for Pin event', async () => {
209
518
  const { client, mockIframe } = createHostEventClient();
210
519
  const hostEvent = HostEvent.Pin;
@@ -217,7 +526,9 @@ describe('HostEventClient', () => {
217
526
  },
218
527
  };
219
528
 
220
- mockProcessTrigger.mockResolvedValue([mockResponse]);
529
+ mockProcessTrigger
530
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
531
+ .mockResolvedValueOnce([mockResponse]);
221
532
 
222
533
  const result = await client.triggerHostEvent(hostEvent, payload);
223
534
 
@@ -243,7 +554,9 @@ describe('HostEventClient', () => {
243
554
  },
244
555
  };
245
556
 
246
- mockProcessTrigger.mockResolvedValue([mockResponse]);
557
+ mockProcessTrigger
558
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
559
+ .mockResolvedValueOnce([mockResponse]);
247
560
 
248
561
  const result = await client.triggerHostEvent(hostEvent, payload);
249
562
 
@@ -275,7 +588,9 @@ describe('HostEventClient', () => {
275
588
  },
276
589
  refId: 'testVizId',
277
590
  }];
278
- mockProcessTrigger.mockResolvedValue(mockResponse);
591
+ mockProcessTrigger
592
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
593
+ .mockResolvedValueOnce(mockResponse);
279
594
  const result = await client.triggerHostEvent(hostEvent, payload);
280
595
  expect(result.liveboardId).toBe('testLiveboard');
281
596
  });
@@ -297,7 +612,9 @@ describe('HostEventClient', () => {
297
612
  },
298
613
  refId: 'testVizId',
299
614
  }];
300
- mockProcessTrigger.mockResolvedValue(mockResponse);
615
+ mockProcessTrigger
616
+ .mockResolvedValueOnce(mockGetAvailablePassthroughs())
617
+ .mockResolvedValueOnce(mockResponse);
301
618
  const result = await client.triggerHostEvent(hostEvent, payload);
302
619
  expect(result.liveboardId).toBe('testLiveboard');
303
620
  expect(mockProcessTrigger).toHaveBeenCalledWith(
@@ -318,4 +635,185 @@ describe('HostEventClient', () => {
318
635
  });
319
636
  });
320
637
  });
638
+
639
+ describe('getDataWithPassthroughFallback', () => {
640
+ const callMethod = (client: HostEventClient, ...args: any[]) => (client as any).getDataWithPassthroughFallback(...args);
641
+
642
+ it('should return unwrapped value when passthrough succeeds', async () => {
643
+ const { client } = createHostEventClient();
644
+ mockProcessTrigger.mockResolvedValue([{ value: { session: 's1', embedAnswerData: { id: 'a1' } } }]);
645
+
646
+ const result = await callMethod(
647
+ client, UIPassthroughEvent.GetAnswerSession, HostEvent.GetAnswerSession, { vizId: '1' },
648
+ );
649
+
650
+ expect(result).toEqual({ session: 's1', embedAnswerData: { id: 'a1' } });
651
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
652
+ });
653
+
654
+ it('should fall back to legacy when passthrough returns empty array', async () => {
655
+ const { client } = createHostEventClient();
656
+ const legacyResponse = { session: 'legacy' };
657
+ mockProcessTrigger
658
+ .mockResolvedValueOnce([])
659
+ .mockResolvedValueOnce(legacyResponse);
660
+
661
+ const result = await callMethod(
662
+ client, UIPassthroughEvent.GetAnswerSession, HostEvent.GetAnswerSession, { vizId: '1' },
663
+ );
664
+
665
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
666
+ expect(result).toEqual(legacyResponse);
667
+ });
668
+
669
+ it('should fall back to legacy when passthrough returns null', async () => {
670
+ const { client } = createHostEventClient();
671
+ const legacyResponse = { parameters: [] as any[] };
672
+ mockProcessTrigger
673
+ .mockResolvedValueOnce(null)
674
+ .mockResolvedValueOnce(legacyResponse);
675
+
676
+ const result = await callMethod(
677
+ client, UIPassthroughEvent.GetParameters, HostEvent.GetParameters, {},
678
+ );
679
+
680
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
681
+ expect(result).toEqual(legacyResponse);
682
+ });
683
+
684
+ it('should fall back to legacy when passthrough returns undefined', async () => {
685
+ const { client } = createHostEventClient();
686
+ const legacyResponse = { iframeUrl: 'https://ts.example.com' };
687
+ mockProcessTrigger
688
+ .mockResolvedValueOnce(undefined)
689
+ .mockResolvedValueOnce(legacyResponse);
690
+
691
+ const result = await callMethod(
692
+ client, UIPassthroughEvent.GetIframeUrl, HostEvent.GetIframeUrl, {},
693
+ );
694
+
695
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
696
+ expect(result).toEqual(legacyResponse);
697
+ });
698
+
699
+ it('should fall back when response array has no matching entries', async () => {
700
+ const { client } = createHostEventClient();
701
+ const legacyResponse = { v2Content: 'data' };
702
+ mockProcessTrigger
703
+ .mockResolvedValueOnce([{ refId: 'r1' }])
704
+ .mockResolvedValueOnce(legacyResponse);
705
+
706
+ const result = await callMethod(
707
+ client, UIPassthroughEvent.GetExportRequestForCurrentPinboard,
708
+ HostEvent.getExportRequestForCurrentPinboard, {},
709
+ );
710
+
711
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
712
+ expect(result).toEqual(legacyResponse);
713
+ });
714
+
715
+ it('should throw when response has error field', async () => {
716
+ const { client } = createHostEventClient();
717
+ mockProcessTrigger.mockResolvedValue([{ error: 'Permission denied' }]);
718
+
719
+ await expect(callMethod(
720
+ client, UIPassthroughEvent.GetFilters, HostEvent.GetFilters, {},
721
+ )).rejects.toThrow('Permission denied');
722
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
723
+ });
724
+
725
+ it('should throw when response value contains errors field', async () => {
726
+ const { client } = createHostEventClient();
727
+ mockProcessTrigger.mockResolvedValue([{ value: { errors: 'Invalid vizId' } }]);
728
+
729
+ await expect(callMethod(
730
+ client, UIPassthroughEvent.GetTML, HostEvent.GetTML, { vizId: 'bad' },
731
+ )).rejects.toThrow('Invalid vizId');
732
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
733
+ });
734
+
735
+ it('should throw when response value contains error field', async () => {
736
+ const { client } = createHostEventClient();
737
+ mockProcessTrigger.mockResolvedValue([{ value: { error: 'Not found' } }]);
738
+
739
+ await expect(callMethod(
740
+ client, UIPassthroughEvent.GetTabs, HostEvent.GetTabs, {},
741
+ )).rejects.toThrow('Not found');
742
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
743
+ });
744
+
745
+ it('should stringify object errors instead of producing [object Object]', async () => {
746
+ const { client } = createHostEventClient();
747
+ const errorObj = { code: 403, reason: 'Forbidden' };
748
+ mockProcessTrigger.mockResolvedValue([{ error: errorObj }]);
749
+
750
+ await expect(callMethod(
751
+ client, UIPassthroughEvent.GetFilters, HostEvent.GetFilters, {},
752
+ )).rejects.toThrow(JSON.stringify(errorObj));
753
+ expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
754
+ });
755
+
756
+ it('should default payload to empty object when null', async () => {
757
+ const { client, mockIframe } = createHostEventClient();
758
+ mockProcessTrigger.mockResolvedValue([{ value: { iframeUrl: 'https://ts.example.com' } }]);
759
+
760
+ await callMethod(
761
+ client, UIPassthroughEvent.GetIframeUrl, HostEvent.GetIframeUrl, null,
762
+ );
763
+
764
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
765
+ mockIframe,
766
+ HostEvent.UIPassthrough,
767
+ mockThoughtSpotHost,
768
+ { type: UIPassthroughEvent.GetIframeUrl, parameters: {} },
769
+ undefined,
770
+ );
771
+ });
772
+ });
773
+
774
+ describe('UI passthrough available keys tests', () => {
775
+ const mockKeys = () => [{ value: { keys: Object.values(UIPassthroughEvent) } }];
776
+
777
+ it('triggerHostEvent Pin returns passthrough response', async () => {
778
+ const { client } = createHostEventClient();
779
+ mockProcessTrigger
780
+ .mockResolvedValueOnce(mockKeys())
781
+ .mockResolvedValueOnce([{ value: { pinboardId: 'lb1', tabId: 't1', vizId: 'v1' } }]);
782
+
783
+ const result = await client.triggerHostEvent(HostEvent.Pin, { newVizName: 'Viz' });
784
+
785
+ expect(result).toMatchObject({ pinboardId: 'lb1', liveboardId: 'lb1' });
786
+ });
787
+
788
+ it('triggerHostEvent GetAnswerSession returns session', async () => {
789
+ const { client } = createHostEventClient();
790
+ mockProcessTrigger
791
+ .mockResolvedValueOnce(mockKeys())
792
+ .mockResolvedValueOnce([{ value: { session: 's1' } }]);
793
+
794
+ const result = await client.triggerHostEvent(HostEvent.GetAnswerSession, {});
795
+
796
+ expect(result).toEqual({ session: 's1' });
797
+ });
798
+
799
+ it('triggerHostEvent unmapped event uses fallback', async () => {
800
+ const { client } = createHostEventClient();
801
+ mockProcessTrigger.mockResolvedValue({ data: 'legacy' });
802
+
803
+ const result = await client.triggerHostEvent('unknownEvent' as HostEvent, {});
804
+
805
+ expect(mockProcessTrigger).toHaveBeenCalledWith(expect.anything(), 'unknownEvent', mockThoughtSpotHost, {}, undefined);
806
+ expect(result).toEqual({ data: 'legacy' });
807
+ });
808
+
809
+ it('hostEventFallback delegates to processTrigger', async () => {
810
+ const { client, mockIframe } = createHostEventClient();
811
+ mockProcessTrigger.mockResolvedValue({ ok: true });
812
+
813
+ const result = await client.hostEventFallback(HostEvent.Save, { x: 1 });
814
+
815
+ expect(mockProcessTrigger).toHaveBeenCalledWith(mockIframe, HostEvent.Save, mockThoughtSpotHost, { x: 1 }, undefined);
816
+ expect(result).toEqual({ ok: true });
817
+ });
818
+ });
321
819
  });