@thoughtspot/visual-embed-sdk 1.49.3 → 1.50.1

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 (241) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/authToken.spec.js +5 -0
  3. package/cjs/src/authToken.spec.js.map +1 -1
  4. package/cjs/src/css-variables.d.ts +59 -0
  5. package/cjs/src/css-variables.d.ts.map +1 -1
  6. package/cjs/src/embed/app.d.ts +31 -2
  7. package/cjs/src/embed/app.d.ts.map +1 -1
  8. package/cjs/src/embed/app.js +19 -2
  9. package/cjs/src/embed/app.js.map +1 -1
  10. package/cjs/src/embed/app.spec.js +112 -2
  11. package/cjs/src/embed/app.spec.js.map +1 -1
  12. package/cjs/src/embed/conversation.d.ts +38 -0
  13. package/cjs/src/embed/conversation.d.ts.map +1 -1
  14. package/cjs/src/embed/conversation.js +12 -2
  15. package/cjs/src/embed/conversation.js.map +1 -1
  16. package/cjs/src/embed/conversation.spec.js +53 -0
  17. package/cjs/src/embed/conversation.spec.js.map +1 -1
  18. package/cjs/src/embed/embedConfig.spec.d.ts +2 -0
  19. package/cjs/src/embed/embedConfig.spec.d.ts.map +1 -0
  20. package/cjs/src/embed/embedConfig.spec.js +74 -0
  21. package/cjs/src/embed/embedConfig.spec.js.map +1 -0
  22. package/cjs/src/embed/events.spec.js +593 -0
  23. package/cjs/src/embed/events.spec.js.map +1 -1
  24. package/cjs/src/embed/host-events.spec.d.ts +2 -0
  25. package/cjs/src/embed/host-events.spec.d.ts.map +1 -0
  26. package/cjs/src/embed/host-events.spec.js +1325 -0
  27. package/cjs/src/embed/host-events.spec.js.map +1 -0
  28. package/cjs/src/embed/hostEventClient/contracts.d.ts +36 -14
  29. package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  30. package/cjs/src/embed/hostEventClient/contracts.js +10 -1
  31. package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
  32. package/cjs/src/embed/hostEventClient/host-event-client.d.ts +1 -0
  33. package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  34. package/cjs/src/embed/hostEventClient/host-event-client.js +8 -0
  35. package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
  36. package/cjs/src/embed/hostEventClient/host-event-client.spec.js +209 -0
  37. package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  38. package/cjs/src/embed/hostEventClient/utils.d.ts +2 -0
  39. package/cjs/src/embed/hostEventClient/utils.d.ts.map +1 -1
  40. package/cjs/src/embed/hostEventClient/utils.js +32 -2
  41. package/cjs/src/embed/hostEventClient/utils.js.map +1 -1
  42. package/cjs/src/embed/hostEventClient/utils.spec.js +178 -0
  43. package/cjs/src/embed/hostEventClient/utils.spec.js.map +1 -1
  44. package/cjs/src/embed/liveboard.d.ts +6 -0
  45. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  46. package/cjs/src/embed/liveboard.js.map +1 -1
  47. package/cjs/src/embed/spotter-viz-utils.d.ts +34 -0
  48. package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -1
  49. package/cjs/src/embed/spotter-viz-utils.js.map +1 -1
  50. package/cjs/src/embed/spotter-viz-utils.spec.js +17 -0
  51. package/cjs/src/embed/spotter-viz-utils.spec.js.map +1 -1
  52. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  53. package/cjs/src/embed/ts-embed.js +14 -7
  54. package/cjs/src/embed/ts-embed.js.map +1 -1
  55. package/cjs/src/embed/ts-embed.spec.js +146 -0
  56. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  57. package/cjs/src/errors.d.ts +1 -0
  58. package/cjs/src/errors.d.ts.map +1 -1
  59. package/cjs/src/errors.js +1 -0
  60. package/cjs/src/errors.js.map +1 -1
  61. package/cjs/src/index.d.ts +2 -2
  62. package/cjs/src/index.d.ts.map +1 -1
  63. package/cjs/src/index.js +3 -2
  64. package/cjs/src/index.js.map +1 -1
  65. package/cjs/src/mixpanel-service.spec.js +14 -0
  66. package/cjs/src/mixpanel-service.spec.js.map +1 -1
  67. package/cjs/src/react/util.spec.js +251 -0
  68. package/cjs/src/react/util.spec.js.map +1 -1
  69. package/cjs/src/types.d.ts +212 -8
  70. package/cjs/src/types.d.ts.map +1 -1
  71. package/cjs/src/types.js +185 -3
  72. package/cjs/src/types.js.map +1 -1
  73. package/cjs/src/utils/custom-actions.spec.js +26 -0
  74. package/cjs/src/utils/custom-actions.spec.js.map +1 -1
  75. package/cjs/src/utils/processData.spec.js +123 -0
  76. package/cjs/src/utils/processData.spec.js.map +1 -1
  77. package/cjs/src/utils/processTrigger.spec.js +61 -0
  78. package/cjs/src/utils/processTrigger.spec.js.map +1 -1
  79. package/cjs/src/utils/reporting.spec.js +21 -0
  80. package/cjs/src/utils/reporting.spec.js.map +1 -1
  81. package/cjs/src/utils/sessionInfoService.spec.d.ts +2 -0
  82. package/cjs/src/utils/sessionInfoService.spec.d.ts.map +1 -0
  83. package/cjs/src/utils/sessionInfoService.spec.js +130 -0
  84. package/cjs/src/utils/sessionInfoService.spec.js.map +1 -0
  85. package/cjs/src/utils.spec.js +158 -0
  86. package/cjs/src/utils.spec.js.map +1 -1
  87. package/dist/{index-DsSQndIB.js → index-fCne7kmU.js} +1 -1
  88. package/dist/src/css-variables.d.ts +59 -0
  89. package/dist/src/css-variables.d.ts.map +1 -1
  90. package/dist/src/embed/app.d.ts +31 -2
  91. package/dist/src/embed/app.d.ts.map +1 -1
  92. package/dist/src/embed/conversation.d.ts +38 -0
  93. package/dist/src/embed/conversation.d.ts.map +1 -1
  94. package/dist/src/embed/embedConfig.spec.d.ts +2 -0
  95. package/dist/src/embed/embedConfig.spec.d.ts.map +1 -0
  96. package/dist/src/embed/host-events.spec.d.ts +2 -0
  97. package/dist/src/embed/host-events.spec.d.ts.map +1 -0
  98. package/dist/src/embed/hostEventClient/contracts.d.ts +36 -14
  99. package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  100. package/dist/src/embed/hostEventClient/host-event-client.d.ts +1 -0
  101. package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  102. package/dist/src/embed/hostEventClient/utils.d.ts +2 -0
  103. package/dist/src/embed/hostEventClient/utils.d.ts.map +1 -1
  104. package/dist/src/embed/liveboard.d.ts +6 -0
  105. package/dist/src/embed/liveboard.d.ts.map +1 -1
  106. package/dist/src/embed/spotter-viz-utils.d.ts +34 -0
  107. package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -1
  108. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  109. package/dist/src/errors.d.ts +1 -0
  110. package/dist/src/errors.d.ts.map +1 -1
  111. package/dist/src/index.d.ts +2 -2
  112. package/dist/src/index.d.ts.map +1 -1
  113. package/dist/src/types.d.ts +212 -8
  114. package/dist/src/types.d.ts.map +1 -1
  115. package/dist/src/utils/sessionInfoService.spec.d.ts +2 -0
  116. package/dist/src/utils/sessionInfoService.spec.d.ts.map +1 -0
  117. package/dist/tsembed-react.es.js +482 -86
  118. package/dist/tsembed-react.js +481 -85
  119. package/dist/tsembed.es.js +483 -87
  120. package/dist/tsembed.js +481 -85
  121. package/dist/visual-embed-sdk-react-full.d.ts +407 -23
  122. package/dist/visual-embed-sdk-react.d.ts +407 -23
  123. package/dist/visual-embed-sdk.d.ts +411 -23
  124. package/lib/package.json +1 -1
  125. package/lib/src/authToken.spec.js +5 -0
  126. package/lib/src/authToken.spec.js.map +1 -1
  127. package/lib/src/css-variables.d.ts +59 -0
  128. package/lib/src/css-variables.d.ts.map +1 -1
  129. package/lib/src/embed/app.d.ts +31 -2
  130. package/lib/src/embed/app.d.ts.map +1 -1
  131. package/lib/src/embed/app.js +19 -2
  132. package/lib/src/embed/app.js.map +1 -1
  133. package/lib/src/embed/app.spec.js +112 -2
  134. package/lib/src/embed/app.spec.js.map +1 -1
  135. package/lib/src/embed/conversation.d.ts +38 -0
  136. package/lib/src/embed/conversation.d.ts.map +1 -1
  137. package/lib/src/embed/conversation.js +11 -1
  138. package/lib/src/embed/conversation.js.map +1 -1
  139. package/lib/src/embed/conversation.spec.js +54 -1
  140. package/lib/src/embed/conversation.spec.js.map +1 -1
  141. package/lib/src/embed/embedConfig.spec.d.ts +2 -0
  142. package/lib/src/embed/embedConfig.spec.d.ts.map +1 -0
  143. package/lib/src/embed/embedConfig.spec.js +72 -0
  144. package/lib/src/embed/embedConfig.spec.js.map +1 -0
  145. package/lib/src/embed/events.spec.js +593 -0
  146. package/lib/src/embed/events.spec.js.map +1 -1
  147. package/lib/src/embed/host-events.spec.d.ts +2 -0
  148. package/lib/src/embed/host-events.spec.d.ts.map +1 -0
  149. package/lib/src/embed/host-events.spec.js +1322 -0
  150. package/lib/src/embed/host-events.spec.js.map +1 -0
  151. package/lib/src/embed/hostEventClient/contracts.d.ts +36 -14
  152. package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  153. package/lib/src/embed/hostEventClient/contracts.js +9 -0
  154. package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
  155. package/lib/src/embed/hostEventClient/host-event-client.d.ts +1 -0
  156. package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  157. package/lib/src/embed/hostEventClient/host-event-client.js +9 -1
  158. package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
  159. package/lib/src/embed/hostEventClient/host-event-client.spec.js +209 -0
  160. package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  161. package/lib/src/embed/hostEventClient/utils.d.ts +2 -0
  162. package/lib/src/embed/hostEventClient/utils.d.ts.map +1 -1
  163. package/lib/src/embed/hostEventClient/utils.js +28 -1
  164. package/lib/src/embed/hostEventClient/utils.js.map +1 -1
  165. package/lib/src/embed/hostEventClient/utils.spec.js +179 -1
  166. package/lib/src/embed/hostEventClient/utils.spec.js.map +1 -1
  167. package/lib/src/embed/liveboard.d.ts +6 -0
  168. package/lib/src/embed/liveboard.d.ts.map +1 -1
  169. package/lib/src/embed/liveboard.js.map +1 -1
  170. package/lib/src/embed/spotter-viz-utils.d.ts +34 -0
  171. package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -1
  172. package/lib/src/embed/spotter-viz-utils.js.map +1 -1
  173. package/lib/src/embed/spotter-viz-utils.spec.js +17 -0
  174. package/lib/src/embed/spotter-viz-utils.spec.js.map +1 -1
  175. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  176. package/lib/src/embed/ts-embed.js +14 -7
  177. package/lib/src/embed/ts-embed.js.map +1 -1
  178. package/lib/src/embed/ts-embed.spec.js +146 -0
  179. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  180. package/lib/src/errors.d.ts +1 -0
  181. package/lib/src/errors.d.ts.map +1 -1
  182. package/lib/src/errors.js +1 -0
  183. package/lib/src/errors.js.map +1 -1
  184. package/lib/src/index.d.ts +2 -2
  185. package/lib/src/index.d.ts.map +1 -1
  186. package/lib/src/index.js +2 -2
  187. package/lib/src/index.js.map +1 -1
  188. package/lib/src/mixpanel-service.spec.js +14 -0
  189. package/lib/src/mixpanel-service.spec.js.map +1 -1
  190. package/lib/src/react/util.spec.js +251 -0
  191. package/lib/src/react/util.spec.js.map +1 -1
  192. package/lib/src/types.d.ts +212 -8
  193. package/lib/src/types.d.ts.map +1 -1
  194. package/lib/src/types.js +185 -3
  195. package/lib/src/types.js.map +1 -1
  196. package/lib/src/utils/custom-actions.spec.js +26 -0
  197. package/lib/src/utils/custom-actions.spec.js.map +1 -1
  198. package/lib/src/utils/processData.spec.js +123 -0
  199. package/lib/src/utils/processData.spec.js.map +1 -1
  200. package/lib/src/utils/processTrigger.spec.js +61 -0
  201. package/lib/src/utils/processTrigger.spec.js.map +1 -1
  202. package/lib/src/utils/reporting.spec.js +21 -0
  203. package/lib/src/utils/reporting.spec.js.map +1 -1
  204. package/lib/src/utils/sessionInfoService.spec.d.ts +2 -0
  205. package/lib/src/utils/sessionInfoService.spec.d.ts.map +1 -0
  206. package/lib/src/utils/sessionInfoService.spec.js +127 -0
  207. package/lib/src/utils/sessionInfoService.spec.js.map +1 -0
  208. package/lib/src/utils.spec.js +159 -1
  209. package/lib/src/utils.spec.js.map +1 -1
  210. package/lib/src/visual-embed-sdk.d.ts +411 -23
  211. package/package.json +1 -1
  212. package/src/authToken.spec.ts +6 -0
  213. package/src/css-variables.ts +73 -0
  214. package/src/embed/app.spec.ts +155 -2
  215. package/src/embed/app.ts +44 -2
  216. package/src/embed/conversation.spec.ts +64 -1
  217. package/src/embed/conversation.ts +41 -0
  218. package/src/embed/embedConfig.spec.ts +79 -0
  219. package/src/embed/events.spec.ts +705 -1
  220. package/src/embed/host-events.spec.ts +1759 -0
  221. package/src/embed/hostEventClient/contracts.ts +41 -14
  222. package/src/embed/hostEventClient/host-event-client.spec.ts +326 -0
  223. package/src/embed/hostEventClient/host-event-client.ts +15 -0
  224. package/src/embed/hostEventClient/utils.spec.ts +204 -0
  225. package/src/embed/hostEventClient/utils.ts +37 -10
  226. package/src/embed/liveboard.ts +6 -0
  227. package/src/embed/spotter-viz-utils.spec.ts +17 -0
  228. package/src/embed/spotter-viz-utils.ts +34 -0
  229. package/src/embed/ts-embed.spec.ts +186 -0
  230. package/src/embed/ts-embed.ts +12 -4
  231. package/src/errors.ts +1 -0
  232. package/src/index.ts +2 -1
  233. package/src/mixpanel-service.spec.ts +15 -0
  234. package/src/react/util.spec.tsx +255 -0
  235. package/src/types.ts +215 -6
  236. package/src/utils/custom-actions.spec.ts +28 -0
  237. package/src/utils/processData.spec.ts +129 -0
  238. package/src/utils/processTrigger.spec.ts +91 -0
  239. package/src/utils/reporting.spec.ts +27 -0
  240. package/src/utils/sessionInfoService.spec.ts +151 -0
  241. package/src/utils.spec.ts +195 -0
