@thoughtspot/visual-embed-sdk 1.39.2-alpha.1 → 1.39.2-alpha.3

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 (171) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/config.spec.js +9 -0
  3. package/cjs/src/config.spec.js.map +1 -1
  4. package/cjs/src/embed/app.d.ts +75 -15
  5. package/cjs/src/embed/app.d.ts.map +1 -1
  6. package/cjs/src/embed/app.js +68 -9
  7. package/cjs/src/embed/app.js.map +1 -1
  8. package/cjs/src/embed/app.spec.js +360 -7
  9. package/cjs/src/embed/app.spec.js.map +1 -1
  10. package/cjs/src/embed/bodyless-conversation.d.ts +19 -7
  11. package/cjs/src/embed/bodyless-conversation.d.ts.map +1 -1
  12. package/cjs/src/embed/bodyless-conversation.js +24 -4
  13. package/cjs/src/embed/bodyless-conversation.js.map +1 -1
  14. package/cjs/src/embed/bodyless-conversation.spec.js +8 -190
  15. package/cjs/src/embed/bodyless-conversation.spec.js.map +1 -1
  16. package/cjs/src/embed/conversation.d.ts +2 -60
  17. package/cjs/src/embed/conversation.d.ts.map +1 -1
  18. package/cjs/src/embed/conversation.js +1 -9
  19. package/cjs/src/embed/conversation.js.map +1 -1
  20. package/cjs/src/embed/conversation.spec.js +0 -102
  21. package/cjs/src/embed/conversation.spec.js.map +1 -1
  22. package/cjs/src/embed/liveboard.d.ts +56 -0
  23. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  24. package/cjs/src/embed/liveboard.js +46 -0
  25. package/cjs/src/embed/liveboard.js.map +1 -1
  26. package/cjs/src/embed/liveboard.spec.js +206 -0
  27. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  28. package/cjs/src/errors.d.ts +1 -0
  29. package/cjs/src/errors.d.ts.map +1 -1
  30. package/cjs/src/errors.js +1 -0
  31. package/cjs/src/errors.js.map +1 -1
  32. package/cjs/src/index.d.ts +2 -2
  33. package/cjs/src/index.d.ts.map +1 -1
  34. package/cjs/src/index.js +2 -1
  35. package/cjs/src/index.js.map +1 -1
  36. package/cjs/src/react/all-types-export.d.ts +1 -1
  37. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  38. package/cjs/src/react/all-types-export.js +3 -2
  39. package/cjs/src/react/all-types-export.js.map +1 -1
  40. package/cjs/src/react/index.d.ts +71 -20
  41. package/cjs/src/react/index.d.ts.map +1 -1
  42. package/cjs/src/react/index.js +79 -42
  43. package/cjs/src/react/index.js.map +1 -1
  44. package/cjs/src/react/index.spec.js +436 -100
  45. package/cjs/src/react/index.spec.js.map +1 -1
  46. package/cjs/src/types.d.ts +46 -4
  47. package/cjs/src/types.d.ts.map +1 -1
  48. package/cjs/src/types.js +28 -0
  49. package/cjs/src/types.js.map +1 -1
  50. package/cjs/src/utils/graphql/nlsService/conversation-service.d.ts.map +1 -1
  51. package/cjs/src/utils/graphql/nlsService/conversation-service.js +2 -0
  52. package/cjs/src/utils/graphql/nlsService/conversation-service.js.map +1 -1
  53. package/cjs/src/utils/processTrigger.js +2 -1
  54. package/cjs/src/utils/processTrigger.js.map +1 -1
  55. package/cjs/src/utils.d.ts +6 -0
  56. package/cjs/src/utils.d.ts.map +1 -1
  57. package/cjs/src/utils.js +23 -3
  58. package/cjs/src/utils.js.map +1 -1
  59. package/cjs/src/utils.spec.js +237 -1
  60. package/cjs/src/utils.spec.js.map +1 -1
  61. package/dist/index-D1pyb7RG.js +7371 -0
  62. package/dist/index-e3Uw3YFO.js +7371 -0
  63. package/dist/src/embed/app.d.ts +75 -15
  64. package/dist/src/embed/app.d.ts.map +1 -1
  65. package/dist/src/embed/bodyless-conversation.d.ts +19 -7
  66. package/dist/src/embed/bodyless-conversation.d.ts.map +1 -1
  67. package/dist/src/embed/conversation.d.ts +2 -60
  68. package/dist/src/embed/conversation.d.ts.map +1 -1
  69. package/dist/src/embed/liveboard.d.ts +56 -0
  70. package/dist/src/embed/liveboard.d.ts.map +1 -1
  71. package/dist/src/errors.d.ts +1 -0
  72. package/dist/src/errors.d.ts.map +1 -1
  73. package/dist/src/index.d.ts +2 -2
  74. package/dist/src/index.d.ts.map +1 -1
  75. package/dist/src/react/all-types-export.d.ts +1 -1
  76. package/dist/src/react/all-types-export.d.ts.map +1 -1
  77. package/dist/src/react/index.d.ts +71 -20
  78. package/dist/src/react/index.d.ts.map +1 -1
  79. package/dist/src/types.d.ts +46 -4
  80. package/dist/src/types.d.ts.map +1 -1
  81. package/dist/src/utils/graphql/nlsService/conversation-service.d.ts.map +1 -1
  82. package/dist/src/utils.d.ts +6 -0
  83. package/dist/src/utils.d.ts.map +1 -1
  84. package/dist/tsembed-react.es.js +276 -74
  85. package/dist/tsembed-react.js +276 -72
  86. package/dist/tsembed.es.js +194 -27
  87. package/dist/tsembed.js +192 -25
  88. package/dist/visual-embed-sdk-react-full.d.ts +246 -105
  89. package/dist/visual-embed-sdk-react.d.ts +246 -105
  90. package/dist/visual-embed-sdk.d.ts +176 -86
  91. package/lib/package.json +1 -1
  92. package/lib/src/config.spec.js +9 -0
  93. package/lib/src/config.spec.js.map +1 -1
  94. package/lib/src/embed/app.d.ts +75 -15
  95. package/lib/src/embed/app.d.ts.map +1 -1
  96. package/lib/src/embed/app.js +68 -9
  97. package/lib/src/embed/app.js.map +1 -1
  98. package/lib/src/embed/app.spec.js +361 -8
  99. package/lib/src/embed/app.spec.js.map +1 -1
  100. package/lib/src/embed/bodyless-conversation.d.ts +19 -7
  101. package/lib/src/embed/bodyless-conversation.d.ts.map +1 -1
  102. package/lib/src/embed/bodyless-conversation.js +23 -4
  103. package/lib/src/embed/bodyless-conversation.js.map +1 -1
  104. package/lib/src/embed/bodyless-conversation.spec.js +9 -191
  105. package/lib/src/embed/bodyless-conversation.spec.js.map +1 -1
  106. package/lib/src/embed/conversation.d.ts +2 -60
  107. package/lib/src/embed/conversation.d.ts.map +1 -1
  108. package/lib/src/embed/conversation.js +2 -10
  109. package/lib/src/embed/conversation.js.map +1 -1
  110. package/lib/src/embed/conversation.spec.js +2 -104
  111. package/lib/src/embed/conversation.spec.js.map +1 -1
  112. package/lib/src/embed/liveboard.d.ts +56 -0
  113. package/lib/src/embed/liveboard.d.ts.map +1 -1
  114. package/lib/src/embed/liveboard.js +47 -1
  115. package/lib/src/embed/liveboard.js.map +1 -1
  116. package/lib/src/embed/liveboard.spec.js +206 -0
  117. package/lib/src/embed/liveboard.spec.js.map +1 -1
  118. package/lib/src/errors.d.ts +1 -0
  119. package/lib/src/errors.d.ts.map +1 -1
  120. package/lib/src/errors.js +1 -0
  121. package/lib/src/errors.js.map +1 -1
  122. package/lib/src/index.d.ts +2 -2
  123. package/lib/src/index.d.ts.map +1 -1
  124. package/lib/src/index.js +2 -2
  125. package/lib/src/index.js.map +1 -1
  126. package/lib/src/react/all-types-export.d.ts +1 -1
  127. package/lib/src/react/all-types-export.d.ts.map +1 -1
  128. package/lib/src/react/all-types-export.js +1 -1
  129. package/lib/src/react/all-types-export.js.map +1 -1
  130. package/lib/src/react/index.d.ts +71 -20
  131. package/lib/src/react/index.d.ts.map +1 -1
  132. package/lib/src/react/index.js +79 -43
  133. package/lib/src/react/index.js.map +1 -1
  134. package/lib/src/react/index.spec.js +439 -103
  135. package/lib/src/react/index.spec.js.map +1 -1
  136. package/lib/src/types.d.ts +46 -4
  137. package/lib/src/types.d.ts.map +1 -1
  138. package/lib/src/types.js +28 -0
  139. package/lib/src/types.js.map +1 -1
  140. package/lib/src/utils/graphql/nlsService/conversation-service.d.ts.map +1 -1
  141. package/lib/src/utils/graphql/nlsService/conversation-service.js +2 -0
  142. package/lib/src/utils/graphql/nlsService/conversation-service.js.map +1 -1
  143. package/lib/src/utils/processTrigger.js +2 -1
  144. package/lib/src/utils/processTrigger.js.map +1 -1
  145. package/lib/src/utils.d.ts +6 -0
  146. package/lib/src/utils.d.ts.map +1 -1
  147. package/lib/src/utils.js +21 -2
  148. package/lib/src/utils.js.map +1 -1
  149. package/lib/src/utils.spec.js +238 -2
  150. package/lib/src/utils.spec.js.map +1 -1
  151. package/lib/src/visual-embed-sdk.d.ts +178 -88
  152. package/package.json +1 -1
  153. package/src/config.spec.ts +11 -0
  154. package/src/embed/app.spec.ts +451 -8
  155. package/src/embed/app.ts +131 -27
  156. package/src/embed/bodyless-conversation.spec.ts +9 -203
  157. package/src/embed/bodyless-conversation.ts +24 -10
  158. package/src/embed/conversation.spec.ts +5 -131
  159. package/src/embed/conversation.ts +10 -82
  160. package/src/embed/liveboard.spec.ts +254 -1
  161. package/src/embed/liveboard.ts +96 -5
  162. package/src/errors.ts +1 -0
  163. package/src/index.ts +2 -0
  164. package/src/react/all-types-export.ts +2 -1
  165. package/src/react/index.spec.tsx +556 -157
  166. package/src/react/index.tsx +117 -51
  167. package/src/types.ts +42 -0
  168. package/src/utils/graphql/nlsService/conversation-service.ts +2 -0
  169. package/src/utils/processTrigger.ts +1 -1
  170. package/src/utils.spec.ts +279 -2
  171. package/src/utils.ts +28 -2
