@thoughtspot/visual-embed-sdk 1.48.0 → 1.49.0

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 (201) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/css-variables.d.ts +140 -0
  3. package/cjs/src/css-variables.d.ts.map +1 -1
  4. package/cjs/src/embed/app.d.ts +62 -1
  5. package/cjs/src/embed/app.d.ts.map +1 -1
  6. package/cjs/src/embed/app.js +57 -6
  7. package/cjs/src/embed/app.js.map +1 -1
  8. package/cjs/src/embed/app.spec.js +191 -1
  9. package/cjs/src/embed/app.spec.js.map +1 -1
  10. package/cjs/src/embed/auto-frame-renderer.js +7 -2
  11. package/cjs/src/embed/auto-frame-renderer.js.map +1 -1
  12. package/cjs/src/embed/auto-frame-renderer.spec.js +385 -6
  13. package/cjs/src/embed/auto-frame-renderer.spec.js.map +1 -1
  14. package/cjs/src/embed/base.d.ts +1 -0
  15. package/cjs/src/embed/base.d.ts.map +1 -1
  16. package/cjs/src/embed/base.js +13 -1
  17. package/cjs/src/embed/base.js.map +1 -1
  18. package/cjs/src/embed/base.spec.js +21 -0
  19. package/cjs/src/embed/base.spec.js.map +1 -1
  20. package/cjs/src/embed/bodyless-conversation.spec.js +86 -0
  21. package/cjs/src/embed/bodyless-conversation.spec.js.map +1 -1
  22. package/cjs/src/embed/conversation.d.ts +16 -1
  23. package/cjs/src/embed/conversation.d.ts.map +1 -1
  24. package/cjs/src/embed/conversation.js +5 -1
  25. package/cjs/src/embed/conversation.js.map +1 -1
  26. package/cjs/src/embed/conversation.spec.js +26 -0
  27. package/cjs/src/embed/conversation.spec.js.map +1 -1
  28. package/cjs/src/embed/liveboard.d.ts +47 -1
  29. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  30. package/cjs/src/embed/liveboard.js +47 -6
  31. package/cjs/src/embed/liveboard.js.map +1 -1
  32. package/cjs/src/embed/liveboard.spec.js +129 -1
  33. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  34. package/cjs/src/embed/spotter-viz-utils.d.ts +85 -0
  35. package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -0
  36. package/cjs/src/embed/spotter-viz-utils.js +17 -0
  37. package/cjs/src/embed/spotter-viz-utils.js.map +1 -0
  38. package/cjs/src/embed/spotter-viz-utils.spec.d.ts +2 -0
  39. package/cjs/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
  40. package/cjs/src/embed/spotter-viz-utils.spec.js +31 -0
  41. package/cjs/src/embed/spotter-viz-utils.spec.js.map +1 -0
  42. package/cjs/src/embed/ts-embed.d.ts +58 -38
  43. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  44. package/cjs/src/embed/ts-embed.js +245 -149
  45. package/cjs/src/embed/ts-embed.js.map +1 -1
  46. package/cjs/src/embed/ts-embed.spec.js +369 -123
  47. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  48. package/cjs/src/index.d.ts +2 -1
  49. package/cjs/src/index.d.ts.map +1 -1
  50. package/cjs/src/index.js.map +1 -1
  51. package/cjs/src/react/index.d.ts.map +1 -1
  52. package/cjs/src/react/index.js +3 -0
  53. package/cjs/src/react/index.js.map +1 -1
  54. package/cjs/src/types.d.ts +267 -27
  55. package/cjs/src/types.d.ts.map +1 -1
  56. package/cjs/src/types.js +223 -19
  57. package/cjs/src/types.js.map +1 -1
  58. package/cjs/src/utils/authService/tokenizedAuthService.spec.js +6 -7
  59. package/cjs/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
  60. package/cjs/src/utils/logger.js +2 -1
  61. package/cjs/src/utils/logger.js.map +1 -1
  62. package/cjs/src/utils/logger.spec.d.ts +1 -0
  63. package/cjs/src/utils/logger.spec.d.ts.map +1 -1
  64. package/cjs/src/utils/logger.spec.js +10 -9
  65. package/cjs/src/utils/logger.spec.js.map +1 -1
  66. package/cjs/src/utils.d.ts +4 -1
  67. package/cjs/src/utils.d.ts.map +1 -1
  68. package/cjs/src/utils.js +107 -10
  69. package/cjs/src/utils.js.map +1 -1
  70. package/cjs/src/utils.spec.js +163 -4
  71. package/cjs/src/utils.spec.js.map +1 -1
  72. package/dist/{index-Ck-r09gt.js → index-_UGCSSDR.js} +1 -1
  73. package/dist/src/css-variables.d.ts +140 -0
  74. package/dist/src/css-variables.d.ts.map +1 -1
  75. package/dist/src/embed/app.d.ts +62 -1
  76. package/dist/src/embed/app.d.ts.map +1 -1
  77. package/dist/src/embed/base.d.ts +1 -0
  78. package/dist/src/embed/base.d.ts.map +1 -1
  79. package/dist/src/embed/conversation.d.ts +16 -1
  80. package/dist/src/embed/conversation.d.ts.map +1 -1
  81. package/dist/src/embed/liveboard.d.ts +47 -1
  82. package/dist/src/embed/liveboard.d.ts.map +1 -1
  83. package/dist/src/embed/spotter-viz-utils.d.ts +85 -0
  84. package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -0
  85. package/dist/src/embed/spotter-viz-utils.spec.d.ts +2 -0
  86. package/dist/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
  87. package/dist/src/embed/ts-embed.d.ts +58 -38
  88. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  89. package/dist/src/index.d.ts +2 -1
  90. package/dist/src/index.d.ts.map +1 -1
  91. package/dist/src/react/index.d.ts.map +1 -1
  92. package/dist/src/types.d.ts +267 -27
  93. package/dist/src/types.d.ts.map +1 -1
  94. package/dist/src/utils/logger.spec.d.ts +1 -0
  95. package/dist/src/utils/logger.spec.d.ts.map +1 -1
  96. package/dist/src/utils.d.ts +4 -1
  97. package/dist/src/utils.d.ts.map +1 -1
  98. package/dist/tsembed-react.es.js +3708 -3226
  99. package/dist/tsembed-react.js +3358 -2876
  100. package/dist/tsembed.es.js +3713 -3229
  101. package/dist/tsembed.js +3708 -3224
  102. package/dist/visual-embed-sdk-react-full.d.ts +643 -63
  103. package/dist/visual-embed-sdk-react.d.ts +643 -63
  104. package/dist/visual-embed-sdk.d.ts +658 -65
  105. package/lib/package.json +1 -1
  106. package/lib/src/css-variables.d.ts +140 -0
  107. package/lib/src/css-variables.d.ts.map +1 -1
  108. package/lib/src/embed/app.d.ts +62 -1
  109. package/lib/src/embed/app.d.ts.map +1 -1
  110. package/lib/src/embed/app.js +58 -7
  111. package/lib/src/embed/app.js.map +1 -1
  112. package/lib/src/embed/app.spec.js +192 -2
  113. package/lib/src/embed/app.spec.js.map +1 -1
  114. package/lib/src/embed/auto-frame-renderer.js +7 -2
  115. package/lib/src/embed/auto-frame-renderer.js.map +1 -1
  116. package/lib/src/embed/auto-frame-renderer.spec.js +387 -8
  117. package/lib/src/embed/auto-frame-renderer.spec.js.map +1 -1
  118. package/lib/src/embed/base.d.ts +1 -0
  119. package/lib/src/embed/base.d.ts.map +1 -1
  120. package/lib/src/embed/base.js +11 -0
  121. package/lib/src/embed/base.js.map +1 -1
  122. package/lib/src/embed/base.spec.js +22 -1
  123. package/lib/src/embed/base.spec.js.map +1 -1
  124. package/lib/src/embed/bodyless-conversation.spec.js +86 -0
  125. package/lib/src/embed/bodyless-conversation.spec.js.map +1 -1
  126. package/lib/src/embed/conversation.d.ts +16 -1
  127. package/lib/src/embed/conversation.d.ts.map +1 -1
  128. package/lib/src/embed/conversation.js +5 -1
  129. package/lib/src/embed/conversation.js.map +1 -1
  130. package/lib/src/embed/conversation.spec.js +27 -1
  131. package/lib/src/embed/conversation.spec.js.map +1 -1
  132. package/lib/src/embed/liveboard.d.ts +47 -1
  133. package/lib/src/embed/liveboard.d.ts.map +1 -1
  134. package/lib/src/embed/liveboard.js +48 -7
  135. package/lib/src/embed/liveboard.js.map +1 -1
  136. package/lib/src/embed/liveboard.spec.js +129 -1
  137. package/lib/src/embed/liveboard.spec.js.map +1 -1
  138. package/lib/src/embed/spotter-viz-utils.d.ts +85 -0
  139. package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -0
  140. package/lib/src/embed/spotter-viz-utils.js +13 -0
  141. package/lib/src/embed/spotter-viz-utils.js.map +1 -0
  142. package/lib/src/embed/spotter-viz-utils.spec.d.ts +2 -0
  143. package/lib/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
  144. package/lib/src/embed/spotter-viz-utils.spec.js +29 -0
  145. package/lib/src/embed/spotter-viz-utils.spec.js.map +1 -0
  146. package/lib/src/embed/ts-embed.d.ts +58 -38
  147. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  148. package/lib/src/embed/ts-embed.js +248 -152
  149. package/lib/src/embed/ts-embed.js.map +1 -1
  150. package/lib/src/embed/ts-embed.spec.js +369 -123
  151. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  152. package/lib/src/index.d.ts +2 -1
  153. package/lib/src/index.d.ts.map +1 -1
  154. package/lib/src/index.js.map +1 -1
  155. package/lib/src/react/index.d.ts.map +1 -1
  156. package/lib/src/react/index.js +3 -0
  157. package/lib/src/react/index.js.map +1 -1
  158. package/lib/src/types.d.ts +267 -27
  159. package/lib/src/types.d.ts.map +1 -1
  160. package/lib/src/types.js +223 -19
  161. package/lib/src/types.js.map +1 -1
  162. package/lib/src/utils/authService/tokenizedAuthService.spec.js +6 -7
  163. package/lib/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
  164. package/lib/src/utils/logger.js +2 -1
  165. package/lib/src/utils/logger.js.map +1 -1
  166. package/lib/src/utils/logger.spec.d.ts +1 -0
  167. package/lib/src/utils/logger.spec.d.ts.map +1 -1
  168. package/lib/src/utils/logger.spec.js +10 -9
  169. package/lib/src/utils/logger.spec.js.map +1 -1
  170. package/lib/src/utils.d.ts +4 -1
  171. package/lib/src/utils.d.ts.map +1 -1
  172. package/lib/src/utils.js +103 -9
  173. package/lib/src/utils.js.map +1 -1
  174. package/lib/src/utils.spec.js +164 -5
  175. package/lib/src/utils.spec.js.map +1 -1
  176. package/lib/src/visual-embed-sdk.d.ts +658 -65
  177. package/package.json +1 -1
  178. package/src/css-variables.ts +175 -1
  179. package/src/embed/app.spec.ts +247 -3
  180. package/src/embed/app.ts +125 -5
  181. package/src/embed/auto-frame-renderer.spec.ts +457 -58
  182. package/src/embed/auto-frame-renderer.ts +7 -2
  183. package/src/embed/base.spec.ts +25 -1
  184. package/src/embed/base.ts +19 -5
  185. package/src/embed/bodyless-conversation.spec.ts +93 -0
  186. package/src/embed/conversation.spec.ts +34 -0
  187. package/src/embed/conversation.ts +22 -1
  188. package/src/embed/liveboard.spec.ts +149 -1
  189. package/src/embed/liveboard.ts +102 -6
  190. package/src/embed/spotter-viz-utils.spec.ts +30 -0
  191. package/src/embed/spotter-viz-utils.ts +94 -0
  192. package/src/embed/ts-embed.spec.ts +532 -234
  193. package/src/embed/ts-embed.ts +383 -257
  194. package/src/index.ts +3 -0
  195. package/src/react/index.tsx +3 -0
  196. package/src/types.ts +284 -23
  197. package/src/utils/authService/tokenizedAuthService.spec.ts +6 -6
  198. package/src/utils/logger.spec.ts +11 -9
  199. package/src/utils/logger.ts +2 -2
  200. package/src/utils.spec.ts +200 -4
  201. package/src/utils.ts +128 -9
