@thoughtspot/visual-embed-sdk 1.39.2 → 1.39.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/config.spec.js +9 -0
  3. package/cjs/src/config.spec.js.map +1 -1
  4. package/cjs/src/embed/app.d.ts +19 -15
  5. package/cjs/src/embed/app.d.ts.map +1 -1
  6. package/cjs/src/embed/app.js +23 -2
  7. package/cjs/src/embed/app.js.map +1 -1
  8. package/cjs/src/embed/app.spec.js +56 -8
  9. package/cjs/src/embed/app.spec.js.map +1 -1
  10. package/cjs/src/embed/bodyless-conversation.d.ts +23 -7
  11. package/cjs/src/embed/bodyless-conversation.d.ts.map +1 -1
  12. package/cjs/src/embed/bodyless-conversation.js +31 -5
  13. package/cjs/src/embed/bodyless-conversation.js.map +1 -1
  14. package/cjs/src/embed/bodyless-conversation.spec.js +8 -190
  15. package/cjs/src/embed/bodyless-conversation.spec.js.map +1 -1
  16. package/cjs/src/embed/conversation.spec.js +28 -0
  17. package/cjs/src/embed/conversation.spec.js.map +1 -1
  18. package/cjs/src/embed/embedConfig.d.ts +9 -7
  19. package/cjs/src/embed/embedConfig.d.ts.map +1 -1
  20. package/cjs/src/embed/embedConfig.js +9 -7
  21. package/cjs/src/embed/embedConfig.js.map +1 -1
  22. package/cjs/src/embed/liveboard.d.ts +0 -17
  23. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  24. package/cjs/src/embed/liveboard.js +2 -4
  25. package/cjs/src/embed/liveboard.js.map +1 -1
  26. package/cjs/src/embed/liveboard.spec.js +12 -11
  27. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  28. package/cjs/src/errors.d.ts +1 -0
  29. package/cjs/src/errors.d.ts.map +1 -1
  30. package/cjs/src/errors.js +1 -0
  31. package/cjs/src/errors.js.map +1 -1
  32. package/cjs/src/index.d.ts +2 -2
  33. package/cjs/src/index.d.ts.map +1 -1
  34. package/cjs/src/index.js +2 -1
  35. package/cjs/src/index.js.map +1 -1
  36. package/cjs/src/react/all-types-export.d.ts +1 -1
  37. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  38. package/cjs/src/react/all-types-export.js +3 -2
  39. package/cjs/src/react/all-types-export.js.map +1 -1
  40. package/cjs/src/react/index.d.ts +73 -20
  41. package/cjs/src/react/index.d.ts.map +1 -1
  42. package/cjs/src/react/index.js +79 -42
  43. package/cjs/src/react/index.js.map +1 -1
  44. package/cjs/src/react/index.spec.js +438 -100
  45. package/cjs/src/react/index.spec.js.map +1 -1
  46. package/cjs/src/types.d.ts +262 -6
  47. package/cjs/src/types.d.ts.map +1 -1
  48. package/cjs/src/types.js +228 -2
  49. package/cjs/src/types.js.map +1 -1
  50. package/cjs/src/utils/global-styles.js +1 -1
  51. package/cjs/src/utils/graphql/nlsService/conversation-service.d.ts.map +1 -1
  52. package/cjs/src/utils/graphql/nlsService/conversation-service.js +7 -1
  53. package/cjs/src/utils/graphql/nlsService/conversation-service.js.map +1 -1
  54. package/cjs/src/utils.spec.js +25 -0
  55. package/cjs/src/utils.spec.js.map +1 -1
  56. package/dist/{index-CmEQfuE3.js → index-ZrE8YYq8.js} +1 -1
  57. package/dist/src/embed/app.d.ts +19 -15
  58. package/dist/src/embed/app.d.ts.map +1 -1
  59. package/dist/src/embed/bodyless-conversation.d.ts +23 -7
  60. package/dist/src/embed/bodyless-conversation.d.ts.map +1 -1
  61. package/dist/src/embed/embedConfig.d.ts +9 -7
  62. package/dist/src/embed/embedConfig.d.ts.map +1 -1
  63. package/dist/src/embed/liveboard.d.ts +0 -17
  64. package/dist/src/embed/liveboard.d.ts.map +1 -1
  65. package/dist/src/errors.d.ts +1 -0
  66. package/dist/src/errors.d.ts.map +1 -1
  67. package/dist/src/index.d.ts +2 -2
  68. package/dist/src/index.d.ts.map +1 -1
  69. package/dist/src/react/all-types-export.d.ts +1 -1
  70. package/dist/src/react/all-types-export.d.ts.map +1 -1
  71. package/dist/src/react/index.d.ts +73 -20
  72. package/dist/src/react/index.d.ts.map +1 -1
  73. package/dist/src/types.d.ts +262 -6
  74. package/dist/src/types.d.ts.map +1 -1
  75. package/dist/src/utils/graphql/nlsService/conversation-service.d.ts.map +1 -1
  76. package/dist/tsembed-react.es.js +385 -71
  77. package/dist/tsembed-react.js +385 -69
  78. package/dist/tsembed.es.js +303 -24
  79. package/dist/tsembed.js +301 -22
  80. package/dist/visual-embed-sdk-react-full.d.ts +386 -72
  81. package/dist/visual-embed-sdk-react.d.ts +386 -72
  82. package/dist/visual-embed-sdk.d.ts +314 -53
  83. package/lib/package.json +1 -1
  84. package/lib/src/config.spec.js +9 -0
  85. package/lib/src/config.spec.js.map +1 -1
  86. package/lib/src/embed/app.d.ts +19 -15
  87. package/lib/src/embed/app.d.ts.map +1 -1
  88. package/lib/src/embed/app.js +22 -1
  89. package/lib/src/embed/app.js.map +1 -1
  90. package/lib/src/embed/app.spec.js +58 -10
  91. package/lib/src/embed/app.spec.js.map +1 -1
  92. package/lib/src/embed/bodyless-conversation.d.ts +23 -7
  93. package/lib/src/embed/bodyless-conversation.d.ts.map +1 -1
  94. package/lib/src/embed/bodyless-conversation.js +30 -5
  95. package/lib/src/embed/bodyless-conversation.js.map +1 -1
  96. package/lib/src/embed/bodyless-conversation.spec.js +9 -191
  97. package/lib/src/embed/bodyless-conversation.spec.js.map +1 -1
  98. package/lib/src/embed/conversation.spec.js +30 -2
  99. package/lib/src/embed/conversation.spec.js.map +1 -1
  100. package/lib/src/embed/embedConfig.d.ts +9 -7
  101. package/lib/src/embed/embedConfig.d.ts.map +1 -1
  102. package/lib/src/embed/embedConfig.js +9 -7
  103. package/lib/src/embed/embedConfig.js.map +1 -1
  104. package/lib/src/embed/liveboard.d.ts +0 -17
  105. package/lib/src/embed/liveboard.d.ts.map +1 -1
  106. package/lib/src/embed/liveboard.js +2 -4
  107. package/lib/src/embed/liveboard.js.map +1 -1
  108. package/lib/src/embed/liveboard.spec.js +12 -11
  109. package/lib/src/embed/liveboard.spec.js.map +1 -1
  110. package/lib/src/errors.d.ts +1 -0
  111. package/lib/src/errors.d.ts.map +1 -1
  112. package/lib/src/errors.js +1 -0
  113. package/lib/src/errors.js.map +1 -1
  114. package/lib/src/index.d.ts +2 -2
  115. package/lib/src/index.d.ts.map +1 -1
  116. package/lib/src/index.js +2 -2
  117. package/lib/src/index.js.map +1 -1
  118. package/lib/src/react/all-types-export.d.ts +1 -1
  119. package/lib/src/react/all-types-export.d.ts.map +1 -1
  120. package/lib/src/react/all-types-export.js +1 -1
  121. package/lib/src/react/all-types-export.js.map +1 -1
  122. package/lib/src/react/index.d.ts +73 -20
  123. package/lib/src/react/index.d.ts.map +1 -1
  124. package/lib/src/react/index.js +79 -43
  125. package/lib/src/react/index.js.map +1 -1
  126. package/lib/src/react/index.spec.js +441 -103
  127. package/lib/src/react/index.spec.js.map +1 -1
  128. package/lib/src/types.d.ts +262 -6
  129. package/lib/src/types.d.ts.map +1 -1
  130. package/lib/src/types.js +228 -2
  131. package/lib/src/types.js.map +1 -1
  132. package/lib/src/utils/global-styles.js +1 -1
  133. package/lib/src/utils/graphql/nlsService/conversation-service.d.ts.map +1 -1
  134. package/lib/src/utils/graphql/nlsService/conversation-service.js +7 -1
  135. package/lib/src/utils/graphql/nlsService/conversation-service.js.map +1 -1
  136. package/lib/src/utils.spec.js +26 -1
  137. package/lib/src/utils.spec.js.map +1 -1
  138. package/lib/src/visual-embed-sdk.d.ts +315 -54
  139. package/package.json +1 -1
  140. package/src/config.spec.ts +11 -0
  141. package/src/embed/app.spec.ts +90 -23
  142. package/src/embed/app.ts +27 -15
  143. package/src/embed/bodyless-conversation.spec.ts +9 -203
  144. package/src/embed/bodyless-conversation.ts +34 -10
  145. package/src/embed/conversation.spec.ts +40 -2
  146. package/src/embed/embedConfig.ts +10 -8
  147. package/src/embed/liveboard.spec.ts +5 -4
  148. package/src/embed/liveboard.ts +2 -22
  149. package/src/errors.ts +1 -0
  150. package/src/index.ts +2 -0
  151. package/src/react/all-types-export.ts +2 -1
  152. package/src/react/index.spec.tsx +558 -157
  153. package/src/react/index.tsx +117 -51
  154. package/src/types.ts +301 -44
  155. package/src/utils/global-styles.ts +1 -1
  156. package/src/utils/graphql/nlsService/conversation-service.ts +7 -1
  157. package/src/utils.spec.ts +29 -0
