@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
@@ -129,120 +129,458 @@ describe('React Components', () => {
129
129
  expect((0, test_utils_1.getIFrameSrc)(container)).toBe(`http://${thoughtSpotHost}/?embedApp=true&hostAppUrl=local-host&viewPortHeight=768&viewPortWidth=1024&sdkVersion=${package_json_1.version}&authType=None&blockNonEmbedFullAppAccess=true&hideAction=[%22${types_1.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`);
130
130
  });
131
131
  });
132
- describe('SpotterAgentEmbed', () => {
133
- it('Should work as a React component integrating BodylessConversation', async () => {
134
- const mockDiv = document.createElement('div');
135
- let conversationService = null;
136
- (0, react_2.render)(react_1.default.createElement(index_1.SpotterAgentEmbed, { ref: (instance) => {
137
- conversationService = instance;
138
- if (instance) {
139
- instance.sendMessage = jest.fn().mockResolvedValue({
140
- container: mockDiv
141
- });
142
- }
143
- }, worksheetId: "test-worksheet-id" }));
144
- expect(conversationService).not.toBeNull();
145
- if (conversationService) {
146
- expect(typeof conversationService.sendMessage).toBe('function');
147
- const response = await conversationService.sendMessage("What are my sales this month?");
148
- expect(response.container).toBe(mockDiv);
149
- }
132
+ describe('SpotterMessage', () => {
133
+ const mockMessage = {
134
+ sessionId: "session123",
135
+ genNo: 1,
136
+ acSessionId: "acSession123",
137
+ acGenNo: 2,
138
+ worksheetId: "worksheet123",
139
+ convId: "conv123",
140
+ messageId: "message123"
141
+ };
142
+ it('Should render the SpotterMessage component with required props', async () => {
143
+ const { container } = (0, react_2.render)(react_1.default.createElement(index_1.SpotterMessage, { message: mockMessage }));
144
+ await (0, react_2.waitFor)(() => (0, test_utils_1.getIFrameEl)(container));
145
+ expect((0, test_utils_1.getIFrameEl)(container)).not.toBe(null);
146
+ expect((0, test_utils_1.getIFrameSrc)(container)).toContain('sessionId=session123');
147
+ expect((0, test_utils_1.getIFrameSrc)(container)).toContain('genNo=1');
148
+ expect((0, test_utils_1.getIFrameSrc)(container)).toContain('acSessionId=acSession123');
149
+ expect((0, test_utils_1.getIFrameSrc)(container)).toContain('acGenNo=2');
150
150
  });
151
- it('Should work as a React component with ref support', () => {
152
- const mockSendMessage = jest.fn().mockResolvedValue({
153
- container: document.createElement('div'),
154
- viz: {}
155
- });
151
+ it('Should render the SpotterMessage component with optional query', async () => {
152
+ const { container } = (0, react_2.render)(react_1.default.createElement(index_1.SpotterMessage, { message: mockMessage, query: "show me sales" }));
153
+ await (0, react_2.waitFor)(() => (0, test_utils_1.getIFrameEl)(container));
154
+ expect((0, test_utils_1.getIFrameEl)(container)).not.toBe(null);
155
+ expect((0, test_utils_1.getIFrameSrc)(container)).toContain('sessionId=session123');
156
+ });
157
+ it('Should have the correct container element with className', async () => {
158
+ const { container } = (0, react_2.render)(react_1.default.createElement(index_1.SpotterMessage, { message: mockMessage, className: "custom-class" }));
159
+ await (0, react_2.waitFor)(() => (0, test_utils_1.getIFrameEl)(container));
160
+ expect((0, test_utils_1.getIFrameEl)(container).parentElement.classList.contains('custom-class')).toBe(true);
161
+ });
162
+ // Note: insertAsSibling is not supported for SpotterMessage as it's not part of the allowed props
163
+ });
164
+ describe('Component Factory Coverage', () => {
165
+ it('Should test basic component creation', () => {
166
+ expect(() => {
167
+ (0, react_2.render)(react_1.default.createElement(index_1.LiveboardEmbed, { liveboardId: "test" }));
168
+ }).not.toThrow();
169
+ expect(() => {
170
+ (0, react_2.render)(react_1.default.createElement(index_1.SearchEmbed, { dataSource: "test" }));
171
+ }).not.toThrow();
172
+ expect(() => {
173
+ (0, react_2.render)(react_1.default.createElement(index_1.AppEmbed, { showPrimaryNavbar: false }));
174
+ }).not.toThrow();
175
+ });
176
+ it('Should test component factory existence', () => {
177
+ expect(index_1.PreRenderedLiveboardEmbed).toBeDefined();
178
+ expect(index_1.PreRenderedSearchEmbed).toBeDefined();
179
+ expect(index_1.PreRenderedAppEmbed).toBeDefined();
180
+ expect(typeof index_1.PreRenderedLiveboardEmbed).toBe('object');
181
+ expect(typeof index_1.PreRenderedSearchEmbed).toBe('object');
182
+ expect(typeof index_1.PreRenderedAppEmbed).toBe('object');
183
+ });
184
+ });
185
+ describe('Components with insertAsSibling', () => {
186
+ it('Should render LiveboardEmbed with insertAsSibling', async () => {
187
+ var _a;
188
+ const { container } = (0, react_2.render)(react_1.default.createElement(index_1.LiveboardEmbed, { liveboardId: "test-liveboard", insertAsSibling: true }));
189
+ await (0, react_2.waitFor)(() => (0, test_utils_1.getIFrameEl)(container));
190
+ expect(container.querySelector('span')).not.toBe(null);
191
+ expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
192
+ });
193
+ it('Should render SearchEmbed with insertAsSibling', async () => {
194
+ var _a;
195
+ const { container } = (0, react_2.render)(react_1.default.createElement(index_1.SearchEmbed, { dataSource: "test-datasource", insertAsSibling: true }));
196
+ await (0, react_2.waitFor)(() => (0, test_utils_1.getIFrameEl)(container));
197
+ expect(container.querySelector('span')).not.toBe(null);
198
+ expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
199
+ });
200
+ it('Should render AppEmbed with insertAsSibling', async () => {
201
+ var _a;
202
+ const { container } = (0, react_2.render)(react_1.default.createElement(index_1.AppEmbed, { showPrimaryNavbar: false, insertAsSibling: true }));
203
+ await (0, react_2.waitFor)(() => (0, test_utils_1.getIFrameEl)(container));
204
+ expect(container.querySelector('span')).not.toBe(null);
205
+ expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
206
+ });
207
+ it('Should render SearchBarEmbed with insertAsSibling', async () => {
208
+ var _a;
209
+ const { container } = (0, react_2.render)(react_1.default.createElement(index_1.SearchBarEmbed, { dataSource: "test-datasource", insertAsSibling: true }));
210
+ await (0, react_2.waitFor)(() => (0, test_utils_1.getIFrameEl)(container));
211
+ expect(container.querySelector('span')).not.toBe(null);
212
+ expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
213
+ });
214
+ it('Should render components with both insertAsSibling and className', async () => {
215
+ const { container } = (0, react_2.render)(react_1.default.createElement(index_1.LiveboardEmbed, { liveboardId: "test-liveboard", insertAsSibling: true, className: "custom-class" }));
216
+ await (0, react_2.waitFor)(() => (0, test_utils_1.getIFrameEl)(container));
217
+ expect(container.querySelector('span')).not.toBe(null);
218
+ expect((0, test_utils_1.getIFrameEl)(container).classList.contains('custom-class')).toBe(true);
219
+ });
220
+ });
221
+ describe('useSpotterAgent', () => {
222
+ it('Should return an object with sendMessage function', () => {
156
223
  const TestComponent = () => {
157
- const conversationRef = react_1.default.useRef(null);
158
- const handleClick = () => {
159
- if (conversationRef.current) {
160
- conversationRef.current.sendMessage = mockSendMessage;
161
- conversationRef.current.sendMessage("Test message");
162
- }
163
- };
164
- return (react_1.default.createElement(react_1.default.Fragment, null,
165
- react_1.default.createElement(index_1.SpotterAgentEmbed, { ref: conversationRef, worksheetId: "test-worksheet-id" }),
166
- react_1.default.createElement("button", { "data-testid": "test-button", onClick: handleClick }, "Send Message")));
224
+ const spotterAgent = (0, index_1.useSpotterAgent)({ worksheetId: 'test-worksheet' });
225
+ expect(typeof spotterAgent).toBe('object');
226
+ expect(typeof spotterAgent.sendMessage).toBe('function');
227
+ return react_1.default.createElement("div", null, "Test");
167
228
  };
168
- const { getByTestId } = (0, react_2.render)(react_1.default.createElement(TestComponent, null));
169
- react_2.fireEvent.click(getByTestId('test-button'));
170
- expect(mockSendMessage).toHaveBeenCalledWith("Test message");
171
- });
172
- it('Should work with the useEmbedRef hook', () => {
173
- const mockSendMessage = jest.fn().mockResolvedValue({
174
- container: document.createElement('div'),
175
- viz: {}
229
+ (0, react_2.render)(react_1.default.createElement(TestComponent, null));
230
+ });
231
+ it('Should have proper sendMessage callback structure', () => {
232
+ const TestComponent = () => {
233
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId: 'test-worksheet' });
234
+ // Test that sendMessage is a function that accepts a string
235
+ expect(typeof sendMessage).toBe('function');
236
+ expect(sendMessage.length).toBe(1); // Should accept one parameter
237
+ return react_1.default.createElement("div", null, "Test");
238
+ };
239
+ (0, react_2.render)(react_1.default.createElement(TestComponent, null));
240
+ });
241
+ it('Should return error when service is not initialized', async () => {
242
+ let sendMessageResult;
243
+ const TestComponent = () => {
244
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId: 'test-worksheet' });
245
+ // Call sendMessage immediately before service has time to initialize
246
+ sendMessageResult = sendMessage('test query');
247
+ return react_1.default.createElement("div", null, "Test");
248
+ };
249
+ (0, react_2.render)(react_1.default.createElement(TestComponent, null));
250
+ const result = await sendMessageResult;
251
+ expect(result).toEqual({
252
+ error: expect.any(Error)
176
253
  });
254
+ expect(result.error.message).toBe('SpotterAgent not initialized');
255
+ });
256
+ it('Should call sendMessage and handle async behavior', async () => {
257
+ let sendMessageFunction;
177
258
  const TestComponent = () => {
178
- const embedRef = (0, index_1.useEmbedRef)();
179
- const handleClick = () => {
180
- if (embedRef.current) {
181
- const service = embedRef.current;
182
- service.sendMessage = mockSendMessage;
183
- service.sendMessage("Test with useEmbedRef");
184
- }
259
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId: 'test-worksheet' });
260
+ sendMessageFunction = sendMessage;
261
+ return react_1.default.createElement("div", null, "Test");
262
+ };
263
+ (0, react_2.render)(react_1.default.createElement(TestComponent, null));
264
+ // Test that sendMessage is a function
265
+ expect(typeof sendMessageFunction).toBe('function');
266
+ // Call sendMessage - should not throw
267
+ expect(() => {
268
+ sendMessageFunction('test query');
269
+ }).not.toThrow();
270
+ });
271
+ it('Should handle multiple calls to sendMessage', async () => {
272
+ let sendMessageFunction;
273
+ const TestComponent = () => {
274
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId: 'test-worksheet' });
275
+ sendMessageFunction = sendMessage;
276
+ return react_1.default.createElement("div", null, "Test");
277
+ };
278
+ (0, react_2.render)(react_1.default.createElement(TestComponent, null));
279
+ // Multiple calls should not throw
280
+ expect(() => {
281
+ sendMessageFunction('query 1');
282
+ sendMessageFunction('query 2');
283
+ sendMessageFunction('query 3');
284
+ }).not.toThrow();
285
+ });
286
+ it('Should handle config object changes', () => {
287
+ const TestComponent = ({ config }) => {
288
+ const { sendMessage } = (0, index_1.useSpotterAgent)(config);
289
+ expect(sendMessage).toBeDefined();
290
+ return react_1.default.createElement("div", null, "Test");
291
+ };
292
+ const config1 = { worksheetId: 'test1' };
293
+ const config2 = { worksheetId: 'test2' };
294
+ const { rerender } = (0, react_2.render)(react_1.default.createElement(TestComponent, { config: config1 }));
295
+ // Should not throw when config changes
296
+ expect(() => {
297
+ rerender(react_1.default.createElement(TestComponent, { config: config2 }));
298
+ }).not.toThrow();
299
+ });
300
+ it('Should handle unmounting without errors', () => {
301
+ const TestComponent = () => {
302
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId: 'test-worksheet' });
303
+ expect(sendMessage).toBeDefined();
304
+ return react_1.default.createElement("div", null, "Test");
305
+ };
306
+ const { unmount } = (0, react_2.render)(react_1.default.createElement(TestComponent, null));
307
+ // Should not throw when unmounting
308
+ expect(() => {
309
+ unmount();
310
+ }).not.toThrow();
311
+ });
312
+ it('Should create stable hook structure', () => {
313
+ let hookResult1, hookResult2;
314
+ const TestComponent = ({ counter }) => {
315
+ const result = (0, index_1.useSpotterAgent)({ worksheetId: 'test-worksheet' });
316
+ if (counter === 1) {
317
+ hookResult1 = result;
318
+ }
319
+ else {
320
+ hookResult2 = result;
321
+ }
322
+ return react_1.default.createElement("div", null, "Test");
323
+ };
324
+ const { rerender } = (0, react_2.render)(react_1.default.createElement(TestComponent, { counter: 1 }));
325
+ rerender(react_1.default.createElement(TestComponent, { counter: 2 }));
326
+ // Both should have same structure
327
+ expect(hookResult1).toEqual({ sendMessage: expect.any(Function) });
328
+ expect(hookResult2).toEqual({ sendMessage: expect.any(Function) });
329
+ });
330
+ it('Should handle different worksheet IDs', () => {
331
+ const TestComponent = ({ worksheetId }) => {
332
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId });
333
+ expect(sendMessage).toBeDefined();
334
+ return react_1.default.createElement("div", null, "Test");
335
+ };
336
+ const { rerender } = (0, react_2.render)(react_1.default.createElement(TestComponent, { worksheetId: "worksheet1" }));
337
+ // Should handle different worksheet IDs
338
+ expect(() => {
339
+ rerender(react_1.default.createElement(TestComponent, { worksheetId: "worksheet2" }));
340
+ rerender(react_1.default.createElement(TestComponent, { worksheetId: "worksheet3" }));
341
+ }).not.toThrow();
342
+ });
343
+ it('Should handle empty query strings', () => {
344
+ let sendMessageFunction;
345
+ const TestComponent = () => {
346
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId: 'test-worksheet' });
347
+ sendMessageFunction = sendMessage;
348
+ return react_1.default.createElement("div", null, "Test");
349
+ };
350
+ (0, react_2.render)(react_1.default.createElement(TestComponent, null));
351
+ // Should handle empty strings
352
+ expect(() => {
353
+ sendMessageFunction('');
354
+ sendMessageFunction(' ');
355
+ }).not.toThrow();
356
+ });
357
+ it('Should handle complex config objects', () => {
358
+ const complexConfig = {
359
+ worksheetId: 'test-worksheet',
360
+ hiddenActions: [types_1.Action.ReportError],
361
+ className: 'test-class',
362
+ searchOptions: {
363
+ searchQuery: 'test query'
364
+ }
365
+ };
366
+ const TestComponent = () => {
367
+ const { sendMessage } = (0, index_1.useSpotterAgent)(complexConfig);
368
+ expect(sendMessage).toBeDefined();
369
+ return react_1.default.createElement("div", null, "Test");
370
+ };
371
+ // Should not throw with complex config
372
+ expect(() => {
373
+ (0, react_2.render)(react_1.default.createElement(TestComponent, null));
374
+ }).not.toThrow();
375
+ });
376
+ it('Should maintain function identity across re-renders with same config', () => {
377
+ let sendMessage1, sendMessage2;
378
+ const TestComponent = ({ forceRender }) => {
379
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId: 'test-worksheet' });
380
+ if (forceRender === 1) {
381
+ sendMessage1 = sendMessage;
382
+ }
383
+ else {
384
+ sendMessage2 = sendMessage;
385
+ }
386
+ return react_1.default.createElement("div", null, "Test");
387
+ };
388
+ const { rerender } = (0, react_2.render)(react_1.default.createElement(TestComponent, { forceRender: 1 }));
389
+ rerender(react_1.default.createElement(TestComponent, { forceRender: 2 }));
390
+ // Functions should exist
391
+ expect(sendMessage1).toBeDefined();
392
+ expect(sendMessage2).toBeDefined();
393
+ expect(typeof sendMessage1).toBe('function');
394
+ expect(typeof sendMessage2).toBe('function');
395
+ });
396
+ it('Should handle sendMessage calls with null service ref', async () => {
397
+ let capturedSendMessage;
398
+ const TestComponent = () => {
399
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId: 'test-worksheet' });
400
+ capturedSendMessage = sendMessage;
401
+ return react_1.default.createElement("div", null, "Test");
402
+ };
403
+ const { unmount } = (0, react_2.render)(react_1.default.createElement(TestComponent, null));
404
+ // Unmount to trigger cleanup
405
+ unmount();
406
+ // Now call sendMessage after unmount - should return error
407
+ const result = await capturedSendMessage('test query');
408
+ expect(result).toEqual({
409
+ error: expect.any(Error)
410
+ });
411
+ });
412
+ it('Should test service ref cleanup on config change', () => {
413
+ const TestComponent = ({ worksheetId }) => {
414
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId });
415
+ expect(sendMessage).toBeDefined();
416
+ return react_1.default.createElement("div", null, "Test");
417
+ };
418
+ const { rerender } = (0, react_2.render)(react_1.default.createElement(TestComponent, { worksheetId: "worksheet1" }));
419
+ // This should trigger the cleanup and create new service
420
+ rerender(react_1.default.createElement(TestComponent, { worksheetId: "worksheet2" }));
421
+ // Should still work after rerender
422
+ expect(() => {
423
+ rerender(react_1.default.createElement(TestComponent, { worksheetId: "worksheet3" }));
424
+ }).not.toThrow();
425
+ });
426
+ it('Should test different config variations', () => {
427
+ const configs = [
428
+ { worksheetId: 'test1' },
429
+ { worksheetId: 'test2', hiddenActions: [types_1.Action.ReportError] },
430
+ { worksheetId: 'test3', className: 'test-class' },
431
+ { worksheetId: 'test4', searchOptions: { searchQuery: 'test' } }
432
+ ];
433
+ configs.forEach((config, index) => {
434
+ const TestComponent = () => {
435
+ const { sendMessage } = (0, index_1.useSpotterAgent)(config);
436
+ expect(sendMessage).toBeDefined();
437
+ return react_1.default.createElement("div", null,
438
+ "Test ",
439
+ index);
185
440
  };
186
- return (react_1.default.createElement(react_1.default.Fragment, null,
187
- react_1.default.createElement(index_1.SpotterAgentEmbed, { ref: embedRef, worksheetId: "test-worksheet-id" }),
188
- react_1.default.createElement("button", { "data-testid": "use-embed-ref-button", onClick: handleClick }, "Send with useEmbedRef")));
441
+ expect(() => {
442
+ const { unmount } = (0, react_2.render)(react_1.default.createElement(TestComponent, null));
443
+ unmount();
444
+ }).not.toThrow();
445
+ });
446
+ });
447
+ it('Should handle rapid config changes', () => {
448
+ const TestComponent = ({ worksheetId }) => {
449
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId });
450
+ expect(sendMessage).toBeDefined();
451
+ return react_1.default.createElement("div", null, "Test");
189
452
  };