@@ -133,9 +133,9 @@ const getMockAppInitPayload = (data: any) => {
133
133
  customVariablesForThirdPartyTools,
134
134
  interceptTimeout: undefined,
135
135
  interceptUrls: [],
136
- shouldBypassPayloadValidation:undefined,
137
- useHostEventsV2:undefined,
138
- embedExpiryInAuthToken:true
136
+ shouldBypassPayloadValidation: undefined,
137
+ useHostEventsV2: undefined,
138
+ embedExpiryInAuthToken: true,
139
139
  };
140
140
  return {
141
141
  type: EmbedEvent.APP_INIT,
@@ -144,7 +144,7 @@ const getMockAppInitPayload = (data: any) => {
144
144
  ...data,
145
145
  },
146
146
  };
147
- }
147
+ };
148
148
 
149
149
  describe('Unit test case for ts embed', () => {
150
150
  const mockMixPanelEvent = jest.spyOn(mixpanelInstance, 'uploadMixpanelEvent');
@@ -223,9 +223,7 @@ describe('Unit test case for ts embed', () => {
223
223
  liveboardEmbed.render();
224
224
  mockProcessTrigger.mockResolvedValue({ session: 'test' });
225
225
  await executeAfterWait(async () => {
226
- await liveboardEmbed.trigger(
227
- HostEvent.Save,
228
- );
226
+ await liveboardEmbed.trigger(HostEvent.Save);
229
227
  expect(mockProcessTrigger).toHaveBeenCalledWith(
230
228
  getIFrameEl(),
231
229
  HostEvent.Save,
@@ -244,10 +242,7 @@ describe('Unit test case for ts embed', () => {
244
242
  liveboardEmbed.render();
245
243
  mockProcessTrigger.mockResolvedValue({ session: 'test' });
246
244
  await executeAfterWait(async () => {
247
- await liveboardEmbed.trigger(
248
- HostEvent.Save,
249
- false,
250
- );
245
+ await liveboardEmbed.trigger(HostEvent.Save, false);
251
246
  expect(mockProcessTrigger).toHaveBeenCalledWith(
252
247
  getIFrameEl(),
253
248
  HostEvent.Save,
@@ -398,9 +393,11 @@ describe('Unit test case for ts embed', () => {
398
393
  postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
399
394
  });
400
395
  await executeAfterWait(() => {
401
- expect(mockPort.postMessage).toHaveBeenCalledWith(getMockAppInitPayload({
402
- customisations: customisationsView,
403
- }));
396
+ expect(mockPort.postMessage).toHaveBeenCalledWith(
397
+ getMockAppInitPayload({
398
+ customisations: customisationsView,
399
+ }),
400
+ );
404
401
  });
405
402
  });
406
403
 
@@ -427,9 +424,11 @@ describe('Unit test case for ts embed', () => {
427
424
  postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
428
425
  });
429
426
  await executeAfterWait(() => {
430
- expect(mockPort.postMessage).toHaveBeenCalledWith(getMockAppInitPayload({
431
- hiddenHomepageModules: [HomepageModule.MyLibrary, HomepageModule.Learning],
432
- }));
427
+ expect(mockPort.postMessage).toHaveBeenCalledWith(
428
+ getMockAppInitPayload({
429
+ hiddenHomepageModules: [HomepageModule.MyLibrary, HomepageModule.Learning],
430
+ }),
431
+ );
433
432
  });
434
433
  });
435
434
 
@@ -480,10 +479,14 @@ describe('Unit test case for ts embed', () => {
480
479
  postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
481
480
  });
482
481
  await executeAfterWait(() => {
483
- expect(mockPort.postMessage).toHaveBeenCalledWith(getMockAppInitPayload({
484
- reorderedHomepageModules:
485
- [HomepageModule.MyLibrary, HomepageModule.Watchlist],
486
- }));
482
+ expect(mockPort.postMessage).toHaveBeenCalledWith(
483
+ getMockAppInitPayload({
484
+ reorderedHomepageModules: [
485
+ HomepageModule.MyLibrary,
486
+ HomepageModule.Watchlist,
487
+ ],
488
+ }),
489
+ );
487
490
  });
488
491
  });
489
492
 
@@ -513,9 +516,11 @@ describe('Unit test case for ts embed', () => {
513
516
  postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
514
517
  });
515
518
  await executeAfterWait(() => {
516
- expect(mockPort.postMessage).toHaveBeenCalledWith(getMockAppInitPayload({
517
- runtimeParameterParams: 'param1=color&paramVal1=blue',
518
- }));
519
+ expect(mockPort.postMessage).toHaveBeenCalledWith(
520
+ getMockAppInitPayload({
521
+ runtimeParameterParams: 'param1=color&paramVal1=blue',
522
+ }),
523
+ );
519
524
  });
520
525
  });
521
526
 
@@ -546,9 +551,11 @@ describe('Unit test case for ts embed', () => {
546
551
  postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
547
552
  });
548
553
  await executeAfterWait(() => {
549
- expect(mockPort.postMessage).toHaveBeenCalledWith(getMockAppInitPayload({
550
- runtimeFilterParams: 'col1=color&op1=EQ&val1=blue',
551
- }));
554
+ expect(mockPort.postMessage).toHaveBeenCalledWith(
555
+ getMockAppInitPayload({
556
+ runtimeFilterParams: 'col1=color&op1=EQ&val1=blue',
557
+ }),
558
+ );
552
559
  });
553
560
  });
554
561
 
@@ -638,10 +645,14 @@ describe('Unit test case for ts embed', () => {
638
645
  });
639
646
 
640
647
  await executeAfterWait(() => {
641
- expect(mockPort.postMessage).toHaveBeenCalledWith(getMockAppInitPayload({
642
- hiddenHomeLeftNavItems:
643
- [HomeLeftNavItem.Home, HomeLeftNavItem.MonitorSubscription],
644
- }));
648
+ expect(mockPort.postMessage).toHaveBeenCalledWith(
649
+ getMockAppInitPayload({
650
+ hiddenHomeLeftNavItems: [
651
+ HomeLeftNavItem.Home,
652
+ HomeLeftNavItem.MonitorSubscription,
653
+ ],
654
+ }),
655
+ );
645
656
  });
646
657
  });
647
658
 
@@ -824,10 +835,12 @@ describe('Unit test case for ts embed', () => {
824
835
  postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
825
836
  });
826
837
  await executeAfterWait(() => {
827
- expect(mockPort.postMessage).toHaveBeenCalledWith(getMockAppInitPayload({
828
- authToken: 'test_auth_token1',
829
- customVariablesForThirdPartyTools: {},
830
- }));
838
+ expect(mockPort.postMessage).toHaveBeenCalledWith(
839
+ getMockAppInitPayload({
840
+ authToken: 'test_auth_token1',
841
+ customVariablesForThirdPartyTools: {},
842
+ }),
843
+ );
831
844
  });
832
845
 
833
846
  jest.spyOn(authService, 'verifyTokenService').mockClear();