@@ -1,10 +1,10 @@
1
1
  import React from 'react';
2
2
  import '@testing-library/jest-dom';
3
3
  import '@testing-library/jest-dom/extend-expect';
4
- import { fireEvent, render, waitFor, } from '@testing-library/react';
4
+ import { render, waitFor, } from '@testing-library/react';
5
5
  import { Action, EmbedEvent, HostEvent, RuntimeFilterOp, } from '../types';
6
6
  import { executeAfterWait, getIFrameEl, getIFrameSrc, postMessageToParent, mockMessageChannel, } from '../test/test-utils';
7
- import { SearchEmbed, LiveboardEmbed, useEmbedRef, SearchBarEmbed, PreRenderedLiveboardEmbed, SpotterAgentEmbed } from './index';
7
+ import { SearchEmbed, AppEmbed, LiveboardEmbed, useEmbedRef, SearchBarEmbed, PreRenderedLiveboardEmbed, PreRenderedSearchEmbed, PreRenderedAppEmbed, useSpotterAgent, SpotterMessage, useInit } from './index';
8
8
  import * as allExports from './index';
9
9
  import { AuthType, init, } from '../index';
10
10
  import { version } from '../../package.json';
@@ -126,120 +126,458 @@ describe('React Components', () => {
126
126
  expect(getIFrameSrc(container)).toBe(`http://${thoughtSpotHost}/?embedApp=true&hostAppUrl=local-host&viewPortHeight=768&viewPortWidth=1024&sdkVersion=${version}&authType=None&blockNonEmbedFullAppAccess=true&hideAction=[%22${Action.ReportError}%22]&preAuthCache=true&overrideConsoleLogs=true&clientLogLevel=ERROR&dataSources=[%22test%22]&searchTokenString=%5Brevenue%5D&executeSearch=true&useLastSelectedSources=false&isSearchEmbed=true#/embed/search-bar-embed`);
127
127
  });
