@thoughtspot/visual-embed-sdk 1.52.2-beta.2 → 1.53.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.
- package/cjs/package.json +1 -1
- package/cjs/src/css-variables.d.ts +373 -5
- package/cjs/src/css-variables.d.ts.map +1 -1
- package/cjs/src/embed/app.d.ts +14 -0
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js +6 -3
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/app.spec.js +28 -0
- package/cjs/src/embed/app.spec.js.map +1 -1
- package/cjs/src/embed/auto-frame-renderer.d.ts.map +1 -1
- package/cjs/src/embed/auto-frame-renderer.js +244 -4
- package/cjs/src/embed/auto-frame-renderer.js.map +1 -1
- package/cjs/src/embed/auto-frame-renderer.spec.js +389 -0
- package/cjs/src/embed/auto-frame-renderer.spec.js.map +1 -1
- package/cjs/src/embed/bodyless-conversation.js +1 -1
- package/cjs/src/embed/bodyless-conversation.js.map +1 -1
- package/cjs/src/embed/conversation.d.ts +15 -0
- package/cjs/src/embed/conversation.d.ts.map +1 -1
- package/cjs/src/embed/conversation.js +7 -3
- package/cjs/src/embed/conversation.js.map +1 -1
- package/cjs/src/embed/conversation.spec.js +66 -0
- package/cjs/src/embed/conversation.spec.js.map +1 -1
- package/cjs/src/embed/liveboard-override-utils.d.ts +59 -0
- package/cjs/src/embed/liveboard-override-utils.d.ts.map +1 -0
- package/cjs/src/embed/liveboard-override-utils.js +19 -0
- package/cjs/src/embed/liveboard-override-utils.js.map +1 -0
- package/cjs/src/embed/liveboard-override-utils.spec.d.ts +2 -0
- package/cjs/src/embed/liveboard-override-utils.spec.d.ts.map +1 -0
- package/cjs/src/embed/liveboard-override-utils.spec.js +34 -0
- package/cjs/src/embed/liveboard-override-utils.spec.js.map +1 -0
- package/cjs/src/embed/liveboard.d.ts +58 -13
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js +11 -34
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/liveboard.spec.js +104 -79
- package/cjs/src/embed/liveboard.spec.js.map +1 -1
- package/cjs/src/embed/search-bar.js +1 -1
- package/cjs/src/embed/search-bar.js.map +1 -1
- package/cjs/src/embed/search.js +1 -1
- package/cjs/src/embed/search.js.map +1 -1
- package/cjs/src/embed/search.spec.js +20 -0
- package/cjs/src/embed/search.spec.js.map +1 -1
- package/cjs/src/embed/spotter-utils.d.ts +11 -0
- package/cjs/src/embed/spotter-utils.d.ts.map +1 -1
- package/cjs/src/embed/spotter-utils.js +13 -1
- package/cjs/src/embed/spotter-utils.js.map +1 -1
- package/cjs/src/embed/spotter-viz-utils.d.ts +15 -0
- package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -1
- package/cjs/src/embed/spotter-viz-utils.js.map +1 -1
- package/cjs/src/embed/spotter-viz-utils.spec.js +11 -0
- package/cjs/src/embed/spotter-viz-utils.spec.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts +27 -34
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +224 -102
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +543 -166
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/index.d.ts +4 -2
- package/cjs/src/index.d.ts.map +1 -1
- package/cjs/src/index.js +4 -2
- package/cjs/src/index.js.map +1 -1
- package/cjs/src/mixpanel-service.d.ts +1 -0
- package/cjs/src/mixpanel-service.d.ts.map +1 -1
- package/cjs/src/mixpanel-service.js +1 -0
- package/cjs/src/mixpanel-service.js.map +1 -1
- package/cjs/src/react/all-types-export.d.ts +1 -1
- package/cjs/src/react/all-types-export.d.ts.map +1 -1
- package/cjs/src/react/all-types-export.js +2 -1
- package/cjs/src/react/all-types-export.js.map +1 -1
- package/cjs/src/types.d.ts +182 -2
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +109 -0
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
- package/cjs/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
- package/cjs/src/utils/graphql/answerService/answer-queries.js +8 -1
- package/cjs/src/utils/graphql/answerService/answer-queries.js.map +1 -1
- package/cjs/src/utils/graphql/answerService/answerService.d.ts +28 -4
- package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/cjs/src/utils/graphql/answerService/answerService.js +39 -4
- package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
- package/cjs/src/utils/graphql/answerService/answerService.spec.js +124 -0
- package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
- package/dist/{index-CnHREfvN.js → index-CyDR8j_0.js} +1 -1
- package/dist/src/css-variables.d.ts +373 -5
- package/dist/src/css-variables.d.ts.map +1 -1
- package/dist/src/embed/app.d.ts +14 -0
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/auto-frame-renderer.d.ts.map +1 -1
- package/dist/src/embed/conversation.d.ts +15 -0
- package/dist/src/embed/conversation.d.ts.map +1 -1
- package/dist/src/embed/liveboard-override-utils.d.ts +59 -0
- package/dist/src/embed/liveboard-override-utils.d.ts.map +1 -0
- package/dist/src/embed/liveboard-override-utils.spec.d.ts +2 -0
- package/dist/src/embed/liveboard-override-utils.spec.d.ts.map +1 -0
- package/dist/src/embed/liveboard.d.ts +58 -13
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/spotter-utils.d.ts +11 -0
- package/dist/src/embed/spotter-utils.d.ts.map +1 -1
- package/dist/src/embed/spotter-viz-utils.d.ts +15 -0
- package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts +27 -34
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
- package/dist/src/index.d.ts +4 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/mixpanel-service.d.ts +1 -0
- package/dist/src/mixpanel-service.d.ts.map +1 -1
- package/dist/src/react/all-types-export.d.ts +1 -1
- package/dist/src/react/all-types-export.d.ts.map +1 -1
- package/dist/src/types.d.ts +182 -2
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
- package/dist/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
- package/dist/src/utils/graphql/answerService/answerService.d.ts +28 -4
- package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/dist/tsembed-react.es.js +437 -191
- package/dist/tsembed-react.js +436 -190
- package/dist/tsembed.es.js +680 -196
- package/dist/tsembed.js +678 -194
- package/dist/visual-embed-sdk-react-full.d.ts +702 -56
- package/dist/visual-embed-sdk-react.d.ts +697 -56
- package/dist/visual-embed-sdk.d.ts +744 -57
- package/lib/package.json +1 -1
- package/lib/src/css-variables.d.ts +373 -5
- package/lib/src/css-variables.d.ts.map +1 -1
- package/lib/src/embed/app.d.ts +14 -0
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +7 -4
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +28 -0
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/auto-frame-renderer.d.ts.map +1 -1
- package/lib/src/embed/auto-frame-renderer.js +244 -4
- package/lib/src/embed/auto-frame-renderer.js.map +1 -1
- package/lib/src/embed/auto-frame-renderer.spec.js +389 -0
- package/lib/src/embed/auto-frame-renderer.spec.js.map +1 -1
- package/lib/src/embed/bodyless-conversation.js +1 -1
- package/lib/src/embed/bodyless-conversation.js.map +1 -1
- package/lib/src/embed/conversation.d.ts +15 -0
- package/lib/src/embed/conversation.d.ts.map +1 -1
- package/lib/src/embed/conversation.js +8 -4
- package/lib/src/embed/conversation.js.map +1 -1
- package/lib/src/embed/conversation.spec.js +67 -1
- package/lib/src/embed/conversation.spec.js.map +1 -1
- package/lib/src/embed/liveboard-override-utils.d.ts +59 -0
- package/lib/src/embed/liveboard-override-utils.d.ts.map +1 -0
- package/lib/src/embed/liveboard-override-utils.js +15 -0
- package/lib/src/embed/liveboard-override-utils.js.map +1 -0
- package/lib/src/embed/liveboard-override-utils.spec.d.ts +2 -0
- package/lib/src/embed/liveboard-override-utils.spec.d.ts.map +1 -0
- package/lib/src/embed/liveboard-override-utils.spec.js +32 -0
- package/lib/src/embed/liveboard-override-utils.spec.js.map +1 -0
- package/lib/src/embed/liveboard.d.ts +58 -13
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +11 -33
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +104 -79
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/search-bar.js +1 -1
- package/lib/src/embed/search-bar.js.map +1 -1
- package/lib/src/embed/search.js +1 -1
- package/lib/src/embed/search.js.map +1 -1
- package/lib/src/embed/search.spec.js +20 -0
- package/lib/src/embed/search.spec.js.map +1 -1
- package/lib/src/embed/spotter-utils.d.ts +11 -0
- package/lib/src/embed/spotter-utils.d.ts.map +1 -1
- package/lib/src/embed/spotter-utils.js +12 -0
- package/lib/src/embed/spotter-utils.js.map +1 -1
- package/lib/src/embed/spotter-viz-utils.d.ts +15 -0
- package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -1
- package/lib/src/embed/spotter-viz-utils.js.map +1 -1
- package/lib/src/embed/spotter-viz-utils.spec.js +11 -0
- package/lib/src/embed/spotter-viz-utils.spec.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts +27 -34
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +224 -102
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +544 -167
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/index.d.ts +4 -2
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js +3 -2
- package/lib/src/index.js.map +1 -1
- package/lib/src/mixpanel-service.d.ts +1 -0
- package/lib/src/mixpanel-service.d.ts.map +1 -1
- package/lib/src/mixpanel-service.js +1 -0
- package/lib/src/mixpanel-service.js.map +1 -1
- package/lib/src/react/all-types-export.d.ts +1 -1
- package/lib/src/react/all-types-export.d.ts.map +1 -1
- package/lib/src/react/all-types-export.js +1 -1
- package/lib/src/react/all-types-export.js.map +1 -1
- package/lib/src/types.d.ts +182 -2
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +109 -0
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
- package/lib/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
- package/lib/src/utils/graphql/answerService/answer-queries.js +7 -0
- package/lib/src/utils/graphql/answerService/answer-queries.js.map +1 -1
- package/lib/src/utils/graphql/answerService/answerService.d.ts +28 -4
- package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/lib/src/utils/graphql/answerService/answerService.js +39 -4
- package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
- package/lib/src/utils/graphql/answerService/answerService.spec.js +125 -1
- package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +744 -57
- package/package.json +1 -1
- package/src/css-variables.ts +475 -26
- package/src/embed/app.spec.ts +32 -0
- package/src/embed/app.ts +28 -4
- package/src/embed/auto-frame-renderer.spec.ts +464 -0
- package/src/embed/auto-frame-renderer.ts +305 -6
- package/src/embed/bodyless-conversation.ts +1 -1
- package/src/embed/conversation.spec.ts +94 -1
- package/src/embed/conversation.ts +28 -3
- package/src/embed/liveboard-override-utils.spec.ts +38 -0
- package/src/embed/liveboard-override-utils.ts +71 -0
- package/src/embed/liveboard.spec.ts +119 -92
- package/src/embed/liveboard.ts +56 -40
- package/src/embed/search-bar.tsx +1 -1
- package/src/embed/search.spec.ts +23 -0
- package/src/embed/search.ts +1 -1
- package/src/embed/spotter-utils.ts +12 -0
- package/src/embed/spotter-viz-utils.spec.ts +11 -0
- package/src/embed/spotter-viz-utils.ts +15 -0
- package/src/embed/ts-embed.spec.ts +685 -207
- package/src/embed/ts-embed.ts +227 -97
- package/src/index.ts +16 -1
- package/src/mixpanel-service.ts +1 -0
- package/src/react/all-types-export.ts +6 -0
- package/src/types.ts +186 -5
- package/src/utils/graphql/answerService/answer-queries.ts +8 -0
- package/src/utils/graphql/answerService/answerService.spec.ts +145 -1
- package/src/utils/graphql/answerService/answerService.ts +65 -3
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
import * as config from '../config';
|
|
54
54
|
import * as embedConfig from './embedConfig';
|
|
55
55
|
import * as tsEmbedInstance from './ts-embed';
|
|
56
|
+
import { BOOTSTRAP_URL_PARAMS } from './ts-embed';
|
|
56
57
|
import * as mixpanelInstance from '../mixpanel-service';
|
|
57
58
|
import * as authInstance from '../auth';
|
|
58
59
|
import * as baseInstance from './base';
|
|
@@ -1312,6 +1313,34 @@ describe('Unit test case for ts embed', () => {
|
|
|
1312
1313
|
);
|
|
1313
1314
|
});
|
|
1314
1315
|
|
|
1316
|
+
test('should send visual-sdk-init-actions with configured actions, [] when unused', async () => {
|
|
1317
|
+
await new SearchEmbed(getRootEl(), {
|
|
1318
|
+
hiddenActions: [Action.Download],
|
|
1319
|
+
disabledActions: [Action.Edit],
|
|
1320
|
+
}).render();
|
|
1321
|
+
expect(mockMixPanelEvent).toHaveBeenCalledWith(
|
|
1322
|
+
MIXPANEL_EVENT.VISUAL_SDK_INIT_ACTIONS,
|
|
1323
|
+
expect.objectContaining({
|
|
1324
|
+
hiddenActions: [Action.Download],
|
|
1325
|
+
visibleActions: [],
|
|
1326
|
+
disabledActions: [Action.Edit],
|
|
1327
|
+
}),
|
|
1328
|
+
);
|
|
1329
|
+
|
|
1330
|
+
mockMixPanelEvent.mockClear();
|
|
1331
|
+
await new SearchEmbed(getRootEl(), {
|
|
1332
|
+
visibleActions: [Action.Save],
|
|
1333
|
+
}).render();
|
|
1334
|
+
expect(mockMixPanelEvent).toHaveBeenCalledWith(
|
|
1335
|
+
MIXPANEL_EVENT.VISUAL_SDK_INIT_ACTIONS,
|
|
1336
|
+
expect.objectContaining({
|
|
1337
|
+
hiddenActions: [],
|
|
1338
|
+
visibleActions: [Action.Save],
|
|
1339
|
+
disabledActions: [],
|
|
1340
|
+
}),
|
|
1341
|
+
);
|
|
1342
|
+
});
|
|
1343
|
+
|
|
1315
1344
|
test('Should remove prefetch iframe', async () => {
|
|
1316
1345
|
await setup(true);
|
|
1317
1346
|
const prefetchIframe = document.querySelectorAll<HTMLIFrameElement>('.prefetchIframe');
|
|
@@ -2549,6 +2578,85 @@ describe('Unit test case for ts embed', () => {
|
|
|
2549
2578
|
});
|
|
2550
2579
|
});
|
|
2551
2580
|
|
|
2581
|
+
describe('isDarkMode', () => {
|
|
2582
|
+
const renderAppEmbed = async (viewConfig = {}) => {
|
|
2583
|
+
const appEmbed = new AppEmbed(getRootEl(), {
|
|
2584
|
+
frameParams: {
|
|
2585
|
+
width: '100%',
|
|
2586
|
+
height: '100%',
|
|
2587
|
+
},
|
|
2588
|
+
...viewConfig,
|
|
2589
|
+
});
|
|
2590
|
+
appEmbed.render();
|
|
2591
|
+
await waitFor(() => !!getIFrameEl());
|
|
2592
|
+
return getIFrameSrc();
|
|
2593
|
+
};
|
|
2594
|
+
|
|
2595
|
+
it('sends the appearance the host asked for in init, with the radiant theme', async () => {
|
|
2596
|
+
init({
|
|
2597
|
+
thoughtSpotHost: 'tshost',
|
|
2598
|
+
authType: AuthType.None,
|
|
2599
|
+
isDarkMode: true,
|
|
2600
|
+
});
|
|
2601
|
+
|
|
2602
|
+
expectUrlToHaveParamsWithValues(await renderAppEmbed(), {
|
|
2603
|
+
isDarkMode: true,
|
|
2604
|
+
radiantThemeEnabled: true,
|
|
2605
|
+
});
|
|
2606
|
+
});
|
|
2607
|
+
|
|
2608
|
+
it('sends an explicit false', async () => {
|
|
2609
|
+
init({
|
|
2610
|
+
thoughtSpotHost: 'tshost',
|
|
2611
|
+
authType: AuthType.None,
|
|
2612
|
+
isDarkMode: false,
|
|
2613
|
+
});
|
|
2614
|
+
|
|
2615
|
+
const src = await renderAppEmbed();
|
|
2616
|
+
expectUrlToHaveParamsWithValues(src, { isDarkMode: false });
|
|
2617
|
+
// `false` leaves the radiant theme to the cluster.
|
|
2618
|
+
expect(src).not.toContain('radiantThemeEnabled=');
|
|
2619
|
+
});
|
|
2620
|
+
|
|
2621
|
+
it('omits the param when the host says nothing', async () => {
|
|
2622
|
+
init({
|
|
2623
|
+
thoughtSpotHost: 'tshost',
|
|
2624
|
+
authType: AuthType.None,
|
|
2625
|
+
});
|
|
2626
|
+
|
|
2627
|
+
// Absent rather than `isDarkMode=false`: an omitted param keeps the
|
|
2628
|
+
// URL short, and the app treats a missing param like `false`.
|
|
2629
|
+
const src = await renderAppEmbed();
|
|
2630
|
+
expect(src).not.toContain('isDarkMode=');
|
|
2631
|
+
expect(src).not.toContain('radiantThemeEnabled=');
|
|
2632
|
+
});
|
|
2633
|
+
|
|
2634
|
+
it('lets the view config override the value set in init', async () => {
|
|
2635
|
+
init({
|
|
2636
|
+
thoughtSpotHost: 'tshost',
|
|
2637
|
+
authType: AuthType.None,
|
|
2638
|
+
isDarkMode: true,
|
|
2639
|
+
});
|
|
2640
|
+
|
|
2641
|
+
const src = await renderAppEmbed({ isDarkMode: false });
|
|
2642
|
+
expectUrlToHaveParamsWithValues(src, { isDarkMode: false });
|
|
2643
|
+
expect(src).not.toContain('radiantThemeEnabled=');
|
|
2644
|
+
});
|
|
2645
|
+
|
|
2646
|
+
it('lets additionalFlags override the radiant theme it turns on', async () => {
|
|
2647
|
+
init({
|
|
2648
|
+
thoughtSpotHost: 'tshost',
|
|
2649
|
+
authType: AuthType.None,
|
|
2650
|
+
isDarkMode: true,
|
|
2651
|
+
});
|
|
2652
|
+
|
|
2653
|
+
expectUrlToHaveParamsWithValues(
|
|
2654
|
+
await renderAppEmbed({ additionalFlags: { radiantThemeEnabled: false } }),
|
|
2655
|
+
{ isDarkMode: true, radiantThemeEnabled: false },
|
|
2656
|
+
);
|
|
2657
|
+
});
|
|
2658
|
+
});
|
|
2659
|
+
|
|
2552
2660
|
describe('validate preRender flow', () => {
|
|
2553
2661
|
beforeAll(() => {
|
|
2554
2662
|
init({
|
|
@@ -2620,11 +2728,12 @@ describe('Unit test case for ts embed', () => {
|
|
|
2620
2728
|
contentRect: { height: 297, width: 987 },
|
|
2621
2729
|
},
|
|
2622
2730
|
]);
|
|
2731
|
+
|
|
2623
2732
|
expect(preRenderWrapper.style.height).toEqual(`${297}px`);
|
|
2624
2733
|
expect(preRenderWrapper.style.width).toEqual(`${987}px`);
|
|
2625
2734
|
|
|
2626
2735
|
expect(preRenderWrapper.style.opacity).toBe('');
|
|
2627
|
-
expect(preRenderWrapper.style.pointerEvents).toBe('
|
|
2736
|
+
expect(preRenderWrapper.style.pointerEvents).toBe('');
|
|
2628
2737
|
expect(preRenderWrapper.style.zIndex).toBe('');
|
|
2629
2738
|
|
|
2630
2739
|
libEmbed.hidePreRender();
|
|
@@ -2661,7 +2770,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
2661
2770
|
const preRenderWrapper = document.getElementById(preRenderIds.wrapper);
|
|
2662
2771
|
|
|
2663
2772
|
expect(preRenderWrapper.style.opacity).toBe('');
|
|
2664
|
-
expect(preRenderWrapper.style.pointerEvents).toBe('
|
|
2773
|
+
expect(preRenderWrapper.style.pointerEvents).toBe('');
|
|
2665
2774
|
expect(preRenderWrapper.style.zIndex).toBe('');
|
|
2666
2775
|
});
|
|
2667
2776
|
|
|
@@ -2834,211 +2943,6 @@ describe('Unit test case for ts embed', () => {
|
|
|
2834
2943
|
(logger.debug as any).mockRestore();
|
|
2835
2944
|
});
|
|
2836
2945
|
|
|
2837
|
-
describe('position tracking (SCAL-338563)', () => {
|
|
2838
|
-
/**
|
|
2839
|
-
* A host app whose page scrolls in an inner element rather than the
|
|
2840
|
-
* document — the shape both reported cases have. The placeholder's
|
|
2841
|
-
* rect is driven off that element's scrollTop, the way a real
|
|
2842
|
-
* layout would move it.
|
|
2843
|
-
*/
|
|
2844
|
-
const mountInNestedScroller = () => {
|
|
2845
|
-
createRootEleForEmbed();
|
|
2846
|
-
const scroller = document.createElement('div');
|
|
2847
|
-
scroller.id = 'inner-scroller';
|
|
2848
|
-
document.body.appendChild(scroller);
|
|
2849
|
-
scroller.appendChild(document.getElementById('tsEmbedDiv'));
|
|
2850
|
-
|
|
2851
|
-
let scrollTop = 0;
|
|
2852
|
-
Object.defineProperty(scroller, 'scrollTop', {
|
|
2853
|
-
configurable: true,
|
|
2854
|
-
get: () => scrollTop,
|
|
2855
|
-
set: (value) => {
|
|
2856
|
-
scrollTop = value;
|
|
2857
|
-
},
|
|
2858
|
-
});
|
|
2859
|
-
scroller.getBoundingClientRect = () =>
|
|
2860
|
-
({
|
|
2861
|
-
x: 0, y: 0, width: 800, height: 600,
|
|
2862
|
-
top: 0, left: 0, bottom: 600, right: 800,
|
|
2863
|
-
} as DOMRect);
|
|
2864
|
-
|
|
2865
|
-
const placeholderTopAtRest = 400;
|
|
2866
|
-
const readPlaceholderTop = () => placeholderTopAtRest - scroller.scrollTop;
|
|
2867
|
-
|
|
2868
|
-
return { scroller, readPlaceholderTop };
|
|
2869
|
-
};
|
|
2870
|
-
|
|
2871
|
-
const stubPlaceholderRect = (embed: any, readTop: () => number) => {
|
|
2872
|
-
const placeholder = embed.getPreRenderPlaceHolderElement() as HTMLElement;
|
|
2873
|
-
placeholder.getBoundingClientRect = () => {
|
|
2874
|
-
const top = readTop();
|
|
2875
|
-
return {
|
|
2876
|
-
x: 0, y: top, width: 800, height: 300,
|
|
2877
|
-
top, left: 0, bottom: top + 300, right: 800,
|
|
2878
|
-
} as DOMRect;
|
|
2879
|
-
};
|
|
2880
|
-
return placeholder;
|
|
2881
|
-
};
|
|
2882
|
-
|
|
2883
|
-
it('should stop observing the placeholder once the frame is hidden', async () => {
|
|
2884
|
-
const { scroller } = mountInNestedScroller();
|
|
2885
|
-
|
|
2886
|
-
const libEmbed = new LiveboardEmbed('#tsEmbedDiv', {
|
|
2887
|
-
preRenderId: 'observer-stops-on-hide',
|
|
2888
|
-
liveboardId: 'myLiveboardId',
|
|
2889
|
-
});
|
|
2890
|
-
libEmbed.preRender();
|
|
2891
|
-
await waitFor(() => !!getIFrameEl());
|
|
2892
|
-
await libEmbed.showPreRender();
|
|
2893
|
-
|
|
2894
|
-
// Size is the only thing the browser will not handle for us, so
|
|
2895
|
-
// the observer is the one live resource a hide has to release.
|
|
2896
|
-
const observer = (libEmbed as any).resizeObserver;
|
|
2897
|
-
expect(observer).toBeDefined();
|
|
2898
|
-
const disconnectSpy = jest.spyOn(observer, 'disconnect');
|
|
2899
|
-
|
|
2900
|
-
libEmbed.hidePreRender();
|
|
2901
|
-
|
|
2902
|
-
expect(disconnectSpy).toHaveBeenCalled();
|
|
2903
|
-
|
|
2904
|
-
disconnectSpy.mockRestore();
|
|
2905
|
-
libEmbed.destroy();
|
|
2906
|
-
scroller.remove();
|
|
2907
|
-
});
|
|
2908
|
-
|
|
2909
|
-
it('should default the container to the host scrolling ancestor', async () => {
|
|
2910
|
-
const { scroller } = mountInNestedScroller();
|
|
2911
|
-
scroller.style.overflowY = 'auto';
|
|
2912
|
-
|
|
2913
|
-
const libEmbed = new LiveboardEmbed('#tsEmbedDiv', {
|
|
2914
|
-
preRenderId: 'auto-scroll-container',
|
|
2915
|
-
liveboardId: 'myLiveboardId',
|
|
2916
|
-
});
|
|
2917
|
-
libEmbed.preRender();
|
|
2918
|
-
await waitFor(() => !!getIFrameEl());
|
|
2919
|
-
await libEmbed.showPreRender();
|
|
2920
|
-
|
|
2921
|
-
const wrapper = document.getElementById(libEmbed.getPreRenderIds().wrapper);
|
|
2922
|
-
// In the scroller, so the browser moves it — no repositioning.
|
|
2923
|
-
expect(wrapper.parentElement).toBe(scroller);
|
|
2924
|
-
expect((libEmbed as any).preRenderContainerEl).toBe(scroller);
|
|
2925
|
-
|
|
2926
|
-
libEmbed.destroy();
|
|
2927
|
-
scroller.remove();
|
|
2928
|
-
});
|
|
2929
|
-
|
|
2930
|
-
it('should still use document.body when nothing scrolls', async () => {
|
|
2931
|
-
createRootEleForEmbed();
|
|
2932
|
-
|
|
2933
|
-
const libEmbed = new LiveboardEmbed('#tsEmbedDiv', {
|
|
2934
|
-
preRenderId: 'no-scroller-body',
|
|
2935
|
-
liveboardId: 'myLiveboardId',
|
|
2936
|
-
});
|
|
2937
|
-
libEmbed.preRender();
|
|
2938
|
-
await waitFor(() => !!getIFrameEl());
|
|
2939
|
-
await libEmbed.showPreRender();
|
|
2940
|
-
|
|
2941
|
-
const wrapper = document.getElementById(libEmbed.getPreRenderIds().wrapper);
|
|
2942
|
-
expect(wrapper.parentElement).toBe(document.body);
|
|
2943
|
-
|
|
2944
|
-
libEmbed.destroy();
|
|
2945
|
-
});
|
|
2946
|
-
|
|
2947
|
-
it('should set pointer-events on show rather than dropping the property', async () => {
|
|
2948
|
-
createRootEleForEmbed();
|
|
2949
|
-
const container = document.createElement('div');
|
|
2950
|
-
container.id = 'parking-root';
|
|
2951
|
-
// Usual styling for a parking root: no swallowed clicks.
|
|
2952
|
-
container.style.pointerEvents = 'none';
|
|
2953
|
-
document.body.appendChild(container);
|
|
2954
|
-
|
|
2955
|
-
const libEmbed = new LiveboardEmbed('#tsEmbedDiv', {
|
|
2956
|
-
preRenderId: 'pointer-events-restored',
|
|
2957
|
-
liveboardId: 'myLiveboardId',
|
|
2958
|
-
preRenderContainer: '#parking-root',
|
|
2959
|
-
});
|
|
2960
|
-
libEmbed.preRender();
|
|
2961
|
-
await waitFor(() => !!getIFrameEl());
|
|
2962
|
-
await libEmbed.showPreRender();
|
|
2963
|
-
|
|
2964
|
-
const wrapper = document.getElementById(libEmbed.getPreRenderIds().wrapper);
|
|
2965
|
-
// Merely removing the property would leave the container's
|
|
2966
|
-
// inherited `none` in force, and the frame dead to input.
|
|
2967
|
-
expect(wrapper.style.pointerEvents).toBe('auto');
|
|
2968
|
-
|
|
2969
|
-
libEmbed.destroy();
|
|
2970
|
-
container.remove();
|
|
2971
|
-
});
|
|
2972
|
-
|
|
2973
|
-
it('should park a hidden wrapper out of the scrollable area', async () => {
|
|
2974
|
-
createRootEleForEmbed();
|
|
2975
|
-
|
|
2976
|
-
const libEmbed = new LiveboardEmbed('#tsEmbedDiv', {
|
|
2977
|
-
preRenderId: 'hidden-parked',
|
|
2978
|
-
liveboardId: 'myLiveboardId',
|
|
2979
|
-
});
|
|
2980
|
-
libEmbed.preRender();
|
|
2981
|
-
await waitFor(() => !!getIFrameEl());
|
|
2982
|
-
await libEmbed.showPreRender();
|
|
2983
|
-
|
|
2984
|
-
const wrapper = document.getElementById(libEmbed.getPreRenderIds().wrapper);
|
|
2985
|
-
expect(wrapper.style.transform).toBe('');
|
|
2986
|
-
|
|
2987
|
-
libEmbed.hidePreRender();
|
|
2988
|
-
expect(wrapper.style.transform).toBe('translateY(-100%)');
|
|
2989
|
-
|
|
2990
|
-
await libEmbed.showPreRender();
|
|
2991
|
-
expect(wrapper.style.transform).toBe('');
|
|
2992
|
-
|
|
2993
|
-
libEmbed.destroy();
|
|
2994
|
-
});
|
|
2995
|
-
|
|
2996
|
-
it('should not seed the placeholder with the unmeasured wrapper height', async () => {
|
|
2997
|
-
createRootEleForEmbed();
|
|
2998
|
-
|
|
2999
|
-
const libEmbed = new LiveboardEmbed('#tsEmbedDiv', {
|
|
3000
|
-
preRenderId: 'unmeasured-height',
|
|
3001
|
-
liveboardId: 'myLiveboardId',
|
|
3002
|
-
fullHeight: true,
|
|
3003
|
-
frameParams: { height: 420 },
|
|
3004
|
-
});
|
|
3005
|
-
libEmbed.preRender();
|
|
3006
|
-
await waitFor(() => !!getIFrameEl());
|
|
3007
|
-
|
|
3008
|
-
const wrapper = document.getElementById(libEmbed.getPreRenderIds().wrapper);
|
|
3009
|
-
// createPreRenderWrapper() seeds 100vh, not a measurement.
|
|
3010
|
-
expect(wrapper.style.height).toBe('100vh');
|
|
3011
|
-
|
|
3012
|
-
await libEmbed.showPreRender();
|
|
3013
|
-
|
|
3014
|
-
const placeholder = (libEmbed as any).getPreRenderPlaceHolderElement() as HTMLElement;
|
|
3015
|
-
expect(placeholder.style.height).toBe('420px');
|
|
3016
|
-
|
|
3017
|
-
libEmbed.destroy();
|
|
3018
|
-
});
|
|
3019
|
-
|
|
3020
|
-
it('should seed the placeholder with a height fullHeight has measured', async () => {
|
|
3021
|
-
createRootEleForEmbed();
|
|
3022
|
-
|
|
3023
|
-
const libEmbed = new LiveboardEmbed('#tsEmbedDiv', {
|
|
3024
|
-
preRenderId: 'measured-height',
|
|
3025
|
-
liveboardId: 'myLiveboardId',
|
|
3026
|
-
fullHeight: true,
|
|
3027
|
-
frameParams: { height: 420 },
|
|
3028
|
-
});
|
|
3029
|
-
libEmbed.preRender();
|
|
3030
|
-
await waitFor(() => !!getIFrameEl());
|
|
3031
|
-
|
|
3032
|
-
(libEmbed as any).setIFrameHeight(1180);
|
|
3033
|
-
await libEmbed.showPreRender();
|
|
3034
|
-
|
|
3035
|
-
const placeholder = (libEmbed as any).getPreRenderPlaceHolderElement() as HTMLElement;
|
|
3036
|
-
expect(placeholder.style.height).toBe('1180px');
|
|
3037
|
-
|
|
3038
|
-
libEmbed.destroy();
|
|
3039
|
-
});
|
|
3040
|
-
});
|
|
3041
|
-
|
|
3042
2946
|
describe('preRenderContainer', () => {
|
|
3043
2947
|
it('should append preRenderWrapper to document.body when preRenderContainer is not set', async () => {
|
|
3044
2948
|
createRootEleForEmbed();
|
|
@@ -3312,16 +3216,21 @@ describe('Unit test case for ts embed', () => {
|
|
|
3312
3216
|
|
|
3313
3217
|
// Simulate React remounting the container: the old node (with
|
|
3314
3218
|
// our wrapper) is detached and a fresh node takes its place.
|
|
3219
|
+
const removeSpy = jest.spyOn(oldContainer, 'removeEventListener');
|
|
3315
3220
|
oldContainer.remove();
|
|
3316
3221
|
const newContainer = document.createElement('div');
|
|
3317
3222
|
newContainer.id = 'remount-container';
|
|
3318
3223
|
document.body.appendChild(newContainer);
|
|
3224
|
+
const addSpy = jest.spyOn(newContainer, 'addEventListener');
|
|
3319
3225
|
|
|
3320
3226
|
// A reposition (scroll/resize/re-show) heals the stale ref.
|
|
3321
3227
|
libEmbed.syncPreRenderStyle();
|
|
3322
3228
|
|
|
3323
3229
|
expect(newContainer.contains(wrapper)).toBe(true);
|
|
3324
3230
|
expect(oldContainer.contains(wrapper)).toBe(false);
|
|
3231
|
+
// The scroll listener is migrated to the live container.
|
|
3232
|
+
expect(removeSpy).toHaveBeenCalledWith('scroll', expect.any(Function));
|
|
3233
|
+
expect(addSpy).toHaveBeenCalledWith('scroll', expect.any(Function));
|
|
3325
3234
|
|
|
3326
3235
|
libEmbed.destroy();
|
|
3327
3236
|
newContainer.remove();
|
|
@@ -6894,3 +6803,572 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
|
6894
6803
|
});
|
|
6895
6804
|
});
|
|
6896
6805
|
});
|
|
6806
|
+
|
|
6807
|
+
describe('excludeConfigFromURL', () => {
|
|
6808
|
+
const lbConfig = {
|
|
6809
|
+
liveboardId,
|
|
6810
|
+
hiddenActions: [Action.Download],
|
|
6811
|
+
additionalFlags: { internalBlinkFlag: true },
|
|
6812
|
+
liveboardV2: true,
|
|
6813
|
+
};
|
|
6814
|
+
|
|
6815
|
+
const withPostMessage = (viewConfig: any) => ({
|
|
6816
|
+
...viewConfig,
|
|
6817
|
+
additionalFlags: { ...viewConfig.additionalFlags, excludeConfigFromURL: true },
|
|
6818
|
+
});
|
|
6819
|
+
|
|
6820
|
+
const renderAndGetSrc = async (viewConfig: any) => {
|
|
6821
|
+
const embed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, ...viewConfig });
|
|
6822
|
+
await embed.render();
|
|
6823
|
+
await waitFor(() => !!getIFrameEl());
|
|
6824
|
+
return { embed, src: getIFrameSrc() };
|
|
6825
|
+
};
|
|
6826
|
+
|
|
6827
|
+
const signalFrameReady = () => {
|
|
6828
|
+
postMessageToParent(getIFrameEl().contentWindow, {
|
|
6829
|
+
type: EmbedEvent.EmbedListenerReady,
|
|
6830
|
+
});
|
|
6831
|
+
};
|
|
6832
|
+
|
|
6833
|
+
beforeEach(() => {
|
|
6834
|
+
document.body.innerHTML = getDocumentBody();
|
|
6835
|
+
mockProcessTrigger.mockReset();
|
|
6836
|
+
mockProcessTrigger.mockResolvedValue({});
|
|
6837
|
+
init({
|
|
6838
|
+
thoughtSpotHost,
|
|
6839
|
+
authType: AuthType.None,
|
|
6840
|
+
});
|
|
6841
|
+
});
|
|
6842
|
+
|
|
6843
|
+
test('leaves the URL untouched when the flag is not set', async () => {
|
|
6844
|
+
const { src } = await renderAndGetSrc(lbConfig);
|
|
6845
|
+
|
|
6846
|
+
expect(src).toContain('hideAction=');
|
|
6847
|
+
expect(src).toContain('internalBlinkFlag=true');
|
|
6848
|
+
expect(src).toContain('isPinboardV2Enabled=true');
|
|
6849
|
+
});
|
|
6850
|
+
|
|
6851
|
+
test('keeps only the bootstrap params on the URL when the flag is set', async () => {
|
|
6852
|
+
const { src } = await renderAndGetSrc(withPostMessage(lbConfig));
|
|
6853
|
+
|
|
6854
|
+
// Boot and auth handshake stays on the URL.
|
|
6855
|
+
expect(src).toContain('hostAppUrl=');
|
|
6856
|
+
expect(src).toContain(`authType=${AuthType.None}`);
|
|
6857
|
+
expect(src).toContain(`sdkVersion=${version}`);
|
|
6858
|
+
expect(src).toContain('blockNonEmbedFullAppAccess=true');
|
|
6859
|
+
expect(src).toContain('viewPortHeight=');
|
|
6860
|
+
|
|
6861
|
+
// View configuration and internal flags do not.
|
|
6862
|
+
expect(src).not.toContain('hideAction=');
|
|
6863
|
+
expect(src).not.toContain('internalBlinkFlag');
|
|
6864
|
+
});
|
|
6865
|
+
|
|
6866
|
+
describe('BOOTSTRAP_URL_PARAMS', () => {
|
|
6867
|
+
test('keeps the auth and origin params', () => {
|
|
6868
|
+
[Param.EmbedApp, Param.HostAppUrl, Param.Version, Param.AuthType].forEach(
|
|
6869
|
+
(param) => {
|
|
6870
|
+
expect(BOOTSTRAP_URL_PARAMS.has(param)).toBe(true);
|
|
6871
|
+
},
|
|
6872
|
+
);
|
|
6873
|
+
});
|
|
6874
|
+
|
|
6875
|
+
test('leaves the layout flags to the APP_INIT payload', () => {
|
|
6876
|
+
[
|
|
6877
|
+
Param.LiveboardV2Enabled,
|
|
6878
|
+
Param.PrimaryNavHidden,
|
|
6879
|
+
Param.HideSearchBar,
|
|
6880
|
+
Param.SpotterExperienceVersion,
|
|
6881
|
+
].forEach((param) => {
|
|
6882
|
+
expect(BOOTSTRAP_URL_PARAMS.has(param)).toBe(false);
|
|
6883
|
+
});
|
|
6884
|
+
});
|
|
6885
|
+
});
|
|
6886
|
+
|
|
6887
|
+
describe('params held back from the URL go in the APP_INIT payload', () => {
|
|
6888
|
+
const renderEmbed = async (EmbedClass: any, viewConfig: any, excludeConfig = true) => {
|
|
6889
|
+
const embed = new EmbedClass(getRootEl(), {
|
|
6890
|
+
...defaultViewConfig,
|
|
6891
|
+
...viewConfig,
|
|
6892
|
+
additionalFlags: {
|
|
6893
|
+
...viewConfig.additionalFlags,
|
|
6894
|
+
...(excludeConfig && { excludeConfigFromURL: true }),
|
|
6895
|
+
},
|
|
6896
|
+
});
|
|
6897
|
+
await embed.render();
|
|
6898
|
+
await waitFor(() => !!getIFrameEl());
|
|
6899
|
+
return embed;
|
|
6900
|
+
};
|
|
6901
|
+
|
|
6902
|
+
const requestAppInit = async (): Promise<any> => {
|
|
6903
|
+
const mockPort: any = { postMessage: jest.fn() };
|
|
6904
|
+
postMessageToParent(
|
|
6905
|
+
getIFrameEl().contentWindow,
|
|
6906
|
+
{ type: EmbedEvent.APP_INIT, data: {} },
|
|
6907
|
+
mockPort,
|
|
6908
|
+
);
|
|
6909
|
+
await waitFor(() => mockPort.postMessage.mock.calls.length > 0);
|
|
6910
|
+
return mockPort.postMessage.mock.calls[0][0].data;
|
|
6911
|
+
};
|
|
6912
|
+
|
|
6913
|
+
const getAppInitFor = async (EmbedClass: any, viewConfig: any) => {
|
|
6914
|
+
await renderEmbed(EmbedClass, viewConfig);
|
|
6915
|
+
return requestAppInit();
|
|
6916
|
+
};
|
|
6917
|
+
|
|
6918
|
+
test('sends the app navigation and page version flags', async () => {
|
|
6919
|
+
const { embedParams } = await getAppInitFor(AppEmbed, {
|
|
6920
|
+
showPrimaryNavbar: false,
|
|
6921
|
+
hideHamburger: true,
|
|
6922
|
+
hideNotification: true,
|
|
6923
|
+
hideObjectSearch: true,
|
|
6924
|
+
hideOrgSwitcher: true,
|
|
6925
|
+
hideApplicationSwitcher: true,
|
|
6926
|
+
disableProfileAndHelp: true,
|
|
6927
|
+
hideHomepageLeftNav: true,
|
|
6928
|
+
hideTagFilterChips: true,
|
|
6929
|
+
modularHomeExperience: true,
|
|
6930
|
+
liveboardV2: true,
|
|
6931
|
+
});
|
|
6932
|
+
|
|
6933
|
+
expect(embedParams).toEqual(
|
|
6934
|
+
expect.objectContaining({
|
|
6935
|
+
[Param.PrimaryNavHidden]: true,
|
|
6936
|
+
[Param.HideHamburger]: true,
|
|
6937
|
+
[Param.HideNotification]: true,
|
|
6938
|
+
[Param.HideObjectSearch]: true,
|
|
6939
|
+
[Param.HideOrgSwitcher]: true,
|
|
6940
|
+
[Param.HideApplicationSwitcher]: true,
|
|
6941
|
+
[Param.HideProfleAndHelp]: true,
|
|
6942
|
+
[Param.HideHomepageLeftNav]: true,
|
|
6943
|
+
[Param.HideTagFilterChips]: true,
|
|
6944
|
+
[Param.ModularHomeExperienceEnabled]: true,
|
|
6945
|
+
[Param.LiveboardV2Enabled]: true,
|
|
6946
|
+
[Param.NavigationVersion]: expect.any(String),
|
|
6947
|
+
[Param.HomepageVersion]: expect.any(String),
|
|
6948
|
+
}),
|
|
6949
|
+
);
|
|
6950
|
+
});
|
|
6951
|
+
|
|
6952
|
+
test('sends the Liveboard layout flags', async () => {
|
|
6953
|
+
const { embedParams } = await getAppInitFor(LiveboardEmbed, {
|
|
6954
|
+
liveboardId,
|
|
6955
|
+
visibleVizs: ['viz-1'],
|
|
6956
|
+
hideLiveboardHeader: true,
|
|
6957
|
+
showLiveboardTitle: true,
|
|
6958
|
+
showLiveboardDescription: true,
|
|
6959
|
+
hideTabPanel: true,
|
|
6960
|
+
enable2ColumnLayout: true,
|
|
6961
|
+
isLiveboardHeaderSticky: true,
|
|
6962
|
+
showLiveboardVerifiedBadge: true,
|
|
6963
|
+
});
|
|
6964
|
+
|
|
6965
|
+
expect(embedParams).toEqual(
|
|
6966
|
+
expect.objectContaining({
|
|
6967
|
+
[Param.visibleVizs]: ['viz-1'],
|
|
6968
|
+
[Param.HideLiveboardHeader]: true,
|
|
6969
|
+
[Param.ShowLiveboardTitle]: true,
|
|
6970
|
+
[Param.ShowLiveboardDescription]: true,
|
|
6971
|
+
[Param.HideTabPanel]: true,
|
|
6972
|
+
[Param.Enable2ColumnLayout]: true,
|
|
6973
|
+
[Param.LiveboardHeaderSticky]: true,
|
|
6974
|
+
[Param.ShowLiveboardVerifiedBadge]: true,
|
|
6975
|
+
}),
|
|
6976
|
+
);
|
|
6977
|
+
});
|
|
6978
|
+
|
|
6979
|
+
test('sends the search layout flags and the initial query', async () => {
|
|
6980
|
+
const { embedParams } = await getAppInitFor(SearchEmbed, {
|
|
6981
|
+
dataSource: 'ds-1',
|
|
6982
|
+
searchOptions: {
|
|
6983
|
+
searchTokenString: '[revenue]',
|
|
6984
|
+
executeSearch: true,
|
|
6985
|
+
},
|
|
6986
|
+
hideResults: true,
|
|
6987
|
+
hideSearchBar: true,
|
|
6988
|
+
collapseSearchBarInitially: true,
|
|
6989
|
+
enableSearchAssist: true,
|
|
6990
|
+
});
|
|
6991
|
+
|
|
6992
|
+
expect(embedParams).toEqual(
|
|
6993
|
+
expect.objectContaining({
|
|
6994
|
+
[Param.HideResult]: true,
|
|
6995
|
+
[Param.HideSearchBar]: true,
|
|
6996
|
+
[Param.CollapseSearchBarInitially]: true,
|
|
6997
|
+
[Param.EnableSearchAssist]: true,
|
|
6998
|
+
[Param.executeSearch]: true,
|
|
6999
|
+
[Param.DataSourceMode]: expect.anything(),
|
|
7000
|
+
}),
|
|
7001
|
+
);
|
|
7002
|
+
expect(embedParams).not.toHaveProperty(Param.searchTokenString);
|
|
7003
|
+
});
|
|
7004
|
+
|
|
7005
|
+
test('sends the Spotter empty-screen flags', async () => {
|
|
7006
|
+
const { embedParams } = await getAppInitFor(SpotterEmbed, {
|
|
7007
|
+
worksheetId: 'worksheet-1',
|
|
7008
|
+
hideSampleQuestions: true,
|
|
7009
|
+
hideSourceSelection: true,
|
|
7010
|
+
disableSourceSelection: true,
|
|
7011
|
+
showSpotterLimitations: true,
|
|
7012
|
+
showSpotterRadiance: true,
|
|
7013
|
+
updatedSpotterChatPrompt: true,
|
|
7014
|
+
spotterChatConfig: { enableStarterPrompts: true },
|
|
7015
|
+
});
|
|
7016
|
+
|
|
7017
|
+
expect(embedParams).toEqual(
|
|
7018
|
+
expect.objectContaining({
|
|
7019
|
+
[Param.HideSampleQuestions]: true,
|
|
7020
|
+
[Param.HideSourceSelection]: true,
|
|
7021
|
+
[Param.DisableSourceSelection]: true,
|
|
7022
|
+
[Param.ShowSpotterLimitations]: true,
|
|
7023
|
+
[Param.ShowSpotterRadiance]: true,
|
|
7024
|
+
[Param.UpdatedSpotterChatPrompt]: true,
|
|
7025
|
+
[Param.IsStarterPromptsEnabled]: true,
|
|
7026
|
+
}),
|
|
7027
|
+
);
|
|
7028
|
+
});
|
|
7029
|
+
|
|
7030
|
+
test('sends the action and tab lists and the additionalFlags', async () => {
|
|
7031
|
+
await renderEmbed(LiveboardEmbed, {
|
|
7032
|
+
liveboardId,
|
|
7033
|
+
visibleActions: [Action.Download],
|
|
7034
|
+
visibleTabs: ['tab-1'],
|
|
7035
|
+
additionalFlags: { internalBlinkFlag: true },
|
|
7036
|
+
});
|
|
7037
|
+
const src = getIFrameSrc();
|
|
7038
|
+
const { embedParams } = await requestAppInit();
|
|
7039
|
+
|
|
7040
|
+
expect(src).not.toContain(`${Param.VisibleActions}=`);
|
|
7041
|
+
expect(src).not.toContain(`${Param.VisibleTabs}=`);
|
|
7042
|
+
expect(embedParams).toEqual(
|
|
7043
|
+
expect.objectContaining({
|
|
7044
|
+
[Param.VisibleActions]: [Action.Download],
|
|
7045
|
+
[Param.VisibleTabs]: ['tab-1'],
|
|
7046
|
+
internalBlinkFlag: true,
|
|
7047
|
+
}),
|
|
7048
|
+
);
|
|
7049
|
+
});
|
|
7050
|
+
|
|
7051
|
+
test('sends the feature flags only in embedParams', async () => {
|
|
7052
|
+
const appInitData = await getAppInitFor(AppEmbed, {
|
|
7053
|
+
showPrimaryNavbar: false,
|
|
7054
|
+
liveboardV2: true,
|
|
7055
|
+
dataPanelV2: true,
|
|
7056
|
+
});
|
|
7057
|
+
const featureFlags = {
|
|
7058
|
+
[Param.PrimaryNavHidden]: true,
|
|
7059
|
+
[Param.LiveboardV2Enabled]: true,
|
|
7060
|
+
[Param.DataPanelV2Enabled]: true,
|
|
7061
|
+
};
|
|
7062
|
+
|
|
7063
|
+
// The app overrides its feature flags from embedParams.
|
|
7064
|
+
expect(appInitData.embedParams).toEqual(expect.objectContaining(featureFlags));
|
|
7065
|
+
Object.keys(featureFlags).forEach((flag) => {
|
|
7066
|
+
expect(appInitData).not.toHaveProperty(flag);
|
|
7067
|
+
});
|
|
7068
|
+
});
|
|
7069
|
+
|
|
7070
|
+
test("lets the embed's own embedParams win over a param of the same name", async () => {
|
|
7071
|
+
const { embedParams } = await getAppInitFor(SpotterEmbed, {
|
|
7072
|
+
worksheetId: 'worksheet-1',
|
|
7073
|
+
spotterSidebarConfig: { enablePastConversationsSidebar: true },
|
|
7074
|
+
additionalFlags: { spotterSidebarConfig: 'from-flags' },
|
|
7075
|
+
});
|
|
7076
|
+
|
|
7077
|
+
expect(embedParams.spotterSidebarConfig).toEqual(
|
|
7078
|
+
expect.objectContaining({ enablePastConversationsSidebar: true }),
|
|
7079
|
+
);
|
|
7080
|
+
});
|
|
7081
|
+
|
|
7082
|
+
test("keeps the embed's own embedParams alongside the params", async () => {
|
|
7083
|
+
const { embedParams } = await getAppInitFor(SpotterEmbed, {
|
|
7084
|
+
worksheetId: 'worksheet-1',
|
|
7085
|
+
hideSampleQuestions: true,
|
|
7086
|
+
spotterSidebarConfig: { enablePastConversationsSidebar: true },
|
|
7087
|
+
});
|
|
7088
|
+
|
|
7089
|
+
expect(embedParams).toEqual(
|
|
7090
|
+
expect.objectContaining({
|
|
7091
|
+
[Param.HideSampleQuestions]: true,
|
|
7092
|
+
spotterSidebarConfig: expect.objectContaining({
|
|
7093
|
+
enablePastConversationsSidebar: true,
|
|
7094
|
+
}),
|
|
7095
|
+
}),
|
|
7096
|
+
);
|
|
7097
|
+
});
|
|
7098
|
+
|
|
7099
|
+
test('keeps the search token on the URL', async () => {
|
|
7100
|
+
const { embedParams } = await getAppInitFor(SearchEmbed, {
|
|
7101
|
+
dataSource: 'ds-1',
|
|
7102
|
+
searchOptions: { searchTokenString: '[revenue] [region]' },
|
|
7103
|
+
});
|
|
7104
|
+
|
|
7105
|
+
expect(new URL(getIFrameSrc()).searchParams.get(Param.searchTokenString)).toBe(
|
|
7106
|
+
'[revenue] [region]',
|
|
7107
|
+
);
|
|
7108
|
+
expect(embedParams).not.toHaveProperty(Param.searchTokenString);
|
|
7109
|
+
});
|
|
7110
|
+
|
|
7111
|
+
test('sends the token in searchOptions when it is excluded from the URL', async () => {
|
|
7112
|
+
const appInitData = await getAppInitFor(SearchEmbed, {
|
|
7113
|
+
dataSource: 'ds-1',
|
|
7114
|
+
excludeSearchTokenStringFromURL: true,
|
|
7115
|
+
searchOptions: { searchTokenString: '[revenue]' },
|
|
7116
|
+
});
|
|
7117
|
+
|
|
7118
|
+
expect(getIFrameSrc()).not.toContain(Param.searchTokenString);
|
|
7119
|
+
// The app merges searchOptions.searchTokenString into embedParams.
|
|
7120
|
+
expect(appInitData.searchOptions).toEqual({ searchTokenString: '[revenue]' });
|
|
7121
|
+
expect(appInitData.embedParams).not.toHaveProperty(Param.searchTokenString);
|
|
7122
|
+
});
|
|
7123
|
+
|
|
7124
|
+
test('sends a flag the caller set to false', async () => {
|
|
7125
|
+
const { embedParams } = await getAppInitFor(AppEmbed, {
|
|
7126
|
+
showPrimaryNavbar: true,
|
|
7127
|
+
liveboardV2: false,
|
|
7128
|
+
modularHomeExperience: false,
|
|
7129
|
+
});
|
|
7130
|
+
|
|
7131
|
+
expect(embedParams).toEqual(
|
|
7132
|
+
expect.objectContaining({
|
|
7133
|
+
[Param.PrimaryNavHidden]: false,
|
|
7134
|
+
[Param.LiveboardV2Enabled]: false,
|
|
7135
|
+
[Param.ModularHomeExperienceEnabled]: false,
|
|
7136
|
+
}),
|
|
7137
|
+
);
|
|
7138
|
+
});
|
|
7139
|
+
|
|
7140
|
+
test('sends a flag only when the caller sets it', async () => {
|
|
7141
|
+
const { embedParams } = await getAppInitFor(AppEmbed, {});
|
|
7142
|
+
|
|
7143
|
+
expect(embedParams).not.toHaveProperty(Param.HideHamburger);
|
|
7144
|
+
expect(embedParams).not.toHaveProperty(Param.HideNotification);
|
|
7145
|
+
expect(embedParams).not.toHaveProperty(Param.ModularHomeExperienceEnabled);
|
|
7146
|
+
});
|
|
7147
|
+
|
|
7148
|
+
test('does not repeat the params that stay on the URL', async () => {
|
|
7149
|
+
const { embedParams } = await getAppInitFor(LiveboardEmbed, { liveboardId });
|
|
7150
|
+
|
|
7151
|
+
Object.keys(embedParams).forEach((key) => {
|
|
7152
|
+
expect(BOOTSTRAP_URL_PARAMS.has(key)).toBe(false);
|
|
7153
|
+
});
|
|
7154
|
+
});
|
|
7155
|
+
|
|
7156
|
+
test('leaves the APP_INIT payload unchanged when the flag is not set', async () => {
|
|
7157
|
+
await renderEmbed(LiveboardEmbed, { liveboardId, hideLiveboardHeader: true }, false);
|
|
7158
|
+
const appInitData = await requestAppInit();
|
|
7159
|
+
|
|
7160
|
+
expect(appInitData).not.toHaveProperty('embedParams');
|
|
7161
|
+
expect(appInitData).not.toHaveProperty(Param.HideLiveboardHeader);
|
|
7162
|
+
});
|
|
7163
|
+
|
|
7164
|
+
test('sends no embedParams when every param stays on the URL', async () => {
|
|
7165
|
+
const getParams = jest
|
|
7166
|
+
.spyOn(LiveboardEmbed.prototype as any, 'getEmbedParamsObject')
|
|
7167
|
+
.mockReturnValue({
|
|
7168
|
+
[Param.EmbedApp]: true,
|
|
7169
|
+
[Param.AuthType]: AuthType.None,
|
|
7170
|
+
});
|
|
7171
|
+
await renderEmbed(LiveboardEmbed, { liveboardId });
|
|
7172
|
+
const appInitData = await requestAppInit();
|
|
7173
|
+
getParams.mockRestore();
|
|
7174
|
+
|
|
7175
|
+
expect(appInitData).not.toHaveProperty('embedParams');
|
|
7176
|
+
});
|
|
7177
|
+
|
|
7178
|
+
test('sends the params when excludeConfigFromURL is set in init', async () => {
|
|
7179
|
+
init({
|
|
7180
|
+
thoughtSpotHost,
|
|
7181
|
+
authType: AuthType.None,
|
|
7182
|
+
additionalFlags: { excludeConfigFromURL: true },
|
|
7183
|
+
});
|
|
7184
|
+
await renderEmbed(LiveboardEmbed, { liveboardId, hideLiveboardHeader: true }, false);
|
|
7185
|
+
const { embedParams } = await requestAppInit();
|
|
7186
|
+
|
|
7187
|
+
expect(getIFrameSrc()).not.toContain(`${Param.HideLiveboardHeader}=`);
|
|
7188
|
+
expect(embedParams).toEqual(
|
|
7189
|
+
expect.objectContaining({ [Param.HideLiveboardHeader]: true }),
|
|
7190
|
+
);
|
|
7191
|
+
});
|
|
7192
|
+
|
|
7193
|
+
test('sends the params for a pre-rendered embed', async () => {
|
|
7194
|
+
(window as any).ResizeObserver =
|
|
7195
|
+
window.ResizeObserver ||
|
|
7196
|
+
jest.fn().mockImplementation(() => ({
|
|
7197
|
+
disconnect: jest.fn(),
|
|
7198
|
+
observe: jest.fn(),
|
|
7199
|
+
unobserve: jest.fn(),
|
|
7200
|
+
}));
|
|
7201
|
+
const embed = new LiveboardEmbed(getRootEl(), {
|
|
7202
|
+
...defaultViewConfig,
|
|
7203
|
+
...withPostMessage({ liveboardId, hideLiveboardHeader: true }),
|
|
7204
|
+
preRenderId: 'app-init-pre-render',
|
|
7205
|
+
});
|
|
7206
|
+
await embed.preRender();
|
|
7207
|
+
await waitFor(() => !!getIFrameEl());
|
|
7208
|
+
const { embedParams } = await requestAppInit();
|
|
7209
|
+
|
|
7210
|
+
expect(embedParams).toEqual(
|
|
7211
|
+
expect.objectContaining({ [Param.HideLiveboardHeader]: true }),
|
|
7212
|
+
);
|
|
7213
|
+
});
|
|
7214
|
+
|
|
7215
|
+
test('does not add the APP_INIT copy to UpdateEmbedParams', async () => {
|
|
7216
|
+
mockMessageChannel();
|
|
7217
|
+
(window as any).ResizeObserver =
|
|
7218
|
+
window.ResizeObserver ||
|
|
7219
|
+
jest.fn().mockImplementation(() => ({
|
|
7220
|
+
disconnect: jest.fn(),
|
|
7221
|
+
observe: jest.fn(),
|
|
7222
|
+
unobserve: jest.fn(),
|
|
7223
|
+
}));
|
|
7224
|
+
const embed = new LiveboardEmbed(getRootEl(), {
|
|
7225
|
+
...defaultViewConfig,
|
|
7226
|
+
...withPostMessage({ liveboardId, hideLiveboardHeader: true }),
|
|
7227
|
+
preRenderId: 'app-init-copy-pre-render',
|
|
7228
|
+
});
|
|
7229
|
+
await embed.preRender();
|
|
7230
|
+
await waitFor(() => !!getIFrameEl());
|
|
7231
|
+
signalFrameReady();
|
|
7232
|
+
await executeAfterWait(() => {
|
|
7233
|
+
expect(embed.isEmbedContainerLoaded).toBe(true);
|
|
7234
|
+
});
|
|
7235
|
+
// The show cycle is what sends UpdateEmbedParams.
|
|
7236
|
+
await embed.showPreRender();
|
|
7237
|
+
|
|
7238
|
+
await executeAfterWait(() => {
|
|
7239
|
+
const updateCall = mockProcessTrigger.mock.calls.find(
|
|
7240
|
+
(call) => call[1] === HostEvent.UpdateEmbedParams,
|
|
7241
|
+
);
|
|
7242
|
+
expect(updateCall[3]).toEqual(
|
|
7243
|
+
expect.objectContaining({ [Param.HideLiveboardHeader]: true }),
|
|
7244
|
+
);
|
|
7245
|
+
expect(updateCall[3]).not.toHaveProperty('embedParams');
|
|
7246
|
+
});
|
|
7247
|
+
});
|
|
7248
|
+
|
|
7249
|
+
// BOOTSTRAP_URL_PARAMS is the source of truth. Each param goes
|
|
7250
|
+
// through additionalFlags so it is checked on its own.
|
|
7251
|
+
test.each([...BOOTSTRAP_URL_PARAMS])('keeps %s on the URL', async (param) => {
|
|
7252
|
+
await renderEmbed(LiveboardEmbed, {
|
|
7253
|
+
liveboardId,
|
|
7254
|
+
additionalFlags: { [param]: 'bootstrap-value' },
|
|
7255
|
+
});
|
|
7256
|
+
|
|
7257
|
+
expect(new URL(getIFrameSrc()).searchParams.has(param)).toBe(true);
|
|
7258
|
+
});
|
|
7259
|
+
});
|
|
7260
|
+
|
|
7261
|
+
test('strips a non-bootstrap additionalFlag from the URL when the flag is set', async () => {
|
|
7262
|
+
const { src } = await renderAndGetSrc({
|
|
7263
|
+
...lbConfig,
|
|
7264
|
+
additionalFlags: {
|
|
7265
|
+
internalBlinkFlag: true,
|
|
7266
|
+
someCustomFlag: 'abc',
|
|
7267
|
+
excludeConfigFromURL: true,
|
|
7268
|
+
},
|
|
7269
|
+
});
|
|
7270
|
+
|
|
7271
|
+
expect(src).not.toContain('internalBlinkFlag');
|
|
7272
|
+
expect(src).not.toContain('someCustomFlag');
|
|
7273
|
+
});
|
|
7274
|
+
|
|
7275
|
+
test('keeps an additionalFlag that overrides a bootstrap param on the URL', async () => {
|
|
7276
|
+
const { src } = await renderAndGetSrc({
|
|
7277
|
+
...lbConfig,
|
|
7278
|
+
additionalFlags: { [Param.OverrideOrgId]: 42, excludeConfigFromURL: true },
|
|
7279
|
+
});
|
|
7280
|
+
|
|
7281
|
+
expect(src).toContain(`${Param.OverrideOrgId}=42`);
|
|
7282
|
+
});
|
|
7283
|
+
|
|
7284
|
+
test('keeps the dark mode params on the URL when the flag is set', async () => {
|
|
7285
|
+
const { src } = await renderAndGetSrc(withPostMessage({ ...lbConfig, isDarkMode: true }));
|
|
7286
|
+
|
|
7287
|
+
expect(src).toContain(`${Param.IsDarkMode}=true`);
|
|
7288
|
+
expect(src).toContain(`${Param.RadiantThemeEnabled}=true`);
|
|
7289
|
+
});
|
|
7290
|
+
|
|
7291
|
+
test('keeps the deep-link route on the URL when the flag is set', async () => {
|
|
7292
|
+
const { src } = await renderAndGetSrc(withPostMessage(lbConfig));
|
|
7293
|
+
|
|
7294
|
+
expect(src).toContain(`/embed/viz/${liveboardId}`);
|
|
7295
|
+
});
|
|
7296
|
+
|
|
7297
|
+
test('sends the config in APP_INIT, not UpdateEmbedParams, on the first load', async () => {
|
|
7298
|
+
await renderAndGetSrc(withPostMessage(lbConfig));
|
|
7299
|
+
const mockPort: any = { postMessage: jest.fn() };
|
|
7300
|
+
postMessageToParent(
|
|
7301
|
+
getIFrameEl().contentWindow,
|
|
7302
|
+
{ type: EmbedEvent.APP_INIT, data: {} },
|
|
7303
|
+
mockPort,
|
|
7304
|
+
);
|
|
7305
|
+
await waitFor(() => mockPort.postMessage.mock.calls.length > 0);
|
|
7306
|
+
signalFrameReady();
|
|
7307
|
+
|
|
7308
|
+
expect(mockPort.postMessage.mock.calls[0][0].data.embedParams).toEqual(
|
|
7309
|
+
expect.objectContaining({
|
|
7310
|
+
internalBlinkFlag: true,
|
|
7311
|
+
[Param.HideActions]: expect.arrayContaining([Action.Download]),
|
|
7312
|
+
}),
|
|
7313
|
+
);
|
|
7314
|
+
await executeAfterWait(() => {
|
|
7315
|
+
const updateCalls = mockProcessTrigger.mock.calls.filter(
|
|
7316
|
+
(call) => call[1] === HostEvent.UpdateEmbedParams,
|
|
7317
|
+
);
|
|
7318
|
+
expect(updateCalls).toHaveLength(0);
|
|
7319
|
+
});
|
|
7320
|
+
});
|
|
7321
|
+
|
|
7322
|
+
test('does not send UpdateEmbedParams when the flag is not set', async () => {
|
|
7323
|
+
await renderAndGetSrc(lbConfig);
|
|
7324
|
+
|
|
7325
|
+
signalFrameReady();
|
|
7326
|
+
|
|
7327
|
+
await executeAfterWait(() => {
|
|
7328
|
+
const updateCalls = mockProcessTrigger.mock.calls.filter(
|
|
7329
|
+
(call) => call[1] === HostEvent.UpdateEmbedParams,
|
|
7330
|
+
);
|
|
7331
|
+
expect(updateCalls).toHaveLength(0);
|
|
7332
|
+
});
|
|
7333
|
+
});
|
|
7334
|
+
|
|
7335
|
+
test('does not double-send for a pre-rendered embed that is shown', async () => {
|
|
7336
|
+
mockMessageChannel();
|
|
7337
|
+
(window as any).ResizeObserver =
|
|
7338
|
+
window.ResizeObserver ||
|
|
7339
|
+
jest.fn().mockImplementation(() => ({
|
|
7340
|
+
disconnect: jest.fn(),
|
|
7341
|
+
observe: jest.fn(),
|
|
7342
|
+
unobserve: jest.fn(),
|
|
7343
|
+
}));
|
|
7344
|
+
|
|
7345
|
+
const embed = new LiveboardEmbed(getRootEl(), {
|
|
7346
|
+
...defaultViewConfig,
|
|
7347
|
+
...withPostMessage(lbConfig),
|
|
7348
|
+
preRenderId: 'send-config-post-message',
|
|
7349
|
+
});
|
|
7350
|
+
await embed.preRender();
|
|
7351
|
+
await waitFor(() => !!getIFrameEl());
|
|
7352
|
+
|
|
7353
|
+
signalFrameReady();
|
|
7354
|
+
await executeAfterWait(() => {
|
|
7355
|
+
expect(embed.isEmbedContainerLoaded).toBe(true);
|
|
7356
|
+
});
|
|
7357
|
+
// The frame being ready sends nothing; the config went in APP_INIT.
|
|
7358
|
+
expect(
|
|
7359
|
+
mockProcessTrigger.mock.calls.filter(
|
|
7360
|
+
(call) => call[1] === HostEvent.UpdateEmbedParams,
|
|
7361
|
+
),
|
|
7362
|
+
).toHaveLength(0);
|
|
7363
|
+
|
|
7364
|
+
mockProcessTrigger.mockClear();
|
|
7365
|
+
await embed.showPreRender();
|
|
7366
|
+
|
|
7367
|
+
await executeAfterWait(() => {
|
|
7368
|
+
const updateCalls = mockProcessTrigger.mock.calls.filter(
|
|
7369
|
+
(call) => call[1] === HostEvent.UpdateEmbedParams,
|
|
7370
|
+
);
|
|
7371
|
+
expect(updateCalls).toHaveLength(1);
|
|
7372
|
+
});
|
|
7373
|
+
});
|
|
7374
|
+
});
|