190
- const { getByTestId } = (0, react_2.render)(react_1.default.createElement(TestComponent, null));
191
- react_2.fireEvent.click(getByTestId('use-embed-ref-button'));
192
- expect(mockSendMessage).toHaveBeenCalledWith("Test with useEmbedRef");
453
+ const { rerender } = (0, react_2.render)(react_1.default.createElement(TestComponent, { worksheetId: "worksheet1" }));
454
+ // Rapid config changes to test cleanup logic
455
+ for (let i = 2; i <= 10; i++) {
456
+ rerender(react_1.default.createElement(TestComponent, { worksheetId: `worksheet${i}` }));
457
+ }
458
+ // Should still work after many changes
459
+ expect(() => {
460
+ rerender(react_1.default.createElement(TestComponent, { worksheetId: "final-worksheet" }));
461
+ }).not.toThrow();
193
462
  });
194
- it('Should work with the className prop', async () => {
195
- let capturedInstance = null;
463
+ it('Should handle sendMessage with different query types', () => {
464
+ let sendMessageFunction;
196
465
  const TestComponent = () => {
197
- const embedRef = (0, index_1.useEmbedRef)();
198
- react_1.default.useEffect(() => {
199
- capturedInstance = embedRef.current;
200
- if (capturedInstance) {
201
- const mockConversationService = {
202
- sendMessage: jest.fn().mockResolvedValue({
203
- data: {
204
- sessionId: 'test-session',
205
- genNo: 1,
206
- stateKey: {
207
- transactionId: 'test-transaction',
208
- generationNumber: 1
209
- }
210
- }
211
- })
212
- };
213
- capturedInstance.conversationService = mockConversationService;
214
- }
215
- }, []);
216
- return (react_1.default.createElement(index_1.SpotterAgentEmbed, { ref: embedRef, worksheetId: "test-worksheet-id", className: "embedClass" }));
466
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId: 'test-worksheet' });
467
+ sendMessageFunction = sendMessage;
468
+ return react_1.default.createElement("div", null, "Test");
217
469
  };
218
470
  (0, react_2.render)(react_1.default.createElement(TestComponent, null));
219
- expect(capturedInstance).not.toBeNull();
220
- if (capturedInstance) {
221
- const result = await capturedInstance.sendMessage("test");
222
- expect(result.container.className).toBe("embedClass");
471
+ // Test different query types
472
+ const queries = [
473
+ 'simple query',
474
+ 'query with numbers 123',
475
+ 'query with special chars !@#$%',
476
+ 'very long query that might test different code paths in the system when processing',
477
+ '',
478
+ ' whitespace ',
479
+ 'null',
480
+ 'undefined'
481
+ ];
482
+ queries.forEach(query => {
483
+ expect(() => {
484
+ sendMessageFunction(query);
485
+ }).not.toThrow();
486
+ });
487
+ });
488
+ it('Should handle service ref cleanup when it already exists', () => {
489
+ const TestComponent = ({ worksheetId }) => {
490
+ const { sendMessage } = (0, index_1.useSpotterAgent)({ worksheetId });
491
+ expect(sendMessage).toBeDefined();
492
+ return react_1.default.createElement("div", null, "Test");
493
+ };
494
+ const { rerender } = (0, react_2.render)(react_1.default.createElement(TestComponent, { worksheetId: "worksheet1" }));
495
+ // This should trigger the "if (serviceRef.current)" branch in useEffect
496
+ rerender(react_1.default.createElement(TestComponent, { worksheetId: "worksheet1" }));
497
+ rerender(react_1.default.createElement(TestComponent, { worksheetId: "worksheet2" }));
498
+ rerender(react_1.default.createElement(TestComponent, { worksheetId: "worksheet3" }));
499
+ // Multiple rapid changes should exercise the cleanup logic
500
+ for (let i = 0; i < 5; i++) {
501
+ rerender(react_1.default.createElement(TestComponent, { worksheetId: `worksheet${i}` }));
223
502
  }
224
503
  });
504
+ it('Should test various config combinations to hit all branches', () => {
505
+ const testConfigs = [
506
+ { worksheetId: 'test1' },
507
+ { worksheetId: 'test2', className: 'custom-class' },
508
+ { worksheetId: 'test3', hiddenActions: [types_1.Action.ReportError] },
509
+ { worksheetId: 'test4', searchOptions: { searchQuery: 'test' } },
510
+ { worksheetId: 'test5', insertAsSibling: true },
511
+ { worksheetId: 'test6', insertAsSibling: false },
512
+ ];
513
+ testConfigs.forEach((config, index) => {
514
+ const TestComponent = () => {
515
+ const { sendMessage } = (0, index_1.useSpotterAgent)(config);
516
+ expect(sendMessage).toBeDefined();
517
+ return react_1.default.createElement("div", null,
518
+ "Test ",
519
+ index);
520
+ };
521
+ const { unmount } = (0, react_2.render)(react_1.default.createElement(TestComponent, null));
522
+ unmount();
523
+ });
524
+ });
525
+ });
526
+ describe('Component Props and Functions', () => {
527
+ it('Should have PreRenderedLiveboardEmbed component', () => {
528
+ expect(index_1.PreRenderedLiveboardEmbed).toBeDefined();
529
+ expect(typeof index_1.PreRenderedLiveboardEmbed).toBe('object');
530
+ });
531
+ it('Should have useInit hook', () => {
532
+ expect(typeof index_1.useInit).toBe('function');
533
+ });
534
+ it('Should test basic component factory patterns', () => {
535
+ // Test that components can be created without errors
536
+ expect(() => {
537
+ const TestComponent = () => react_1.default.createElement("div", null, "Test");
538
+ (0, react_2.render)(react_1.default.createElement(TestComponent, null));
539
+ }).not.toThrow();
540
+ });
225
541
  });