@@ -878,37 +891,40 @@ describe('Unit test case for ts embed', () => {
878
891
 
879
892
  await executeAfterWait(() => {
880
893
  const iframe = getIFrameEl();
881
- expect(iframe.src).toContain('overrideStringIDsUrl=https://sample-string-ids-url.com');
894
+ expect(iframe.src).toContain(
895
+ 'overrideStringIDsUrl=https://sample-string-ids-url.com',
896
+ );
882
897
  postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
883
898
  });
884
899
 
885
900
  await executeAfterWait(() => {
886
- expect(mockPort.postMessage).toHaveBeenCalledWith(getMockAppInitPayload({
887
- customisations: {
888
- content: {
889
- strings: {
890
- Liveboard: 'Dashboard',
901
+ expect(mockPort.postMessage).toHaveBeenCalledWith(
902
+ getMockAppInitPayload({
903
+ customisations: {
904
+ content: {
905
+ strings: {
906
+ Liveboard: 'Dashboard',
907
+ },
908
+ stringIDsUrl: 'https://sample-string-ids-url.com',
909
+ stringIDs: {
910
+ 'liveboard.header.title': 'Dashboard name',
911
+ },
891
912
  },
892
- stringIDsUrl: 'https://sample-string-ids-url.com',
893
- stringIDs: {
894
- 'liveboard.header.title': 'Dashboard name',
913
+ style: {
914
+ customCSS: {},
915
+ customCSSUrl: undefined,
895
916
  },
896
917
  },
897
- style: {
898
- customCSS: {},
899
- customCSSUrl: undefined,
900
- },
901
- },
902
- authToken: 'test_auth_token1',
903
- customVariablesForThirdPartyTools: {},
904
- }));
905
- const customisationContent = mockPort.postMessage.mock.calls[0][0].data.customisations.content;
906
- expect(customisationContent.stringIDsUrl)
907
- .toBe('https://sample-string-ids-url.com');
908
- expect(customisationContent.stringIDs)
909
- .toEqual({
910
- 'liveboard.header.title': 'Dashboard name',
911
- });
918
+ authToken: 'test_auth_token1',
919
+ customVariablesForThirdPartyTools: {},
920
+ }),
921
+ );
922
+ const customisationContent =
923
+ mockPort.postMessage.mock.calls[0][0].data.customisations.content;
924
+ expect(customisationContent.stringIDsUrl).toBe('https://sample-string-ids-url.com');
925
+ expect(customisationContent.stringIDs).toEqual({
926
+ 'liveboard.header.title': 'Dashboard name',
927
+ });
912
928
  });
913
929
  });
914
930
 
@@ -917,7 +933,10 @@ describe('Unit test case for ts embed', () => {
917
933
  type: EmbedEvent.APP_INIT,
918
934
  data: {},
919
935
  };
920
- const searchEmbed = new SearchEmbed(getRootEl(), { ...defaultViewConfig, exposeTranslationIDs: true });
936
+ const searchEmbed = new SearchEmbed(getRootEl(), {
937
+ ...defaultViewConfig,
938
+ exposeTranslationIDs: true,
939
+ });
921
940
  searchEmbed.render();
922
941
  const mockPort: any = {
923
942
  postMessage: jest.fn(),
@@ -963,16 +982,16 @@ describe('Unit test case for ts embed', () => {
963
982
  name: 'Valid Action',
964
983
  target: CustomActionTarget.LIVEBOARD,
965
984
  position: CustomActionsPosition.PRIMARY,
966
- metadataIds: { liveboardIds: ['lb123'] }
985
+ metadataIds: { liveboardIds: ['lb123'] },
967
986
  },
968
987
  {
969
988
  id: 'action2',
970
989
  name: 'Another Valid Action',
971
990
  target: CustomActionTarget.VIZ,
972
991
  position: CustomActionsPosition.MENU,
973
- metadataIds: { vizIds: ['viz456'] }
974
- }
975
- ]
992
+ metadataIds: { vizIds: ['viz456'] },
993
+ },
994
+ ],
976
995
  });
977
996
 
978
997
  searchEmbed.render();
@@ -986,33 +1005,35 @@ describe('Unit test case for ts embed', () => {
986
1005
  });
987
1006
 
988
1007
  await executeAfterWait(() => {
989
- expect(mockPort.postMessage).toHaveBeenCalledWith(getMockAppInitPayload({
990
- customisations: {
991
- content: {},
992
- style: {
993
- customCSS: {},
994
- customCSSUrl: undefined,
995
- },
996
- },
997
- authToken: 'test_auth_token1',
998
- customActions: [
999
- {
1000
- id: 'action2',
1001
- name: 'Another Valid Action',
1002
- target: CustomActionTarget.VIZ,
1003
- position: CustomActionsPosition.MENU,
1004
- metadataIds: { vizIds: ['viz456'] }
1008
+ expect(mockPort.postMessage).toHaveBeenCalledWith(
1009
+ getMockAppInitPayload({
1010
+ customisations: {
1011
+ content: {},
1012
+ style: {
1013
+ customCSS: {},
1014
+ customCSSUrl: undefined,
1015
+ },
1005
1016
  },
1006
- {
1007
- id: 'action1',
1008
- name: 'Valid Action',
1009
- target: CustomActionTarget.LIVEBOARD,
1010
- position: CustomActionsPosition.PRIMARY,
1011
- metadataIds: { liveboardIds: ['lb123'] }
1012
- }
1013
- ], // Actions should be sorted by name
1014
- customVariablesForThirdPartyTools: {},
1015
- }));
1017
+ authToken: 'test_auth_token1',
1018
+ customActions: [
1019
+ {
1020
+ id: 'action2',
1021
+ name: 'Another Valid Action',
1022
+ target: CustomActionTarget.VIZ,
1023
+ position: CustomActionsPosition.MENU,
1024
+ metadataIds: { vizIds: ['viz456'] },
1025
+ },
1026
+ {
1027
+ id: 'action1',
1028
+ name: 'Valid Action',
1029
+ target: CustomActionTarget.LIVEBOARD,
1030
+ position: CustomActionsPosition.PRIMARY,
1031
+ metadataIds: { liveboardIds: ['lb123'] },
1032
+ },
1033
+ ], // Actions should be sorted by name
1034
+ customVariablesForThirdPartyTools: {},
1035
+ }),
1036
+ );
1016
1037
 
1017
1038
  // Verify that CustomActionsValidationResult structure is
1018
1039
  // correct
@@ -1024,15 +1045,15 @@ describe('Unit test case for ts embed', () => {
1024
1045
  id: 'action1',
1025
1046
  name: 'Valid Action',
1026
1047
  target: CustomActionTarget.LIVEBOARD,
1027
- position: CustomActionsPosition.PRIMARY
1048
+ position: CustomActionsPosition.PRIMARY,
1028
1049
  }),
1029
1050
  expect.objectContaining({
1030
1051
  id: 'action2',
1031
1052
  name: 'Another Valid Action',
1032
1053
  target: CustomActionTarget.VIZ,
1033
- position: CustomActionsPosition.MENU
1034
- })
1035
- ])
1054
+ position: CustomActionsPosition.MENU,
1055
+ }),
1056
+ ]),
1036
1057
  );
1037
1058
 
1038
1059
  // Verify actions are sorted by name (alphabetically)