@@ -64,6 +64,24 @@ describe('test communication between host app and ThoughtSpot', () => {
64
64
  });
65
65
  });
66
66
 
67
+ test('should capture SpotterResponseComplete event from ThoughtSpot app', (done) => {
68
+ const appEmbed = new AppEmbed(getRootEl(), defaultViewConfig);
69
+ appEmbed
70
+ .on(EmbedEvent.SpotterResponseComplete, (data) => {
71
+ expect(data.data).toEqual({ convId: 'c1', messageId: 'm1' });
72
+ done();
73
+ })
74
+ .render();
75
+
76
+ executeAfterWait(() => {
77
+ const iframe = getIFrameEl();
78
+ postMessageToParent(iframe.contentWindow, {
79
+ type: EmbedEvent.SpotterResponseComplete,
80
+ data: { convId: 'c1', messageId: 'm1' },
81
+ });
82
+ });
83
+ });
84
+
67
85
  // TODO: enable test once we are actually able to load stuff in the iframe
68
86
  xtest('should trigger iframe load event', async () => {
69
87
  const onLoadSpy = jest.fn();
@@ -324,6 +342,42 @@ describe('test communication between host app and ThoughtSpot', () => {
324
342
  }, EVENT_WAIT_TIME);
325
343
  });
326
344
 
