import { LiveboardViewConfig, LiveboardEmbed } from './liveboard'; import { init, UIPassthroughEvent } from '../index'; import { Action, AuthType, ContextMenuTriggerOptions, EmbedEvent, HostEvent, RuntimeFilterOp, } from '../types'; import { executeAfterWait, getDocumentBody, getIFrameSrc, getRootEl, defaultParams, defaultParamsWithoutHiddenActions, expectUrlMatchesWithParams, expectUrlToHaveParamsWithValues, postMessageToParent, getIFrameEl, mockMessageChannel, waitFor, } from '../test/test-utils'; import * as tsEmbed from './ts-embed'; import * as processTriggerInstance from '../utils/processTrigger'; import * as auth from '../auth'; import * as previewService from '../utils/graphql/preview-service'; import * as SessionInfoService from '../utils/sessionInfoService'; import { logger } from '../utils/logger'; const defaultViewConfig = { frameParams: { width: 1280, height: 720, }, }; const liveboardId = 'eca215d4-0d2c-4a55-90e3-d81ef6848ae0'; const activeTabId = '502693ba-9818-4e71-8ecd-d1a194e46861'; const newActiveTabId = '910e2398-eed9-443c-a975-355976629d27'; const vizId = '6e73f724-660e-11eb-ae93-0242ac130002'; const thoughtSpotHost = 'tshost'; const prefixParams = '&isLiveboardEmbed=true'; const prefixParamsVizEmbed = '&isLiveboardEmbed=true&isVizEmbed=true'; const mockGetSessionInfo = (mockSessionInfo?: any) => { jest.spyOn(SessionInfoService, 'getSessionInfo').mockResolvedValue(mockSessionInfo || { releaseVersion: '1.0.0', userGUID: '1234567890', currentOrgId: 1, privileges: [], mixpanelToken: '1234567890', }) }; beforeAll(() => { init({ thoughtSpotHost, authType: AuthType.None, }); jest.spyOn(auth, 'postLoginService').mockImplementation(() => Promise.resolve(undefined)); }); describe('Liveboard/viz embed tests', () => { beforeEach(() => { document.body.innerHTML = getDocumentBody(); }); test('should render liveboard', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should render liveboard with data panel v2 flag set to false by default', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}&enableDataPanelV2=true#/embed/viz/${liveboardId}`, ); }); }); test('should set disabled actions using PersonalizedViewsDropdown alias', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { disabledActions: [Action.PersonalizedViewsDropdown], disabledActionReason: 'Action denied', ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true&${defaultParamsWithoutHiddenActions}&disableAction=[%22${Action.PersonalisedViewsDropdown}%22]&disableHint=Action%20denied&hideAction=[%22${Action.ReportError}%22]${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set hidden actions using OrganizeFavorites alias', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { hiddenActions: [Action.OrganizeFavorites], ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true&${defaultParamsWithoutHiddenActions}&hideAction=[%22${Action.ReportError}%22,%22${Action.OrganiseFavourites}%22]${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set disabled actions', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { disabledActions: [Action.DownloadAsCsv, Action.DownloadAsPdf, Action.DownloadAsXlsx], disabledActionReason: 'Action denied', ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true&${defaultParamsWithoutHiddenActions}&disableAction=[%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]&disableHint=Action%20denied&hideAction=[%22${Action.ReportError}%22]${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set hidden actions', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { hiddenActions: [Action.DownloadAsCsv, Action.DownloadAsPdf, Action.DownloadAsXlsx], ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true&${defaultParamsWithoutHiddenActions}&hideAction=[%22${Action.ReportError}%22,%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set visible actions', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { visibleActions: [Action.DownloadAsCsv, Action.DownloadAsPdf, Action.DownloadAsXlsx], ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&visibleAction=[%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set LiveboardStylePanel in visible actions', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { visibleActions: [Action.LiveboardStylePanel], ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlToHaveParamsWithValues(getIFrameSrc(), { visibleAction: JSON.stringify([Action.LiveboardStylePanel]), }); }); }); test('should set enable2ColumnLayout to true in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { enable2ColumnLayout: true, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&enable2ColumnLayout=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set isLiveboardStylingAndGroupingEnabled to true in url (deprecated, use isLiveboardMasterpiecesEnabled)', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { isLiveboardStylingAndGroupingEnabled: true, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardStylingAndGroupingEnabled=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set isThisPeriodInDateFiltersEnabled to true in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, isThisPeriodInDateFiltersEnabled: true, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isThisPeriodInDateFiltersEnabled=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set isLiveboardPermissionV2Enabled to true in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { isEnhancedFilterInteractivityEnabled: true, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardPermissionV2Enabled=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set isPNGInScheduledEmailsEnabled to true in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { isPNGInScheduledEmailsEnabled: true, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isPNGInScheduledEmailsEnabled=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set isWYSIWYGLiveboardPDFEnabled to true in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { isContinuousLiveboardPDFEnabled: true, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isWYSIWYGLiveboardPDFEnabled=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should disable isWYSIWYGLiveboardPDFEnabled by default in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isWYSIWYGLiveboardPDFEnabled=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set isLiveboardXLSXCSVDownloadEnabled to true in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { isLiveboardXLSXCSVDownloadEnabled: true, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardXLSXCSVDownloadEnabled=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set isLiveboardXLSXCSVDownloadEnabled to false in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { isLiveboardXLSXCSVDownloadEnabled: false, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardXLSXCSVDownloadEnabled=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set isGranularXLSXCSVSchedulesEnabled to true in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { isGranularXLSXCSVSchedulesEnabled: true, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isGranularXLSXCSVSchedulesEnabled=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set isGranularXLSXCSVSchedulesEnabled to false in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { isGranularXLSXCSVSchedulesEnabled: false, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isGranularXLSXCSVSchedulesEnabled=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set isLinkParametersEnabled to true in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { isLinkParametersEnabled: true, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLinkParametersEnabled=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set isLinkParametersEnabled to false in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { isLinkParametersEnabled: false, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLinkParametersEnabled=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set visible actions as empty array', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { visibleActions: [], ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&visibleAction=[]${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should enable viz transformations true', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { enableVizTransformations: true, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&enableVizTransform=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should enable viz oAuthPollingInterval true', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { oAuthPollingInterval: 1000, isForceRedirect: true, dataSourceId: '12356', ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&oAuthPollingInterval=1000&isForceRedirect=true&dataSourceId=12356${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should disable viz transformations when enableVizTransformations false', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { enableVizTransformations: false, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&enableVizTransform=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set enableLiveboardDataCache to true in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { enableLiveboardDataCache: true, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&enableLiveboardDataCache=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should set enableLiveboardDataCache to false in url', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { enableLiveboardDataCache: false, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&enableLiveboardDataCache=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should not set enableLiveboardDataCache in url when not provided', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expect(getIFrameSrc()).not.toContain('enableLiveboardDataCache'); }); }); test('should render viz', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, vizId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParamsVizEmbed}#/embed/viz/${liveboardId}/${vizId}`, ); }); }); test('should apply runtime filters', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, vizId, runtimeFilters: [ { columnName: 'sales', operator: RuntimeFilterOp.EQ, values: [1000], }, ], excludeRuntimeFiltersfromURL: false, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true&col1=sales&op1=EQ&val1=1000${defaultParams}${prefixParamsVizEmbed}#/embed/viz/${liveboardId}/${vizId}`, ); }); }); test('Should add isLiveboardHeaderSticky flag to the iframe src', async () => { const appEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, isLiveboardHeaderSticky: false, } as LiveboardViewConfig); appEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardHeaderSticky=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('Should add isLiveboardCompactHeaderEnabled flag to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, isLiveboardCompactHeaderEnabled: false, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardHeaderV2Enabled=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('Should add showLiveboardReverifyBanner flag to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, showLiveboardReverifyBanner: false, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&showLiveboardReverifyBanner=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('Should add showLiveboardVerifiedBadge flag to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, showLiveboardVerifiedBadge: false, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&showLiveboardVerifiedBadge=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('Should add showMaskedFilterChip flag set to true to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, showMaskedFilterChip: true, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&showMaskedFilterChip=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('Should add showMaskedFilterChip flag set to false to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, showMaskedFilterChip: false, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&showMaskedFilterChip=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('Should add isLiveboardMasterpiecesEnabled flag set to true to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, isLiveboardMasterpiecesEnabled: true, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardMasterpiecesEnabled=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('Should add isLiveboardMasterpiecesEnabled flag set to false to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, isLiveboardMasterpiecesEnabled: false, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardMasterpiecesEnabled=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('Should add newChartsLibrary flag set to true to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, newChartsLibrary: true, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&muzeChartPhase1EnabledGA=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('Should add newChartsLibrary flag set to false to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, newChartsLibrary: false, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&muzeChartPhase1EnabledGA=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('Should add hideIrrelevantFiltersAtTabLevel flag to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, hideIrrelevantChipsInLiveboardTabs: true, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&hideIrrelevantFiltersAtTabLevel=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should add coverAndFilterOptionInPDF flag and set value to true to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, coverAndFilterOptionInPDF: true, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&arePdfCoverFilterPageCheckboxesEnabled=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should add coverAndFilterOptionInPDF flag and set value to false to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, coverAndFilterOptionInPDF: false, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&arePdfCoverFilterPageCheckboxesEnabled=false&${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should add isCentralizedLiveboardFilterUXEnabled flag and set value to true to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, isCentralizedLiveboardFilterUXEnabled: true, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isCentralizedLiveboardFilterUXEnabled=true${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should add isCentralizedLiveboardFilterUXEnabled flag and set value to false to the iframe src', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, isCentralizedLiveboardFilterUXEnabled: false, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isCentralizedLiveboardFilterUXEnabled=false${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should not append runtime filters in URL if excludeRuntimeFiltersfromURL is true', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, vizId, runtimeFilters: [ { columnName: 'sales', operator: RuntimeFilterOp.EQ, values: [1000], }, ], } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParamsVizEmbed}#/embed/viz/${liveboardId}/${vizId}`, ); }); }); test('Should not append runtime parameters in URL if excludeRuntimeParametersfromURL is true', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, vizId, runtimeParameters: [ { name: 'sales', value: 1000, }, ], excludeRuntimeParametersfromURL: true, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParamsVizEmbed}#/embed/viz/${liveboardId}/${vizId}`, ); }); }); test('should append runtime filters in URL if excludeRuntimeFiltersfromURL is undefined', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, vizId, runtimeFilters: [ { columnName: 'sales', operator: RuntimeFilterOp.EQ, values: [1000], }, ], excludeRuntimeFiltersfromURL: undefined, } as LiveboardViewConfig); liveboardEmbed.render(); const runtimeFilter = 'col1=sales&op1=EQ&val1=1000'; await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParamsVizEmbed}&${runtimeFilter}#/embed/viz/${liveboardId}/${vizId}`, ); }); }); test('should register event handler to adjust iframe height', async () => { const onSpy = jest.spyOn(LiveboardEmbed.prototype, 'on'); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, fullHeight: true, liveboardId, vizId, } as LiveboardViewConfig); liveboardEmbed.render(); executeAfterWait(() => { expect(onSpy).toHaveBeenCalledWith(EmbedEvent.EmbedHeight, expect.anything()); }); }); test('should not call setIFrameHeight if currentPath starts with "/embed/viz/"', () => { const myObject = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, fullHeight: true, liveboardId, } as LiveboardViewConfig) as any; const spySetIFrameHeight = jest.spyOn(myObject, 'setIFrameHeight'); myObject.render(); myObject.setIframeHeightForNonEmbedLiveboard({ data: { currentPath: '/embed/viz/' }, type: 'Route', }); // Assert that setIFrameHeight is not called expect(spySetIFrameHeight).not.toHaveBeenCalled(); }); test('should not call setIFrameHeight if currentPath starts with "/embed/insights/viz/"', () => { const myObject = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, fullHeight: true, liveboardId, } as LiveboardViewConfig) as any; const spySetIFrameHeight = jest.spyOn(myObject, 'setIFrameHeight'); myObject.render(); myObject.setIframeHeightForNonEmbedLiveboard({ data: { currentPath: '/embed/insights/viz/' }, type: 'Route', }); // Assert that setIFrameHeight is not called expect(spySetIFrameHeight).not.toHaveBeenCalled(); }); test('should call setIFrameHeight if currentPath starts with "/some/other/path/"', () => { const myObject = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, fullHeight: true, liveboardId, } as LiveboardViewConfig) as any; const spySetIFrameHeight = jest .spyOn(myObject, 'setIFrameHeight') .mockImplementation(jest.fn()); myObject.render(); myObject.setIframeHeightForNonEmbedLiveboard({ data: { currentPath: '/some/other/path/' }, type: 'Route', }); // Assert that setIFrameHeight is not called expect(spySetIFrameHeight).toHaveBeenCalled(); }); test('Should set the visible vizs', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, visibleVizs: ['abcd', 'pqrs'], } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&pinboardVisibleVizs=[%22abcd%22,%22pqrs%22]${prefixParams}#/embed/viz/${liveboardId}`, ); }); }); test('should process the trigger, for vizEmbed', async () => { const mockProcessTrigger = jest.spyOn(processTriggerInstance, 'processTrigger').mockImplementation(jest.fn()); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { enableVizTransformations: true, ...defaultViewConfig, vizId: '1234', liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(async () => { await liveboardEmbed.trigger(HostEvent.Pin); expect(mockProcessTrigger).toHaveBeenCalled(); }); }); test('should render active tab when activeTab present', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, activeTabId, liveboardV2: true, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardEmbed=true&isPinboardV2Enabled=true#/embed/viz/${liveboardId}/tab/${activeTabId}`, ); }); }); test('Should set liveboard options', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, activeTabId, liveboardV2: true, defaultHeight: 100, preventLiveboardFilterRemoval: true, enableAskSage: true, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&preventPinboardFilterRemoval=true&isLiveboardEmbed=true&isPinboardV2Enabled=true&enableAskSage=true#/embed/viz/${liveboardId}/tab/${activeTabId}`, ); }); }); test('Should set contextMenuTrigger options', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, activeTabId, liveboardV2: true, contextMenuTrigger: ContextMenuTriggerOptions.LEFT_CLICK, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&contextMenuEnabledOnWhichClick=left&isLiveboardEmbed=true&isPinboardV2Enabled=true#/embed/viz/${liveboardId}/tab/${activeTabId}`, ); }); }); test('Should set hideTabPanel option', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, activeTabId, liveboardV2: true, hideTabPanel: true, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&hideTabPanel=true&isLiveboardEmbed=true&isPinboardV2Enabled=true#/embed/viz/${liveboardId}/tab/${activeTabId}`, ); }); }); describe('personalizedViewId functionality', () => { const personalizedViewId = 'view-456-guid'; test('should render liveboard with personalizedViewId', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, personalizedViewId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlToHaveParamsWithValues(getIFrameSrc(), { view: personalizedViewId }); }); }); test('should render liveboard with personalizedViewId and activeTabId together', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, personalizedViewId, activeTabId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { // URL should be: #/embed/viz/{id}/tab/{tabId}?view={viewId} expect(getIFrameSrc()).toMatch( new RegExp( `#/embed/viz/${liveboardId}/tab/${activeTabId}\\?view=${personalizedViewId}`, ), ); }); }); test('should render liveboard with personalizedViewId and vizId together', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, personalizedViewId, vizId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { // URL should be: #/embed/viz/{id}/{vizId}?view={viewId} expect(getIFrameSrc()).toMatch( new RegExp(`#/embed/viz/${liveboardId}/${vizId}\\?view=${personalizedViewId}`), ); }); }); test('should render liveboard with personalizedViewId, activeTabId, and vizId together', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, personalizedViewId, activeTabId, vizId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { // URL should be: // #/embed/viz/{id}/tab/{tabId}/{vizId}?view={viewId} expect(getIFrameSrc()).toMatch( new RegExp( `#/embed/viz/${liveboardId}/tab/${activeTabId}/${vizId}\\?view=${personalizedViewId}`, ), ); }); }); test('should not include view param when personalizedViewId is not provided', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expect(getIFrameSrc()).not.toContain('view='); }); }); test('should include personalizedViewId in getLiveboardUrl', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, personalizedViewId, } as LiveboardViewConfig); await liveboardEmbed.render(); expect(liveboardEmbed.getLiveboardUrl()).toBe( `http://${thoughtSpotHost}/#/pinboard/${liveboardId}?view=${personalizedViewId}`, ); }); test('should include personalizedViewId with activeTabId in getLiveboardUrl', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, personalizedViewId, activeTabId, } as LiveboardViewConfig); await liveboardEmbed.render(); expect(liveboardEmbed.getLiveboardUrl()).toBe( `http://${thoughtSpotHost}/#/pinboard/${liveboardId}/tab/${activeTabId}?view=${personalizedViewId}`, ); }); test('personalizedViewId should work with runtime filters', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, personalizedViewId, runtimeFilters: [ { columnName: 'sales', operator: RuntimeFilterOp.EQ, values: [1000], }, ], excludeRuntimeFiltersfromURL: false, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { expectUrlToHaveParamsWithValues(getIFrameSrc(), { view: personalizedViewId, col1: 'sales', op1: 'EQ', val1: '1000', }); }); }); describe('backward compatibility with liveboardId?view= workaround', () => { const workaroundViewId = 'workaround-view-id'; const liveboardIdWithView = `${liveboardId}?view=${workaroundViewId}`; test('should extract view from workaround and add at end of URL', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId: liveboardIdWithView, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { // URL: #/embed/viz/{cleanId}?view={workaroundViewId} expect(getIFrameSrc()).toMatch( new RegExp(`#/embed/viz/${liveboardId}\\?view=${workaroundViewId}`), ); }); }); test('should extract view and place after tab when activeTabId is provided', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId: liveboardIdWithView, activeTabId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { // URL: #/embed/viz/{id}/tab/{tabId}?view={viewId} // (view at END, not middle) expect(getIFrameSrc()).toMatch( new RegExp( `#/embed/viz/${liveboardId}/tab/${activeTabId}\\?view=${workaroundViewId}`, ), ); }); }); test('should use personalizedViewId over workaround when both provided', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId: liveboardIdWithView, personalizedViewId, } as LiveboardViewConfig); liveboardEmbed.render(); await executeAfterWait(() => { // personalizedViewId wins, workaround stripped expect(getIFrameSrc()).toMatch( new RegExp(`#/embed/viz/${liveboardId}\\?view=${personalizedViewId}`), ); }); }); }); }); test('navigateToLiveboard should trigger the navigate event with the correct path', async () => { mockMessageChannel(); // mock getSessionInfo mockGetSessionInfo(); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, } as LiveboardViewConfig); const onSpy = jest.spyOn(liveboardEmbed, 'trigger'); await liveboardEmbed.prerenderGeneric(); await executeAfterWait(() => { const iframe = getIFrameEl(); postMessageToParent(iframe.contentWindow, { type: EmbedEvent.APP_INIT, }); postMessageToParent(iframe.contentWindow, { type: EmbedEvent.AuthInit, }); liveboardEmbed.navigateToLiveboard('lb1', 'viz1'); }); await executeAfterWait(() => { expect(onSpy).toHaveBeenCalledWith(HostEvent.Navigate, 'embed/viz/lb1/viz1'); }, 1002); }); test('navigateToLiveboard with preRender', async () => { mockMessageChannel(); // mock getSessionInfo jest.spyOn(SessionInfoService, 'getSessionInfo').mockResolvedValue({ releaseVersion: '1.0.0', userGUID: '1234567890', currentOrgId: 1, privileges: [], mixpanelToken: '1234567890', } as any); mockGetSessionInfo(); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, preRenderId: 'test', } as LiveboardViewConfig); const onSpy = jest.spyOn(liveboardEmbed, 'trigger'); await liveboardEmbed.prerenderGeneric(); await executeAfterWait(() => { const iframe = getIFrameEl(); postMessageToParent(iframe.contentWindow, { type: EmbedEvent.APP_INIT, }); postMessageToParent(iframe.contentWindow, { type: EmbedEvent.AuthInit, }); }); await executeAfterWait(() => { liveboardEmbed.navigateToLiveboard('lb1', 'viz1'); expect(onSpy).toHaveBeenCalledWith(HostEvent.Navigate, 'embed/viz/lb1/viz1'); }, 1002); }); test('should set runtime parametere values in url params', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, runtimeParameters: [ { name: 'Integer Date Range', value: 1, }, ], excludeRuntimeParametersfromURL: undefined, } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}¶m1=Integer%20Date%20Range¶mVal1=1#/embed/viz/${liveboardId}`, ); }); }); test('should set showSpotterLimitations parameter in url params', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, showSpotterLimitations: true, } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}&showSpotterLimitations=true#/embed/viz/${liveboardId}`, ); }); }); test('should render the liveboard embed with updatedSpotterChatPrompt', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, updatedSpotterChatPrompt: true, } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}&updatedSpotterChatPrompt=true#/embed/viz/${liveboardId}`, ); }); }); test('should render the liveboard embed with updatedSpotterChatPrompt disabled', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, updatedSpotterChatPrompt: false, } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}&updatedSpotterChatPrompt=false#/embed/viz/${liveboardId}`, ); }); }); test('should set hideToolResponseCardBranding parameter in url params via spotterChatConfig', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, spotterChatConfig: { hideToolResponseCardBranding: true, }, } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}&hideToolResponseCardBranding=true#/embed/viz/${liveboardId}`, ); }); }); test('should set toolResponseCardBrandingLabel parameter in url params via spotterChatConfig', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, spotterChatConfig: { toolResponseCardBrandingLabel: 'MyBrand', }, } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { expectUrlMatchesWithParams( getIFrameSrc(), `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}&toolResponseCardBrandingLabel=MyBrand#/embed/viz/${liveboardId}`, ); }); }); test('SetActiveTab Hostevent should not trigger the navigate event with the correct path, for vizEmbed', async () => { const mockProcessTrigger = jest.spyOn(tsEmbed.TsEmbed.prototype, 'trigger'); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { enableVizTransformations: true, ...defaultViewConfig, liveboardId, vizId, } as LiveboardViewConfig); liveboardEmbed.render(); executeAfterWait(() => { const result = liveboardEmbed.trigger(HostEvent.SetActiveTab, { tabId: newActiveTabId, }); expect(mockProcessTrigger).not.toHaveBeenCalled(); }); }); test('SetActiveTab Hostevent trigger the navigate event with the correct path, not vizEmbed', async () => { const mockProcessTrigger = jest.spyOn(tsEmbed.TsEmbed.prototype, 'trigger'); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { enableVizTransformations: true, ...defaultViewConfig, liveboardId, } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { const result = liveboardEmbed.trigger(HostEvent.SetActiveTab, { tabId: newActiveTabId, }); expect(mockProcessTrigger).toHaveBeenCalledWith( HostEvent.Navigate, `embed/viz/${liveboardId}/tab/${newActiveTabId}`, ); }); }); describe('PreRender flow for liveboard embed', () => { beforeAll(() => { init({ thoughtSpotHost: "http://tshost", authType: AuthType.None, }); }); test('it should preRender generic with liveboard id is not passed', async () => { const consoleSpy = jest.spyOn(console, 'error'); const libEmbed = new LiveboardEmbed(getRootEl(), { preRenderId: 'testPreRender', }); const prerenderGenericSpy = jest.spyOn(libEmbed, 'prerenderGeneric'); await libEmbed.preRender(); await executeAfterWait(() => { const iFrame = document.getElementById( libEmbed.getPreRenderIds().child, ) as HTMLIFrameElement; // should render the generic link expect(prerenderGenericSpy).toHaveBeenCalledTimes(1); expect(iFrame.src).toMatch(/http:\/\/tshost\/.*&isLiveboardEmbed=true.*#$/); expect(consoleSpy).toHaveBeenCalledTimes(0); }); }); test('Show preview loader should not show the loader if not viz embed or showPreviewLoader is false', async () => { const libEmbed = new LiveboardEmbed(getRootEl(), { liveboardId: '1234', }); await libEmbed.render(); await executeAfterWait(() => { expect(getRootEl().innerHTML).not.toContain('ts-viz-preview-loader'); }); }); test('get liveboard url value', async () => { const libEmbed = new LiveboardEmbed(getRootEl(), { liveboardId: '1234', }); await libEmbed.render(); await executeAfterWait(() => { const url = libEmbed.getLiveboardUrl(); expect(url).toEqual('http://tshost/#/pinboard/1234'); }); }); test('Show preview loader should show the loader if viz embed and showPreviewLoader is true', async () => { jest.spyOn(previewService, 'getPreview').mockResolvedValue({ vizContent: '
test
', }); const libEmbed = new LiveboardEmbed(getRootEl(), { liveboardId: '1234', vizId: '5678', showPreviewLoader: true, }); await libEmbed.render(); expect(previewService.getPreview).toHaveBeenCalledWith('http://tshost', '5678', '1234'); await executeAfterWait(() => { expect(getRootEl().style.position).toEqual('relative'); expect(getRootEl().innerHTML).toContain('
'); expect(getRootEl().innerHTML).toContain('
test
'); }); libEmbed.test__executeCallbacks(EmbedEvent.Data, {}); await executeAfterWait(() => { expect(getRootEl().innerHTML).not.toContain('ts-viz-preview-loader'); }); }); test('it should navigateToLiveboard with liveboard id is not passed with EmbedListenerReady event', async () => { mockMessageChannel(); const consoleSpy = jest.spyOn(console, 'error'); const testPreRenderId = 'testPreRender'; const libEmbed = new LiveboardEmbed(getRootEl(), { preRenderId: testPreRenderId, }); let resizeObserverCb: any; (window as any).ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation((resizeObserverCbParam: any) => { resizeObserverCb = resizeObserverCbParam; return { disconnect: jest.fn(), observe: jest.fn(), unobserve: jest.fn(), }; }); await libEmbed.preRender(); await waitFor(() => !!getIFrameEl()); const ts = '__tsEmbed'; expect((document.getElementById(libEmbed.getPreRenderIds().wrapper) as any)[ts]).toEqual( libEmbed, ); await executeAfterWait(() => { const iframe = getIFrameEl(); postMessageToParent(iframe.contentWindow, { type: EmbedEvent.EmbedListenerReady, }); }); const testLiveboardId = 'testLiveboardId'; const newLibEmbed = new LiveboardEmbed(getRootEl(), { preRenderId: testPreRenderId, liveboardId: testLiveboardId, vizId: 'testVizId', activeTabId: 'testActiveTabId', }); const navigateToLiveboardSpy = jest.spyOn(newLibEmbed, 'navigateToLiveboard'); await newLibEmbed.showPreRender(); await executeAfterWait(() => { const iFrame = document.getElementById( libEmbed.getPreRenderIds().child, ) as HTMLIFrameElement; // should render the generic link expect(navigateToLiveboardSpy).toHaveBeenCalledWith( testLiveboardId, 'testVizId', 'testActiveTabId', undefined, ); expect(iFrame.src).toMatch(/http:\/\/tshost\/.*&isLiveboardEmbed=true.*#$/); expect(consoleSpy).toHaveBeenCalledTimes(0); }); }); test('it should navigateToLiveboard with liveboard id is not passed with AuthInit event', async () => { mockMessageChannel(); const consoleSpy = jest.spyOn(console, 'error'); const testPreRenderId = 'testPreRender'; const libEmbed = new LiveboardEmbed(getRootEl(), { preRenderId: testPreRenderId, }); mockGetSessionInfo(); let resizeObserverCb: any; (window as any).ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation((resizeObserverCbParam: any) => { resizeObserverCb = resizeObserverCbParam; return { disconnect: jest.fn(), observe: jest.fn(), unobserve: jest.fn(), }; }); await libEmbed.preRender(); await waitFor(() => !!getIFrameEl()); const ts = '__tsEmbed'; expect((document.getElementById(libEmbed.getPreRenderIds().wrapper) as any)[ts]).toEqual( libEmbed, ); const testLiveboardId = 'testLiveboardId'; const newLibEmbed = new LiveboardEmbed(getRootEl(), { preRenderId: testPreRenderId, liveboardId: testLiveboardId, vizId: 'testVizId', activeTabId: 'testActiveTabId', }); const navigateToLiveboardSpy = jest.spyOn(newLibEmbed, 'navigateToLiveboard'); await newLibEmbed.showPreRender(); await executeAfterWait(() => { const iFrame = document.getElementById( newLibEmbed.getPreRenderIds().child, ) as HTMLIFrameElement; postMessageToParent(iFrame.contentWindow, { type: EmbedEvent.AuthInit, }); }); await executeAfterWait(() => { const iFrame = document.getElementById( libEmbed.getPreRenderIds().child, ) as HTMLIFrameElement; // should render the generic link expect(navigateToLiveboardSpy).toHaveBeenCalledWith( testLiveboardId, 'testVizId', 'testActiveTabId', undefined, ); expect(iFrame.src).toMatch(/http:\/\/tshost\/.*&isLiveboardEmbed=true.*#$/); expect(consoleSpy).toHaveBeenCalledTimes(0); }, 1005); }); test('should replace existing preRender when replaceExistingPreRender is true', async () => { const testPreRenderId = 'testReplacePreRender'; // Stub ResizeObserver for JSDOM (window as any).ResizeObserver = (window as any).ResizeObserver || jest.fn().mockImplementation(() => ({ disconnect: jest.fn(), observe: jest.fn(), unobserve: jest.fn(), })); // Create initial embed and show preRender (this will create the // preRender wrapper/child) const embedA = new LiveboardEmbed(getRootEl(), { preRenderId: testPreRenderId, }); await embedA.showPreRender(); await waitFor(() => !!getIFrameEl()); const ids = embedA.getPreRenderIds(); const oldWrapper = document.getElementById(ids.wrapper); const oldChild = document.getElementById(ids.child); const tsKey = '__tsEmbed'; expect((oldWrapper as any)[tsKey]).toBe(embedA); // Create a new embed instance and preRender with // replaceExistingPreRender = true const embedB = new LiveboardEmbed(getRootEl(), { preRenderId: testPreRenderId, }); const prerenderGenericSpy = jest.spyOn(embedB, 'prerenderGeneric'); await embedB.preRender(false, true); await waitFor(() => (document.getElementById(ids.wrapper) as any)?.[tsKey] === embedB); const newWrapper = document.getElementById(ids.wrapper); const newChild = document.getElementById(ids.child); // Should have called prerenderGeneric for the new embed instance expect(prerenderGenericSpy).toHaveBeenCalledTimes(1); // Wrapper should be replaced (new wrapper element), child iframe // may be reused expect(newWrapper).not.toBe(oldWrapper); // __tsEmbed on wrapper should now point to the new embed instance expect((newWrapper as any)[tsKey]).toBe(embedB); }); }); describe('LazyLoadingForFullHeight functionality', () => { let mockIFrame: HTMLIFrameElement; beforeEach(() => { mockIFrame = document.createElement('iframe'); mockIFrame.getBoundingClientRect = jest.fn().mockReturnValue({ top: 100, left: 150, bottom: 600, right: 800, width: 650, height: 500, }); jest.spyOn(document, 'createElement').mockImplementation((tagName) => { if (tagName === 'iframe') { return mockIFrame; } return document.createElement(tagName); }); }); afterEach(() => { jest.restoreAllMocks(); }); test('should set lazyLoadingMargin parameter when provided', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, fullHeight: true, lazyLoadingForFullHeight: true, lazyLoadingMargin: '100px 0px', } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { const iframeSrc = getIFrameSrc(); expect(iframeSrc).toContain('isLazyLoadingForEmbedEnabled=true'); expect(iframeSrc).toContain('isFullHeightPinboard=true'); expect(iframeSrc).toContain('rootMarginForLazyLoad=100px%200px'); }, 100); }); test('should set isLazyLoadingForEmbedEnabled=true when both fullHeight and lazyLoadingForFullHeight are enabled', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, fullHeight: true, lazyLoadingForFullHeight: true, lazyLoadingMargin: '10px', } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { const iframeSrc = getIFrameSrc(); expect(iframeSrc).toContain('isLazyLoadingForEmbedEnabled=true'); expect(iframeSrc).toContain('isFullHeightPinboard=true'); }, 100); }); test('should not set lazyLoadingForEmbed when lazyLoadingForFullHeight is enabled but fullHeight is false', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, fullHeight: false, lazyLoadingForFullHeight: true, } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { const iframeSrc = getIFrameSrc(); expect(iframeSrc).not.toContain('isLazyLoadingForEmbedEnabled=true'); expect(iframeSrc).not.toContain('isFullHeightPinboard=true'); }, 100); }); test('should not set isLazyLoadingForEmbedEnabled when fullHeight is true but lazyLoadingForFullHeight is false', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, fullHeight: true, lazyLoadingForFullHeight: false, } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { const iframeSrc = getIFrameSrc(); expect(iframeSrc).not.toContain('isLazyLoadingForEmbedEnabled=true'); expect(iframeSrc).toContain('isFullHeightPinboard=true'); }, 100); }); test('should register event handlers to adjust iframe height', async () => { const onSpy = jest.spyOn(LiveboardEmbed.prototype, 'on'); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, fullHeight: true, lazyLoadingForFullHeight: true, lazyLoadingMargin: '10px', } as LiveboardViewConfig); await liveboardEmbed.render(); await executeAfterWait(() => { expect(onSpy).toHaveBeenCalledWith(EmbedEvent.EmbedHeight, expect.anything()); expect(onSpy).toHaveBeenCalledWith(EmbedEvent.RouteChange, expect.anything()); expect(onSpy).toHaveBeenCalledWith(EmbedEvent.EmbedIframeCenter, expect.anything()); expect(onSpy).toHaveBeenCalledWith(EmbedEvent.RequestVisibleEmbedCoordinates, expect.anything()); }, 100); }); test('should send correct visible data when RequestVisibleEmbedCoordinates is triggered', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, fullHeight: true, lazyLoadingForFullHeight: true, lazyLoadingMargin: '10px', } as LiveboardViewConfig); const mockTrigger = jest.spyOn(liveboardEmbed, 'trigger'); await liveboardEmbed.render(); // Trigger the lazy load data calculation (liveboardEmbed as any).sendFullHeightLazyLoadData(); expect(mockTrigger).toHaveBeenCalledWith(HostEvent.VisibleEmbedCoordinates, { top: 0, height: 500, left: 0, width: 650, }); }); test('should send correct visible data when RequestVisibleEmbedCoordinates is triggered', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, fullHeight: true, lazyLoadingMargin: '10px', } as LiveboardViewConfig); const mockTrigger = jest.spyOn(liveboardEmbed, 'trigger'); await liveboardEmbed.render(); // Trigger the lazy load data calculation (liveboardEmbed as any).sendFullHeightLazyLoadData(); expect(mockTrigger).not.toHaveBeenCalledWith(HostEvent.VisibleEmbedCoordinates, { top: 0, height: 500, left: 0, width: 650, }); }); test('should calculate correct visible data for partially visible full height element', async () => { mockIFrame.getBoundingClientRect = jest.fn().mockReturnValue({ top: -50, left: -30, bottom: 700, right: 1024, width: 1054, height: 750, }); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, fullHeight: true, lazyLoadingForFullHeight: true, lazyLoadingMargin: '10px', } as LiveboardViewConfig); const mockTrigger = jest.spyOn(liveboardEmbed, 'trigger'); await liveboardEmbed.render(); // Trigger the lazy load data calculation (liveboardEmbed as any).sendFullHeightLazyLoadData(); expect(mockTrigger).toHaveBeenCalledWith(HostEvent.VisibleEmbedCoordinates, { top: 50, height: 700, left: 30, width: 1024, }); }); test('should add window event listeners for resize and scroll when fullHeight and lazyLoadingForFullHeight are enabled', async () => { const addEventListenerSpy = jest.spyOn(window, 'addEventListener'); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, fullHeight: true, lazyLoadingForFullHeight: true, lazyLoadingMargin: '10px', } as LiveboardViewConfig); await liveboardEmbed.render(); // Wait for the post-render events to be registered await executeAfterWait(() => { expect(addEventListenerSpy).toHaveBeenCalledWith('resize', expect.anything()); expect(addEventListenerSpy).toHaveBeenCalledWith('scroll', expect.anything(), true); }, 100); addEventListenerSpy.mockRestore(); }); test('should remove window event listeners on destroy when fullHeight and lazyLoadingForFullHeight are enabled', async () => { const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener'); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, fullHeight: true, lazyLoadingForFullHeight: true, lazyLoadingMargin: '10px', } as LiveboardViewConfig); await liveboardEmbed.render(); liveboardEmbed.destroy(); expect(removeEventListenerSpy).toHaveBeenCalledWith('resize', expect.anything()); expect(removeEventListenerSpy).toHaveBeenCalledWith('scroll', expect.anything()); removeEventListenerSpy.mockRestore(); }); test('should handle RequestVisibleEmbedCoordinates event and respond with correct data', async () => { // Mock the iframe element mockIFrame.getBoundingClientRect = jest.fn().mockReturnValue({ top: 100, left: 150, bottom: 600, right: 800, width: 650, height: 500, }); Object.defineProperty(mockIFrame, 'scrollHeight', { value: 500 }); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, liveboardId, fullHeight: true, lazyLoadingForFullHeight: true, lazyLoadingMargin: '10px', } as LiveboardViewConfig); // Set the iframe before render (liveboardEmbed as any).iFrame = mockIFrame; await liveboardEmbed.render(); // Create a mock responder function const mockResponder = jest.fn(); // Trigger the handler directly (liveboardEmbed as any).requestVisibleEmbedCoordinatesHandler({}, mockResponder); // Verify the responder was called with the correct data expect(mockResponder).toHaveBeenCalledWith({ type: EmbedEvent.RequestVisibleEmbedCoordinates, data: { top: 0, height: 500, left: 0, width: 650, }, }); }); }); describe('Host events for liveborad', () => { test('Host event with empty param', async () => { const mockProcessTrigger = jest.spyOn(tsEmbed.TsEmbed.prototype, 'trigger'); const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId: '123', ...defaultViewConfig, vizId: 'testViz', }); await liveboardEmbed.render(); mockProcessTrigger.mockResolvedValue({ session: 'test' }); await executeAfterWait(async () => { await liveboardEmbed.trigger(HostEvent.Save); expect(mockProcessTrigger).toHaveBeenCalledWith( HostEvent.Save, { vizId: 'testViz', }, undefined, ); }); }); }); describe('Liveboard Embed Container Loading and PreRender', () => { beforeEach(() => { document.body.innerHTML = getDocumentBody(); }); test('should call navigateToLiveboard after embed container is loaded in beforePrerenderVisible', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, vizId, activeTabId, ...defaultViewConfig, }); const navigateToLiveboardSpy = jest.spyOn(liveboardEmbed, 'navigateToLiveboard').mockImplementation(() => Promise.resolve(undefined)); // Mock embed container as not loaded initially liveboardEmbed.isEmbedContainerLoaded = false; // Call beforePrerenderVisible liveboardEmbed['beforePrerenderVisible'](); // navigateToLiveboard should not be called immediately expect(navigateToLiveboardSpy).not.toHaveBeenCalled(); // Simulate embed container becoming ready liveboardEmbed.isEmbedContainerLoaded = true; liveboardEmbed['executeEmbedContainerReadyCallbacks'](); // Now navigateToLiveboard should be called expect(navigateToLiveboardSpy).toHaveBeenCalledWith( liveboardId, vizId, activeTabId, undefined, ); }); test('should update currentLiveboardState for prerender object when embed container loads', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, vizId, activeTabId, ...defaultViewConfig, }); const mockPreRenderObj = { currentLiveboardState: {}, }; jest.spyOn(liveboardEmbed as any, 'getPreRenderObj').mockReturnValue(mockPreRenderObj as any); jest.spyOn(liveboardEmbed, 'navigateToLiveboard').mockImplementation(() => Promise.resolve(undefined)); // Mock embed container as not loaded initially liveboardEmbed.isEmbedContainerLoaded = false; // Call beforePrerenderVisible liveboardEmbed['beforePrerenderVisible'](); // Simulate embed container becoming ready liveboardEmbed.isEmbedContainerLoaded = true; liveboardEmbed['executeEmbedContainerReadyCallbacks'](); // Check that currentLiveboardState was updated expect(mockPreRenderObj.currentLiveboardState).toEqual({ liveboardId, vizId, activeTabId, }); }); test('should handle beforePrerenderVisible when embed container is already loaded', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, vizId, activeTabId, ...defaultViewConfig, }); const navigateToLiveboardSpy = jest.spyOn(liveboardEmbed, 'navigateToLiveboard').mockImplementation(() => Promise.resolve(undefined)); // Mock embed container as already loaded liveboardEmbed.isEmbedContainerLoaded = true; // Call beforePrerenderVisible liveboardEmbed['beforePrerenderVisible'](); // navigateToLiveboard should be called immediately expect(navigateToLiveboardSpy).toHaveBeenCalledWith( liveboardId, vizId, activeTabId, undefined, ); }); test('should handle beforePrerenderVisible without prerender object', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, vizId, activeTabId, ...defaultViewConfig, }); jest.spyOn(liveboardEmbed as any, 'getPreRenderObj').mockReturnValue(null); const navigateToLiveboardSpy = jest.spyOn(liveboardEmbed, 'navigateToLiveboard').mockImplementation(() => Promise.resolve(undefined)); // Mock embed container as not loaded initially liveboardEmbed.isEmbedContainerLoaded = false; // Call beforePrerenderVisible liveboardEmbed['beforePrerenderVisible'](); // Simulate embed container becoming ready liveboardEmbed.isEmbedContainerLoaded = true; liveboardEmbed['executeEmbedContainerReadyCallbacks'](); // navigateToLiveboard should still be called expect(navigateToLiveboardSpy).toHaveBeenCalledWith( liveboardId, vizId, activeTabId, undefined, ); }); test('should work with all liveboard parameters', async () => { const customLiveboardId = 'custom-liveboard-id'; const customVizId = 'custom-viz-id'; const customActiveTabId = 'custom-active-tab-id'; const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId: customLiveboardId, vizId: customVizId, activeTabId: customActiveTabId, ...defaultViewConfig, }); const navigateToLiveboardSpy = jest.spyOn(liveboardEmbed, 'navigateToLiveboard').mockImplementation(() => Promise.resolve(undefined)); // Mock embed container as already loaded liveboardEmbed.isEmbedContainerLoaded = true; // Call beforePrerenderVisible liveboardEmbed['beforePrerenderVisible'](); // Check that all parameters are passed correctly expect(navigateToLiveboardSpy).toHaveBeenCalledWith( customLiveboardId, customVizId, customActiveTabId, undefined, ); }); test('should work with minimal liveboard parameters', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, ...defaultViewConfig, }); const navigateToLiveboardSpy = jest.spyOn(liveboardEmbed, 'navigateToLiveboard').mockImplementation(() => Promise.resolve(undefined)); // Mock embed container as already loaded liveboardEmbed.isEmbedContainerLoaded = true; // Call beforePrerenderVisible liveboardEmbed['beforePrerenderVisible'](); // Check that undefined parameters are passed correctly expect(navigateToLiveboardSpy).toHaveBeenCalledWith( liveboardId, undefined, undefined, undefined, ); }); }); describe('Liveboard Embed Default Height and Minimum Height Handling', () => { test('should set default height to 800 when minimum height is provided', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, ...defaultViewConfig, fullHeight: true, defaultHeight: 700, minimumHeight: 800, }); await liveboardEmbed.render(); expect(liveboardEmbed['defaultHeight']).toBe(800); }); test('should set default height to 700 when default height is provided', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, ...defaultViewConfig, fullHeight: true, defaultHeight: 700, }); await liveboardEmbed.render(); expect(liveboardEmbed['defaultHeight']).toBe(700); }); test('should set default height to 800 when minimum height is provided but default height is not', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, ...defaultViewConfig, fullHeight: true, minimumHeight: 800, }); await liveboardEmbed.render(); expect(liveboardEmbed['defaultHeight']).toBe(800); }); test('should set default height to 500 when neither default height nor minimum height is provided', async () => { const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId, ...defaultViewConfig, fullHeight: true, }); await liveboardEmbed.render(); expect(liveboardEmbed['defaultHeight']).toBe(500); }); }); });