@@ -1094,7 +1115,10 @@ describe('Unit test case for ts embed', () => {
1094
1115
  type: EmbedEvent.APP_INIT,
1095
1116
  data: {},
1096
1117
  };
1097
- const searchEmbed = new SearchEmbed(getRootEl(), { ...defaultViewConfig, preRenderId: 'test' });
1118
+ const searchEmbed = new SearchEmbed(getRootEl(), {
1119
+ ...defaultViewConfig,
1120
+ preRenderId: 'test',
1121
+ });
1098
1122
  searchEmbed.preRender();
1099
1123
  const mockPort: any = {
1100
1124
  postMessage: jest.fn(),
@@ -1153,7 +1177,10 @@ describe('Unit test case for ts embed', () => {
1153
1177
  type: EmbedEvent.AuthExpire,
1154
1178
  data: {},
1155
1179
  };
1156
- const searchEmbed = new SearchEmbed(getRootEl(), { ...defaultViewConfig, preRenderId: 'test' });
1180
+ const searchEmbed = new SearchEmbed(getRootEl(), {
1181
+ ...defaultViewConfig,
1182
+ preRenderId: 'test',
1183
+ });
1157
1184
  jest.spyOn(baseInstance, 'notifyAuthFailure');
1158
1185
  searchEmbed.preRender();
1159
1186
  const loggerSpy = jest.spyOn(logger, 'error').mockImplementation(() => {});
@@ -1318,23 +1345,27 @@ describe('Unit test case for ts embed', () => {
1318
1345
  let mockGetPreauthInfo = null;
1319
1346
 
1320
1347
  if (overrideOrgId) {
1321
- mockGetPreauthInfo = jest.spyOn(sessionInfoService, 'getPreauthInfo').mockImplementation(jest.fn());
1348
+ mockGetPreauthInfo = jest
1349
+ .spyOn(sessionInfoService, 'getPreauthInfo')
1350
+ .mockImplementation(jest.fn());
1322
1351
  }
1323
1352
 
1324
- const mockPreauthInfoFetch = jest.spyOn(authService, 'fetchPreauthInfoService').mockResolvedValueOnce({
1325
- ok: true,
1326
- headers: new Headers({ 'content-type': 'application/json' }), // Mock headers correctly
1327
- json: async () => ({
1328
- info: {
1329
- configInfo: {
1330
- mixpanelConfig: {
1331
- devSdkKey: 'devSdkKey',
1353
+ const mockPreauthInfoFetch = jest
1354
+ .spyOn(authService, 'fetchPreauthInfoService')
1355
+ .mockResolvedValueOnce({
1356
+ ok: true,
1357
+ headers: new Headers({ 'content-type': 'application/json' }), // Mock headers correctly
1358
+ json: async () => ({
1359
+ info: {
1360
+ configInfo: {
1361
+ mixpanelConfig: {
1362
+ devSdkKey: 'devSdkKey',
1363
+ },
1332
1364
  },
1365
+ userGUID: 'userGUID',
1333
1366
  },
1334
- userGUID: 'userGUID',
1335
- },
1336
- }), // Mock JSON response
1337
- });
1367
+ }), // Mock JSON response
1368
+ });
1338
1369
  const iFrame: any = document.createElement('div');
1339
1370
  jest.spyOn(baseInstance, 'getAuthPromise').mockResolvedValueOnce(isLoggedIn);
1340
1371
  const tsEmbed = new SearchEmbed(getRootEl(), {
@@ -1360,10 +1391,7 @@ describe('Unit test case for ts embed', () => {
1360
1391
  };
1361
1392
 
1362
1393
  test('should call InfoSuccess Event on preauth call success', async () => {
1363
- const {
1364
- mockPreauthInfoFetch,
1365
- iFrame,
1366
- } = await setup(true);
1394
+ const { mockPreauthInfoFetch, iFrame } = await setup(true);
1367
1395
  expect(mockPreauthInfoFetch).toHaveBeenCalledTimes(1);
1368
1396
 
1369
1397
  await executeAfterWait(() => {
@@ -1378,9 +1406,7 @@ describe('Unit test case for ts embed', () => {
1378
1406
  });
1379
1407
 
1380
1408
  test('should not call InfoSuccess Event if overrideOrgId is true', async () => {
1381
- const {
1382
- mockGetPreauthInfo,
1383
- } = await setup(true, 123);
1409
+ const { mockGetPreauthInfo } = await setup(true, 123);
1384
1410
  expect(mockGetPreauthInfo).toHaveBeenCalledTimes(0);
1385
1411
  });
1386
1412
  });
@@ -1405,7 +1431,7 @@ describe('Unit test case for ts embed', () => {
1405
1431
  embedType: 'AppEmbed' | 'SearchEmbed',
1406
1432
  showPrimaryNavbar?: boolean,
1407
1433
  overrideOrgId?: number,
1408
- disablePreauthCache?: boolean
1434
+ disablePreauthCache?: boolean,
1409
1435
  ) => {
1410
1436
  jest.spyOn(window, 'addEventListener').mockImplementationOnce(
1411
1437
  (event, handler, options) => {
@@ -1422,18 +1448,23 @@ describe('Unit test case for ts embed', () => {
1422
1448
  let mockGetPreauthInfo = null;
1423
1449
 
1424
1450
  // Determine if preauth cache should be enabled
1425
- const isAppEmbedWithPrimaryNavbar = embedType === 'AppEmbed' && showPrimaryNavbar === true;
1426
- const shouldDisableCache = overrideOrgId || disablePreauthCache || isAppEmbedWithPrimaryNavbar;
1451
+ const isAppEmbedWithPrimaryNavbar =
1452
+ embedType === 'AppEmbed' && showPrimaryNavbar === true;
1453
+ const shouldDisableCache =
1454
+ overrideOrgId || disablePreauthCache || isAppEmbedWithPrimaryNavbar;
1427
1455
 
1428
1456
  if (shouldDisableCache) {
1429
- mockGetPreauthInfo = jest.spyOn(sessionInfoService, 'getPreauthInfo')
1457
+ mockGetPreauthInfo = jest
1458
+ .spyOn(sessionInfoService, 'getPreauthInfo')
1430
1459
  .mockImplementation(jest.fn());
1431
1460
  } else {
1432
- mockGetPreauthInfo = jest.spyOn(sessionInfoService, 'getPreauthInfo')
1433
- .mockResolvedValue({ info: { test: 'data' } } as any);
1461
+ mockGetPreauthInfo = jest
1462
+ .spyOn(sessionInfoService, 'getPreauthInfo')
1463
+ .mockResolvedValue({ info: { test: 'data' } } as any);
1434
1464
  }
1435
1465
 
1436
- const mockPreauthInfoFetch = jest.spyOn(authService, 'fetchPreauthInfoService')
1466
+ const mockPreauthInfoFetch = jest
1467
+ .spyOn(authService, 'fetchPreauthInfoService')
1437
1468
  .mockResolvedValueOnce({
1438
1469
  ok: true,
1439
1470
  headers: new Headers({ 'content-type': 'application/json' }),
@@ -1568,7 +1599,12 @@ describe('Unit test case for ts embed', () => {
1568
1599
  });
1569
1600
 
1570
1601
  test('should disable preauth cache for FullAppEmbed with disablePreauthCache = true', async () => {
1571
- const { mockGetPreauthInfo } = await setupPreauthTest('AppEmbed', false, undefined, true);
1602
+ const { mockGetPreauthInfo } = await setupPreauthTest(
1603
+ 'AppEmbed',
1604
+ false,
1605
+ undefined,
1606
+ true,
1607
+ );
1572
1608
 
1573
1609
  await executeAfterWait(() => {
1574
1610
  expect(mockGetPreauthInfo).toHaveBeenCalledTimes(0);
@@ -1634,9 +1670,12 @@ describe('Unit test case for ts embed', () => {
1634
1670
 
1635
1671
  test('mixpanel should call with VISUAL_SDK_RENDER_FAILED', () => {
1636
1672
  expect(mockMixPanelEvent).toHaveBeenCalledWith(MIXPANEL_EVENT.VISUAL_SDK_RENDER_START);
1637
- expect(mockMixPanelEvent).toHaveBeenCalledWith(MIXPANEL_EVENT.VISUAL_SDK_RENDER_FAILED, {
1638
- error: 'false',
1639
- });
1673
+ expect(mockMixPanelEvent).toHaveBeenCalledWith(
1674
+ MIXPANEL_EVENT.VISUAL_SDK_RENDER_FAILED,
1675
+ {
1676
+ error: 'false',
1677
+ },
1678
+ );
1640
1679
  });
1641
1680
  });
1642
1681
 
@@ -2003,8 +2042,8 @@ describe('Unit test case for ts embed', () => {
2003
2042
  await appEmbed.render();
2004
2043
  expectUrlMatchesWithParams(
2005
2044
  getIFrameSrc(),
2006
- `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}`
2007
- + `&foo=bar&baz=1&bool=true${defaultParamsPost}#/home`,
2045
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}` +
2046
+ `&foo=bar&baz=1&bool=true${defaultParamsPost}#/home`,
2008
2047
  );
2009
2048
  });
2010
2049
 
@@ -2032,8 +2071,8 @@ describe('Unit test case for ts embed', () => {
2032
2071
  await appEmbed.render();
2033
2072
  expectUrlMatchesWithParams(
2034
2073
  getIFrameSrc(),
2035
- `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}`
2036
- + `&foo=bar&foo2=bar2&foo3=false&baz=1&bool=true${defaultParamsPost}#/home`,
2074
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}` +
2075
+ `&foo=bar&foo2=bar2&foo3=false&baz=1&bool=true${defaultParamsPost}#/home`,
2037
2076
  );
2038
2077
  });
2039
2078
 
@@ -2048,8 +2087,8 @@ describe('Unit test case for ts embed', () => {
2048
2087
  await appEmbed.render();
2049
2088
  expectUrlMatchesWithParams(
2050
2089
  getIFrameSrc(),
2051
- `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}`
2052
- + `&showAlerts=true${defaultParamsPost}#/home`,
2090
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}` +
2091
+ `&showAlerts=true${defaultParamsPost}#/home`,
2053
2092
  );
2054
2093
  });
2055
2094
  it('Sets the locale param', async () => {
@@ -2063,8 +2102,8 @@ describe('Unit test case for ts embed', () => {
2063
2102
  await appEmbed.render();
2064
2103
  expectUrlMatchesWithParams(
2065
2104
  getIFrameSrc(),
2066
- `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}`
2067
- + `&locale=ja-JP${defaultParamsPost}#/home`,
2105
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}` +
2106
+ `&locale=ja-JP${defaultParamsPost}#/home`,
2068
2107
  );
2069
2108
  });
2070
2109
  it('Sets both params when enableLinkOverridesV2 is set', async () => {
@@ -2082,7 +2121,7 @@ describe('Unit test case for ts embed', () => {
2082
2121
  `http://${thoughtSpotHost}/?embedApp=true&${defaultParamsForPinboardEmbed}&enableLinkOverridesV2=true&linkOverride=true${defaultParamsPost}#/embed/viz/test-lb`,
2083
2122
  );
2084
2123
  });
2085
- it('Sets only linkOverride when enableLinkOverridesV2 is not set', async () => {
2124
+ it('Auto-upgrades V1 linkOverride to V2 (sends both flags)', async () => {
2086
2125
  const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
2087
2126
  frameParams: {
2088
2127
  width: '100%',
@@ -2092,10 +2131,40 @@ describe('Unit test case for ts embed', () => {
2092
2131
  linkOverride: true,
2093
2132
  });
2094
2133
  await liveboardEmbed.render();
2095
- expectUrlMatchesWithParams(
2096
- getIFrameSrc(),
2097
- `http://${thoughtSpotHost}/?embedApp=true&${defaultParamsForPinboardEmbed}&linkOverride=true${defaultParamsPost}#/embed/viz/test-lb`,
2098
- );
2134
+ const src = getIFrameSrc();
2135
+ expect(src).toContain('linkOverride=true');
2136
+ expect(src).toContain('enableLinkOverridesV2=true');
2137
+ });
2138
+ it('Auto-disables V2 link overrides when disableRedirectionLinksInNewTab is true', async () => {
2139
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
2140
+ frameParams: {
2141
+ width: '100%',
2142
+ height: '100%',
2143
+ },
2144
+ liveboardId: 'test-lb',
2145
+ enableLinkOverridesV2: true,
2146
+ disableRedirectionLinksInNewTab: true,
2147
+ });
2148
+ await liveboardEmbed.render();
2149
+ const src = getIFrameSrc();
2150
+ expect(src).not.toContain('enableLinkOverridesV2=true');
2151
+ expect(src).not.toContain('linkOverride=true');
2152
+ expect(src).toContain('disableRedirectionLinksInNewTab=true');
2153
+ });
2154
+ it('Auto-disables V1 link override when disableRedirectionLinksInNewTab is true', async () => {
2155
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
2156
+ frameParams: {
2157
+ width: '100%',
2158
+ height: '100%',
2159
+ },
2160
+ liveboardId: 'test-lb',
2161
+ linkOverride: true,
2162
+ disableRedirectionLinksInNewTab: true,
2163
+ });
2164
+ await liveboardEmbed.render();
2165
+ const src = getIFrameSrc();
2166
+ expect(src).not.toContain('linkOverride=true');
2167
+ expect(src).toContain('disableRedirectionLinksInNewTab=true');
2099
2168
  });
2100
2169
  it('Sets the iconSprite url', async () => {
2101
2170
  const appEmbed = new AppEmbed(getRootEl(), {
@@ -2110,8 +2179,8 @@ describe('Unit test case for ts embed', () => {
2110
2179
  await appEmbed.render();
2111
2180
  expectUrlMatchesWithParams(
2112
2181
  getIFrameSrc(),
2113
- `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}`
2114
- + `&iconSprite=iconSprite.com${defaultParamsPost}#/home`,
2182
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}` +
2183
+ `&iconSprite=iconSprite.com${defaultParamsPost}#/home`,
2115
2184
  );
2116
2185
  });
2117
2186
 
@@ -2391,8 +2460,9 @@ describe('Unit test case for ts embed', () => {
2391
2460
  tsEmbedDiv.style.height = '100px';
2392
2461
 
2393
2462
  let resizeObserverCb: any;
2394
- (window as any).ResizeObserver = window.ResizeObserver
2395
- || jest.fn().mockImplementation((resizeObserverCbParam) => {
2463
+ (window as any).ResizeObserver =
2464
+ window.ResizeObserver ||
2465
+ jest.fn().mockImplementation((resizeObserverCbParam) => {
2396
2466
  resizeObserverCb = resizeObserverCbParam;
2397
2467
  return {
2398
2468
  disconnect: jest.fn(),
@@ -2406,9 +2476,12 @@ describe('Unit test case for ts embed', () => {
2406
2476
  libEmbed.showPreRender();
2407
2477
  expect(warnSpy).toHaveBeenCalledTimes(1);
2408
2478
 
2479
+ // The ResizeObserver now tracks the placeholder inside this.el,
2480
+ // not this.el itself, so pass it as the target.
2481
+ const preRenderPlaceholder = tsEmbedDiv.firstElementChild as HTMLElement;
2409
2482
  resizeObserverCb([
2410
2483
  {
2411
- target: tsEmbedDiv,
2484
+ target: preRenderPlaceholder,
2412
2485
  contentRect: { height: 297, width: 987 },
2413
2486
  },
2414
2487
  ]);
@@ -2473,8 +2546,9 @@ describe('Unit test case for ts embed', () => {
2473
2546
  it('should set overflow:hidden when hidePreRender and remove when showPreRender', async () => {
2474
2547
  createRootEleForEmbed();
2475
2548
 
2476
- (window as any).ResizeObserver = window.ResizeObserver
2477
- || jest.fn().mockImplementation(() => ({
2549
+ (window as any).ResizeObserver =
2550
+ window.ResizeObserver ||
2551
+ jest.fn().mockImplementation(() => ({
2478
2552
  disconnect: jest.fn(),
2479
2553
  observe: jest.fn(),
2480
2554
  unobserve: jest.fn(),
@@ -2511,8 +2585,9 @@ describe('Unit test case for ts embed', () => {
2511
2585
  it('it should connect with another object', async () => {
2512
2586
  createRootEleForEmbed();
2513
2587
  mockMessageChannel();
2514
- (window as any).ResizeObserver = window.ResizeObserver
2515
- || jest.fn().mockImplementation(() => ({
2588
+ (window as any).ResizeObserver =
2589
+ window.ResizeObserver ||
2590
+ jest.fn().mockImplementation(() => ({
2516
2591
  disconnect: jest.fn(),
2517
2592
  observe: jest.fn(),
2518
2593
  unobserve: jest.fn(),
@@ -2524,7 +2599,6 @@ describe('Unit test case for ts embed', () => {
2524
2599
 
2525
2600
  libEmbed.preRender();
2526
2601
  await waitFor(() => !!getIFrameEl());
2527
- const warnSpy = jest.spyOn(logger, 'warn');
2528
2602
  const newEmbed = new LiveboardEmbed('#tsEmbedDiv', {
2529
2603
  preRenderId: 'i-am-preRendered',
2530
2604
  liveboardId: 'awdawda',
@@ -2532,9 +2606,10 @@ describe('Unit test case for ts embed', () => {
2532
2606
  frameParams: { height: 90 },
2533
2607
  });
2534
2608
 
2535
- newEmbed.showPreRender();
2609
+ await newEmbed.showPreRender();
2536
2610
 
2537
- expect(warnSpy).toHaveBeenCalledTimes(2);
2611
+ // Verify newEmbed successfully connected to the existing preRender
2612
+ expect((newEmbed as any).isPreRenderConnected()).toBe(true);
2538
2613
  });
2539
2614
  it('showPreRender should not preRender if not available', async () => {
2540
2615
  createRootEleForEmbed();
@@ -2711,7 +2786,10 @@ describe('Unit test case for ts embed', () => {
2711
2786
  document.body.innerHTML = getDocumentBody();
2712
2787
  });
2713
2788
  test('Pre-render should wait for init to complete', async () => {
2714
- const lib = new LiveboardEmbed(getRootEl(), { preRenderId: 'test', liveboardId: 'test' });
2789
+ const lib = new LiveboardEmbed(getRootEl(), {
2790
+ preRenderId: 'test',
2791
+ liveboardId: 'test',
2792
+ });
2715
2793
  lib.preRender();
2716
2794
  await executeAfterWait(() => {
2717
2795
  expect(errorSpy).toHaveBeenCalledWith(ERROR_MESSAGE.RENDER_CALLED_BEFORE_INIT);
@@ -2786,10 +2864,12 @@ describe('Unit test case for ts embed', () => {
2786
2864
  jest.clearAllMocks();
2787
2865
  document.body.innerHTML = getDocumentBody();
2788
2866
  mockPort.postMessage.mockClear();
2789
- jest.spyOn(authToken, 'getAuthenticationToken').mockResolvedValue('mock-test-token-placeholder');
2867
+ jest.spyOn(authToken, 'getAuthenticationToken').mockResolvedValue(
2868
+ 'mock-test-token-placeholder',
2869
+ );
2790
2870
 
2791
2871
  jest.spyOn(baseInstance, 'handleAuth').mockImplementation(() => Promise.resolve(true));
2792
- jest.spyOn(baseInstance, 'notifyAuthFailure').mockImplementation(() => { });
2872
+ jest.spyOn(baseInstance, 'notifyAuthFailure').mockImplementation(() => {});
2793
2873
  });
2794
2874
 
2795
2875
  const renderAndTriggerAuthExpire = async () => {
@@ -2902,7 +2982,7 @@ describe('Unit test case for ts embed', () => {
2902
2982
 
2903
2983
  afterEach(() => {
2904
2984
  expect(baseInstance.notifyAuthFailure).toHaveBeenCalledWith(
2905
- authInstance.AuthFailureType.EXPIRY
2985
+ authInstance.AuthFailureType.EXPIRY,
2906
2986
  );
2907
2987
  });
2908
2988
  });
@@ -2915,8 +2995,10 @@ describe('Unit test case for ts embed', () => {
2915
2995
  jest.clearAllMocks();
2916
2996
  document.body.innerHTML = getDocumentBody();
2917
2997
  mockPort.postMessage.mockClear();
2918
- jest.spyOn(authToken, 'getAuthenticationToken').mockResolvedValue('mock-test-token-placeholder');
2919
- jest.spyOn(processData, 'processAuthFailure').mockImplementation(() => ({} as any));
2998
+ jest.spyOn(authToken, 'getAuthenticationToken').mockResolvedValue(
2999
+ 'mock-test-token-placeholder',
3000
+ );
3001
+ jest.spyOn(processData, 'processAuthFailure').mockImplementation(() => ({}) as any);
2920
3002
  jest.spyOn(logger, 'error').mockImplementation(() => {});
2921
3003
  });
2922
3004
 
@@ -2946,7 +3028,7 @@ describe('Unit test case for ts embed', () => {
2946
3028
  await executeAfterWait(() => {
2947
3029
  expect(authToken.getAuthenticationToken).toHaveBeenCalledWith(
2948
3030
  expect.any(Object),
2949
- true
3031
+ true,
2950
3032
  );
2951
3033
  });
2952
3034
  });
@@ -2963,7 +3045,7 @@ describe('Unit test case for ts embed', () => {
2963
3045
  await executeAfterWait(() => {
2964
3046
  expect(authToken.getAuthenticationToken).toHaveBeenCalledWith(
2965
3047
  expect.any(Object),
2966
- true
3048
+ true,
2967
3049
  );
2968
3050
  });
2969
3051
  });
@@ -2998,17 +3080,19 @@ describe('Unit test case for ts embed', () => {
2998
3080
  await executeAfterWait(() => {
2999
3081
  expect(authToken.getAuthenticationToken).toHaveBeenCalledWith(
3000
3082
  expect.any(Object),
3001
- true
3083
+ true,
3002
3084
  );
3003
3085
  // Check that logger.error was called with the token refresh
3004
3086
  // error
3005
3087
  const errorCalls = (logger.error as jest.Mock).mock.calls.filter(
3006
- (call) => call[0]?.includes(ERROR_MESSAGE.INVALID_TOKEN_ERROR) && call[0]?.includes('Token fetch failed')
3088
+ (call) =>
3089
+ call[0]?.includes(ERROR_MESSAGE.INVALID_TOKEN_ERROR) &&
3090
+ call[0]?.includes('Token fetch failed'),
3007
3091
  );
3008
3092
  expect(errorCalls.length).toBeGreaterThan(0);
3009
3093
  expect(processData.processAuthFailure).toHaveBeenCalledWith(
3010
3094
  error,
3011
- expect.any(Element)
3095
+ expect.any(Element),
3012
3096
  );
3013
3097
  expect(mockPort.postMessage).not.toHaveBeenCalled();
3014
3098
  });
@@ -3197,7 +3281,9 @@ describe('Unit test case for ts embed', () => {
3197
3281
  isEmbedContainerLoaded: true,
3198
3282
  };
3199
3283
 
3200
- jest.spyOn(searchEmbed as any, 'getPreRenderObj').mockReturnValue(mockPreRenderObj as any);
3284
+ jest.spyOn(searchEmbed as any, 'getPreRenderObj').mockReturnValue(
3285
+ mockPreRenderObj as any,
3286
+ );
3201
3287
 
3202
3288
  const result = searchEmbed['checkEmbedContainerLoaded']();
3203
3289
 
@@ -3209,8 +3295,8 @@ describe('Unit test case for ts embed', () => {
3209
3295
  const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3210
3296
  const loggerSpy = jest.spyOn(logger, 'info');
3211
3297
 
3212
- // Mock insertedDomEl to have the embed object
3213
- (searchEmbed as any).insertedDomEl = {
3298
+ // getPreRenderObj reads the embed reference from preRenderWrapper
3299
+ (searchEmbed as any).preRenderWrapper = {
3214
3300
  [searchEmbed['embedNodeKey']]: searchEmbed,
3215
3301
  };
3216
3302
 
@@ -3273,7 +3359,8 @@ describe('Unit test case for ts embed', () => {
3273
3359
  const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3274
3360
  searchEmbed.isEmbedContainerLoaded = true;
3275
3361
 
3276
- const triggerSpy = jest.spyOn(searchEmbed, 'trigger')
3362
+ const triggerSpy = jest
3363
+ .spyOn(searchEmbed, 'trigger')
3277
3364
  .mockResolvedValue(mockContext);
3278
3365
 
3279
3366
  const context = await searchEmbed.getCurrentContext();
@@ -3286,7 +3373,8 @@ describe('Unit test case for ts embed', () => {
3286
3373
  const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3287
3374
  searchEmbed.isEmbedContainerLoaded = false;
3288
3375
 
3289
- const triggerSpy = jest.spyOn(searchEmbed, 'trigger')
3376
+ const triggerSpy = jest
3377
+ .spyOn(searchEmbed, 'trigger')
3290
3378
  .mockResolvedValue(mockContext);
3291
3379
 
3292
3380
  const contextPromise = searchEmbed.getCurrentContext();
@@ -3338,7 +3426,9 @@ describe('Unit test case for ts embed', () => {
3338
3426
  test('should handle handleEmbedContainerLoaded with EmbedListenerReady source', () => {
3339
3427
  const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3340
3428
 
3341
- const handler = searchEmbed['createEmbedContainerHandler'](EmbedEvent.EmbedListenerReady);
3429
+ const handler = searchEmbed['createEmbedContainerHandler'](
3430
+ EmbedEvent.EmbedListenerReady,
3431
+ );
3342
3432
 
3343
3433
  expect(searchEmbed.isEmbedContainerLoaded).toBe(false);
3344
3434
 
@@ -3408,7 +3498,7 @@ describe('Unit test case for ts embed', () => {
3408
3498
  new Error('Auth failed'),
3409
3499
  );
3410
3500
  const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3411
- const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
3501
+ const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
3412
3502
  await searchEmbed.render();
3413
3503
  await executeAfterWait(() => {
3414
3504
  expect(getRootEl().innerHTML).toContain('Not logged in');
@@ -3530,11 +3620,13 @@ describe('Unit test case for ts embed', () => {
3530
3620
  await appEmbed.render();
3531
3621
 
3532
3622
  jest.spyOn(appEmbed, 'trigger').mockRejectedValue(new Error('trigger failed'));
3533
- const removeChildSpy = jest.spyOn(Node.prototype, 'removeChild').mockImplementation(() => getRootEl());
3623
+ const removeChildSpy = jest
3624
+ .spyOn(Node.prototype, 'removeChild')
3625
+ .mockImplementation(() => getRootEl());
3534
3626
 
3535
3627
  appEmbed.destroy();
3536
3628
 
3537
- await new Promise(resolve => setTimeout(resolve, 50));
3629
+ await new Promise((resolve) => setTimeout(resolve, 50));
3538
3630
 
3539
3631
  expect(removeChildSpy).toHaveBeenCalled();
3540
3632
 
@@ -3567,7 +3659,9 @@ describe('Unit test case for ts embed', () => {
3567
3659
  await appEmbed.render();
3568
3660
 
3569
3661
  const triggerSpy = jest.spyOn(appEmbed, 'trigger').mockResolvedValue(null);
3570
- const removeChildSpy = jest.spyOn(Node.prototype, 'removeChild').mockImplementation(() => getRootEl());
3662
+ const removeChildSpy = jest
3663
+ .spyOn(Node.prototype, 'removeChild')
3664
+ .mockImplementation(() => getRootEl());
3571
3665
 
3572
3666
  appEmbed.destroy();
3573
3667
 
@@ -3591,7 +3685,9 @@ describe('Unit test case for ts embed', () => {
3591
3685
  await appEmbed.render();
3592
3686
 
3593
3687
  const triggerSpy = jest.spyOn(appEmbed, 'trigger').mockResolvedValue(null);
3594
- const removeChildSpy = jest.spyOn(Node.prototype, 'removeChild').mockImplementation(() => getRootEl());
3688
+ const removeChildSpy = jest
3689
+ .spyOn(Node.prototype, 'removeChild')
3690
+ .mockImplementation(() => getRootEl());
3595
3691
 
3596
3692
  appEmbed.destroy();
3597
3693
 
@@ -3599,7 +3695,7 @@ describe('Unit test case for ts embed', () => {
3599
3695
  expect(triggerSpy).toHaveBeenCalledWith(HostEvent.DestroyEmbed);
3600
3696
 
3601
3697
  // Wait for the timeout to complete
3602
- await new Promise(resolve => setTimeout(resolve, 1100));
3698
+ await new Promise((resolve) => setTimeout(resolve, 1100));
3603
3699
 
3604
3700
  expect(removeChildSpy).toHaveBeenCalled();
3605
3701
  });
@@ -3620,15 +3716,19 @@ describe('Unit test case for ts embed', () => {
3620
3716
  await appEmbed.render();
3621
3717
 
3622
3718
  // Mock trigger to resolve quickly (before timeout)
3623
- const triggerSpy = jest.spyOn(appEmbed, 'trigger').mockImplementation(() =>
3624
- new Promise(resolve => setTimeout(() => resolve(null), 100))
3625
- );
3626
- const removeChildSpy = jest.spyOn(Node.prototype, 'removeChild').mockImplementation(() => getRootEl());
3719
+ const triggerSpy = jest
3720
+ .spyOn(appEmbed, 'trigger')
3721
+ .mockImplementation(
3722
+ () => new Promise((resolve) => setTimeout(() => resolve(null), 100)),
3723
+ );
3724
+ const removeChildSpy = jest
3725
+ .spyOn(Node.prototype, 'removeChild')
3726
+ .mockImplementation(() => getRootEl());
3627
3727
 
3628
3728
  appEmbed.destroy();
3629
3729
 
3630
3730
  // Wait for the trigger to complete
3631
- await new Promise(resolve => setTimeout(resolve, 200));
3731
+ await new Promise((resolve) => setTimeout(resolve, 200));
3632
3732
 
3633
3733
  expect(triggerSpy).toHaveBeenCalledWith(HostEvent.DestroyEmbed);
3634
3734
  expect(removeChildSpy).toHaveBeenCalled();
@@ -3650,15 +3750,19 @@ describe('Unit test case for ts embed', () => {
3650
3750
  await appEmbed.render();
3651
3751
 
3652
3752
  // Mock trigger to take longer than timeout
3653
- const triggerSpy = jest.spyOn(appEmbed, 'trigger').mockImplementation(() =>
3654
- new Promise(resolve => setTimeout(() => resolve(null), 500))
3655
- );
3656
- const removeChildSpy = jest.spyOn(Node.prototype, 'removeChild').mockImplementation(() => getRootEl());
3753
+ const triggerSpy = jest
3754
+ .spyOn(appEmbed, 'trigger')
3755
+ .mockImplementation(
3756
+ () => new Promise((resolve) => setTimeout(() => resolve(null), 500)),
3757
+ );
3758
+ const removeChildSpy = jest
3759
+ .spyOn(Node.prototype, 'removeChild')
3760
+ .mockImplementation(() => getRootEl());
3657
3761
 
3658
3762
  appEmbed.destroy();
3659
3763
 
3660
3764
  // Wait for the timeout to complete
3661
- await new Promise(resolve => setTimeout(resolve, 200));
3765
+ await new Promise((resolve) => setTimeout(resolve, 200));
3662
3766
 
3663
3767
  expect(triggerSpy).toHaveBeenCalledWith(HostEvent.DestroyEmbed);
3664
3768
  expect(removeChildSpy).toHaveBeenCalled();
@@ -3690,11 +3794,11 @@ describe('Unit test case for ts embed', () => {
3690
3794
  body: JSON.stringify({
3691
3795
  variables: {
3692
3796
  session: { sessionId: 'session-123' },
3693
- contextBookId: 'viz-456'
3694
- }
3695
- })
3696
- }
3697
- })
3797
+ contextBookId: 'viz-456',
3798
+ },
3799
+ }),
3800
+ },
3801
+ }),
3698
3802
  };
3699
3803
 
3700
3804
  const mockPort: any = {
@@ -3731,8 +3835,8 @@ describe('Unit test case for ts embed', () => {
3731
3835
  type: EmbedEvent.ApiIntercept,
3732
3836
  data: JSON.stringify({
3733
3837
  input: '/prism/?op=GetChartWithData',
3734
- init: {}
3735
- })
3838
+ init: {},
3839
+ }),
3736
3840
  };
3737
3841
 
3738
3842
  const mockPort: any = {
@@ -3773,8 +3877,8 @@ describe('Unit test case for ts embed', () => {
3773
3877
  type: EmbedEvent.ApiIntercept,
3774
3878
  data: JSON.stringify({
3775
3879
  input: '/prism/?op=GetChartWithData',
3776
- init: {}
3777
- })
3880
+ init: {},
3881
+ }),
3778
3882
  };
3779
3883
 
3780
3884
  const mockPort: any = {
@@ -3796,7 +3900,7 @@ describe('Unit test case for ts embed', () => {
3796
3900
  // handleInterceptEvent
3797
3901
  const result = await capturedGetUnsavedAnswerTml({
3798
3902
  sessionId: 'session-123',
3799
- vizId: 'viz-456'
3903
+ vizId: 'viz-456',
3800
3904
  });
3801
3905
 
3802
3906
  expect(mockProcessTrigger).toHaveBeenCalled();
@@ -3807,8 +3911,8 @@ describe('Unit test case for ts embed', () => {
3807
3911
  type: 'getUnsavedAnswerTML',
3808
3912
  parameters: {
3809
3913
  sessionId: 'session-123',
3810
- vizId: 'viz-456'
3811
- }
3914
+ vizId: 'viz-456',
3915
+ },
3812
3916
  });
3813
3917
  expect(result).toEqual(mockTmlResponse);
3814
3918
  });
@@ -3828,8 +3932,8 @@ describe('Unit test case for ts embed', () => {
3828
3932
  type: EmbedEvent.ApiIntercept,
3829
3933
  data: JSON.stringify({
3830
3934
  input: '/api/test',
3831
- init: {}
3832
- })
3935
+ init: {},
3936
+ }),
3833
3937
  };
3834
3938
 
3835
3939
  const mockPort: any = {
@@ -3858,8 +3962,8 @@ describe('Unit test case for ts embed', () => {
3858
3962
  type: EmbedEvent.ApiIntercept,
3859
3963
  data: JSON.stringify({
3860
3964
  input: '/prism/?op=GetChartWithData',
3861
- init: {}
3862
- })
3965
+ init: {},
3966
+ }),
3863
3967
  };
3864
3968
 
3865
3969
  const mockPort: any = {
@@ -3911,16 +4015,16 @@ describe('Unit test case for ts embed', () => {
3911
4015
  type: EmbedEvent.ApiIntercept,
3912
4016
  data: JSON.stringify({
3913
4017
  input: '/prism/?op=GetChartWithData',
3914
- init: {}
3915
- })
4018
+ init: {},
4019
+ }),
3916
4020
  };
3917
4021
 
3918
4022
  const mockEventData2 = {
3919
4023
  type: EmbedEvent.ApiIntercept,
3920
4024
  data: JSON.stringify({
3921
4025
  input: '/prism/?op=LoadContextBook',
3922
- init: {}
3923
- })
4026
+ init: {},
4027
+ }),
3924
4028
  };
3925
4029
 
3926
4030
  const mockPort: any = {
@@ -3956,8 +4060,8 @@ describe('Unit test case for ts embed', () => {
3956
4060
  type: EmbedEvent.ApiIntercept,
3957
4061
  data: JSON.stringify({
3958
4062
  input: '/prism/?op=GetChartWithData',
3959
- init: {}
3960
- })
4063
+ init: {},
4064
+ }),
3961
4065
  };
3962
4066
 
3963
4067
  const mockPort: any = {
@@ -3997,8 +4101,8 @@ describe('Unit test case for ts embed', () => {
3997
4101
  type: EmbedEvent.ApiIntercept,
3998
4102
  data: JSON.stringify({
3999
4103
  input: '/prism/?op=GetChartWithData',
4000
- init: {}
4001
- })
4104
+ init: {},
4105
+ }),
4002
4106
  };
4003
4107
 
4004
4108
  const mockPort: any = {
@@ -4015,7 +4119,7 @@ describe('Unit test case for ts embed', () => {
4015
4119
 
4016
4120
  const result = await capturedGetUnsavedAnswerTml({
4017
4121
  sessionId: 'session-123',
4018
- vizId: 'viz-456'
4122
+ vizId: 'viz-456',
4019
4123
  });
4020
4124
 
4021
4125
  expect(result).toBeUndefined();
@@ -4033,8 +4137,8 @@ describe('Unit test case for ts embed', () => {
4033
4137
  type: EmbedEvent.ApiIntercept,
4034
4138
  data: JSON.stringify({
4035
4139
  input: '/prism/?op=LoadContextBook',
4036
- init: {}
4037
- })
4140
+ init: {},
4141
+ }),
4038
4142
  };
4039
4143
 
4040
4144
  const mockPort: any = {
@@ -4051,14 +4155,13 @@ describe('Unit test case for ts embed', () => {
4051
4155
  expect(mockHandleInterceptEvent).toHaveBeenCalledWith(
4052
4156
  expect.objectContaining({
4053
4157
  eventData: mockEventData,
4054
- })
4158
+ }),
4055
4159
  );
4056
4160
  });
4057
4161
  });
4058
4162
  });
4059
4163
  });
4060
4164
 
4061
-
4062
4165
  describe('Additional Coverage Tests', () => {
4063
4166
  beforeAll(() => {
4064
4167
  init({
@@ -4163,9 +4266,7 @@ describe('Trigger method edge cases', () => {
4163
4266
  });
4164
4267
 
4165
4268
  test('should return null when trigger is called before iframe is ready', async () => {
4166
- jest.spyOn(baseInstance, 'getAuthPromise').mockRejectedValueOnce(
4167
- new Error('Auth failed'),
4168
- );
4269
+ jest.spyOn(baseInstance, 'getAuthPromise').mockRejectedValueOnce(new Error('Auth failed'));
4169
4270
  const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
4170
4271
  jest.spyOn(logger, 'debug');
4171
4272
  await searchEmbed.render();
@@ -4333,12 +4434,16 @@ describe('Fullscreen change handler behavior', () => {
4333
4434
  });
4334
4435
 
4335
4436
  describe('ShowPreRender with UpdateEmbedParams', () => {
4336
- const setupPreRenderTest = async (preRenderId: string, initialConfig: Partial<LiveboardViewConfig>) => {
4437
+ const setupPreRenderTest = async (
4438
+ preRenderId: string,
4439
+ initialConfig: Partial<LiveboardViewConfig>,
4440
+ ) => {
4337
4441
  createRootEleForEmbed();
4338
4442
  mockMessageChannel();
4339
4443
 
4340
- (window as any).ResizeObserver = window.ResizeObserver
4341
- || jest.fn().mockImplementation(() => ({
4444
+ (window as any).ResizeObserver =
4445
+ window.ResizeObserver ||
4446
+ jest.fn().mockImplementation(() => ({
4342
4447
  disconnect: jest.fn(),
4343
4448
  observe: jest.fn(),
4344
4449
  unobserve: jest.fn(),
@@ -4548,7 +4653,8 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
4548
4653
  });
4549
4654
  });
4550
4655
 
4551
- // Matches the structure produced by createValidationError / embedErrorDetails
4656
+ // Matches the structure produced by createValidationError /
4657
+ // embedErrorDetails
4552
4658
  const makeNestedValidationData = (message = 'invalid payload') => ({
4553
4659
  type: EmbedEvent.Error,
4554
4660
  data: {
@@ -4559,7 +4665,8 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
4559
4665
  },
4560
4666
  });
4561
4667
 
4562
- // Matches the flat structure where errorType sits at the top level of data
4668
+ // Matches the flat structure where errorType sits at the top level of
4669
+ // data
4563
4670
  const makeFlatValidationData = (message = 'invalid payload') => ({
4564
4671
  errorType: EmbedErrorCodes.HOST_EVENT_VALIDATION,
4565
4672
  message,
@@ -4594,12 +4701,13 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
4594
4701
  const embed = makeEmbed({ useHostEventsV2: true, shouldBypassPayloadValidation: true });
4595
4702
  embed.on(EmbedEvent.Error, errorHandler);
4596
4703
 
4597
- (embed as any).executeCallbacks(EmbedEvent.Error, makeNestedValidationData('nested error'));
4704
+ (embed as any).executeCallbacks(
4705
+ EmbedEvent.Error,
4706
+ makeNestedValidationData('nested error'),
4707
+ );
4598
4708
 
4599
4709
  expect(errorHandler).not.toHaveBeenCalled();
4600
- expect(logger.warn).toHaveBeenCalledWith(
4601
- 'Host Event Validation failed: nested error',
4602
- );
4710
+ expect(logger.warn).toHaveBeenCalledWith('Host Event Validation failed: nested error');
4603
4711
  });
4604
4712
 
4605
4713
  test('skips Error event when errorType is resolved from data.errorType (flat format)', () => {
@@ -4615,7 +4723,10 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
4615
4723
 
4616
4724
  test('delivers Error event to handler when useHostEventsV2 is true and shouldBypassPayloadValidation is undefined', () => {
4617
4725
  const errorHandler = jest.fn();
4618
- const embed = makeEmbed({ useHostEventsV2: true, shouldBypassPayloadValidation: undefined });
4726
+ const embed = makeEmbed({
4727
+ useHostEventsV2: true,
4728
+ shouldBypassPayloadValidation: undefined,
4729
+ });
4619
4730
  embed.on(EmbedEvent.Error, errorHandler);
4620
4731
 
4621
4732
  (embed as any).executeCallbacks(EmbedEvent.Error, makeNestedValidationData());
@@ -4625,7 +4736,10 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
4625
4736
 
4626
4737
  test('delivers Error event to handler when useHostEventsV2 is true and shouldBypassPayloadValidation is false', () => {
4627
4738
  const errorHandler = jest.fn();
4628
- const embed = makeEmbed({ useHostEventsV2: true, shouldBypassPayloadValidation: false });
4739
+ const embed = makeEmbed({
4740
+ useHostEventsV2: true,
4741
+ shouldBypassPayloadValidation: false,
4742
+ });
4629
4743
  embed.on(EmbedEvent.Error, errorHandler);
4630
4744
 
4631
4745
  (embed as any).executeCallbacks(EmbedEvent.Error, makeNestedValidationData());
@@ -4636,7 +4750,10 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
4636
4750
  test('skips Error event when useHostEventsV2 is false regardless of shouldBypassPayloadValidation', () => {
4637
4751
  jest.spyOn(logger, 'warn');
4638
4752
  const errorHandler = jest.fn();
4639
- const embed = makeEmbed({ useHostEventsV2: false, shouldBypassPayloadValidation: undefined });
4753
+ const embed = makeEmbed({
4754
+ useHostEventsV2: false,
4755
+ shouldBypassPayloadValidation: undefined,
4756
+ });
4640
4757
  embed.on(EmbedEvent.Error, errorHandler);
4641
4758
 
4642
4759
  (embed as any).executeCallbacks(EmbedEvent.Error, makeNestedValidationData());
@@ -4660,13 +4777,18 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
4660
4777
  test('skips Error event when useHostEventsV2 is false and shouldBypassPayloadValidation is true', () => {
4661
4778
  jest.spyOn(logger, 'warn');
4662
4779
  const errorHandler = jest.fn();
4663
- const embed = makeEmbed({ useHostEventsV2: false, shouldBypassPayloadValidation: true });
4780
+ const embed = makeEmbed({
4781
+ useHostEventsV2: false,
4782
+ shouldBypassPayloadValidation: true,
4783
+ });
4664
4784
  embed.on(EmbedEvent.Error, errorHandler);
4665
4785
 
4666
4786
  (embed as any).executeCallbacks(EmbedEvent.Error, makeNestedValidationData());
4667
4787
 
4668
4788
  expect(errorHandler).not.toHaveBeenCalled();
4669
- expect(logger.warn).toHaveBeenCalledWith('Host Event Validation failed: invalid payload');
4789
+ expect(logger.warn).toHaveBeenCalledWith(
4790
+ 'Host Event Validation failed: invalid payload',
4791
+ );
4670
4792
  });
4671
4793
 
4672
4794
  test('skips via handleError when shouldBypassPayloadValidation is true', () => {
@@ -4691,7 +4813,10 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
4691
4813
 
4692
4814
  test('delivers Error event to EmbedEvent.ALL handler when not skipped', () => {
4693
4815
  const allHandler = jest.fn();
4694
- const embed = makeEmbed({ useHostEventsV2: true, shouldBypassPayloadValidation: false });
4816
+ const embed = makeEmbed({
4817
+ useHostEventsV2: true,
4818
+ shouldBypassPayloadValidation: false,
4819
+ });
4695
4820
  embed.on(EmbedEvent.ALL, allHandler);
4696
4821
 
4697
4822
  (embed as any).executeCallbacks(EmbedEvent.Error, makeNestedValidationData());
@@ -4701,7 +4826,10 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
4701
4826
 
4702
4827
  test('does not skip non-Error events even with HOST_EVENT_VALIDATION error code', () => {
4703
4828
  const customActionHandler = jest.fn();
4704
- const embed = makeEmbed({ useHostEventsV2: true, shouldBypassPayloadValidation: false });
4829
+ const embed = makeEmbed({
4830
+ useHostEventsV2: true,
4831
+ shouldBypassPayloadValidation: false,
4832
+ });
4705
4833
  embed.on(EmbedEvent.CustomAction, customActionHandler);
4706
4834
 
4707
4835
  (embed as any).executeCallbacks(EmbedEvent.CustomAction, {
@@ -4713,7 +4841,10 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
4713
4841
 
4714
4842
  test('does not skip Error events with unrelated error codes', () => {
4715
4843
  const errorHandler = jest.fn();
4716
- const embed = makeEmbed({ useHostEventsV2: true, shouldBypassPayloadValidation: false });
4844
+ const embed = makeEmbed({
4845
+ useHostEventsV2: true,
4846
+ shouldBypassPayloadValidation: false,
4847
+ });
4717
4848
  embed.on(EmbedEvent.Error, errorHandler);
4718
4849
 
4719
4850
  (embed as any).executeCallbacks(EmbedEvent.Error, {
@@ -4724,4 +4855,171 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
4724
4855
  expect(errorHandler).toHaveBeenCalled();
4725
4856
  });
4726
4857
  });
4858
+
4859
+ describe('constructor init-path branching (SCAL-315058)', () => {
4860
+ beforeEach(() => {
4861
+ init({
4862
+ thoughtSpotHost: 'tshost',
4863
+ authType: AuthType.None,
4864
+ });
4865
+ });
4866
+
4867
+ it('sets hostElement from domSelector', () => {
4868
+ const embed = new SearchEmbed(getRootEl(), defaultViewConfig);
4869
+ expect((embed as any).hostElement).toBe(getRootEl());
4870
+ });
4871
+
4872
+ it('skips isReadyForRenderPromise when init already completed', () => {
4873
+ jest.spyOn(baseInstance, 'getIsInitCompleted').mockReturnValue(true);
4874
+ const embed = new SearchEmbed(getRootEl(), defaultViewConfig);
4875
+ expect((embed as any).shouldWaitForRenderPromise).toBe(false);
4876
+ expect((embed as any).isReadyForRenderPromise).toBeUndefined();
4877
+ });
4878
+
4879
+ it('sets isReadyForRenderPromise when init not yet completed', () => {
4880
+ jest.spyOn(baseInstance, 'getIsInitCompleted').mockReturnValue(false);
4881
+ const embed = new SearchEmbed(getRootEl(), defaultViewConfig);
4882
+ expect((embed as any).shouldWaitForRenderPromise).toBe(true);
4883
+ expect((embed as any).isReadyForRenderPromise).toBeInstanceOf(Promise);
4884
+ });
4885
+
4886
+ it('afterInit runs synchronously when init already completed', () => {
4887
+ jest.spyOn(baseInstance, 'getIsInitCompleted').mockReturnValue(true);
4888
+ const embed = new SearchEmbed(getRootEl(), defaultViewConfig);
4889
+ // thoughtSpotHost is set by afterInit;
4890
+ // must be non-empty after constructor
4891
+ expect((embed as any).thoughtSpotHost).toBeTruthy();
4892
+ });
4893
+
4894
+ it('does not set isReadyForRenderPromise when shouldWaitForRenderPromise is false', () => {
4895
+ jest.spyOn(baseInstance, 'getIsInitCompleted').mockReturnValue(true);
4896
+ const embed = new SearchEmbed(getRootEl(), defaultViewConfig);
4897
+ expect((embed as any).shouldWaitForRenderPromise).toBe(false);
4898
+ // isReadyForRenderPromise must be undefined
4899
+ // so no unnecessary await occurs
4900
+ expect((embed as any).isReadyForRenderPromise).toBeUndefined();
4901
+ });
4902
+
4903
+ it('shouldWaitForRenderPromise flips to false after promise settles', async () => {
4904
+ jest.spyOn(baseInstance, 'getIsInitCompleted').mockReturnValue(false);
4905
+ const embed = new SearchEmbed(getRootEl(), defaultViewConfig);
4906
+ expect((embed as any).shouldWaitForRenderPromise).toBe(true);
4907
+ await (embed as any).isReadyForRenderPromise;
4908
+ expect((embed as any).shouldWaitForRenderPromise).toBe(false);
4909
+ });
4910
+
4911
+ it('calls throwInitError when getInitPromise rejects', async () => {
4912
+ jest.spyOn(baseInstance, 'getIsInitCompleted').mockReturnValue(false);
4913
+ jest.spyOn(baseInstance, 'getInitPromise').mockReturnValue(
4914
+ Promise.reject(new Error('init failed')),
4915
+ );
4916
+ const embed = new SearchEmbed(getRootEl(), defaultViewConfig);
4917
+ const throwInitErrorSpy = jest.spyOn(embed as any, 'throwInitError');
4918
+ await (embed as any).isReadyForRenderPromise;
4919
+ expect(throwInitErrorSpy).toHaveBeenCalled();
4920
+ });
4921
+
4922
+ it('shouldWaitForRenderPromise flips to false even when getInitPromise rejects', async () => {
4923
+ jest.spyOn(baseInstance, 'getIsInitCompleted').mockReturnValue(false);
4924
+ jest.spyOn(baseInstance, 'getInitPromise').mockReturnValue(
4925
+ Promise.reject(new Error('init failed')),
4926
+ );
4927
+ const embed = new SearchEmbed(getRootEl(), defaultViewConfig);
4928
+ await (embed as any).isReadyForRenderPromise;
4929
+ expect((embed as any).shouldWaitForRenderPromise).toBe(false);
4930
+ });
4931
+ });
4932
+
4933
+ describe('preRender ID object includes placeHolder (SCAL-315058)', () => {
4934
+ beforeAll(() => {
4935
+ init({
4936
+ thoughtSpotHost: 'tshost',
4937
+ authType: AuthType.None,
4938
+ });
4939
+ });
4940
+
4941
+ it('getPreRenderIds returns placeHolder key', () => {
4942
+ createRootEleForEmbed();
4943
+ const embed = new LiveboardEmbed('#tsEmbedDiv', {
4944
+ preRenderId: 'ph-test',
4945
+ liveboardId: 'lb-id',
4946
+ });
4947
+ const ids = embed.getPreRenderIds();
4948
+ expect(ids.placeHolder).toBe('tsEmbed-pre-render-placeholder-ph-test');
4949
+ });
4950
+ });
4951
+
4952
+ describe('isPreRenderConnected logic (SCAL-315058)', () => {
4953
+ beforeAll(() => {
4954
+ init({
4955
+ thoughtSpotHost: 'tshost',
4956
+ authType: AuthType.None,
4957
+ });
4958
+ });
4959
+
4960
+ it('returns false when preRenderWrapper is absent', () => {
4961
+ createRootEleForEmbed();
4962
+ const embed = new LiveboardEmbed('#tsEmbedDiv', {
4963
+ preRenderId: 'conn-test',
4964
+ liveboardId: 'lb-id',
4965
+ });
4966
+ expect((embed as any).isPreRenderConnected()).toBe(false);
4967
+ });
4968
+
4969
+ it('returns true once preRenderWrapper and preRenderChild are set', () => {
4970
+ createRootEleForEmbed();
4971
+ const embed = new LiveboardEmbed('#tsEmbedDiv', {
4972
+ preRenderId: 'conn-test-2',
4973
+ liveboardId: 'lb-id',
4974
+ });
4975
+ (embed as any).preRenderWrapper = document.createElement('div');
4976
+ (embed as any).preRenderChild = document.createElement('div');
4977
+ expect((embed as any).isPreRenderConnected()).toBe(true);
4978
+ });
4979
+ });
4980
+
4981
+ describe('showPreRender inserts placeholder into hostElement (SCAL-315058)', () => {
4982
+ beforeAll(() => {
4983
+ // Clear spy implementations that may have leaked from prior
4984
+ // describe blocks (e.g. getIsInitCompleted/getInitPromise mocks set
4985
+ // in 'constructor init-path branching' persist across describes
4986
+ // because clearAllMocks only clears call history, not
4987
+ // implementations).
4988
+ jest.restoreAllMocks();
4989
+ jest.spyOn(authInstance, 'postLoginService').mockResolvedValue(undefined);
4990
+ init({
4991
+ thoughtSpotHost: 'tshost',
4992
+ authType: AuthType.None,
4993
+ });
4994
+ (window as any).ResizeObserver = jest.fn().mockImplementation(() => ({
4995
+ disconnect: jest.fn(),
4996
+ observe: jest.fn(),
4997
+ unobserve: jest.fn(),
4998
+ }));
4999
+ });
5000
+
5001
+ it('showPreRender creates a placeholder element with the correct id', async () => {
5002
+ createRootEleForEmbed();
5003
+ const embed = new LiveboardEmbed('#tsEmbedDiv', {
5004
+ preRenderId: 'ph-lifecycle-test',
5005
+ liveboardId: 'lb-id',
5006
+ });
5007
+ await embed.preRender();
5008
+ await waitFor(
5009
+ () => !!document.querySelector('#tsEmbed-pre-render-child-ph-lifecycle-test'),
5010
+ );
5011
+
5012
+ await embed.showPreRender();
5013
+
5014
+ const placeholderEle = (
5015
+ embed as any
5016
+ ).getPreRenderPlaceHolderElement() as HTMLDivElement;
5017
+ expect(placeholderEle).not.toBeNull();
5018
+ expect(placeholderEle.id).toBe('tsEmbed-pre-render-placeholder-ph-lifecycle-test');
5019
+ // placeholder is attached to a parent element (inside hostElement)
5020
+ expect(placeholderEle.parentElement).not.toBeNull();
5021
+
5022
+ embed.destroy();
5023
+ });
5024
+ });
4727
5025
  });