128
128
  });
129
- describe('SpotterAgentEmbed', () => {
130
- it('Should work as a React component integrating BodylessConversation', async () => {
131
- const mockDiv = document.createElement('div');
132
- let conversationService = null;
133
- render(React.createElement(SpotterAgentEmbed, { ref: (instance) => {
134
- conversationService = instance;
135
- if (instance) {
136
- instance.sendMessage = jest.fn().mockResolvedValue({
137
- container: mockDiv
138
- });
139
- }
140
- }, worksheetId: "test-worksheet-id" }));
141
- expect(conversationService).not.toBeNull();
142
- if (conversationService) {
143
- expect(typeof conversationService.sendMessage).toBe('function');
144
- const response = await conversationService.sendMessage("What are my sales this month?");
145
- expect(response.container).toBe(mockDiv);
146
- }
129
+ describe('SpotterMessage', () => {
130
+ const mockMessage = {
131
+ sessionId: "session123",
132
+ genNo: 1,
133
+ acSessionId: "acSession123",
134
+ acGenNo: 2,
135
+ worksheetId: "worksheet123",
136
+ convId: "conv123",
137
+ messageId: "message123"
138
+ };
139
+ it('Should render the SpotterMessage component with required props', async () => {
140
+ const { container } = render(React.createElement(SpotterMessage, { message: mockMessage }));
141
+ await waitFor(() => getIFrameEl(container));
142
+ expect(getIFrameEl(container)).not.toBe(null);
143
+ expect(getIFrameSrc(container)).toContain('sessionId=session123');
144
+ expect(getIFrameSrc(container)).toContain('genNo=1');
145
+ expect(getIFrameSrc(container)).toContain('acSessionId=acSession123');
146
+ expect(getIFrameSrc(container)).toContain('acGenNo=2');
147
147
  });
148
- it('Should work as a React component with ref support', () => {
149
- const mockSendMessage = jest.fn().mockResolvedValue({
150
- container: document.createElement('div'),
151
- viz: {}
152
- });
148
+ it('Should render the SpotterMessage component with optional query', async () => {
149
+ const { container } = render(React.createElement(SpotterMessage, { message: mockMessage, query: "show me sales" }));
150
+ await waitFor(() => getIFrameEl(container));
151
+ expect(getIFrameEl(container)).not.toBe(null);
152
+ expect(getIFrameSrc(container)).toContain('sessionId=session123');
153
+ });
154
+ it('Should have the correct container element with className', async () => {
155
+ const { container } = render(React.createElement(SpotterMessage, { message: mockMessage, className: "custom-class" }));
156
+ await waitFor(() => getIFrameEl(container));
157
+ expect(getIFrameEl(container).parentElement.classList.contains('custom-class')).toBe(true);
158
+ });
159
+ // Note: insertAsSibling is not supported for SpotterMessage as it's not part of the allowed props
160
+ });
161
+ describe('Component Factory Coverage', () => {
162
+ it('Should test basic component creation', () => {
163
+ expect(() => {
164
+ render(React.createElement(LiveboardEmbed, { liveboardId: "test" }));
165
+ }).not.toThrow();
166
+ expect(() => {
167
+ render(React.createElement(SearchEmbed, { dataSource: "test" }));
168
+ }).not.toThrow();
169
+ expect(() => {
170
+ render(React.createElement(AppEmbed, { showPrimaryNavbar: false }));
171
+ }).not.toThrow();
172
+ });
173
+ it('Should test component factory existence', () => {
174
+ expect(PreRenderedLiveboardEmbed).toBeDefined();
175
+ expect(PreRenderedSearchEmbed).toBeDefined();
176
+ expect(PreRenderedAppEmbed).toBeDefined();
177
+ expect(typeof PreRenderedLiveboardEmbed).toBe('object');
178
+ expect(typeof PreRenderedSearchEmbed).toBe('object');
179
+ expect(typeof PreRenderedAppEmbed).toBe('object');
180
+ });
181
+ });
182
+ describe('Components with insertAsSibling', () => {
183
+ it('Should render LiveboardEmbed with insertAsSibling', async () => {
184
+ var _a;
185
+ const { container } = render(React.createElement(LiveboardEmbed, { liveboardId: "test-liveboard", insertAsSibling: true }));
186
+ await waitFor(() => getIFrameEl(container));
187
+ expect(container.querySelector('span')).not.toBe(null);
188
+ expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
189
+ });
190
+ it('Should render SearchEmbed with insertAsSibling', async () => {
191
+ var _a;
192
+ const { container } = render(React.createElement(SearchEmbed, { dataSource: "test-datasource", insertAsSibling: true }));
193
+ await waitFor(() => getIFrameEl(container));
194
+ expect(container.querySelector('span')).not.toBe(null);
195
+ expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
196
+ });
197
+ it('Should render AppEmbed with insertAsSibling', async () => {
198
+ var _a;
199
+ const { container } = render(React.createElement(AppEmbed, { showPrimaryNavbar: false, insertAsSibling: true }));
200
+ await waitFor(() => getIFrameEl(container));
201
+ expect(container.querySelector('span')).not.toBe(null);
202
+ expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
203
+ });
204
+ it('Should render SearchBarEmbed with insertAsSibling', async () => {
205
+ var _a;
206
+ const { container } = render(React.createElement(SearchBarEmbed, { dataSource: "test-datasource", insertAsSibling: true }));
207
+ await waitFor(() => getIFrameEl(container));
208
+ expect(container.querySelector('span')).not.toBe(null);
209
+ expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
210
+ });
211
+ it('Should render components with both insertAsSibling and className', async () => {
212
+ const { container } = render(React.createElement(LiveboardEmbed, { liveboardId: "test-liveboard", insertAsSibling: true, className: "custom-class" }));
213
+ await waitFor(() => getIFrameEl(container));
214
+ expect(container.querySelector('span')).not.toBe(null);
215
+ expect(getIFrameEl(container).classList.contains('custom-class')).toBe(true);
216
+ });
217
+ });
218
+ describe('useSpotterAgent', () => {
219
+ it('Should return an object with sendMessage function', () => {
153
220
  const TestComponent = () => {
154
- const conversationRef = React.useRef(null);
155
- const handleClick = () => {
156
- if (conversationRef.current) {
157
- conversationRef.current.sendMessage = mockSendMessage;
158
- conversationRef.current.sendMessage("Test message");
159
- }
160
- };
161
- return (React.createElement(React.Fragment, null,
162
- React.createElement(SpotterAgentEmbed, { ref: conversationRef, worksheetId: "test-worksheet-id" }),
163
- React.createElement("button", { "data-testid": "test-button", onClick: handleClick }, "Send Message")));
164
- };
165
- const { getByTestId } = render(React.createElement(TestComponent, null));
166
- fireEvent.click(getByTestId('test-button'));
167
- expect(mockSendMessage).toHaveBeenCalledWith("Test message");
168
- });
169
- it('Should work with the useEmbedRef hook', () => {
170
- const mockSendMessage = jest.fn().mockResolvedValue({
171
- container: document.createElement('div'),
172
- viz: {}
221
+ const spotterAgent = useSpotterAgent({ worksheetId: 'test-worksheet' });
222
+ expect(typeof spotterAgent).toBe('object');
223
+ expect(typeof spotterAgent.sendMessage).toBe('function');
224
+ return React.createElement("div", null, "Test");
225
+ };
226
+ render(React.createElement(TestComponent, null));
227
+ });
228
+ it('Should have proper sendMessage callback structure', () => {
229
+ const TestComponent = () => {
230
+ const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
231
+ // Test that sendMessage is a function that accepts a string
232
+ expect(typeof sendMessage).toBe('function');
233
+ expect(sendMessage.length).toBe(1); // Should accept one parameter
234
+ return React.createElement("div", null, "Test");
235
+ };
236
+ render(React.createElement(TestComponent, null));
237
+ });
238
+ it('Should return error when service is not initialized', async () => {
239
+ let sendMessageResult;
240
+ const TestComponent = () => {
241
+ const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
242
+ // Call sendMessage immediately before service has time to initialize
243
+ sendMessageResult = sendMessage('test query');
244
+ return React.createElement("div", null, "Test");
245
+ };
246
+ render(React.createElement(TestComponent, null));
247
+ const result = await sendMessageResult;
248
+ expect(result).toEqual({
249
+ error: expect.any(Error)
173
250
  });
251
+ expect(result.error.message).toBe('SpotterAgent not initialized');
252
+ });
253
+ it('Should call sendMessage and handle async behavior', async () => {
254
+ let sendMessageFunction;
174
255
  const TestComponent = () => {
175
- const embedRef = useEmbedRef();
176
- const handleClick = () => {
177
- if (embedRef.current) {
178
- const service = embedRef.current;
179
- service.sendMessage = mockSendMessage;
180
- service.sendMessage("Test with useEmbedRef");
181
- }
256
+ const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
257
+ sendMessageFunction = sendMessage;
258
+ return React.createElement("div", null, "Test");
259
+ };
260
+ render(React.createElement(TestComponent, null));
261
+ // Test that sendMessage is a function
262
+ expect(typeof sendMessageFunction).toBe('function');
263
+ // Call sendMessage - should not throw
264
+ expect(() => {
265
+ sendMessageFunction('test query');
266
+ }).not.toThrow();
267
+ });
268
+ it('Should handle multiple calls to sendMessage', async () => {
269
+ let sendMessageFunction;
270
+ const TestComponent = () => {
271
+ const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
272
+ sendMessageFunction = sendMessage;
273
+ return React.createElement("div", null, "Test");
274
+ };
275
+ render(React.createElement(TestComponent, null));
276
+ // Multiple calls should not throw
277
+ expect(() => {
278
+ sendMessageFunction('query 1');
279
+ sendMessageFunction('query 2');
280
+ sendMessageFunction('query 3');
281
+ }).not.toThrow();
282
+ });
283
+ it('Should handle config object changes', () => {
284
+ const TestComponent = ({ config }) => {
285
+ const { sendMessage } = useSpotterAgent(config);
286
+ expect(sendMessage).toBeDefined();
287
+ return React.createElement("div", null, "Test");
288
+ };
289
+ const config1 = { worksheetId: 'test1' };
290
+ const config2 = { worksheetId: 'test2' };
291
+ const { rerender } = render(React.createElement(TestComponent, { config: config1 }));
292
+ // Should not throw when config changes
293
+ expect(() => {
294
+ rerender(React.createElement(TestComponent, { config: config2 }));
295
+ }).not.toThrow();
296
+ });
297
+ it('Should handle unmounting without errors', () => {
298
+ const TestComponent = () => {
299
+ const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
300
+ expect(sendMessage).toBeDefined();
301
+ return React.createElement("div", null, "Test");
302
+ };
303
+ const { unmount } = render(React.createElement(TestComponent, null));
304
+ // Should not throw when unmounting
305
+ expect(() => {
306
+ unmount();
307
+ }).not.toThrow();
308
+ });
309
+ it('Should create stable hook structure', () => {
310
+ let hookResult1, hookResult2;
311
+ const TestComponent = ({ counter }) => {
312
+ const result = useSpotterAgent({ worksheetId: 'test-worksheet' });
313
+ if (counter === 1) {
314
+ hookResult1 = result;
315
+ }
316
+ else {
317
+ hookResult2 = result;
318
+ }
319
+ return React.createElement("div", null, "Test");
320
+ };
321
+ const { rerender } = render(React.createElement(TestComponent, { counter: 1 }));
322
+ rerender(React.createElement(TestComponent, { counter: 2 }));
323
+ // Both should have same structure
324
+ expect(hookResult1).toEqual({ sendMessage: expect.any(Function) });
325
+ expect(hookResult2).toEqual({ sendMessage: expect.any(Function) });
326
+ });
327
+ it('Should handle different worksheet IDs', () => {
328
+ const TestComponent = ({ worksheetId }) => {
329
+ const { sendMessage } = useSpotterAgent({ worksheetId });
330
+ expect(sendMessage).toBeDefined();
331
+ return React.createElement("div", null, "Test");
332
+ };
333
+ const { rerender } = render(React.createElement(TestComponent, { worksheetId: "worksheet1" }));
334
+ // Should handle different worksheet IDs
335
+ expect(() => {
336
+ rerender(React.createElement(TestComponent, { worksheetId: "worksheet2" }));
337
+ rerender(React.createElement(TestComponent, { worksheetId: "worksheet3" }));
338
+ }).not.toThrow();
339
+ });
340
+ it('Should handle empty query strings', () => {
341
+ let sendMessageFunction;
342
+ const TestComponent = () => {
343
+ const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
344
+ sendMessageFunction = sendMessage;
345
+ return React.createElement("div", null, "Test");
346
+ };
347
+ render(React.createElement(TestComponent, null));
348
+ // Should handle empty strings
349
+ expect(() => {
350
+ sendMessageFunction('');
351
+ sendMessageFunction(' ');
352
+ }).not.toThrow();
353
+ });
354
+ it('Should handle complex config objects', () => {
355
+ const complexConfig = {
356
+ worksheetId: 'test-worksheet',
357
+ hiddenActions: [Action.ReportError],
358
+ className: 'test-class',
359
+ searchOptions: {
360
+ searchQuery: 'test query'
361
+ }
362
+ };
363
+ const TestComponent = () => {
364
+ const { sendMessage } = useSpotterAgent(complexConfig);
365
+ expect(sendMessage).toBeDefined();
366
+ return React.createElement("div", null, "Test");
367
+ };
368
+ // Should not throw with complex config
369
+ expect(() => {
370
+ render(React.createElement(TestComponent, null));
371
+ }).not.toThrow();
372
+ });
373
+ it('Should maintain function identity across re-renders with same config', () => {
374
+ let sendMessage1, sendMessage2;
375
+ const TestComponent = ({ forceRender }) => {
376
+ const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
377
+ if (forceRender === 1) {
378
+ sendMessage1 = sendMessage;
379
+ }
380
+ else {
381
+ sendMessage2 = sendMessage;
382
+ }
383
+ return React.createElement("div", null, "Test");
384
+ };
385
+ const { rerender } = render(React.createElement(TestComponent, { forceRender: 1 }));
386
+ rerender(React.createElement(TestComponent, { forceRender: 2 }));
387
+ // Functions should exist
388
+ expect(sendMessage1).toBeDefined();
389
+ expect(sendMessage2).toBeDefined();
390
+ expect(typeof sendMessage1).toBe('function');
391
+ expect(typeof sendMessage2).toBe('function');
392
+ });
393
+ it('Should handle sendMessage calls with null service ref', async () => {
394
+ let capturedSendMessage;
395
+ const TestComponent = () => {
396
+ const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
397
+ capturedSendMessage = sendMessage;
398
+ return React.createElement("div", null, "Test");
399
+ };
400
+ const { unmount } = render(React.createElement(TestComponent, null));
401
+ // Unmount to trigger cleanup
402
+ unmount();
403
+ // Now call sendMessage after unmount - should return error
404
+ const result = await capturedSendMessage('test query');
405
+ expect(result).toEqual({
406
+ error: expect.any(Error)
407
+ });
408
+ });
409
+ it('Should test service ref cleanup on config change', () => {
410
+ const TestComponent = ({ worksheetId }) => {
411
+ const { sendMessage } = useSpotterAgent({ worksheetId });
412
+ expect(sendMessage).toBeDefined();
413
+ return React.createElement("div", null, "Test");
414
+ };
415
+ const { rerender } = render(React.createElement(TestComponent, { worksheetId: "worksheet1" }));
416
+ // This should trigger the cleanup and create new service
417
+ rerender(React.createElement(TestComponent, { worksheetId: "worksheet2" }));
418
+ // Should still work after rerender
419
+ expect(() => {
420
+ rerender(React.createElement(TestComponent, { worksheetId: "worksheet3" }));
421
+ }).not.toThrow();
422
+ });
423
+ it('Should test different config variations', () => {
424
+ const configs = [
425
+ { worksheetId: 'test1' },
426
+ { worksheetId: 'test2', hiddenActions: [Action.ReportError] },
427
+ { worksheetId: 'test3', className: 'test-class' },
428
+ { worksheetId: 'test4', searchOptions: { searchQuery: 'test' } }
429
+ ];
430
+ configs.forEach((config, index) => {
431
+ const TestComponent = () => {
432
+ const { sendMessage } = useSpotterAgent(config);
433
+ expect(sendMessage).toBeDefined();
434
+ return React.createElement("div", null,
435
+ "Test ",
436
+ index);
182
437
  };
183
- return (React.createElement(React.Fragment, null,
184
- React.createElement(SpotterAgentEmbed, { ref: embedRef, worksheetId: "test-worksheet-id" }),
185
- React.createElement("button", { "data-testid": "use-embed-ref-button", onClick: handleClick }, "Send with useEmbedRef")));
438
+ expect(() => {
439
+ const { unmount } = render(React.createElement(TestComponent, null));
440
+ unmount();
441
+ }).not.toThrow();
442
+ });
443
+ });
444
+ it('Should handle rapid config changes', () => {
445
+ const TestComponent = ({ worksheetId }) => {
446
+ const { sendMessage } = useSpotterAgent({ worksheetId });
447
+ expect(sendMessage).toBeDefined();
448
+ return React.createElement("div", null, "Test");
186
449
  };
187
- const { getByTestId } = render(React.createElement(TestComponent, null));
188
- fireEvent.click(getByTestId('use-embed-ref-button'));
189
- expect(mockSendMessage).toHaveBeenCalledWith("Test with useEmbedRef");
450
+ const { rerender } = render(React.createElement(TestComponent, { worksheetId: "worksheet1" }));
451
+ // Rapid config changes to test cleanup logic
452
+ for (let i = 2; i <= 10; i++) {
453
+ rerender(React.createElement(TestComponent, { worksheetId: `worksheet${i}` }));
454
+ }
455
+ // Should still work after many changes
456
+ expect(() => {
457
+ rerender(React.createElement(TestComponent, { worksheetId: "final-worksheet" }));
458
+ }).not.toThrow();
190
459
  });
191
- it('Should work with the className prop', async () => {
192
- let capturedInstance = null;
460
+ it('Should handle sendMessage with different query types', () => {
461
+ let sendMessageFunction;
193
462
  const TestComponent = () => {
194
- const embedRef = useEmbedRef();
195
- React.useEffect(() => {
196
- capturedInstance = embedRef.current;
197
- if (capturedInstance) {
198
- const mockConversationService = {
199
- sendMessage: jest.fn().mockResolvedValue({
200
- data: {
201
- sessionId: 'test-session',
202
- genNo: 1,
203
- stateKey: {
204
- transactionId: 'test-transaction',
205
- generationNumber: 1
206
- }
207
- }
208
- })
209
- };
210
- capturedInstance.conversationService = mockConversationService;
211
- }
212
- }, []);
213
- return (React.createElement(SpotterAgentEmbed, { ref: embedRef, worksheetId: "test-worksheet-id", className: "embedClass" }));
463
+ const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
464
+ sendMessageFunction = sendMessage;
465
+ return React.createElement("div", null, "Test");
214
466
  };
215
467
  render(React.createElement(TestComponent, null));
216
- expect(capturedInstance).not.toBeNull();
217
- if (capturedInstance) {
218
- const result = await capturedInstance.sendMessage("test");
219
- expect(result.container.className).toBe("embedClass");
468
+ // Test different query types
469
+ const queries = [
470
+ 'simple query',
471
+ 'query with numbers 123',
472
+ 'query with special chars !@#$%',
473
+ 'very long query that might test different code paths in the system when processing',
474
+ '',
475
+ ' whitespace ',
476
+ 'null',
477
+ 'undefined'
478
+ ];
479
+ queries.forEach(query => {
480
+ expect(() => {
481
+ sendMessageFunction(query);
482
+ }).not.toThrow();
483
+ });
484
+ });
485
+ it('Should handle service ref cleanup when it already exists', () => {
486
+ const TestComponent = ({ worksheetId }) => {
487
+ const { sendMessage } = useSpotterAgent({ worksheetId });
488
+ expect(sendMessage).toBeDefined();
489
+ return React.createElement("div", null, "Test");
490
+ };
491
+ const { rerender } = render(React.createElement(TestComponent, { worksheetId: "worksheet1" }));
492
+ // This should trigger the "if (serviceRef.current)" branch in useEffect
493
+ rerender(React.createElement(TestComponent, { worksheetId: "worksheet1" }));
494
+ rerender(React.createElement(TestComponent, { worksheetId: "worksheet2" }));
495
+ rerender(React.createElement(TestComponent, { worksheetId: "worksheet3" }));
496
+ // Multiple rapid changes should exercise the cleanup logic
497
+ for (let i = 0; i < 5; i++) {
498
+ rerender(React.createElement(TestComponent, { worksheetId: `worksheet${i}` }));
220
499
  }
221
500
  });
501
+ it('Should test various config combinations to hit all branches', () => {
502
+ const testConfigs = [
503
+ { worksheetId: 'test1' },
504
+ { worksheetId: 'test2', className: 'custom-class' },
505
+ { worksheetId: 'test3', hiddenActions: [Action.ReportError] },
506
+ { worksheetId: 'test4', searchOptions: { searchQuery: 'test' } },
507
+ { worksheetId: 'test5', insertAsSibling: true },
508
+ { worksheetId: 'test6', insertAsSibling: false },
509
+ ];
510
+ testConfigs.forEach((config, index) => {
511
+ const TestComponent = () => {
512
+ const { sendMessage } = useSpotterAgent(config);
513
+ expect(sendMessage).toBeDefined();
514
+ return React.createElement("div", null,
515
+ "Test ",
516
+ index);
517
+ };
518
+ const { unmount } = render(React.createElement(TestComponent, null));
519
+ unmount();
520
+ });
521
+ });
522
+ });
523
+ describe('Component Props and Functions', () => {
524
+ it('Should have PreRenderedLiveboardEmbed component', () => {
525
+ expect(PreRenderedLiveboardEmbed).toBeDefined();
526
+ expect(typeof PreRenderedLiveboardEmbed).toBe('object');
527
+ });
528
+ it('Should have useInit hook', () => {
529
+ expect(typeof useInit).toBe('function');
530
+ });
531
+ it('Should test basic component factory patterns', () => {
532
+ // Test that components can be created without errors
533
+ expect(() => {
534
+ const TestComponent = () => React.createElement("div", null, "Test");
535
+ render(React.createElement(TestComponent, null));
536
+ }).not.toThrow();
537
+ });
222
538
  });
223
- describe('PreRenderedLiveboardEmbed', () => {
224
- it('should preRender the liveboard ', async () => {
225
- const preRenderId = 'tsEmbed-pre-render-wrapper-test';
226
- const { container } = render(React.createElement(PreRenderedLiveboardEmbed, { className: "embedClass", preRenderId: "test", liveboardId: "libId" }));
227
- await waitFor(() => getIFrameEl());
228
- const preRenderWrapper = document.body.querySelector(`#${preRenderId}`);
229
- expect(preRenderWrapper).toBeInstanceOf(HTMLDivElement);
230
- expect(preRenderWrapper.childElementCount).toBe(1);
231
- const preRenderChildId = 'tsEmbed-pre-render-child-test';
232
- const preRenderChild = document.body.querySelector(`#${preRenderChildId}`);
233
- expect(preRenderWrapper.children[0]).toBe(preRenderChild);
234
- window.ResizeObserver = jest.fn().mockImplementation(() => ({
235
- disconnect: jest.fn(),
236
- observe: jest.fn(),
237
- unobserve: jest.fn(),
238
- }));
239
- const { container: libContainer } = render(React.createElement(LiveboardEmbed, { className: "embedClass", preRenderId: "test", liveboardId: "libId" }));
240
- expect(preRenderWrapper.style.opacity).toBe('');
241
- expect(preRenderWrapper.style.pointerEvents).toBe('');
242
- expect(preRenderWrapper.style.zIndex).toBe('');
539
+ describe('Hook Coverage', () => {
540
+ it('Should have useInit function available', () => {
541
+ expect(typeof useInit).toBe('function');
542
+ });
543
+ it('Should test useInit hook basic functionality', () => {
544
+ const TestComponent = () => {
545
+ const authEE = useInit({
546
+ thoughtSpotHost: 'localhost',
547
+ authType: AuthType.None
548
+ });
549
+ expect(authEE).toBeDefined();
550
+ expect(authEE.current).toBeDefined();
551
+ return React.createElement("div", null, "Test");
552
+ };
553
+ render(React.createElement(TestComponent, null));
554
+ });
555
+ it('Should handle useInit with different config changes', () => {
556
+ const TestComponent = ({ host }) => {
557
+ const authEE = useInit({
558
+ thoughtSpotHost: host,
559
+ authType: AuthType.None
560
+ });
561
+ expect(authEE).toBeDefined();
562
+ return React.createElement("div", null, "Test");
563
+ };
564
+ const { rerender } = render(React.createElement(TestComponent, { host: "localhost" }));
565
+ // Change config to test useDeepCompareEffect
566
+ rerender(React.createElement(TestComponent, { host: "localhost2" }));
567
+ rerender(React.createElement(TestComponent, { host: "localhost3" }));
568
+ });
569
+ it('Should test useInit with complex config objects', () => {
570
+ const TestComponent = () => {
571
+ const authEE = useInit({
572
+ thoughtSpotHost: 'localhost',
573
+ authType: AuthType.None,
574
+ suppressNoCookieAccessAlert: true,
575
+ suppressErrorAlerts: true
576
+ });
577
+ expect(authEE).toBeDefined();
578
+ return React.createElement("div", null, "Test");
579
+ };
580
+ render(React.createElement(TestComponent, null));
243
581
  });
244
582
  });
245
583
  });