@thoughtspot/visual-embed-sdk 1.39.1 → 1.39.2-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/package.json +1 -1
- package/cjs/src/config.spec.js +9 -0
- package/cjs/src/config.spec.js.map +1 -1
- package/cjs/src/embed/app.d.ts +75 -15
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js +69 -9
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/app.spec.js +374 -12
- package/cjs/src/embed/app.spec.js.map +1 -1
- package/cjs/src/embed/bodyless-conversation.d.ts +19 -7
- package/cjs/src/embed/bodyless-conversation.d.ts.map +1 -1
- package/cjs/src/embed/bodyless-conversation.js +24 -4
- package/cjs/src/embed/bodyless-conversation.js.map +1 -1
- package/cjs/src/embed/bodyless-conversation.spec.js +8 -190
- package/cjs/src/embed/bodyless-conversation.spec.js.map +1 -1
- package/cjs/src/embed/conversation.spec.js +28 -0
- package/cjs/src/embed/conversation.spec.js.map +1 -1
- package/cjs/src/embed/embedConfig.d.ts +9 -7
- package/cjs/src/embed/embedConfig.d.ts.map +1 -1
- package/cjs/src/embed/embedConfig.js +9 -7
- package/cjs/src/embed/embedConfig.js.map +1 -1
- package/cjs/src/embed/liveboard.d.ts +56 -17
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js +48 -4
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/liveboard.spec.js +215 -11
- package/cjs/src/embed/liveboard.spec.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts +5 -0
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +16 -1
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +164 -0
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/errors.d.ts +1 -0
- package/cjs/src/errors.d.ts.map +1 -1
- package/cjs/src/errors.js +1 -0
- package/cjs/src/errors.js.map +1 -1
- package/cjs/src/index.d.ts +2 -2
- package/cjs/src/index.d.ts.map +1 -1
- package/cjs/src/index.js +2 -1
- package/cjs/src/index.js.map +1 -1
- package/cjs/src/react/all-types-export.d.ts +1 -1
- package/cjs/src/react/all-types-export.d.ts.map +1 -1
- package/cjs/src/react/all-types-export.js +3 -2
- package/cjs/src/react/all-types-export.js.map +1 -1
- package/cjs/src/react/index.d.ts +71 -20
- package/cjs/src/react/index.d.ts.map +1 -1
- package/cjs/src/react/index.js +79 -42
- package/cjs/src/react/index.js.map +1 -1
- package/cjs/src/react/index.spec.js +436 -100
- package/cjs/src/react/index.spec.js.map +1 -1
- package/cjs/src/types.d.ts +80 -6
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +45 -1
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/graphql/nlsService/conversation-service.d.ts.map +1 -1
- package/cjs/src/utils/graphql/nlsService/conversation-service.js +2 -0
- package/cjs/src/utils/graphql/nlsService/conversation-service.js.map +1 -1
- package/cjs/src/utils/processTrigger.js +2 -1
- package/cjs/src/utils/processTrigger.js.map +1 -1
- package/cjs/src/utils.d.ts +6 -0
- package/cjs/src/utils.d.ts.map +1 -1
- package/cjs/src/utils.js +23 -3
- package/cjs/src/utils.js.map +1 -1
- package/cjs/src/utils.spec.js +237 -1
- package/cjs/src/utils.spec.js.map +1 -1
- package/dist/{index-JaFaxrvQ.js → index-CmEQfuE3.js} +1 -1
- package/dist/index-DeFzsyFF.js +7371 -0
- package/dist/index-Dpf0rd6w.js +7371 -0
- package/dist/index-UuEbsISo.js +7447 -0
- package/dist/index-e3Uw3YFO.js +7371 -0
- package/dist/src/embed/app.d.ts +75 -15
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/bodyless-conversation.d.ts +19 -7
- package/dist/src/embed/bodyless-conversation.d.ts.map +1 -1
- package/dist/src/embed/embedConfig.d.ts +9 -7
- package/dist/src/embed/embedConfig.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +56 -17
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts +5 -0
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/errors.d.ts +1 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/react/all-types-export.d.ts +1 -1
- package/dist/src/react/all-types-export.d.ts.map +1 -1
- package/dist/src/react/index.d.ts +71 -20
- package/dist/src/react/index.d.ts.map +1 -1
- package/dist/src/types.d.ts +80 -6
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/graphql/nlsService/conversation-service.d.ts.map +1 -1
- package/dist/src/utils.d.ts +6 -0
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/tsembed-react.es.js +320 -78
- package/dist/tsembed-react.js +320 -76
- package/dist/tsembed.es.js +238 -31
- package/dist/tsembed.js +236 -29
- package/dist/visual-embed-sdk-react-full.d.ts +288 -72
- package/dist/visual-embed-sdk-react.d.ts +288 -72
- package/dist/visual-embed-sdk.d.ts +218 -53
- package/lib/package.json +1 -1
- package/lib/src/config.spec.js +9 -0
- package/lib/src/config.spec.js.map +1 -1
- package/lib/src/embed/app.d.ts +75 -15
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +69 -9
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +376 -14
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/bodyless-conversation.d.ts +19 -7
- package/lib/src/embed/bodyless-conversation.d.ts.map +1 -1
- package/lib/src/embed/bodyless-conversation.js +23 -4
- package/lib/src/embed/bodyless-conversation.js.map +1 -1
- package/lib/src/embed/bodyless-conversation.spec.js +9 -191
- package/lib/src/embed/bodyless-conversation.spec.js.map +1 -1
- package/lib/src/embed/conversation.spec.js +30 -2
- package/lib/src/embed/conversation.spec.js.map +1 -1
- package/lib/src/embed/embedConfig.d.ts +9 -7
- package/lib/src/embed/embedConfig.d.ts.map +1 -1
- package/lib/src/embed/embedConfig.js +9 -7
- package/lib/src/embed/embedConfig.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +56 -17
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +49 -5
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +215 -11
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts +5 -0
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +16 -1
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +164 -0
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/errors.d.ts +1 -0
- package/lib/src/errors.d.ts.map +1 -1
- package/lib/src/errors.js +1 -0
- package/lib/src/errors.js.map +1 -1
- package/lib/src/index.d.ts +2 -2
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js +2 -2
- package/lib/src/index.js.map +1 -1
- package/lib/src/react/all-types-export.d.ts +1 -1
- package/lib/src/react/all-types-export.d.ts.map +1 -1
- package/lib/src/react/all-types-export.js +1 -1
- package/lib/src/react/all-types-export.js.map +1 -1
- package/lib/src/react/index.d.ts +71 -20
- package/lib/src/react/index.d.ts.map +1 -1
- package/lib/src/react/index.js +79 -43
- package/lib/src/react/index.js.map +1 -1
- package/lib/src/react/index.spec.js +439 -103
- package/lib/src/react/index.spec.js.map +1 -1
- package/lib/src/types.d.ts +80 -6
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +45 -1
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/graphql/nlsService/conversation-service.d.ts.map +1 -1
- package/lib/src/utils/graphql/nlsService/conversation-service.js +2 -0
- package/lib/src/utils/graphql/nlsService/conversation-service.js.map +1 -1
- package/lib/src/utils/processTrigger.js +2 -1
- package/lib/src/utils/processTrigger.js.map +1 -1
- package/lib/src/utils.d.ts +6 -0
- package/lib/src/utils.d.ts.map +1 -1
- package/lib/src/utils.js +21 -2
- package/lib/src/utils.js.map +1 -1
- package/lib/src/utils.spec.js +238 -2
- package/lib/src/utils.spec.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +219 -54
- package/package.json +1 -1
- package/src/config.spec.ts +11 -0
- package/src/embed/app.spec.ts +479 -26
- package/src/embed/app.ts +133 -27
- package/src/embed/bodyless-conversation.spec.ts +9 -203
- package/src/embed/bodyless-conversation.ts +24 -10
- package/src/embed/conversation.spec.ts +40 -2
- package/src/embed/embedConfig.ts +10 -8
- package/src/embed/liveboard.spec.ts +256 -5
- package/src/embed/liveboard.ts +99 -27
- package/src/embed/ts-embed.spec.ts +225 -0
- package/src/embed/ts-embed.ts +19 -0
- package/src/errors.ts +1 -0
- package/src/index.ts +2 -0
- package/src/react/all-types-export.ts +2 -1
- package/src/react/index.spec.tsx +556 -157
- package/src/react/index.tsx +117 -51
- package/src/types.ts +117 -43
- package/src/utils/graphql/nlsService/conversation-service.ts +2 -0
- package/src/utils/processTrigger.ts +1 -1
- package/src/utils.spec.ts +279 -2
- package/src/utils.ts +28 -2
|
@@ -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 {
|
|
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,
|
|
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,456 @@ 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('
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
expect(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
+
};
|
|
137
|
+
it('Should render the SpotterMessage component with required props', async () => {
|
|
138
|
+
const { container } = render(React.createElement(SpotterMessage, { message: mockMessage }));
|
|
139
|
+
await waitFor(() => getIFrameEl(container));
|
|
140
|
+
expect(getIFrameEl(container)).not.toBe(null);
|
|
141
|
+
expect(getIFrameSrc(container)).toContain('sessionId=session123');
|
|
142
|
+
expect(getIFrameSrc(container)).toContain('genNo=1');
|
|
143
|
+
expect(getIFrameSrc(container)).toContain('acSessionId=acSession123');
|
|
144
|
+
expect(getIFrameSrc(container)).toContain('acGenNo=2');
|
|
147
145
|
});
|
|
148
|
-
it('Should
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
146
|
+
it('Should render the SpotterMessage component with optional query', async () => {
|
|
147
|
+
const { container } = render(React.createElement(SpotterMessage, { message: mockMessage, query: "show me sales" }));
|
|
148
|
+
await waitFor(() => getIFrameEl(container));
|
|
149
|
+
expect(getIFrameEl(container)).not.toBe(null);
|
|
150
|
+
expect(getIFrameSrc(container)).toContain('sessionId=session123');
|
|
151
|
+
});
|
|
152
|
+
it('Should have the correct container element with className', async () => {
|
|
153
|
+
const { container } = render(React.createElement(SpotterMessage, { message: mockMessage, className: "custom-class" }));
|
|
154
|
+
await waitFor(() => getIFrameEl(container));
|
|
155
|
+
expect(getIFrameEl(container).parentElement.classList.contains('custom-class')).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
// Note: insertAsSibling is not supported for SpotterMessage as it's not part of the allowed props
|
|
158
|
+
});
|
|
159
|
+
describe('Component Factory Coverage', () => {
|
|
160
|
+
it('Should test basic component creation', () => {
|
|
161
|
+
expect(() => {
|
|
162
|
+
render(React.createElement(LiveboardEmbed, { liveboardId: "test" }));
|
|
163
|
+
}).not.toThrow();
|
|
164
|
+
expect(() => {
|
|
165
|
+
render(React.createElement(SearchEmbed, { dataSource: "test" }));
|
|
166
|
+
}).not.toThrow();
|
|
167
|
+
expect(() => {
|
|
168
|
+
render(React.createElement(AppEmbed, { showPrimaryNavbar: false }));
|
|
169
|
+
}).not.toThrow();
|
|
170
|
+
});
|
|
171
|
+
it('Should test component factory existence', () => {
|
|
172
|
+
expect(PreRenderedLiveboardEmbed).toBeDefined();
|
|
173
|
+
expect(PreRenderedSearchEmbed).toBeDefined();
|
|
174
|
+
expect(PreRenderedAppEmbed).toBeDefined();
|
|
175
|
+
expect(typeof PreRenderedLiveboardEmbed).toBe('object');
|
|
176
|
+
expect(typeof PreRenderedSearchEmbed).toBe('object');
|
|
177
|
+
expect(typeof PreRenderedAppEmbed).toBe('object');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
describe('Components with insertAsSibling', () => {
|
|
181
|
+
it('Should render LiveboardEmbed with insertAsSibling', async () => {
|
|
182
|
+
var _a;
|
|
183
|
+
const { container } = render(React.createElement(LiveboardEmbed, { liveboardId: "test-liveboard", insertAsSibling: true }));
|
|
184
|
+
await waitFor(() => getIFrameEl(container));
|
|
185
|
+
expect(container.querySelector('span')).not.toBe(null);
|
|
186
|
+
expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
|
|
187
|
+
});
|
|
188
|
+
it('Should render SearchEmbed with insertAsSibling', async () => {
|
|
189
|
+
var _a;
|
|
190
|
+
const { container } = render(React.createElement(SearchEmbed, { dataSource: "test-datasource", insertAsSibling: true }));
|
|
191
|
+
await waitFor(() => getIFrameEl(container));
|
|
192
|
+
expect(container.querySelector('span')).not.toBe(null);
|
|
193
|
+
expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
|
|
194
|
+
});
|
|
195
|
+
it('Should render AppEmbed with insertAsSibling', async () => {
|
|
196
|
+
var _a;
|
|
197
|
+
const { container } = render(React.createElement(AppEmbed, { showPrimaryNavbar: false, insertAsSibling: true }));
|
|
198
|
+
await waitFor(() => getIFrameEl(container));
|
|
199
|
+
expect(container.querySelector('span')).not.toBe(null);
|
|
200
|
+
expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
|
|
201
|
+
});
|
|
202
|
+
it('Should render SearchBarEmbed with insertAsSibling', async () => {
|
|
203
|
+
var _a;
|
|
204
|
+
const { container } = render(React.createElement(SearchBarEmbed, { dataSource: "test-datasource", insertAsSibling: true }));
|
|
205
|
+
await waitFor(() => getIFrameEl(container));
|
|
206
|
+
expect(container.querySelector('span')).not.toBe(null);
|
|
207
|
+
expect((_a = container.querySelector('span')) === null || _a === void 0 ? void 0 : _a.style.position).toBe('absolute');
|
|
208
|
+
});
|
|
209
|
+
it('Should render components with both insertAsSibling and className', async () => {
|
|
210
|
+
const { container } = render(React.createElement(LiveboardEmbed, { liveboardId: "test-liveboard", insertAsSibling: true, className: "custom-class" }));
|
|
211
|
+
await waitFor(() => getIFrameEl(container));
|
|
212
|
+
expect(container.querySelector('span')).not.toBe(null);
|
|
213
|
+
expect(getIFrameEl(container).classList.contains('custom-class')).toBe(true);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
describe('useSpotterAgent', () => {
|
|
217
|
+
it('Should return an object with sendMessage function', () => {
|
|
153
218
|
const TestComponent = () => {
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
219
|
+
const spotterAgent = useSpotterAgent({ worksheetId: 'test-worksheet' });
|
|
220
|
+
expect(typeof spotterAgent).toBe('object');
|
|
221
|
+
expect(typeof spotterAgent.sendMessage).toBe('function');
|
|
222
|
+
return React.createElement("div", null, "Test");
|
|
223
|
+
};
|
|
224
|
+
render(React.createElement(TestComponent, null));
|
|
225
|
+
});
|
|
226
|
+
it('Should have proper sendMessage callback structure', () => {
|
|
227
|
+
const TestComponent = () => {
|
|
228
|
+
const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
|
|
229
|
+
// Test that sendMessage is a function that accepts a string
|
|
230
|
+
expect(typeof sendMessage).toBe('function');
|
|
231
|
+
expect(sendMessage.length).toBe(1); // Should accept one parameter
|
|
232
|
+
return React.createElement("div", null, "Test");
|
|
233
|
+
};
|
|
234
|
+
render(React.createElement(TestComponent, null));
|
|
235
|
+
});
|
|
236
|
+
it('Should return error when service is not initialized', async () => {
|
|
237
|
+
let sendMessageResult;
|
|
238
|
+
const TestComponent = () => {
|
|
239
|
+
const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
|
|
240
|
+
// Call sendMessage immediately before service has time to initialize
|
|
241
|
+
sendMessageResult = sendMessage('test query');
|
|
242
|
+
return React.createElement("div", null, "Test");
|
|
243
|
+
};
|
|
244
|
+
render(React.createElement(TestComponent, null));
|
|
245
|
+
const result = await sendMessageResult;
|
|
246
|
+
expect(result).toEqual({
|
|
247
|
+
error: expect.any(Error)
|
|
173
248
|
});
|
|
249
|
+
expect(result.error.message).toBe('SpotterAgent not initialized');
|
|
250
|
+
});
|
|
251
|
+
it('Should call sendMessage and handle async behavior', async () => {
|
|
252
|
+
let sendMessageFunction;
|
|
174
253
|
const TestComponent = () => {
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
254
|
+
const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
|
|
255
|
+
sendMessageFunction = sendMessage;
|
|
256
|
+
return React.createElement("div", null, "Test");
|
|
257
|
+
};
|
|
258
|
+
render(React.createElement(TestComponent, null));
|
|
259
|
+
// Test that sendMessage is a function
|
|
260
|
+
expect(typeof sendMessageFunction).toBe('function');
|
|
261
|
+
// Call sendMessage - should not throw
|
|
262
|
+
expect(() => {
|
|
263
|
+
sendMessageFunction('test query');
|
|
264
|
+
}).not.toThrow();
|
|
265
|
+
});
|
|
266
|
+
it('Should handle multiple calls to sendMessage', async () => {
|
|
267
|
+
let sendMessageFunction;
|
|
268
|
+
const TestComponent = () => {
|
|
269
|
+
const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
|
|
270
|
+
sendMessageFunction = sendMessage;
|
|
271
|
+
return React.createElement("div", null, "Test");
|
|
272
|
+
};
|
|
273
|
+
render(React.createElement(TestComponent, null));
|
|
274
|
+
// Multiple calls should not throw
|
|
275
|
+
expect(() => {
|
|
276
|
+
sendMessageFunction('query 1');
|
|
277
|
+
sendMessageFunction('query 2');
|
|
278
|
+
sendMessageFunction('query 3');
|
|
279
|
+
}).not.toThrow();
|
|
280
|
+
});
|
|
281
|
+
it('Should handle config object changes', () => {
|
|
282
|
+
const TestComponent = ({ config }) => {
|
|
283
|
+
const { sendMessage } = useSpotterAgent(config);
|
|
284
|
+
expect(sendMessage).toBeDefined();
|
|
285
|
+
return React.createElement("div", null, "Test");
|
|
286
|
+
};
|
|
287
|
+
const config1 = { worksheetId: 'test1' };
|
|
288
|
+
const config2 = { worksheetId: 'test2' };
|
|
289
|
+
const { rerender } = render(React.createElement(TestComponent, { config: config1 }));
|
|
290
|
+
// Should not throw when config changes
|
|
291
|
+
expect(() => {
|
|
292
|
+
rerender(React.createElement(TestComponent, { config: config2 }));
|
|
293
|
+
}).not.toThrow();
|
|
294
|
+
});
|
|
295
|
+
it('Should handle unmounting without errors', () => {
|
|
296
|
+
const TestComponent = () => {
|
|
297
|
+
const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
|
|
298
|
+
expect(sendMessage).toBeDefined();
|
|
299
|
+
return React.createElement("div", null, "Test");
|
|
300
|
+
};
|
|
301
|
+
const { unmount } = render(React.createElement(TestComponent, null));
|
|
302
|
+
// Should not throw when unmounting
|
|
303
|
+
expect(() => {
|
|
304
|
+
unmount();
|
|
305
|
+
}).not.toThrow();
|
|
306
|
+
});
|
|
307
|
+
it('Should create stable hook structure', () => {
|
|
308
|
+
let hookResult1, hookResult2;
|
|
309
|
+
const TestComponent = ({ counter }) => {
|
|
310
|
+
const result = useSpotterAgent({ worksheetId: 'test-worksheet' });
|
|
311
|
+
if (counter === 1) {
|
|
312
|
+
hookResult1 = result;
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
hookResult2 = result;
|
|
316
|
+
}
|
|
317
|
+
return React.createElement("div", null, "Test");
|
|
318
|
+
};
|
|
319
|
+
const { rerender } = render(React.createElement(TestComponent, { counter: 1 }));
|
|
320
|
+
rerender(React.createElement(TestComponent, { counter: 2 }));
|
|
321
|
+
// Both should have same structure
|
|
322
|
+
expect(hookResult1).toEqual({ sendMessage: expect.any(Function) });
|
|
323
|
+
expect(hookResult2).toEqual({ sendMessage: expect.any(Function) });
|
|
324
|
+
});
|
|
325
|
+
it('Should handle different worksheet IDs', () => {
|
|
326
|
+
const TestComponent = ({ worksheetId }) => {
|
|
327
|
+
const { sendMessage } = useSpotterAgent({ worksheetId });
|
|
328
|
+
expect(sendMessage).toBeDefined();
|
|
329
|
+
return React.createElement("div", null, "Test");
|
|
330
|
+
};
|
|
331
|
+
const { rerender } = render(React.createElement(TestComponent, { worksheetId: "worksheet1" }));
|
|
332
|
+
// Should handle different worksheet IDs
|
|
333
|
+
expect(() => {
|
|
334
|
+
rerender(React.createElement(TestComponent, { worksheetId: "worksheet2" }));
|
|
335
|
+
rerender(React.createElement(TestComponent, { worksheetId: "worksheet3" }));
|
|
336
|
+
}).not.toThrow();
|
|
337
|
+
});
|
|
338
|
+
it('Should handle empty query strings', () => {
|
|
339
|
+
let sendMessageFunction;
|
|
340
|
+
const TestComponent = () => {
|
|
341
|
+
const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
|
|
342
|
+
sendMessageFunction = sendMessage;
|
|
343
|
+
return React.createElement("div", null, "Test");
|
|
344
|
+
};
|
|
345
|
+
render(React.createElement(TestComponent, null));
|
|
346
|
+
// Should handle empty strings
|
|
347
|
+
expect(() => {
|
|
348
|
+
sendMessageFunction('');
|
|
349
|
+
sendMessageFunction(' ');
|
|
350
|
+
}).not.toThrow();
|
|
351
|
+
});
|
|
352
|
+
it('Should handle complex config objects', () => {
|
|
353
|
+
const complexConfig = {
|
|
354
|
+
worksheetId: 'test-worksheet',
|
|
355
|
+
hiddenActions: [Action.ReportError],
|
|
356
|
+
className: 'test-class',
|
|
357
|
+
searchOptions: {
|
|
358
|
+
searchQuery: 'test query'
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
const TestComponent = () => {
|
|
362
|
+
const { sendMessage } = useSpotterAgent(complexConfig);
|
|
363
|
+
expect(sendMessage).toBeDefined();
|
|
364
|
+
return React.createElement("div", null, "Test");
|
|
365
|
+
};
|
|
366
|
+
// Should not throw with complex config
|
|
367
|
+
expect(() => {
|
|
368
|
+
render(React.createElement(TestComponent, null));
|
|
369
|
+
}).not.toThrow();
|
|
370
|
+
});
|
|
371
|
+
it('Should maintain function identity across re-renders with same config', () => {
|
|
372
|
+
let sendMessage1, sendMessage2;
|
|
373
|
+
const TestComponent = ({ forceRender }) => {
|
|
374
|
+
const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
|
|
375
|
+
if (forceRender === 1) {
|
|
376
|
+
sendMessage1 = sendMessage;
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
sendMessage2 = sendMessage;
|
|
380
|
+
}
|
|
381
|
+
return React.createElement("div", null, "Test");
|
|
382
|
+
};
|
|
383
|
+
const { rerender } = render(React.createElement(TestComponent, { forceRender: 1 }));
|
|
384
|
+
rerender(React.createElement(TestComponent, { forceRender: 2 }));
|
|
385
|
+
// Functions should exist
|
|
386
|
+
expect(sendMessage1).toBeDefined();
|
|
387
|
+
expect(sendMessage2).toBeDefined();
|
|
388
|
+
expect(typeof sendMessage1).toBe('function');
|
|
389
|
+
expect(typeof sendMessage2).toBe('function');
|
|
390
|
+
});
|
|
391
|
+
it('Should handle sendMessage calls with null service ref', async () => {
|
|
392
|
+
let capturedSendMessage;
|
|
393
|
+
const TestComponent = () => {
|
|
394
|
+
const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
|
|
395
|
+
capturedSendMessage = sendMessage;
|
|
396
|
+
return React.createElement("div", null, "Test");
|
|
397
|
+
};
|
|
398
|
+
const { unmount } = render(React.createElement(TestComponent, null));
|
|
399
|
+
// Unmount to trigger cleanup
|
|
400
|
+
unmount();
|
|
401
|
+
// Now call sendMessage after unmount - should return error
|
|
402
|
+
const result = await capturedSendMessage('test query');
|
|
403
|
+
expect(result).toEqual({
|
|
404
|
+
error: expect.any(Error)
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
it('Should test service ref cleanup on config change', () => {
|
|
408
|
+
const TestComponent = ({ worksheetId }) => {
|
|
409
|
+
const { sendMessage } = useSpotterAgent({ worksheetId });
|
|
410
|
+
expect(sendMessage).toBeDefined();
|
|
411
|
+
return React.createElement("div", null, "Test");
|
|
412
|
+
};
|
|
413
|
+
const { rerender } = render(React.createElement(TestComponent, { worksheetId: "worksheet1" }));
|
|
414
|
+
// This should trigger the cleanup and create new service
|
|
415
|
+
rerender(React.createElement(TestComponent, { worksheetId: "worksheet2" }));
|
|
416
|
+
// Should still work after rerender
|
|
417
|
+
expect(() => {
|
|
418
|
+
rerender(React.createElement(TestComponent, { worksheetId: "worksheet3" }));
|
|
419
|
+
}).not.toThrow();
|
|
420
|
+
});
|
|
421
|
+
it('Should test different config variations', () => {
|
|
422
|
+
const configs = [
|
|
423
|
+
{ worksheetId: 'test1' },
|
|
424
|
+
{ worksheetId: 'test2', hiddenActions: [Action.ReportError] },
|
|
425
|
+
{ worksheetId: 'test3', className: 'test-class' },
|
|
426
|
+
{ worksheetId: 'test4', searchOptions: { searchQuery: 'test' } }
|
|
427
|
+
];
|
|
428
|
+
configs.forEach((config, index) => {
|
|
429
|
+
const TestComponent = () => {
|
|
430
|
+
const { sendMessage } = useSpotterAgent(config);
|
|
431
|
+
expect(sendMessage).toBeDefined();
|
|
432
|
+
return React.createElement("div", null,
|
|
433
|
+
"Test ",
|
|
434
|
+
index);
|
|
182
435
|
};
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
436
|
+
expect(() => {
|
|
437
|
+
const { unmount } = render(React.createElement(TestComponent, null));
|
|
438
|
+
unmount();
|
|
439
|
+
}).not.toThrow();
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
it('Should handle rapid config changes', () => {
|
|
443
|
+
const TestComponent = ({ worksheetId }) => {
|
|
444
|
+
const { sendMessage } = useSpotterAgent({ worksheetId });
|
|
445
|
+
expect(sendMessage).toBeDefined();
|
|
446
|
+
return React.createElement("div", null, "Test");
|
|
186
447
|
};
|
|
187
|
-
const {
|
|
188
|
-
|
|
189
|
-
|
|
448
|
+
const { rerender } = render(React.createElement(TestComponent, { worksheetId: "worksheet1" }));
|
|
449
|
+
// Rapid config changes to test cleanup logic
|
|
450
|
+
for (let i = 2; i <= 10; i++) {
|
|
451
|
+
rerender(React.createElement(TestComponent, { worksheetId: `worksheet${i}` }));
|
|
452
|
+
}
|
|
453
|
+
// Should still work after many changes
|
|
454
|
+
expect(() => {
|
|
455
|
+
rerender(React.createElement(TestComponent, { worksheetId: "final-worksheet" }));
|
|
456
|
+
}).not.toThrow();
|
|
190
457
|
});
|
|
191
|
-
it('Should
|
|
192
|
-
let
|
|
458
|
+
it('Should handle sendMessage with different query types', () => {
|
|
459
|
+
let sendMessageFunction;
|
|
193
460
|
const TestComponent = () => {
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
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" }));
|
|
461
|
+
const { sendMessage } = useSpotterAgent({ worksheetId: 'test-worksheet' });
|
|
462
|
+
sendMessageFunction = sendMessage;
|
|
463
|
+
return React.createElement("div", null, "Test");
|
|
214
464
|
};
|
|
215
465
|
render(React.createElement(TestComponent, null));
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
466
|
+
// Test different query types
|
|
467
|
+
const queries = [
|
|
468
|
+
'simple query',
|
|
469
|
+
'query with numbers 123',
|
|
470
|
+
'query with special chars !@#$%',
|
|
471
|
+
'very long query that might test different code paths in the system when processing',
|
|
472
|
+
'',
|
|
473
|
+
' whitespace ',
|
|
474
|
+
'null',
|
|
475
|
+
'undefined'
|
|
476
|
+
];
|
|
477
|
+
queries.forEach(query => {
|
|
478
|
+
expect(() => {
|
|
479
|
+
sendMessageFunction(query);
|
|
480
|
+
}).not.toThrow();
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
it('Should handle service ref cleanup when it already exists', () => {
|
|
484
|
+
const TestComponent = ({ worksheetId }) => {
|
|
485
|
+
const { sendMessage } = useSpotterAgent({ worksheetId });
|
|
486
|
+
expect(sendMessage).toBeDefined();
|
|
487
|
+
return React.createElement("div", null, "Test");
|
|
488
|
+
};
|
|
489
|
+
const { rerender } = render(React.createElement(TestComponent, { worksheetId: "worksheet1" }));
|
|
490
|
+
// This should trigger the "if (serviceRef.current)" branch in useEffect
|
|
491
|
+
rerender(React.createElement(TestComponent, { worksheetId: "worksheet1" }));
|
|
492
|
+
rerender(React.createElement(TestComponent, { worksheetId: "worksheet2" }));
|
|
493
|
+
rerender(React.createElement(TestComponent, { worksheetId: "worksheet3" }));
|
|
494
|
+
// Multiple rapid changes should exercise the cleanup logic
|
|
495
|
+
for (let i = 0; i < 5; i++) {
|
|
496
|
+
rerender(React.createElement(TestComponent, { worksheetId: `worksheet${i}` }));
|
|
220
497
|
}
|
|
221
498
|
});
|
|
499
|
+
it('Should test various config combinations to hit all branches', () => {
|
|
500
|
+
const testConfigs = [
|
|
501
|
+
{ worksheetId: 'test1' },
|
|
502
|
+
{ worksheetId: 'test2', className: 'custom-class' },
|
|
503
|
+
{ worksheetId: 'test3', hiddenActions: [Action.ReportError] },
|
|
504
|
+
{ worksheetId: 'test4', searchOptions: { searchQuery: 'test' } },
|
|
505
|
+
{ worksheetId: 'test5', insertAsSibling: true },
|
|
506
|
+
{ worksheetId: 'test6', insertAsSibling: false },
|
|
507
|
+
];
|
|
508
|
+
testConfigs.forEach((config, index) => {
|
|
509
|
+
const TestComponent = () => {
|
|
510
|
+
const { sendMessage } = useSpotterAgent(config);
|
|
511
|
+
expect(sendMessage).toBeDefined();
|
|
512
|
+
return React.createElement("div", null,
|
|
513
|
+
"Test ",
|
|
514
|
+
index);
|
|
515
|
+
};
|
|
516
|
+
const { unmount } = render(React.createElement(TestComponent, null));
|
|
517
|
+
unmount();
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
describe('Component Props and Functions', () => {
|
|
522
|
+
it('Should have PreRenderedLiveboardEmbed component', () => {
|
|
523
|
+
expect(PreRenderedLiveboardEmbed).toBeDefined();
|
|
524
|
+
expect(typeof PreRenderedLiveboardEmbed).toBe('object');
|
|
525
|
+
});
|
|
526
|
+
it('Should have useInit hook', () => {
|
|
527
|
+
expect(typeof useInit).toBe('function');
|
|
528
|
+
});
|
|
529
|
+
it('Should test basic component factory patterns', () => {
|
|
530
|
+
// Test that components can be created without errors
|
|
531
|
+
expect(() => {
|
|
532
|
+
const TestComponent = () => React.createElement("div", null, "Test");
|
|
533
|
+
render(React.createElement(TestComponent, null));
|
|
534
|
+
}).not.toThrow();
|
|
535
|
+
});
|
|
222
536
|
});
|
|
223
|
-
describe('
|
|
224
|
-
it('
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
537
|
+
describe('Hook Coverage', () => {
|
|
538
|
+
it('Should have useInit function available', () => {
|
|
539
|
+
expect(typeof useInit).toBe('function');
|
|
540
|
+
});
|
|
541
|
+
it('Should test useInit hook basic functionality', () => {
|
|
542
|
+
const TestComponent = () => {
|
|
543
|
+
const authEE = useInit({
|
|
544
|
+
thoughtSpotHost: 'localhost',
|
|
545
|
+
authType: AuthType.None
|
|
546
|
+
});
|
|
547
|
+
expect(authEE).toBeDefined();
|
|
548
|
+
expect(authEE.current).toBeDefined();
|
|
549
|
+
return React.createElement("div", null, "Test");
|
|
550
|
+
};
|
|
551
|
+
render(React.createElement(TestComponent, null));
|
|
552
|
+
});
|
|
553
|
+
it('Should handle useInit with different config changes', () => {
|
|
554
|
+
const TestComponent = ({ host }) => {
|
|
555
|
+
const authEE = useInit({
|
|
556
|
+
thoughtSpotHost: host,
|
|
557
|
+
authType: AuthType.None
|
|
558
|
+
});
|
|
559
|
+
expect(authEE).toBeDefined();
|
|
560
|
+
return React.createElement("div", null, "Test");
|
|
561
|
+
};
|
|
562
|
+
const { rerender } = render(React.createElement(TestComponent, { host: "localhost" }));
|
|
563
|
+
// Change config to test useDeepCompareEffect
|
|
564
|
+
rerender(React.createElement(TestComponent, { host: "localhost2" }));
|
|
565
|
+
rerender(React.createElement(TestComponent, { host: "localhost3" }));
|
|
566
|
+
});
|
|
567
|
+
it('Should test useInit with complex config objects', () => {
|
|
568
|
+
const TestComponent = () => {
|
|
569
|
+
const authEE = useInit({
|
|
570
|
+
thoughtSpotHost: 'localhost',
|
|
571
|
+
authType: AuthType.None,
|
|
572
|
+
suppressNoCookieAccessAlert: true,
|
|
573
|
+
suppressErrorAlerts: true
|
|
574
|
+
});
|
|
575
|
+
expect(authEE).toBeDefined();
|
|
576
|
+
return React.createElement("div", null, "Test");
|
|
577
|
+
};
|
|
578
|
+
render(React.createElement(TestComponent, null));
|
|
243
579
|
});
|
|
244
580
|
});
|
|
245
581
|
});
|