226
- describe('PreRenderedLiveboardEmbed', () => {
227
- it('should preRender the liveboard ', async () => {
228
- const preRenderId = 'tsEmbed-pre-render-wrapper-test';
229
- const { container } = (0, react_2.render)(react_1.default.createElement(index_1.PreRenderedLiveboardEmbed, { className: "embedClass", preRenderId: "test", liveboardId: "libId" }));
230
- await (0, react_2.waitFor)(() => (0, test_utils_1.getIFrameEl)());
231
- const preRenderWrapper = document.body.querySelector(`#${preRenderId}`);
232
- expect(preRenderWrapper).toBeInstanceOf(HTMLDivElement);
233
- expect(preRenderWrapper.childElementCount).toBe(1);
234
- const preRenderChildId = 'tsEmbed-pre-render-child-test';
235
- const preRenderChild = document.body.querySelector(`#${preRenderChildId}`);
236
- expect(preRenderWrapper.children[0]).toBe(preRenderChild);
237
- window.ResizeObserver = jest.fn().mockImplementation(() => ({
238
- disconnect: jest.fn(),
239
- observe: jest.fn(),
240
- unobserve: jest.fn(),
241
- }));
242
- const { container: libContainer } = (0, react_2.render)(react_1.default.createElement(index_1.LiveboardEmbed, { className: "embedClass", preRenderId: "test", liveboardId: "libId" }));
243
- expect(preRenderWrapper.style.opacity).toBe('');
244
- expect(preRenderWrapper.style.pointerEvents).toBe('');
245
- expect(preRenderWrapper.style.zIndex).toBe('');
542
+ describe('Hook Coverage', () => {
543
+ it('Should have useInit function available', () => {
544
+ expect(typeof index_1.useInit).toBe('function');
545
+ });
546
+ it('Should test useInit hook basic functionality', () => {
547
+ const TestComponent = () => {
548
+ const authEE = (0, index_1.useInit)({
549
+ thoughtSpotHost: 'localhost',
550
+ authType: index_2.AuthType.None
551
+ });
552
+ expect(authEE).toBeDefined();
553
+ expect(authEE.current).toBeDefined();
554
+ return react_1.default.createElement("div", null, "Test");
555
+ };
556
+ (0, react_2.render)(react_1.default.createElement(TestComponent, null));
557
+ });
558
+ it('Should handle useInit with different config changes', () => {
559
+ const TestComponent = ({ host }) => {
560
+ const authEE = (0, index_1.useInit)({
561
+ thoughtSpotHost: host,
562
+ authType: index_2.AuthType.None
563
+ });
564
+ expect(authEE).toBeDefined();
565
+ return react_1.default.createElement("div", null, "Test");
566
+ };
567
+ const { rerender } = (0, react_2.render)(react_1.default.createElement(TestComponent, { host: "localhost" }));
568
+ // Change config to test useDeepCompareEffect
569
+ rerender(react_1.default.createElement(TestComponent, { host: "localhost2" }));
570
+ rerender(react_1.default.createElement(TestComponent, { host: "localhost3" }));
571
+ });
572
+ it('Should test useInit with complex config objects', () => {
573
+ const TestComponent = () => {
574
+ const authEE = (0, index_1.useInit)({
575
+ thoughtSpotHost: 'localhost',
576
+ authType: index_2.AuthType.None,
577
+ suppressNoCookieAccessAlert: true,
578
+ suppressErrorAlerts: true
579
+ });
580
+ expect(authEE).toBeDefined();
581
+ return react_1.default.createElement("div", null, "Test");
582
+ };
583
+ (0, react_2.render)(react_1.default.createElement(TestComponent, null));
246
584
  });
247
585
  });
248
586
  });