345
+ test('should fire QueryChanged handler when {type:queryChanged} postMessage arrives from iframe', async () => {
346
+ const handler = jest.fn();
347
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
348
+ searchEmbed.on(EmbedEvent.QueryChanged, handler).render();
349
+
350
+ await executeAfterWait(() => {
351
+ const iframe = getIFrameEl();
352
+ postMessageToParent(iframe.contentWindow, {
353
+ type: EmbedEvent.QueryChanged,
354
+ data: PAYLOAD,
355
+ });
356
+ });
357
+
358
+ await executeAfterWait(() => {
359
+ expect(handler).toHaveBeenCalled();
360
+ expect(handler.mock.calls[0][0].data).toBe(PAYLOAD);
361
+ }, EVENT_WAIT_TIME);
362
+ });
363
+
364
+ test('should not fire QueryChanged handler for postMessage from non-iframe source', async () => {
365
+ const handler = jest.fn();
366
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
367
+ searchEmbed.on(EmbedEvent.QueryChanged, handler).render();
368
+
369
+ await executeAfterWait(() => {
370
+ postMessageToParent(window, {
371
+ type: EmbedEvent.QueryChanged,
372
+ data: PAYLOAD,
373
+ });
374
+ });
375
+
376
+ await executeAfterWait(() => {
377
+ expect(handler).not.toHaveBeenCalled();
378
+ }, EVENT_WAIT_TIME);
379
+ });
380
+
327
381
  test('ALL event listener should fire for all events with the event type set correctly', async () => {
328
382
  const embed = new AppEmbed(getRootEl(), defaultViewConfig);
329
383
  const spy = jest.fn();
@@ -376,8 +430,658 @@ describe('Americanized enum alias values', () => {
376
430
  });
377
431
 
378
432
  describe('Action enum values', () => {
379
-
433
+
380
434
  test('RemoveFromFavorites should resolve to its string value', () => {
381
435
  expect(Action.RemoveFromFavorites).toBe('removeFromFavorites');
382
436
  });
383
437
  });
438
+
439
+ describe('EmbedEvent basic routing', () => {
440
+ beforeEach(() => {
441
+ document.body.innerHTML = getDocumentBody();
442
+ });
443
+
444
+ const UNCOVERED_EVENTS: Array<[string, EmbedEvent]> = [
445
+ ['Drilldown', EmbedEvent.Drilldown],
446
+ ['DataSourceSelected', EmbedEvent.DataSourceSelected],
447
+ ['AddRemoveColumns', EmbedEvent.AddRemoveColumns],
448
+ ['VizPointDoubleClick', EmbedEvent.VizPointDoubleClick],
449
+ ['VizPointClick', EmbedEvent.VizPointClick],
450
+ ['Alert', EmbedEvent.Alert],
451
+ ['GetDataClick', EmbedEvent.GetDataClick],
452
+ ['DialogClose', EmbedEvent.DialogClose],
453
+ ['Download', EmbedEvent.Download],
454
+ ['DownloadAsPng', EmbedEvent.DownloadAsPng],
455
+ ['DownloadAsPdf', EmbedEvent.DownloadAsPdf],
456
+ ['DownloadAsCsv', EmbedEvent.DownloadAsCsv],
457
+ ['DownloadAsXlsx', EmbedEvent.DownloadAsXlsx],
458
+ ['DownloadLiveboardAsContinuousPDF', EmbedEvent.DownloadLiveboardAsContinuousPDF],
459
+ ['AnswerDelete', EmbedEvent.AnswerDelete],
460
+ ['AIHighlights', EmbedEvent.AIHighlights],
461
+ ['Pin', EmbedEvent.Pin],
462
+ ['SpotIQAnalyze', EmbedEvent.SpotIQAnalyze],
463
+ ['Share', EmbedEvent.Share],
464
+ ['DrillInclude', EmbedEvent.DrillInclude],
465
+ ['DrillExclude', EmbedEvent.DrillExclude],
466
+ ['CopyToClipboard', EmbedEvent.CopyToClipboard],
467
+ ['UpdateTML', EmbedEvent.UpdateTML],
468
+ ['EditTML', EmbedEvent.EditTML],
469
+ ['ExportTML', EmbedEvent.ExportTML],
470
+ ['SaveAsView', EmbedEvent.SaveAsView],
471
+ ['CopyAEdit', EmbedEvent.CopyAEdit],
472
+ ['ShowUnderlyingData', EmbedEvent.ShowUnderlyingData],
473
+ ['AnswerChartSwitcher', EmbedEvent.AnswerChartSwitcher],
474
+ ['LiveboardInfo', EmbedEvent.LiveboardInfo],
475
+ ['AddToFavorites', EmbedEvent.AddToFavorites],
476
+ ['Schedule', EmbedEvent.Schedule],
477
+ ['Edit', EmbedEvent.Edit],
478
+ ['MakeACopy', EmbedEvent.MakeACopy],
479
+ ['Present', EmbedEvent.Present],
480
+ ['Delete', EmbedEvent.Delete],
481
+ ['SchedulesList', EmbedEvent.SchedulesList],
482
+ ['Cancel', EmbedEvent.Cancel],
483
+ ['Explore', EmbedEvent.Explore],
484
+ ['CopyLink', EmbedEvent.CopyLink],
485
+ ['CrossFilterChanged', EmbedEvent.CrossFilterChanged],
486
+ ['VizPointRightClick', EmbedEvent.VizPointRightClick],
487
+ ['InsertIntoSlide', EmbedEvent.InsertIntoSlide],
488
+ ['FilterChanged', EmbedEvent.FilterChanged],
489
+ ['UpdateConnection', EmbedEvent.UpdateConnection],
490
+ ['CreateConnection', EmbedEvent.CreateConnection],
491
+ ['ResetLiveboard', EmbedEvent.ResetLiveboard],
492
+ ['ChangePersonalizedView', EmbedEvent.ChangePersonalizedView],
493
+ ['CreateWorksheet', EmbedEvent.CreateWorksheet],
494
+ ['AskSageInit', EmbedEvent.AskSageInit],
495
+ ['Rename', EmbedEvent.Rename],
496
+ ['ParameterChanged', EmbedEvent.ParameterChanged],
497
+ ['TableVizRendered', EmbedEvent.TableVizRendered],
498
+ ['CreateLiveboard', EmbedEvent.CreateLiveboard],
499
+ ['CreateModel', EmbedEvent.CreateModel],
500
+ ['SpotterData', EmbedEvent.SpotterData],
501
+ ['PreviewSpotterData', EmbedEvent.PreviewSpotterData],
502
+ ['AddToCoaching', EmbedEvent.AddToCoaching],
503
+ ['DataModelInstructions', EmbedEvent.DataModelInstructions],
504
+ ['SpotterQueryTriggered', EmbedEvent.SpotterQueryTriggered],
505
+ ['LastPromptEdited', EmbedEvent.LastPromptEdited],
506
+ ['LastPromptDeleted', EmbedEvent.LastPromptDeleted],
507
+ ['ResetSpotterConversation', EmbedEvent.ResetSpotterConversation],
508
+ ['SpotterInit', EmbedEvent.SpotterInit],
509
+ ['SpotterLoadComplete', EmbedEvent.SpotterLoadComplete],
510
+ ['OrgSwitched', EmbedEvent.OrgSwitched],
511
+ ['SpotterConversationRenamed', EmbedEvent.SpotterConversationRenamed],
512
+ ['SpotterConversationDeleted', EmbedEvent.SpotterConversationDeleted],
513
+ ['SpotterConversationSelected', EmbedEvent.SpotterConversationSelected],
514
+ ['EmbedPageContextChanged', EmbedEvent.EmbedPageContextChanged],
515
+ ['Subscribed', EmbedEvent.Subscribed],
516
+ ['SendTestScheduleEmail', EmbedEvent.SendTestScheduleEmail],
517
+ ['SpotterVizInit', EmbedEvent.SpotterVizInit],
518
+ ['SpotterVizQueryTriggered', EmbedEvent.SpotterVizQueryTriggered],
519
+ ['SpotterVizResponseComplete', EmbedEvent.SpotterVizResponseComplete],
520
+ ['SpotterVizCheckpointCreated', EmbedEvent.SpotterVizCheckpointCreated],
521
+ ['SpotterVizCheckpointRestored', EmbedEvent.SpotterVizCheckpointRestored],
522
+ ['SpotterVizError', EmbedEvent.SpotterVizError],
523
+ ['SpotterVizClosed', EmbedEvent.SpotterVizClosed],
524
+ ['RefreshLiveboardBrowserCache', EmbedEvent.RefreshLiveboardBrowserCache],
525
+ ['V1Data', EmbedEvent.V1Data],
526
+ ];
527
+
528
+ test.each(UNCOVERED_EVENTS)(
529
+ '%s handler fires on iframe postMessage',
530
+ async (eventName, embedEvent) => {
531
+ const handler = jest.fn();
532
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
533
+ searchEmbed.on(embedEvent, handler).render();
534
+
535
+ await executeAfterWait(() => {
536
+ const iframe = getIFrameEl();
537
+ postMessageToParent(iframe.contentWindow, {
538
+ type: embedEvent,
539
+ data: PAYLOAD,
540
+ });
541
+ });
542
+
543
+ await executeAfterWait(() => {
544
+ expect(handler).toHaveBeenCalled();
545
+ expect(handler.mock.calls[0][0].data).toBe(PAYLOAD);
546
+ }, EVENT_WAIT_TIME);
547
+ },
548
+ );
549
+ });
550
+
551
+ describe('EmbedEvent start/end status', () => {
552
+ beforeEach(() => {
553
+ document.body.innerHTML = getDocumentBody();
554
+ });
555
+
556
+ const START_END_EVENTS: Array<[string, EmbedEvent]> = [
557
+ ['DownloadAsPng', EmbedEvent.DownloadAsPng],
558
+ ['DownloadAsPdf', EmbedEvent.DownloadAsPdf],
559
+ ['DownloadAsCsv', EmbedEvent.DownloadAsCsv],
560
+ ['DownloadAsXlsx', EmbedEvent.DownloadAsXlsx],
561
+ ['AnswerDelete', EmbedEvent.AnswerDelete],
562
+ ['Pin', EmbedEvent.Pin],
563
+ ['SpotIQAnalyze', EmbedEvent.SpotIQAnalyze],
564
+ ['Share', EmbedEvent.Share],
565
+ ['ExportTML', EmbedEvent.ExportTML],
566
+ ['CopyAEdit', EmbedEvent.CopyAEdit],
567
+ ];
568
+
569
+ test.each(START_END_EVENTS)(
570
+ '%s start handler fires on START, not END',
571
+ async (eventName, embedEvent) => {
572
+ const startHandler = jest.fn();
573
+ const endHandler = jest.fn();
574
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
575
+ searchEmbed
576
+ .on(embedEvent, startHandler, { start: true })
577
+ .on(embedEvent, endHandler)
578
+ .render();
579
+
580
+ await executeAfterWait(() => {
581
+ const iframe = getIFrameEl();
582
+ postMessageToParent(iframe.contentWindow, {
583
+ type: embedEvent,
584
+ data: PAYLOAD,
585
+ status: 'start',
586
+ });
587
+ });
588
+
589
+ await executeAfterWait(() => {
590
+ expect(startHandler).toHaveBeenCalled();
591
+ expect(endHandler).not.toHaveBeenCalled();
592
+ }, EVENT_WAIT_TIME);
593
+ },
594
+ );
595
+
596
+ test.each(START_END_EVENTS)(
597
+ '%s end handler fires on END, not START',
598
+ async (eventName, embedEvent) => {
599
+ const startHandler = jest.fn();
600
+ const endHandler = jest.fn();
601
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
602
+ searchEmbed
603
+ .on(embedEvent, startHandler, { start: true })
604
+ .on(embedEvent, endHandler)
605
+ .render();
606
+
607
+ await executeAfterWait(() => {
608
+ const iframe = getIFrameEl();
609
+ postMessageToParent(iframe.contentWindow, {
610
+ type: embedEvent,
611
+ data: PAYLOAD,
612
+ status: 'end',
613
+ });
614
+ });
615
+
616
+ await executeAfterWait(() => {
617
+ expect(endHandler).toHaveBeenCalled();
618
+ expect(startHandler).not.toHaveBeenCalled();
619
+ }, EVENT_WAIT_TIME);
620
+ },
621
+ );
622
+
623
+ const END_ONLY_EVENTS: Array<[string, EmbedEvent]> = [
624
+ ['Download', EmbedEvent.Download],
625
+ ['DownloadLiveboardAsContinuousPDF', EmbedEvent.DownloadLiveboardAsContinuousPDF],
626
+ ];
627
+
628
+ test.each(END_ONLY_EVENTS)(
629
+ '%s ignores start handler (end-only event)',
630
+ async (eventName, embedEvent) => {
631
+ const startHandler = jest.fn();
632
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
633
+ searchEmbed.on(embedEvent, startHandler, { start: true }).render();
634
+
635
+ await executeAfterWait(() => {
636
+ const iframe = getIFrameEl();
637
+ postMessageToParent(iframe.contentWindow, {
638
+ type: embedEvent,
639
+ data: PAYLOAD,
640
+ });
641
+ });
642
+
643
+ await executeAfterWait(() => {
644
+ expect(startHandler).not.toHaveBeenCalled();
645
+ }, EVENT_WAIT_TIME);
646
+ },
647
+ );
648
+ });
649
+
650
+ describe('EmbedEvent payload and routing', () => {
651
+ beforeEach(() => {
652
+ document.body.innerHTML = getDocumentBody();
653
+ });
654
+
655
+ test('Drilldown payload includes additionalFilters, drillDownColumns, nonFilteredColumns', async () => {
656
+ const handler = jest.fn();
657
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
658
+ searchEmbed.on(EmbedEvent.Drilldown, handler).render();
659
+
660
+ const drilldownData = {
661
+ additionalFilters: [{ column: 'region', value: 'west' }],
662
+ drillDownColumns: ['revenue'],
663
+ nonFilteredColumns: ['date'],
664
+ };
665
+
666
+ await executeAfterWait(() => {
667
+ const iframe = getIFrameEl();
668
+ postMessageToParent(iframe.contentWindow, {
669
+ type: EmbedEvent.Drilldown,
670
+ data: drilldownData,
671
+ });
672
+ });
673
+
674
+ await executeAfterWait(() => {
675
+ expect(handler).toHaveBeenCalled();
676
+ const received = handler.mock.calls[0][0].data;
677
+ expect(received.additionalFilters).toEqual(drilldownData.additionalFilters);
678
+ expect(received.drillDownColumns).toEqual(drilldownData.drillDownColumns);
679
+ expect(received.nonFilteredColumns).toEqual(drilldownData.nonFilteredColumns);
680
+ }, EVENT_WAIT_TIME);
681
+ });
682
+
683
+ test('DataSourceSelected payload contains dataSourceIds array', async () => {
684
+ const handler = jest.fn();
685
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
686
+ searchEmbed.on(EmbedEvent.DataSourceSelected, handler).render();
687
+
688
+ const dataSourceIds = ['ds-aaa', 'ds-bbb'];
689
+
690
+ await executeAfterWait(() => {
691
+ const iframe = getIFrameEl();
692
+ postMessageToParent(iframe.contentWindow, {
693
+ type: EmbedEvent.DataSourceSelected,
694
+ data: { dataSourceIds },
695
+ });
696
+ });
697
+
698
+ await executeAfterWait(() => {
699
+ expect(handler).toHaveBeenCalled();
700
+ expect(handler.mock.calls[0][0].data.dataSourceIds).toEqual(dataSourceIds);
701
+ }, EVENT_WAIT_TIME);
702
+ });
703
+
704
+ test('V1Data fires via __type field when type is absent', async () => {
705
+ const handler = jest.fn();
706
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
707
+ searchEmbed.on(EmbedEvent.V1Data, handler).render();
708
+
709
+ await executeAfterWait(() => {
710
+ const iframe = getIFrameEl();
711
+ postMessageToParent(iframe.contentWindow, {
712
+ __type: EmbedEvent.V1Data,
713
+ data: PAYLOAD,
714
+ });
715
+ });
716
+
717
+ await executeAfterWait(() => {
718
+ expect(handler).toHaveBeenCalled();
719
+ }, EVENT_WAIT_TIME);
720
+ });
721
+
722
+ test('subscribedEvent builds composed key and routes to registered handler', async () => {
723
+ const handler = jest.fn();
724
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
725
+ const composedEvent = searchEmbed.subscribedEvent(HostEvent.Save);
726
+
727
+ expect(composedEvent).toBe(`${HostEvent.Save} ${EmbedEvent.Subscribed}`);
728
+
729
+ searchEmbed.on(composedEvent as any, handler).render();
730
+
731
+ await executeAfterWait(() => {
732
+ const iframe = getIFrameEl();
733
+ postMessageToParent(iframe.contentWindow, {
734
+ type: composedEvent,
735
+ data: PAYLOAD,
736
+ });
737
+ });
738
+
739
+ await executeAfterWait(() => {
740
+ expect(handler).toHaveBeenCalled();
741
+ }, EVENT_WAIT_TIME);
742
+ });
743
+
744
+ test('non-iframe postMessage does not trigger registered handler', async () => {
745
+ const handler = jest.fn();
746
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
747
+ searchEmbed.on(EmbedEvent.Drilldown, handler).render();
748
+
749
+ await executeAfterWait(() => {
750
+ postMessageToParent(window, {
751
+ type: EmbedEvent.Drilldown,
752
+ data: PAYLOAD,
753
+ });
754
+ });
755
+
756
+ await executeAfterWait(() => {
757
+ expect(handler).not.toHaveBeenCalled();
758
+ }, EVENT_WAIT_TIME);
759
+ });
760
+
761
+ test('DataSourceSelected falls back to payload field when data is absent', async () => {
762
+ const handler = jest.fn();
763
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
764
+ searchEmbed.on(EmbedEvent.DataSourceSelected, handler).render();
765
+
766
+ const dataSourceIds = ['ds-fallback'];
767
+
768
+ await executeAfterWait(() => {
769
+ const iframe = getIFrameEl();
770
+ postMessageToParent(iframe.contentWindow, {
771
+ type: EmbedEvent.DataSourceSelected,
772
+ payload: { dataSourceIds },
773
+ // no data field — formatEventData should copy payload → data
774
+ });
775
+ });
776
+
777
+ await executeAfterWait(() => {
778
+ expect(handler).toHaveBeenCalled();
779
+ expect(handler.mock.calls[0][0].data.dataSourceIds).toEqual(dataSourceIds);
780
+ }, EVENT_WAIT_TIME);
781
+ });
782
+
783
+ test('Alert handler fires independently of window.alert', async () => {
784
+ const alertSpy = jest.spyOn(window, 'alert').mockImplementation(() => undefined);
785
+ const handler = jest.fn();
786
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
787
+ searchEmbed.on(EmbedEvent.Alert, handler).render();
788
+
789
+ await executeAfterWait(() => {
790
+ const iframe = getIFrameEl();
791
+ postMessageToParent(iframe.contentWindow, {
792
+ type: EmbedEvent.Alert,
793
+ data: { message: 'test alert' },
794
+ });
795
+ });
796
+
797
+ await executeAfterWait(() => {
798
+ expect(handler).toHaveBeenCalled();
799
+ expect(alertSpy).not.toHaveBeenCalled();
800
+ }, EVENT_WAIT_TIME);
801
+
802
+ alertSpy.mockRestore();
803
+ });
804
+
805
+ test('Share reaches EmbedEvent.ALL wildcard handler', async () => {
806
+ const allHandler = jest.fn();
807
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
808
+ searchEmbed.on(EmbedEvent.ALL, allHandler).render();
809
+
810
+ await executeAfterWait(() => {
811
+ const iframe = getIFrameEl();
812
+ postMessageToParent(iframe.contentWindow, {
813
+ type: EmbedEvent.Share,
814
+ data: PAYLOAD,
815
+ });
816
+ });
817
+
818
+ await executeAfterWait(() => {
819
+ const types = allHandler.mock.calls.map((c) => c[0].type);
820
+ expect(types).toContain(EmbedEvent.Share);
821
+ }, EVENT_WAIT_TIME);
822
+ });
823
+
824
+ test('DialogClose reaches EmbedEvent.ALL wildcard handler', async () => {
825
+ const allHandler = jest.fn();
826
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
827
+ searchEmbed.on(EmbedEvent.ALL, allHandler).render();
828
+
829
+ await executeAfterWait(() => {
830
+ const iframe = getIFrameEl();
831
+ postMessageToParent(iframe.contentWindow, {
832
+ type: EmbedEvent.DialogClose,
833
+ data: PAYLOAD,
834
+ });
835
+ });
836
+
837
+ await executeAfterWait(() => {
838
+ const types = allHandler.mock.calls.map((c) => c[0].type);
839
+ expect(types).toContain(EmbedEvent.DialogClose);
840
+ }, EVENT_WAIT_TIME);
841
+ });
842
+
843
+ test('SpotterConversationRenamed payload contains convId, oldTitle, newTitle', async () => {
844
+ const handler = jest.fn();
845
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
846
+ searchEmbed.on(EmbedEvent.SpotterConversationRenamed, handler).render();
847
+
848
+ const convData = { convId: 'conv-1', oldTitle: 'Old', newTitle: 'New' };
849
+
850
+ await executeAfterWait(() => {
851
+ const iframe = getIFrameEl();
852
+ postMessageToParent(iframe.contentWindow, {
853
+ type: EmbedEvent.SpotterConversationRenamed,
854
+ data: convData,
855
+ });
856
+ });
857
+
858
+ await executeAfterWait(() => {
859
+ expect(handler).toHaveBeenCalled();
860
+ expect(handler.mock.calls[0][0].data).toMatchObject(convData);
861
+ }, EVENT_WAIT_TIME);
862
+ });
863
+
864
+ test('SpotterConversationDeleted payload contains convId and title', async () => {
865
+ const handler = jest.fn();
866
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
867
+ searchEmbed.on(EmbedEvent.SpotterConversationDeleted, handler).render();
868
+
869
+ const convData = { convId: 'conv-2', title: 'My Conversation' };
870
+
871
+ await executeAfterWait(() => {
872
+ const iframe = getIFrameEl();
873
+ postMessageToParent(iframe.contentWindow, {
874
+ type: EmbedEvent.SpotterConversationDeleted,
875
+ data: convData,
876
+ });
877
+ });
878
+
879
+ await executeAfterWait(() => {
880
+ expect(handler).toHaveBeenCalled();
881
+ expect(handler.mock.calls[0][0].data).toMatchObject(convData);
882
+ }, EVENT_WAIT_TIME);
883
+ });
884
+
885
+ test('SpotterConversationSelected payload contains convId, title, worksheetId', async () => {
886
+ const handler = jest.fn();
887
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
888
+ searchEmbed.on(EmbedEvent.SpotterConversationSelected, handler).render();
889
+
890
+ const convData = { convId: 'conv-3', title: 'My Conv', worksheetId: 'ws-1' };
891
+
892
+ await executeAfterWait(() => {
893
+ const iframe = getIFrameEl();
894
+ postMessageToParent(iframe.contentWindow, {
895
+ type: EmbedEvent.SpotterConversationSelected,
896
+ data: convData,
897
+ });
898
+ });
899
+
900
+ await executeAfterWait(() => {
901
+ expect(handler).toHaveBeenCalled();
902
+ expect(handler.mock.calls[0][0].data).toMatchObject(convData);
903
+ }, EVENT_WAIT_TIME);
904
+ });
905
+
906
+ test('TableVizRendered payload forwards columnDataLite array intact', async () => {
907
+ const handler = jest.fn();
908
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
909
+ searchEmbed.on(EmbedEvent.TableVizRendered, handler).render();
910
+
911
+ const columnDataLite = [['col1', 'col2'], ['val1', 'val2']];
912
+
913
+ await executeAfterWait(() => {
914
+ const iframe = getIFrameEl();
915
+ postMessageToParent(iframe.contentWindow, {
916
+ type: EmbedEvent.TableVizRendered,
917
+ data: { data: { columnDataLite } },
918
+ });
919
+ });
920
+
921
+ await executeAfterWait(() => {
922
+ expect(handler).toHaveBeenCalled();
923
+ expect(handler.mock.calls[0][0].data.data.columnDataLite).toEqual(columnDataLite);
924
+ }, EVENT_WAIT_TIME);
925
+ });
926
+
927
+ test('SendTestScheduleEmail payload preserves liveboardId and sendToSelf boolean', async () => {
928
+ const handler = jest.fn();
929
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
930
+ searchEmbed.on(EmbedEvent.SendTestScheduleEmail, handler).render();
931
+
932
+ const emailData = { liveboardId: 'lb-123', sendToSelf: true };
933
+
934
+ await executeAfterWait(() => {
935
+ const iframe = getIFrameEl();
936
+ postMessageToParent(iframe.contentWindow, {
937
+ type: EmbedEvent.SendTestScheduleEmail,
938
+ data: emailData,
939
+ });
940
+ });
941
+
942
+ await executeAfterWait(() => {
943
+ expect(handler).toHaveBeenCalled();
944
+ const received = handler.mock.calls[0][0].data;
945
+ expect(received.liveboardId).toBe('lb-123');
946
+ expect(received.sendToSelf).toBe(true);
947
+ expect(typeof received.sendToSelf).toBe('boolean');
948
+ }, EVENT_WAIT_TIME);
949
+ });
950
+
951
+ test('ChangePersonalizedView payload viewId can be null (reset-to-default)', async () => {
952
+ const handler = jest.fn();
953
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
954
+ searchEmbed.on(EmbedEvent.ChangePersonalizedView, handler).render();
955
+
956
+ await executeAfterWait(() => {
957
+ const iframe = getIFrameEl();
958
+ postMessageToParent(iframe.contentWindow, {
959
+ type: EmbedEvent.ChangePersonalizedView,
960
+ data: { viewId: null, viewName: 'Original View', liveboardId: 'lb-1', isPublic: false },
961
+ });
962
+ });
963
+
964
+ await executeAfterWait(() => {
965
+ expect(handler).toHaveBeenCalled();
966
+ expect(handler.mock.calls[0][0].data.viewId).toBeNull();
967
+ expect(handler.mock.calls[0][0].data.viewName).toBe('Original View');
968
+ }, EVENT_WAIT_TIME);
969
+ });
970
+
971
+ test('VizPointDoubleClick payload exposes vizId and clickedPoint.selectedPoints', async () => {
972
+ const handler = jest.fn();
973
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
974
+ searchEmbed.on(EmbedEvent.VizPointDoubleClick, handler).render();
975
+
976
+ const pointData = {
977
+ vizId: 'viz-1',
978
+ clickedPoint: { selectedPoints: [{ x: 10, y: 20 }] },
979
+ };
980
+
981
+ await executeAfterWait(() => {
982
+ const iframe = getIFrameEl();
983
+ postMessageToParent(iframe.contentWindow, {
984
+ type: EmbedEvent.VizPointDoubleClick,
985
+ data: pointData,
986
+ });
987
+ });
988
+
989
+ await executeAfterWait(() => {
990
+ expect(handler).toHaveBeenCalled();
991
+ const { data } = handler.mock.calls[0][0];
992
+ expect(data.vizId).toBe('viz-1');
993
+ expect(data.clickedPoint.selectedPoints).toEqual(pointData.clickedPoint.selectedPoints);
994
+ }, EVENT_WAIT_TIME);
995
+ });
996
+
997
+ test('VizPointClick payload exposes vizId, selectedAttributes and selectedMeasures', async () => {
998
+ const handler = jest.fn();
999
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
1000
+ searchEmbed.on(EmbedEvent.VizPointClick, handler).render();
1001
+
1002
+ const pointData = {
1003
+ vizId: 'viz-2',
1004
+ clickedPoint: {
1005
+ selectedAttributes: [{ value: 'West', column: { name: 'region' } }],
1006
+ selectedMeasures: [{ value: 42, column: { name: 'revenue' } }],
1007
+ },
1008
+ };
1009
+
1010
+ await executeAfterWait(() => {
1011
+ const iframe = getIFrameEl();
1012
+ postMessageToParent(iframe.contentWindow, {
1013
+ type: EmbedEvent.VizPointClick,
1014
+ data: pointData,
1015
+ });
1016
+ });
1017
+
1018
+ await executeAfterWait(() => {
1019
+ expect(handler).toHaveBeenCalled();
1020
+ const { data } = handler.mock.calls[0][0];
1021
+ expect(data.vizId).toBe('viz-2');
1022
+ expect(data.clickedPoint.selectedAttributes[0].value).toBe('West');
1023
+ expect(data.clickedPoint.selectedAttributes[0].column.name).toBe('region');
1024
+ expect(data.clickedPoint.selectedMeasures[0].value).toBe(42);
1025
+ expect(data.clickedPoint.selectedMeasures[0].column.name).toBe('revenue');
1026
+ }, EVENT_WAIT_TIME);
1027
+ });
1028
+
1029
+ test('SpotterVizError reaches EmbedEvent.ALL handler', async () => {
1030
+ const allHandler = jest.fn();
1031
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
1032
+ searchEmbed.on(EmbedEvent.ALL, allHandler).render();
1033
+
1034
+ await executeAfterWait(() => {
1035
+ const iframe = getIFrameEl();
1036
+ postMessageToParent(iframe.contentWindow, {
1037
+ type: EmbedEvent.SpotterVizError,
1038
+ data: PAYLOAD,
1039
+ });
1040
+ });
1041
+
1042
+ await executeAfterWait(() => {
1043
+ const types = allHandler.mock.calls.map((c) => c[0].type);
1044
+ expect(types).toContain(EmbedEvent.SpotterVizError);
1045
+ }, EVENT_WAIT_TIME);
1046
+ });
1047
+
1048
+ test('SpotterVizClosed reaches EmbedEvent.ALL handler', async () => {
1049
+ const allHandler = jest.fn();
1050
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
1051
+ searchEmbed.on(EmbedEvent.ALL, allHandler).render();
1052
+
1053
+ await executeAfterWait(() => {
1054
+ const iframe = getIFrameEl();
1055
+ postMessageToParent(iframe.contentWindow, {
1056
+ type: EmbedEvent.SpotterVizClosed,
1057
+ data: PAYLOAD,
1058
+ });
1059
+ });
1060
+
1061
+ await executeAfterWait(() => {
1062
+ const types = allHandler.mock.calls.map((c) => c[0].type);
1063
+ expect(types).toContain(EmbedEvent.SpotterVizClosed);
1064
+ }, EVENT_WAIT_TIME);
1065
+ });
1066
+
1067
+ test('SpotterVizCheckpointRestored payload newGenNumber is a number', async () => {
1068
+ const handler = jest.fn();
1069
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
1070
+ searchEmbed.on(EmbedEvent.SpotterVizCheckpointRestored, handler).render();
1071
+
1072
+ await executeAfterWait(() => {
1073
+ const iframe = getIFrameEl();
1074
+ postMessageToParent(iframe.contentWindow, {
1075
+ type: EmbedEvent.SpotterVizCheckpointRestored,
1076
+ data: { checkpointId: 'cp-1', newGenNumber: 42 },
1077
+ });
1078
+ });
1079
+
1080
+ await executeAfterWait(() => {
1081
+ expect(handler).toHaveBeenCalled();
1082
+ const { newGenNumber } = handler.mock.calls[0][0].data;
1083
+ expect(newGenNumber).toBe(42);
1084
+ expect(typeof newGenNumber).toBe('number');
1085
+ }, EVENT_WAIT_TIME);
1086
+ });
1087
+ });