UNPKG

@thoughtspot/visual-embed-sdk

Version:
1,017 lines 61.1 kB
/** * Unit tests for HostEvents that had no prior coverage. * Covers: postMessage type correctness, !isRendered guard (returns null + handleError), * and vizId injection on LiveboardEmbed when viewConfig.vizId is set. */ import { init, AuthType, LiveboardEmbed, HostEvent, EmbedErrorCodes, } from '../index'; import { executeAfterWait, getDocumentBody, getIFrameEl, getRootEl, mockMessageChannel, messageChannelMock, } from '../test/test-utils'; import * as authInstance from '../auth'; const thoughtSpotHost = 'https://tshost'; const liveboardId = 'eca215d4-0d2c-4a55-90e3-d81ef6848ae0'; const vizId = '6e73f724-660e-11eb-ae93-0242ac130002'; beforeAll(() => { init({ thoughtSpotHost, authType: AuthType.None }); jest.spyOn(authInstance, 'postLoginService').mockImplementation(() => Promise.resolve(true)); }); beforeEach(() => { document.body.innerHTML = getDocumentBody(); }); // --------------------------------------------------------------------------- // Helper: render a LiveboardEmbed and return it with the iframe spy // --------------------------------------------------------------------------- async function renderLiveboard(extraConfig = {}) { const lb = new LiveboardEmbed(getRootEl(), { frameParams: { width: '100%', height: '100%' }, liveboardId, ...extraConfig, }); await lb.render(); const iframe = getIFrameEl(); jest.spyOn(iframe.contentWindow, 'postMessage'); return { lb, iframe }; } // Helper: create a LiveboardEmbed that has NOT been rendered, with handleError // mocked to prevent the jest-setup console.error → throw. function unrenderedLiveboard() { const lb = new LiveboardEmbed(getRootEl(), { frameParams: { width: '100%', height: '100%' }, liveboardId, }); jest.spyOn(lb, 'handleError').mockImplementation(() => { }); return lb; } // --------------------------------------------------------------------------- // 3 – Filter // --------------------------------------------------------------------------- describe('HostEvent.Filter', () => { test('postMessage type is filter (all lowercase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.Filter, { columnName: 'col', operator: 'EQ', values: ['v'] }); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'filter' }), thoughtSpotHost, expect.anything()); }); }); test('returns null and calls handleError when !isRendered', async () => { const lb = unrenderedLiveboard(); const handleErrorSpy = lb.handleError; const result = await lb.trigger(HostEvent.Filter, {}); expect(result).toBeNull(); expect(handleErrorSpy).toHaveBeenCalledWith(expect.objectContaining({ code: EmbedErrorCodes.RENDER_NOT_CALLED })); }); }); // --------------------------------------------------------------------------- // 8 – UpdateRuntimeFilters // --------------------------------------------------------------------------- describe('HostEvent.UpdateRuntimeFilters', () => { test('postMessage type is UpdateRuntimeFilters (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.UpdateRuntimeFilters, []); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'UpdateRuntimeFilters' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.UpdateRuntimeFilters, []); expect(result).toBeNull(); }); test('vizId is injected when viewConfig.vizId is set and payload is object', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard({ vizId }); await executeAfterWait(() => { lb.trigger(HostEvent.UpdateRuntimeFilters, [{}]); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'UpdateRuntimeFilters' }), thoughtSpotHost, expect.anything()); }); }); }); // --------------------------------------------------------------------------- // 10 – OpenFilter // --------------------------------------------------------------------------- describe('HostEvent.OpenFilter', () => { test('postMessage type is openFilter (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.OpenFilter, { columnId: 'col1' }); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'openFilter' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.OpenFilter, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 11 – AddColumns // --------------------------------------------------------------------------- describe('HostEvent.AddColumns', () => { test('postMessage type is addColumns (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.AddColumns, { columnIds: ['c1'] }); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'addColumns' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.AddColumns, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 12 – RemoveColumn // --------------------------------------------------------------------------- describe('HostEvent.RemoveColumn', () => { test('postMessage type is removeColumn (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.RemoveColumn, { columnId: 'c1' }); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'removeColumn' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.RemoveColumn, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 15 – LiveboardInfo // --------------------------------------------------------------------------- describe('HostEvent.LiveboardInfo', () => { test('postMessage type is pinboardInfo', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.LiveboardInfo); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'pinboardInfo' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.LiveboardInfo); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 16 – Schedule // --------------------------------------------------------------------------- describe('HostEvent.Schedule', () => { test('postMessage type is subscription', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.Schedule); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'subscription' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.Schedule); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 17 – SchedulesList // --------------------------------------------------------------------------- describe('HostEvent.SchedulesList', () => { test('postMessage type is schedule-list (hyphenated)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.SchedulesList); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'schedule-list' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.SchedulesList); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 18 – ExportTML // --------------------------------------------------------------------------- describe('HostEvent.ExportTML', () => { test('postMessage type is exportTSL (uses TSL abbreviation)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.ExportTML); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'exportTSL' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.ExportTML); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 19 – EditTML // --------------------------------------------------------------------------- describe('HostEvent.EditTML', () => { test('postMessage type is editTSL', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.EditTML); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'editTSL' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.EditTML); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 20 – UpdateTML // --------------------------------------------------------------------------- describe('HostEvent.UpdateTML', () => { test('postMessage type is updateTSL', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.UpdateTML); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'updateTSL' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.UpdateTML); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 21 – DownloadAsPdf // --------------------------------------------------------------------------- describe('HostEvent.DownloadAsPdf', () => { test('postMessage type is downloadAsPdf (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.DownloadAsPdf); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'downloadAsPdf' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.DownloadAsPdf); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 22 – DownloadLiveboardAsContinuousPDF // --------------------------------------------------------------------------- describe('HostEvent.DownloadLiveboardAsContinuousPDF', () => { test('postMessage type is downloadLiveboardAsContinuousPDF', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.DownloadLiveboardAsContinuousPDF); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'downloadLiveboardAsContinuousPDF' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.DownloadLiveboardAsContinuousPDF); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 23 – AIHighlights // --------------------------------------------------------------------------- describe('HostEvent.AIHighlights', () => { test('postMessage type is AIHighlights (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.AIHighlights); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'AIHighlights' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.AIHighlights); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 24 – MakeACopy // --------------------------------------------------------------------------- describe('HostEvent.MakeACopy', () => { test('postMessage type is makeACopy (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.MakeACopy); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'makeACopy' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.MakeACopy); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 25 – Remove (maps to 'delete' string) // --------------------------------------------------------------------------- describe('HostEvent.Remove', () => { test("postMessage type is 'delete' (NOT 'Remove')", async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.Remove); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'delete' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.Remove); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 26 – Explore // --------------------------------------------------------------------------- describe('HostEvent.Explore', () => { test('postMessage type is explore (all lowercase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.Explore, { vizId: 'v1' }); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'explore' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.Explore, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 27 – CreateMonitor // --------------------------------------------------------------------------- describe('HostEvent.CreateMonitor', () => { test('postMessage type is createMonitor (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.CreateMonitor); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'createMonitor' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.CreateMonitor); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 28 – ManageMonitor // --------------------------------------------------------------------------- describe('HostEvent.ManageMonitor', () => { test('postMessage type is manageMonitor (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.ManageMonitor); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'manageMonitor' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.ManageMonitor); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 29 – Edit // --------------------------------------------------------------------------- describe('HostEvent.Edit', () => { test('postMessage type is edit (all lowercase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.Edit); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'edit' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.Edit); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 30 – CopyLink (maps to 'embedDocument') // --------------------------------------------------------------------------- describe('HostEvent.CopyLink', () => { test("postMessage type is 'embedDocument' (NOT 'CopyLink')", async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.CopyLink); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'embedDocument' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.CopyLink); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 33 – ShowUnderlyingData // --------------------------------------------------------------------------- describe('HostEvent.ShowUnderlyingData', () => { test('postMessage type is showUnderlyingData (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.ShowUnderlyingData); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'showUnderlyingData' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.ShowUnderlyingData); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 34 – Delete (maps to 'onDeleteAnswer') // --------------------------------------------------------------------------- describe('HostEvent.Delete', () => { test("postMessage type is 'onDeleteAnswer' (NOT 'delete' or 'Delete')", async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.Delete); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'onDeleteAnswer' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.Delete); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 35 – SpotIQAnalyze // --------------------------------------------------------------------------- describe('HostEvent.SpotIQAnalyze', () => { test('postMessage type is spotIQAnalyze (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.SpotIQAnalyze); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'spotIQAnalyze' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.SpotIQAnalyze); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 36 – Download (maps to 'downloadAsPng', same as DownloadAsPng) // --------------------------------------------------------------------------- describe('HostEvent.Download', () => { test("postMessage type is 'downloadAsPng' (same string as DownloadAsPng)", async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.Download); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'downloadAsPng' }), thoughtSpotHost, expect.anything()); }); }); test('Download and DownloadAsPng share the identical string value', () => { expect(HostEvent.Download).toBe(HostEvent.DownloadAsPng); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.Download); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 37 – DownloadAsPng // --------------------------------------------------------------------------- describe('HostEvent.DownloadAsPng', () => { test('postMessage type is downloadAsPng', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.DownloadAsPng); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'downloadAsPng' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.DownloadAsPng); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 39 – DownloadAsXlsx // --------------------------------------------------------------------------- describe('HostEvent.DownloadAsXlsx', () => { test('postMessage type is downloadAsXLSX (capital X-L-S-X)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.DownloadAsXlsx); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'downloadAsXLSX' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.DownloadAsXlsx); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 40 – Share // --------------------------------------------------------------------------- describe('HostEvent.Share', () => { test('postMessage type is share (all lowercase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.Share); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'share' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.Share); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 42 – SyncToSheets // --------------------------------------------------------------------------- describe('HostEvent.SyncToSheets', () => { test('postMessage type is sync-to-sheets (hyphenated, all lowercase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.SyncToSheets); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'sync-to-sheets' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.SyncToSheets); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 43 – SyncToOtherApps // --------------------------------------------------------------------------- describe('HostEvent.SyncToOtherApps', () => { test('postMessage type is sync-to-other-apps (hyphenated)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.SyncToOtherApps); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'sync-to-other-apps' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.SyncToOtherApps); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 44 – ManagePipelines // --------------------------------------------------------------------------- describe('HostEvent.ManagePipelines', () => { test("postMessage type is 'manage-pipeline' (singular, hyphenated)", async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.ManagePipelines); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'manage-pipeline' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.ManagePipelines); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 45 – ResetSearch // --------------------------------------------------------------------------- describe('HostEvent.ResetSearch', () => { test('postMessage type is resetSearch (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.ResetSearch); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'resetSearch' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.ResetSearch); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 49 – SetVisibleTabs // --------------------------------------------------------------------------- describe('HostEvent.SetVisibleTabs', () => { test("postMessage type is 'SetPinboardVisibleTabs' (NOT 'SetVisibleTabs')", async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.SetVisibleTabs, ['tab1']); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'SetPinboardVisibleTabs' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.SetVisibleTabs, []); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 50 – SetHiddenTabs // --------------------------------------------------------------------------- describe('HostEvent.SetHiddenTabs', () => { test("postMessage type is 'SetPinboardHiddenTabs' (NOT 'SetHiddenTabs')", async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.SetHiddenTabs, ['tab1']); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'SetPinboardHiddenTabs' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.SetHiddenTabs, []); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 52 – AskSage // --------------------------------------------------------------------------- describe('HostEvent.AskSage', () => { test('postMessage type is AskSage (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.AskSage); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'AskSage' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.AskSage); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 53 – UpdateCrossFilter // --------------------------------------------------------------------------- describe('HostEvent.UpdateCrossFilter', () => { test('postMessage type is UpdateCrossFilter (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.UpdateCrossFilter, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'UpdateCrossFilter' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.UpdateCrossFilter, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 56 – UpdateParameters // --------------------------------------------------------------------------- describe('HostEvent.UpdateParameters', () => { test('postMessage type is UpdateParameters (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.UpdateParameters, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'UpdateParameters' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.UpdateParameters, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 60 – SelectPersonalizedView (maps to British spelling) // --------------------------------------------------------------------------- describe('HostEvent.SelectPersonalizedView', () => { test("postMessage type is 'SelectPersonalisedView' (British spelling)", async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.SelectPersonalizedView, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'SelectPersonalisedView' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.SelectPersonalizedView, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 64 – TransformTableVizData // --------------------------------------------------------------------------- describe('HostEvent.TransformTableVizData', () => { test('postMessage type is TransformTableVizData (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.TransformTableVizData, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'TransformTableVizData' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.TransformTableVizData, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 65 – SpotterSearch // --------------------------------------------------------------------------- describe('HostEvent.SpotterSearch', () => { test('postMessage type is SpotterSearch (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.SpotterSearch, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'SpotterSearch' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.SpotterSearch, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 66 – EditLastPrompt // --------------------------------------------------------------------------- describe('HostEvent.EditLastPrompt', () => { test('postMessage type is EditLastPrompt (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.EditLastPrompt, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'EditLastPrompt' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.EditLastPrompt, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 67 – PreviewSpotterData // --------------------------------------------------------------------------- describe('HostEvent.PreviewSpotterData', () => { test('postMessage type is PreviewSpotterData (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.PreviewSpotterData, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'PreviewSpotterData' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.PreviewSpotterData, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 68 – AddToCoaching // --------------------------------------------------------------------------- describe('HostEvent.AddToCoaching', () => { test('postMessage type is addToCoaching (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.AddToCoaching, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'addToCoaching' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.AddToCoaching, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 69 – DataModelInstructions // --------------------------------------------------------------------------- describe('HostEvent.DataModelInstructions', () => { test('postMessage type is DataModelInstructions (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.DataModelInstructions, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'DataModelInstructions' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.DataModelInstructions, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 70 – ResetSpotterConversation // --------------------------------------------------------------------------- describe('HostEvent.ResetSpotterConversation', () => { test('postMessage type is ResetSpotterConversation (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.ResetSpotterConversation, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'ResetSpotterConversation' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.ResetSpotterConversation, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 71 – DeleteLastPrompt // --------------------------------------------------------------------------- describe('HostEvent.DeleteLastPrompt', () => { test('postMessage type is DeleteLastPrompt (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.DeleteLastPrompt, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'DeleteLastPrompt' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.DeleteLastPrompt, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 72 – AnswerChartSwitcher // --------------------------------------------------------------------------- describe('HostEvent.AnswerChartSwitcher', () => { test('postMessage type is answerChartSwitcher (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.AnswerChartSwitcher, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'answerChartSwitcher' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.AnswerChartSwitcher, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 75 – AskSpotter // --------------------------------------------------------------------------- describe('HostEvent.AskSpotter', () => { test('postMessage type is AskSpotter (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.AskSpotter, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'AskSpotter' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.AskSpotter, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 78 – StartNewSpotterConversation // --------------------------------------------------------------------------- describe('HostEvent.StartNewSpotterConversation', () => { test('postMessage type is StartNewSpotterConversation (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.StartNewSpotterConversation, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'StartNewSpotterConversation' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.StartNewSpotterConversation, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 80 – SendTestScheduleEmail // --------------------------------------------------------------------------- describe('HostEvent.SendTestScheduleEmail', () => { test('postMessage type is sendTestScheduleEmail (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.SendTestScheduleEmail, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'sendTestScheduleEmail' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.SendTestScheduleEmail, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 81 – SpotterVizSendUserMessage // --------------------------------------------------------------------------- describe('HostEvent.SpotterVizSendUserMessage', () => { test('postMessage type is SpotterVizSendUserMessage (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.SpotterVizSendUserMessage, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'SpotterVizSendUserMessage' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.SpotterVizSendUserMessage, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 82 – InitSpotterVizConversation // --------------------------------------------------------------------------- describe('HostEvent.InitSpotterVizConversation', () => { test('postMessage type is InitSpotterVizConversation (PascalCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.InitSpotterVizConversation, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'InitSpotterVizConversation' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.InitSpotterVizConversation, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // 83 – RefreshLiveboardBrowserCache // --------------------------------------------------------------------------- describe('HostEvent.RefreshLiveboardBrowserCache', () => { test('postMessage type is refreshLiveboardBrowserCache (camelCase)', async () => { mockMessageChannel(); const { lb, iframe } = await renderLiveboard(); await executeAfterWait(() => { lb.trigger(HostEvent.RefreshLiveboardBrowserCache, {}); expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'refreshLiveboardBrowserCache' }), thoughtSpotHost, expect.anything()); }); }); test('returns null when !isRendered', async () => { const lb = unrenderedLiveboard(); const result = await lb.trigger(HostEvent.RefreshLiveboardBrowserCache, {}); expect(result).toBeNull(); }); }); // --------------------------------------------------------------------------- // vizId injection tests — verifies LiveboardEmbed injects viewConfig.vizId // --------------------------------------------------------------------------- describe('vizId injection on LiveboardEmbed trigger (object payload)', () => { const eventsWithVizId = [ ['Filter', HostEvent.Filter, { columnName: 'c' }], ['OpenFilter', HostEvent.OpenFilter, { columnId: 'c1' }], ['AddColumns', HostEv