@@ -6,6 +6,7 @@ import {
6
6
  HomePageSearchBarMode,
7
7
  PrimaryNavbarVersion,
8
8
  HomePage,
9
+ ListPage,
9
10
  } from './app';
10
11
  import { init } from '../index';
11
12
  import { Action, AuthType, EmbedEvent, HostEvent, RuntimeFilterOp } from '../types';
@@ -130,7 +131,7 @@ describe('App embed tests', () => {
130
131
  });
131
132
 
132
133
  describe('should render the correct routes for pages', () => {
133
- /* eslint-disable no-loop-func */
134
+
134
135
  const pageRouteMap = {
135
136
  [Page.Search]: 'answer',
136
137
  [Page.Answers]: 'answers',
@@ -147,7 +148,7 @@ describe('App embed tests', () => {
147
148
  const pageId = pageIds[i];
148
149
 
149
150
  test(`${pageId}`, async () => {
150
- const route = pageRouteMap[pageId];
151
+ const route = pageRouteMap[pageId as keyof typeof pageRouteMap];
151
152
  const appEmbed = new AppEmbed(getRootEl(), {
152
153
  ...defaultViewConfig,
153
154
  pageId: pageId as Page,
@@ -180,7 +181,7 @@ describe('App embed tests', () => {
180
181
  const pageIdsForModularHome = pageIdsForModularHomes[i];
181
182
 
182
183
  test(`${pageIdsForModularHome}`, async () => {
183
- const route = pageRouteMap[pageIdsForModularHome];
184
+ const route = pageRouteMapForModularHome[pageIdsForModularHome as keyof typeof pageRouteMapForModularHome];
184
185
  const appEmbed = new AppEmbed(getRootEl(), {
185
186
  ...defaultViewConfig,
186
187
  modularHomeExperience: true,
@@ -624,6 +625,59 @@ describe('App embed tests', () => {
624
625
  });
625
626
  });
626
627
 
628
+ test('Should add listpageVersion=v3 when listPageVersion is ListWithUXChanges to the iframe src', async () => {
629
+ const appEmbed = new AppEmbed(getRootEl(), {
630
+ ...defaultViewConfig,
631
+ discoveryExperience: {
632
+ listPageVersion: ListPage.ListWithUXChanges,
633
+ },
634
+ } as AppViewConfig);
635
+
636
+ appEmbed.render();
637
+ await executeAfterWait(() => {
638
+ expectUrlMatchesWithParams(
639
+ getIFrameSrc(),
640
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false&listpageVersion=v3${defaultParams}${defaultParamsPost}#/home`,
641
+ );
642
+ });
643
+ });
644
+
645
+ test('Should not add listpageVersion when listPageVersion is List (v2) to the iframe src', async () => {
646
+ const appEmbed = new AppEmbed(getRootEl(), {
647
+ ...defaultViewConfig,
648
+ discoveryExperience: {
649
+ listPageVersion: ListPage.List,
650
+ },
651
+ } as AppViewConfig);
652
+
653
+ appEmbed.render();
654
+ await executeAfterWait(() => {
655
+ expectUrlMatchesWithParams(
656
+ getIFrameSrc(),
657
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false${defaultParams}${defaultParamsPost}#/home`,
658
+ );
659
+ });
660
+ });
661
+
662
+ test('Should add listpageVersion=v3 combined with other discoveryExperience options to the iframe src', async () => {
663
+ const appEmbed = new AppEmbed(getRootEl(), {
664
+ ...defaultViewConfig,
665
+ discoveryExperience: {
666
+ primaryNavbarVersion: PrimaryNavbarVersion.Sliding,
667
+ homePage: HomePage.Modular,
668
+ listPageVersion: ListPage.ListWithUXChanges,
669
+ },
670
+ } as AppViewConfig);
671
+
672
+ appEmbed.render();
673
+ await executeAfterWait(() => {
674
+ expectUrlMatchesWithParams(
675
+ getIFrameSrc(),
676
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=true&navigationVersion=v3&listpageVersion=v3${defaultParams}${defaultParamsPost}#/home`,
677
+ );
678
+ });
679
+ });
680
+
627
681
  test('Should add enablePendoHelp flag to the iframe src conditional on navbar', async () => {
628
682
  const appEmbed = new AppEmbed(getRootEl(), {
629
683
  ...defaultViewConfig,
@@ -699,7 +753,7 @@ describe('App embed tests', () => {
699
753
  test('Should add dataPanelCustomGroupsAccordionInitialState flag to the iframe src', async () => {
700
754
  const appEmbed = new AppEmbed(getRootEl(), {
701
755
  ...defaultViewConfig,
702
- // eslint-disable-next-line max-len
756
+
703
757
  dataPanelCustomGroupsAccordionInitialState:
704
758
  DataPanelCustomColumnGroupsAccordionState.EXPAND_FIRST,
705
759
  } as AppViewConfig);
@@ -714,12 +768,13 @@ describe('App embed tests', () => {
714
768
  });
715
769
 
716
770
  test('should register event handlers to adjust iframe height', async () => {
771
+ let embedHeightCallback: any = () => { };
717
772
  const onSpy = jest.spyOn(AppEmbed.prototype, 'on').mockImplementation((event, callback) => {
718
773
  if (event === EmbedEvent.RouteChange) {
719
774
  callback({ data: { currentPath: '/answers' } }, jest.fn());
720
775
  }
721
776
  if (event === EmbedEvent.EmbedHeight) {
722
- callback({ data: '100%' });
777
+ embedHeightCallback = callback;
723
778
  }
724
779
  if (event === EmbedEvent.EmbedIframeCenter) {
725
780
  callback({}, jest.fn());
@@ -731,16 +786,23 @@ describe('App embed tests', () => {
731
786
  const appEmbed = new AppEmbed(getRootEl(), {
732
787
  ...defaultViewConfig,
733
788
  fullHeight: true,
789
+ lazyLoadingForFullHeight: true,
734
790
  } as AppViewConfig);
735
791
 
736
- appEmbed.render();
792
+ // Set the iframe before render
793
+ (appEmbed as any).iFrame = document.createElement('iframe');
737
794
 
795
+ // Wait for render to complete
796
+ await appEmbed.render();
797
+ embedHeightCallback({ data: '100%' });
798
+
799
+ // Verify event handlers were registered
738
800
  await executeAfterWait(() => {
739
801
  expect(onSpy).toHaveBeenCalledWith(EmbedEvent.EmbedHeight, expect.anything());
740
802
  expect(onSpy).toHaveBeenCalledWith(EmbedEvent.RouteChange, expect.anything());
741
803
  expect(onSpy).toHaveBeenCalledWith(EmbedEvent.EmbedIframeCenter, expect.anything());
742
- });
743
- jest.clearAllMocks();
804
+ expect(onSpy).toHaveBeenCalledWith(EmbedEvent.RequestVisibleEmbedCoordinates, expect.anything());
805
+ }, 100);
744
806
  });
745
807
 
746
808
  describe('Navigate to Page API', () => {
@@ -828,4 +890,385 @@ describe('App embed tests', () => {
828
890
  );
829
891
  });
830
892
  });
893
+
894
+ describe('LazyLoadingForFullHeight functionality', () => {
895
+ let mockIFrame: HTMLIFrameElement;
896
+
897
+ beforeEach(() => {
898
+ mockIFrame = document.createElement('iframe');
899
+ mockIFrame.getBoundingClientRect = jest.fn().mockReturnValue({
900
+ top: 100,
901
+ left: 150,
902
+ bottom: 600,
903
+ right: 800,
904
+ width: 650,
905
+ height: 500,
906
+ });
907
+ jest.spyOn(document, 'createElement').mockImplementation((tagName) => {
908
+ if (tagName === 'iframe') {
909
+ return mockIFrame;
910
+ }
911
+ return document.createElement(tagName);
912
+ });
913
+ });
914
+
915
+ afterEach(() => {
916
+ jest.restoreAllMocks();
917
+ });
918
+
919
+ test('should set lazyLoadingMargin parameter when provided', async () => {
920
+ const appEmbed = new AppEmbed(getRootEl(), {
921
+ ...defaultViewConfig,
922
+ fullHeight: true,
923
+ lazyLoadingForFullHeight: true,
924
+ lazyLoadingMargin: '100px 0px',
925
+ } as AppViewConfig);
926
+
927
+ await appEmbed.render();
928
+
929
+ await executeAfterWait(() => {
930
+ const iframeSrc = getIFrameSrc();
931
+ expect(iframeSrc).toContain('isLazyLoadingForEmbedEnabled=true');
932
+ expect(iframeSrc).toContain('isFullHeightPinboard=true');
933
+ expect(iframeSrc).toContain('rootMarginForLazyLoad=100px%200px');
934
+ }, 100);
935
+ });
936
+
937
+ test('should set isLazyLoadingForEmbedEnabled=true when both fullHeight and lazyLoadingForFullHeight are enabled', async () => {
938
+ // Mock the iframe element first
939
+ mockIFrame.getBoundingClientRect = jest.fn().mockReturnValue({
940
+ top: 100,
941
+ left: 150,
942
+ bottom: 600,
943
+ right: 800,
944
+ width: 650,
945
+ height: 500,
946
+ });
947
+ Object.defineProperty(mockIFrame, 'scrollHeight', { value: 500 });
948
+
949
+ // Mock the event handlers
950
+ const onSpy = jest.spyOn(AppEmbed.prototype, 'on').mockImplementation((event, callback) => {
951
+ return null;
952
+ });
953
+ jest.spyOn(TsEmbed.prototype as any, 'getIframeCenter').mockReturnValue({});
954
+ jest.spyOn(TsEmbed.prototype as any, 'setIFrameHeight').mockReturnValue({});
955
+
956
+ // Create the AppEmbed instance
957
+ const appEmbed = new AppEmbed(getRootEl(), {
958
+ ...defaultViewConfig,
959
+ fullHeight: true,
960
+ lazyLoadingForFullHeight: true,
961
+ } as AppViewConfig);
962
+
963
+ // Set the iframe before render
964
+ (appEmbed as any).iFrame = mockIFrame;
965
+
966
+ // Add the iframe to the DOM
967
+ const rootEl = getRootEl();
968
+ rootEl.appendChild(mockIFrame);
969
+
970
+ // Wait for render to complete
971
+ await appEmbed.render();
972
+
973
+ // Wait for iframe initialization and URL parameters to be set
974
+ await executeAfterWait(() => {
975
+ const iframeSrc = appEmbed.getIFrameSrc();
976
+ expect(iframeSrc).toContain('isLazyLoadingForEmbedEnabled=true');
977
+ expect(iframeSrc).toContain('isFullHeightPinboard=true');
978
+ }, 100);
979
+ });
980
+
981
+ test('should not set lazyLoadingForEmbed when lazyLoadingForFullHeight is enabled but fullHeight is false', async () => {
982
+ const appEmbed = new AppEmbed(getRootEl(), {
983
+ ...defaultViewConfig,
984
+ fullHeight: false,
985
+ lazyLoadingForFullHeight: true,
986
+ } as AppViewConfig);
987
+
988
+ // Wait for render to complete
989
+ await appEmbed.render();
990
+
991
+ // Wait for iframe initialization and URL parameters to be set
992
+ await executeAfterWait(() => {
993
+ const iframeSrc = getIFrameSrc();
994
+ expect(iframeSrc).not.toContain('isLazyLoadingForEmbedEnabled=true');
995
+ expect(iframeSrc).not.toContain('isFullHeightPinboard=true');
996
+ }, 100); // 100ms wait time to ensure iframe src is set
997
+ });
998
+
999
+ test('should not set isLazyLoadingForEmbedEnabled when fullHeight is true but lazyLoadingForFullHeight is false', async () => {
1000
+ const appEmbed = new AppEmbed(getRootEl(), {
1001
+ ...defaultViewConfig,
1002
+ fullHeight: true,
1003
+ lazyLoadingForFullHeight: false,
1004
+ } as AppViewConfig);
1005
+
1006
+ // Wait for render to complete
1007
+ await appEmbed.render();
1008
+
1009
+ // Wait for iframe initialization and URL parameters to be set
1010
+ await executeAfterWait(() => {
1011
+ const iframeSrc = getIFrameSrc();
1012
+ expect(iframeSrc).not.toContain('isLazyLoadingForEmbedEnabled=true');
1013
+ expect(iframeSrc).toContain('isFullHeightPinboard=true');
1014
+ }, 100); // 100ms wait time to ensure iframe src is set
1015
+ });
1016
+
1017
+ test('should register RequestFullHeightLazyLoadData event handler when fullHeight is enabled', async () => {
1018
+ const onSpy = jest.spyOn(AppEmbed.prototype, 'on');
1019
+
1020
+ const appEmbed = new AppEmbed(getRootEl(), {
1021
+ ...defaultViewConfig,
1022
+ fullHeight: true,
1023
+ } as AppViewConfig);
1024
+
1025
+ await appEmbed.render();
1026
+
1027
+ expect(onSpy).toHaveBeenCalledWith(EmbedEvent.RequestVisibleEmbedCoordinates, expect.any(Function));
1028
+
1029
+ onSpy.mockRestore();
1030
+ });
1031
+
1032
+ test('should send correct visible data when RequestFullHeightLazyLoadData is triggered', async () => {
1033
+ const appEmbed = new AppEmbed(getRootEl(), {
1034
+ ...defaultViewConfig,
1035
+ fullHeight: true,
1036
+ lazyLoadingForFullHeight: true,
1037
+ } as AppViewConfig);
1038
+
1039
+ const mockTrigger = jest.spyOn(appEmbed, 'trigger');
1040
+
1041
+ await appEmbed.render();
1042
+
1043
+ // Trigger the lazy load data calculation
1044
+ (appEmbed as any).sendFullHeightLazyLoadData();
1045
+
1046
+ expect(mockTrigger).toHaveBeenCalledWith(HostEvent.VisibleEmbedCoordinates, {
1047
+ top: 0,
1048
+ height: 500,
1049
+ left: 0,
1050
+ width: 650,
1051
+ });
1052
+ });
1053
+
1054
+ test('should calculate correct visible data for partially visible full height element', async () => {
1055
+ // Mock iframe partially clipped from top and left
1056
+ mockIFrame.getBoundingClientRect = jest.fn().mockReturnValue({
1057
+ top: -50,
1058
+ left: -30,
1059
+ bottom: 700,
1060
+ right: 1024,
1061
+ width: 1054,
1062
+ height: 750,
1063
+ });
1064
+
1065
+ const appEmbed = new AppEmbed(getRootEl(), {
1066
+ ...defaultViewConfig,
1067
+ fullHeight: true,
1068
+ lazyLoadingForFullHeight: true,
1069
+ } as AppViewConfig);
1070
+
1071
+ const mockTrigger = jest.spyOn(appEmbed, 'trigger');
1072
+
1073
+ await appEmbed.render();
1074
+
1075
+ // Trigger the lazy load data calculation
1076
+ (appEmbed as any).sendFullHeightLazyLoadData();
1077
+
1078
+ expect(mockTrigger).toHaveBeenCalledWith(HostEvent.VisibleEmbedCoordinates, {
1079
+ top: 50, // 50px clipped from top
1080
+ height: 700, // visible height (from 0 to 700)
1081
+ left: 30, // 30px clipped from left
1082
+ width: 1024, // visible width (from 0 to 1024)
1083
+ });
1084
+ });
1085
+
1086
+ test('should add window event listeners for resize and scroll when fullHeight and lazyLoadingForFullHeight are enabled', async () => {
1087
+ const addEventListenerSpy = jest.spyOn(window, 'addEventListener');
1088
+
1089
+ const appEmbed = new AppEmbed(getRootEl(), {
1090
+ ...defaultViewConfig,
1091
+ fullHeight: true,
1092
+ lazyLoadingForFullHeight: true,
1093
+ } as AppViewConfig);
1094
+
1095
+ await appEmbed.render();
1096
+
1097
+ // Wait for the post-render events to be registered
1098
+ await executeAfterWait(() => {
1099
+ expect(addEventListenerSpy).toHaveBeenCalledWith('resize', expect.any(Function));
1100
+ expect(addEventListenerSpy).toHaveBeenCalledWith('scroll', expect.any(Function), true);
1101
+ }, 100);
1102
+
1103
+ addEventListenerSpy.mockRestore();
1104
+ });
1105
+
1106
+ test('should remove window event listeners on destroy when fullHeight and lazyLoadingForFullHeight are enabled', async () => {
1107
+ const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener');
1108
+
1109
+ const appEmbed = new AppEmbed(getRootEl(), {
1110
+ ...defaultViewConfig,
1111
+ fullHeight: true,
1112
+ lazyLoadingForFullHeight: true,
1113
+ } as AppViewConfig);
1114
+
1115
+ await appEmbed.render();
1116
+ appEmbed.destroy();
1117
+
1118
+ expect(removeEventListenerSpy).toHaveBeenCalledWith('resize', expect.any(Function));
1119
+ expect(removeEventListenerSpy).toHaveBeenCalledWith('scroll', expect.any(Function));
1120
+
1121
+ removeEventListenerSpy.mockRestore();
1122
+ });
1123
+
1124
+ test('should handle RequestVisibleEmbedCoordinates event and respond with correct data', async () => {
1125
+ // Mock the iframe element
1126
+ mockIFrame.getBoundingClientRect = jest.fn().mockReturnValue({
1127
+ top: 100,
1128
+ left: 150,
1129
+ bottom: 600,
1130
+ right: 800,
1131
+ width: 650,
1132
+ height: 500,
1133
+ });
1134
+ Object.defineProperty(mockIFrame, 'scrollHeight', { value: 500 });
1135
+
1136
+ const appEmbed = new AppEmbed(getRootEl(), {
1137
+ ...defaultViewConfig,
1138
+ fullHeight: true,
1139
+ lazyLoadingForFullHeight: true,
1140
+ } as AppViewConfig);
1141
+
1142
+ // Set the iframe before render
1143
+ (appEmbed as any).iFrame = mockIFrame;
1144
+
1145
+ await appEmbed.render();
1146
+
1147
+ // Create a mock responder function
1148
+ const mockResponder = jest.fn();
1149
+
1150
+ // Trigger the handler directly
1151
+ (appEmbed as any).requestVisibleEmbedCoordinatesHandler({}, mockResponder);
1152
+
1153
+ // Verify the responder was called with the correct data
1154
+ expect(mockResponder).toHaveBeenCalledWith({
1155
+ type: EmbedEvent.RequestVisibleEmbedCoordinates,
1156
+ data: {
1157
+ top: 0,
1158
+ height: 500,
1159
+ left: 0,
1160
+ width: 650,
1161
+ },
1162
+ });
1163
+ });
1164
+ });
1165
+
1166
+ describe('IFrame height management', () => {
1167
+ let mockIFrame: HTMLIFrameElement;
1168
+
1169
+ beforeEach(() => {
1170
+ mockIFrame = document.createElement('iframe');
1171
+ mockIFrame.getBoundingClientRect = jest.fn().mockReturnValue({
1172
+ top: 100,
1173
+ left: 150,
1174
+ bottom: 600,
1175
+ right: 800,
1176
+ width: 650,
1177
+ height: 500,
1178
+ });
1179
+ Object.defineProperty(mockIFrame, 'scrollHeight', { value: 500 });
1180
+ });
1181
+
1182
+ test('should not call setIFrameHeight if currentPath starts with "/embed/viz/"', () => {
1183
+ const appEmbed = new AppEmbed(getRootEl(), {
1184
+ ...defaultViewConfig,
1185
+ fullHeight: true,
1186
+ } as AppViewConfig) as any;
1187
+ const spySetIFrameHeight = jest.spyOn(appEmbed, 'setIFrameHeight');
1188
+
1189
+ appEmbed.render();
1190
+ appEmbed.setIframeHeightForNonEmbedLiveboard({
1191
+ data: { currentPath: '/embed/viz/' },
1192
+ type: 'Route',
1193
+ });
1194
+
1195
+ expect(spySetIFrameHeight).not.toHaveBeenCalled();
1196
+ });
1197
+
1198
+ test('should not call setIFrameHeight if currentPath starts with "/embed/insights/viz/"', () => {
1199
+ const appEmbed = new AppEmbed(getRootEl(), {
1200
+ ...defaultViewConfig,
1201
+ fullHeight: true,
1202
+ } as AppViewConfig) as any;
1203
+ const spySetIFrameHeight = jest.spyOn(appEmbed, 'setIFrameHeight');
1204
+
1205
+ appEmbed.render();
1206
+ appEmbed.setIframeHeightForNonEmbedLiveboard({
1207
+ data: { currentPath: '/embed/insights/viz/' },
1208
+ type: 'Route',
1209
+ });
1210
+
1211
+ expect(spySetIFrameHeight).not.toHaveBeenCalled();
1212
+ });
1213
+
1214
+ test('should call setIFrameHeight if currentPath starts with "/some/other/path/"', () => {
1215
+ const appEmbed = new AppEmbed(getRootEl(), {
1216
+ ...defaultViewConfig,
1217
+ fullHeight: true,
1218
+ } as AppViewConfig) as any;
1219
+ const spySetIFrameHeight = jest
1220
+ .spyOn(appEmbed, 'setIFrameHeight')
1221
+ .mockImplementation(jest.fn());
1222
+
1223
+ appEmbed.render();
1224
+ appEmbed.setIframeHeightForNonEmbedLiveboard({
1225
+ data: { currentPath: '/some/other/path/' },
1226
+ type: 'Route',
1227
+ });
1228
+
1229
+ expect(spySetIFrameHeight).toHaveBeenCalled();
1230
+ });
1231
+
1232
+ test('should update iframe height correctly', async () => {
1233
+ const appEmbed = new AppEmbed(getRootEl(), {
1234
+ ...defaultViewConfig,
1235
+ fullHeight: true,
1236
+ } as AppViewConfig) as any;
1237
+
1238
+ // Set up the mock iframe
1239
+ appEmbed.iFrame = mockIFrame;
1240
+ document.body.appendChild(mockIFrame);
1241
+
1242
+ await appEmbed.render();
1243
+ const mockEvent = {
1244
+ data: 600,
1245
+ type: EmbedEvent.EmbedHeight,
1246
+ };
1247
+ appEmbed.updateIFrameHeight(mockEvent);
1248
+
1249
+ // Check if the iframe style was updated
1250
+ expect(mockIFrame.style.height).toBe('600px');
1251
+ });
1252
+
1253
+ test('should handle updateIFrameHeight with default height', async () => {
1254
+ const appEmbed = new AppEmbed(getRootEl(), {
1255
+ ...defaultViewConfig,
1256
+ fullHeight: true,
1257
+ } as AppViewConfig) as any;
1258
+
1259
+ // Set up the mock iframe
1260
+ appEmbed.iFrame = mockIFrame;
1261
+ document.body.appendChild(mockIFrame);
1262
+
1263
+ await appEmbed.render();
1264
+ const mockEvent = {
1265
+ data: 0, // This will make it use the scrollHeight
1266
+ type: EmbedEvent.EmbedHeight,
1267
+ };
1268
+ appEmbed.updateIFrameHeight(mockEvent);
1269
+
1270
+ // Should use the scrollHeight
1271
+ expect(mockIFrame.style.height).toBe('500px');
1272
+ });
1273
+ });
831
1274
  });