@thoughtspot/visual-embed-sdk 1.43.0 → 1.43.1

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 (178) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/api-intercept.d.ts +51 -0
  3. package/cjs/src/api-intercept.d.ts.map +1 -0
  4. package/cjs/src/api-intercept.js +180 -0
  5. package/cjs/src/api-intercept.js.map +1 -0
  6. package/cjs/src/api-intercept.spec.d.ts +2 -0
  7. package/cjs/src/api-intercept.spec.d.ts.map +1 -0
  8. package/cjs/src/api-intercept.spec.js +672 -0
  9. package/cjs/src/api-intercept.spec.js.map +1 -0
  10. package/cjs/src/css-variables.d.ts +4 -0
  11. package/cjs/src/css-variables.d.ts.map +1 -1
  12. package/cjs/src/embed/app.d.ts +0 -5
  13. package/cjs/src/embed/app.d.ts.map +1 -1
  14. package/cjs/src/embed/app.js +4 -5
  15. package/cjs/src/embed/app.js.map +1 -1
  16. package/cjs/src/embed/app.spec.js +10 -0
  17. package/cjs/src/embed/app.spec.js.map +1 -1
  18. package/cjs/src/embed/conversation.d.ts +2 -2
  19. package/cjs/src/embed/conversation.js +1 -1
  20. package/cjs/src/embed/conversation.js.map +1 -1
  21. package/cjs/src/embed/conversation.spec.js +17 -0
  22. package/cjs/src/embed/conversation.spec.js.map +1 -1
  23. package/cjs/src/embed/hostEventClient/contracts.d.ts +11 -1
  24. package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  25. package/cjs/src/embed/hostEventClient/contracts.js +1 -0
  26. package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
  27. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  28. package/cjs/src/embed/liveboard.js +4 -2
  29. package/cjs/src/embed/liveboard.js.map +1 -1
  30. package/cjs/src/embed/liveboard.spec.js +11 -0
  31. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  32. package/cjs/src/embed/search.d.ts +0 -7
  33. package/cjs/src/embed/search.d.ts.map +1 -1
  34. package/cjs/src/embed/search.js +1 -4
  35. package/cjs/src/embed/search.js.map +1 -1
  36. package/cjs/src/embed/ts-embed.d.ts +10 -0
  37. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  38. package/cjs/src/embed/ts-embed.js +56 -15
  39. package/cjs/src/embed/ts-embed.js.map +1 -1
  40. package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
  41. package/cjs/src/embed/ts-embed.spec.js +412 -238
  42. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  43. package/cjs/src/index.d.ts +2 -2
  44. package/cjs/src/index.d.ts.map +1 -1
  45. package/cjs/src/index.js +2 -1
  46. package/cjs/src/index.js.map +1 -1
  47. package/cjs/src/react/all-types-export.d.ts +1 -1
  48. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  49. package/cjs/src/react/all-types-export.js +2 -1
  50. package/cjs/src/react/all-types-export.js.map +1 -1
  51. package/cjs/src/types.d.ts +244 -88
  52. package/cjs/src/types.d.ts.map +1 -1
  53. package/cjs/src/types.js +181 -70
  54. package/cjs/src/types.js.map +1 -1
  55. package/cjs/src/utils/logger.d.ts.map +1 -1
  56. package/cjs/src/utils/logger.js +1 -2
  57. package/cjs/src/utils/logger.js.map +1 -1
  58. package/cjs/src/utils/processData.d.ts +1 -1
  59. package/cjs/src/utils/processData.d.ts.map +1 -1
  60. package/cjs/src/utils/processData.js +8 -8
  61. package/cjs/src/utils/processData.js.map +1 -1
  62. package/cjs/src/utils/processData.spec.js.map +1 -1
  63. package/dist/{index-HZ94j9Ey.js → index-CpkMygsc.js} +1 -1
  64. package/dist/src/api-intercept.d.ts +51 -0
  65. package/dist/src/api-intercept.d.ts.map +1 -0
  66. package/dist/src/api-intercept.spec.d.ts +2 -0
  67. package/dist/src/api-intercept.spec.d.ts.map +1 -0
  68. package/dist/src/css-variables.d.ts +4 -0
  69. package/dist/src/css-variables.d.ts.map +1 -1
  70. package/dist/src/embed/app.d.ts +0 -5
  71. package/dist/src/embed/app.d.ts.map +1 -1
  72. package/dist/src/embed/conversation.d.ts +2 -2
  73. package/dist/src/embed/hostEventClient/contracts.d.ts +11 -1
  74. package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  75. package/dist/src/embed/liveboard.d.ts.map +1 -1
  76. package/dist/src/embed/search.d.ts +0 -7
  77. package/dist/src/embed/search.d.ts.map +1 -1
  78. package/dist/src/embed/ts-embed.d.ts +10 -0
  79. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  80. package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
  81. package/dist/src/index.d.ts +2 -2
  82. package/dist/src/index.d.ts.map +1 -1
  83. package/dist/src/react/all-types-export.d.ts +1 -1
  84. package/dist/src/react/all-types-export.d.ts.map +1 -1
  85. package/dist/src/types.d.ts +244 -88
  86. package/dist/src/types.d.ts.map +1 -1
  87. package/dist/src/utils/logger.d.ts.map +1 -1
  88. package/dist/src/utils/processData.d.ts +1 -1
  89. package/dist/src/utils/processData.d.ts.map +1 -1
  90. package/dist/tsembed-react.es.js +435 -118
  91. package/dist/tsembed-react.js +434 -117
  92. package/dist/tsembed.es.js +3577 -3260
  93. package/dist/tsembed.js +3575 -3258
  94. package/dist/visual-embed-sdk-react-full.d.ts +271 -103
  95. package/dist/visual-embed-sdk-react.d.ts +268 -103
  96. package/dist/visual-embed-sdk.d.ts +271 -103
  97. package/lib/package.json +1 -1
  98. package/lib/src/api-intercept.d.ts +51 -0
  99. package/lib/src/api-intercept.d.ts.map +1 -0
  100. package/lib/src/api-intercept.js +173 -0
  101. package/lib/src/api-intercept.js.map +1 -0
  102. package/lib/src/api-intercept.spec.d.ts +2 -0
  103. package/lib/src/api-intercept.spec.d.ts.map +1 -0
  104. package/lib/src/api-intercept.spec.js +669 -0
  105. package/lib/src/api-intercept.spec.js.map +1 -0
  106. package/lib/src/css-variables.d.ts +4 -0
  107. package/lib/src/css-variables.d.ts.map +1 -1
  108. package/lib/src/embed/app.d.ts +0 -5
  109. package/lib/src/embed/app.d.ts.map +1 -1
  110. package/lib/src/embed/app.js +4 -5
  111. package/lib/src/embed/app.js.map +1 -1
  112. package/lib/src/embed/app.spec.js +10 -0
  113. package/lib/src/embed/app.spec.js.map +1 -1
  114. package/lib/src/embed/conversation.d.ts +2 -2
  115. package/lib/src/embed/conversation.js +1 -1
  116. package/lib/src/embed/conversation.js.map +1 -1
  117. package/lib/src/embed/conversation.spec.js +17 -0
  118. package/lib/src/embed/conversation.spec.js.map +1 -1
  119. package/lib/src/embed/hostEventClient/contracts.d.ts +11 -1
  120. package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  121. package/lib/src/embed/hostEventClient/contracts.js +1 -0
  122. package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
  123. package/lib/src/embed/liveboard.d.ts.map +1 -1
  124. package/lib/src/embed/liveboard.js +4 -2
  125. package/lib/src/embed/liveboard.js.map +1 -1
  126. package/lib/src/embed/liveboard.spec.js +11 -0
  127. package/lib/src/embed/liveboard.spec.js.map +1 -1
  128. package/lib/src/embed/search.d.ts +0 -7
  129. package/lib/src/embed/search.d.ts.map +1 -1
  130. package/lib/src/embed/search.js +1 -4
  131. package/lib/src/embed/search.js.map +1 -1
  132. package/lib/src/embed/ts-embed.d.ts +10 -0
  133. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  134. package/lib/src/embed/ts-embed.js +56 -15
  135. package/lib/src/embed/ts-embed.js.map +1 -1
  136. package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
  137. package/lib/src/embed/ts-embed.spec.js +412 -238
  138. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  139. package/lib/src/index.d.ts +2 -2
  140. package/lib/src/index.d.ts.map +1 -1
  141. package/lib/src/index.js +2 -2
  142. package/lib/src/index.js.map +1 -1
  143. package/lib/src/react/all-types-export.d.ts +1 -1
  144. package/lib/src/react/all-types-export.d.ts.map +1 -1
  145. package/lib/src/react/all-types-export.js +1 -1
  146. package/lib/src/react/all-types-export.js.map +1 -1
  147. package/lib/src/types.d.ts +244 -88
  148. package/lib/src/types.d.ts.map +1 -1
  149. package/lib/src/types.js +180 -69
  150. package/lib/src/types.js.map +1 -1
  151. package/lib/src/utils/logger.d.ts.map +1 -1
  152. package/lib/src/utils/logger.js +1 -2
  153. package/lib/src/utils/logger.js.map +1 -1
  154. package/lib/src/utils/processData.d.ts +1 -1
  155. package/lib/src/utils/processData.d.ts.map +1 -1
  156. package/lib/src/utils/processData.js +8 -8
  157. package/lib/src/utils/processData.js.map +1 -1
  158. package/lib/src/utils/processData.spec.js.map +1 -1
  159. package/package.json +1 -1
  160. package/src/api-intercept.spec.ts +856 -0
  161. package/src/api-intercept.ts +204 -0
  162. package/src/css-variables.ts +5 -0
  163. package/src/embed/app.spec.ts +11 -0
  164. package/src/embed/app.ts +5 -16
  165. package/src/embed/conversation.spec.ts +22 -0
  166. package/src/embed/conversation.ts +3 -3
  167. package/src/embed/hostEventClient/contracts.ts +10 -0
  168. package/src/embed/liveboard.spec.ts +12 -0
  169. package/src/embed/liveboard.ts +6 -2
  170. package/src/embed/search.ts +1 -14
  171. package/src/embed/ts-embed.spec.ts +498 -250
  172. package/src/embed/ts-embed.ts +80 -32
  173. package/src/index.ts +2 -0
  174. package/src/react/all-types-export.ts +1 -0
  175. package/src/types.ts +327 -165
  176. package/src/utils/logger.ts +1 -2
  177. package/src/utils/processData.spec.ts +0 -1
  178. package/src/utils/processData.ts +10 -11
@@ -0,0 +1,669 @@
1
+ import * as apiIntercept from './api-intercept';
2
+ import * as config from './config';
3
+ import * as embedConfig from './embed/embedConfig';
4
+ import { InterceptedApiType, EmbedEvent } from './types';
5
+ import { embedEventStatus } from './utils';
6
+ import { logger } from './utils/logger';
7
+ jest.mock('./config');
8
+ jest.mock('./embed/embedConfig');
9
+ jest.mock('./utils/logger');
10
+ const mockGetThoughtSpotHost = config.getThoughtSpotHost;
11
+ const mockGetEmbedConfig = embedConfig.getEmbedConfig;
12
+ const mockLogger = logger;
13
+ describe('api-intercept', () => {
14
+ const thoughtSpotHost = 'https://test.thoughtspot.com';
15
+ let originalJsonParse;
16
+ beforeAll(() => {
17
+ originalJsonParse = JSON.parse;
18
+ });
19
+ beforeEach(() => {
20
+ jest.clearAllMocks();
21
+ mockGetThoughtSpotHost.mockReturnValue(thoughtSpotHost);
22
+ mockGetEmbedConfig.mockReturnValue({});
23
+ // Restore JSON.parse before each test
24
+ JSON.parse = originalJsonParse;
25
+ });
26
+ afterEach(() => {
27
+ // Ensure JSON.parse is restored after each test
28
+ JSON.parse = originalJsonParse;
29
+ });
30
+ describe('getInterceptInitData', () => {
31
+ it('should return default intercept flags when no intercepts are configured', () => {
32
+ const viewConfig = {};
33
+ const result = apiIntercept.getInterceptInitData(viewConfig);
34
+ expect(result).toEqual({
35
+ interceptUrls: [],
36
+ interceptTimeout: undefined,
37
+ });
38
+ });
39
+ it('should expand InterceptedApiType.AnswerData to specific URLs', () => {
40
+ const viewConfig = {
41
+ interceptUrls: [InterceptedApiType.AnswerData]
42
+ };
43
+ const result = apiIntercept.getInterceptInitData(viewConfig);
44
+ expect(result.interceptUrls).toEqual([
45
+ `${thoughtSpotHost}/prism/?op=GetChartWithData`,
46
+ `${thoughtSpotHost}/prism/?op=GetTableWithHeadlineData`,
47
+ `${thoughtSpotHost}/prism/?op=GetTableWithData`,
48
+ ]);
49
+ });
50
+ it('should expand InterceptedApiType.LiveboardData to specific URLs', () => {
51
+ const viewConfig = {
52
+ interceptUrls: [InterceptedApiType.LiveboardData]
53
+ };
54
+ const result = apiIntercept.getInterceptInitData(viewConfig);
55
+ expect(result.interceptUrls).toEqual([
56
+ `${thoughtSpotHost}/prism/?op=LoadContextBook`
57
+ ]);
58
+ });
59
+ it('should handle multiple intercept types', () => {
60
+ const viewConfig = {
61
+ interceptUrls: [
62
+ InterceptedApiType.AnswerData,
63
+ InterceptedApiType.LiveboardData
64
+ ]
65
+ };
66
+ const result = apiIntercept.getInterceptInitData(viewConfig);
67
+ expect(result.interceptUrls).toContain(`${thoughtSpotHost}/prism/?op=GetChartWithData`);
68
+ expect(result.interceptUrls).toContain(`${thoughtSpotHost}/prism/?op=LoadContextBook`);
69
+ expect(result.interceptUrls.length).toBe(4);
70
+ });
71
+ it('should handle custom URL strings', () => {
72
+ const customUrl = '/api/custom-endpoint';
73
+ const viewConfig = {
74
+ interceptUrls: [customUrl]
75
+ };
76
+ const result = apiIntercept.getInterceptInitData(viewConfig);
77
+ expect(result.interceptUrls).toEqual([`${thoughtSpotHost}${customUrl}`]);
78
+ });
79
+ it('should handle full URL strings', () => {
80
+ const fullUrl = 'https://example.com/api/endpoint';
81
+ const viewConfig = {
82
+ interceptUrls: [fullUrl]
83
+ };
84
+ const result = apiIntercept.getInterceptInitData(viewConfig);
85
+ expect(result.interceptUrls).toEqual([fullUrl]);
86
+ });
87
+ it('should handle InterceptedApiType.ALL', () => {
88
+ const viewConfig = {
89
+ interceptUrls: [InterceptedApiType.ALL]
90
+ };
91
+ const result = apiIntercept.getInterceptInitData(viewConfig);
92
+ expect(result.interceptUrls).toEqual([InterceptedApiType.ALL]);
93
+ });
94
+ it('should prioritize ALL over other intercept types', () => {
95
+ const viewConfig = {
96
+ interceptUrls: [
97
+ InterceptedApiType.AnswerData,
98
+ InterceptedApiType.ALL,
99
+ '/api/custom'
100
+ ]
101
+ };
102
+ const result = apiIntercept.getInterceptInitData(viewConfig);
103
+ expect(result.interceptUrls).toEqual([InterceptedApiType.ALL]);
104
+ });
105
+ it('should handle legacy isOnBeforeGetVizDataInterceptEnabled flag', () => {
106
+ const viewConfig = {
107
+ isOnBeforeGetVizDataInterceptEnabled: true
108
+ };
109
+ const result = apiIntercept.getInterceptInitData(viewConfig);
110
+ expect(result.interceptUrls).toContain(`${thoughtSpotHost}/prism/?op=GetChartWithData`);
111
+ });
112
+ it('should combine legacy flag with interceptUrls', () => {
113
+ const viewConfig = {
114
+ isOnBeforeGetVizDataInterceptEnabled: true,
115
+ interceptUrls: [InterceptedApiType.LiveboardData]
116
+ };
117
+ const result = apiIntercept.getInterceptInitData(viewConfig);
118
+ expect(result.interceptUrls).toContain(`${thoughtSpotHost}/prism/?op=GetChartWithData`);
119
+ expect(result.interceptUrls).toContain(`${thoughtSpotHost}/prism/?op=LoadContextBook`);
120
+ });
121
+ it('should pass through interceptTimeout', () => {
122
+ const viewConfig = {
123
+ interceptUrls: [],
124
+ interceptTimeout: 5000
125
+ };
126
+ const result = apiIntercept.getInterceptInitData(viewConfig);
127
+ expect(result.interceptTimeout).toBe(5000);
128
+ });
129
+ it('should deduplicate URLs when same type is added multiple times', () => {
130
+ const viewConfig = {
131
+ interceptUrls: [
132
+ InterceptedApiType.AnswerData,
133
+ InterceptedApiType.AnswerData
134
+ ]
135
+ };
136
+ const result = apiIntercept.getInterceptInitData(viewConfig);
137
+ expect(result.interceptUrls.length).toBe(3); // 3 answer data URLs
138
+ });
139
+ });
140
+ describe('handleInterceptEvent', () => {
141
+ let executeEvent;
142
+ let getUnsavedAnswerTml;
143
+ let viewConfig;
144
+ beforeEach(() => {
145
+ executeEvent = jest.fn();
146
+ getUnsavedAnswerTml = jest.fn().mockResolvedValue({ answer: { tml: 'test-tml' } });
147
+ viewConfig = {};
148
+ });
149
+ it('should handle valid intercept data', async () => {
150
+ const eventData = {
151
+ data: JSON.stringify({
152
+ input: '/prism/?op=GetChartWithData',
153
+ init: {
154
+ method: 'POST',
155
+ body: JSON.stringify({
156
+ variables: {
157
+ session: { sessionId: 'session-123' },
158
+ contextBookId: 'viz-456'
159
+ }
160
+ })
161
+ }
162
+ })
163
+ };
164
+ await apiIntercept.handleInterceptEvent({
165
+ eventData,
166
+ executeEvent,
167
+ viewConfig,
168
+ getUnsavedAnswerTml
169
+ });
170
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.ApiIntercept, expect.objectContaining({
171
+ input: '/prism/?op=GetChartWithData',
172
+ urlType: InterceptedApiType.AnswerData
173
+ }));
174
+ });
175
+ it('should trigger legacy OnBeforeGetVizDataIntercept for answer data URLs', async () => {
176
+ viewConfig.isOnBeforeGetVizDataInterceptEnabled = true;
177
+ const eventData = {
178
+ data: JSON.stringify({
179
+ input: '/prism/?op=GetChartWithData',
180
+ init: {
181
+ method: 'POST',
182
+ body: JSON.stringify({
183
+ variables: {
184
+ session: { sessionId: 'session-123' },
185
+ contextBookId: 'viz-456'
186
+ }
187
+ })
188
+ }
189
+ })
190
+ };
191
+ await apiIntercept.handleInterceptEvent({
192
+ eventData,
193
+ executeEvent,
194
+ viewConfig,
195
+ getUnsavedAnswerTml
196
+ });
197
+ expect(getUnsavedAnswerTml).toHaveBeenCalledWith({
198
+ sessionId: 'session-123',
199
+ vizId: 'viz-456'
200
+ });
201
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.OnBeforeGetVizDataIntercept, {
202
+ data: {
203
+ data: { answer: { tml: 'test-tml' } },
204
+ status: embedEventStatus.END,
205
+ type: EmbedEvent.OnBeforeGetVizDataIntercept
206
+ }
207
+ });
208
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.ApiIntercept, expect.any(Object));
209
+ });
210
+ it('should not trigger legacy intercept for non-answer data URLs', async () => {
211
+ viewConfig.isOnBeforeGetVizDataInterceptEnabled = true;
212
+ const eventData = {
213
+ data: JSON.stringify({
214
+ input: '/prism/?op=LoadContextBook',
215
+ init: {
216
+ method: 'POST',
217
+ body: '{}'
218
+ }
219
+ })
220
+ };
221
+ await apiIntercept.handleInterceptEvent({
222
+ eventData,
223
+ executeEvent,
224
+ viewConfig,
225
+ getUnsavedAnswerTml
226
+ });
227
+ expect(getUnsavedAnswerTml).not.toHaveBeenCalled();
228
+ expect(executeEvent).toHaveBeenCalledTimes(1);
229
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.ApiIntercept, expect.any(Object));
230
+ });
231
+ it('should handle GetTableWithHeadlineData URL as answer data', async () => {
232
+ viewConfig.isOnBeforeGetVizDataInterceptEnabled = true;
233
+ const eventData = {
234
+ data: JSON.stringify({
235
+ input: '/prism/?op=GetTableWithHeadlineData',
236
+ init: {
237
+ body: JSON.stringify({
238
+ variables: { session: { sessionId: 'test' } }
239
+ })
240
+ }
241
+ })
242
+ };
243
+ await apiIntercept.handleInterceptEvent({
244
+ eventData,
245
+ executeEvent,
246
+ viewConfig,
247
+ getUnsavedAnswerTml
248
+ });
249
+ expect(getUnsavedAnswerTml).toHaveBeenCalled();
250
+ });
251
+ it('should handle GetTableWithData URL as answer data', async () => {
252
+ viewConfig.isOnBeforeGetVizDataInterceptEnabled = true;
253
+ const eventData = {
254
+ data: JSON.stringify({
255
+ input: '/prism/?op=GetTableWithData',
256
+ init: {
257
+ body: JSON.stringify({
258
+ variables: { session: { sessionId: 'test' } }
259
+ })
260
+ }
261
+ })
262
+ };
263
+ await apiIntercept.handleInterceptEvent({
264
+ eventData,
265
+ executeEvent,
266
+ viewConfig,
267
+ getUnsavedAnswerTml
268
+ });
269
+ expect(getUnsavedAnswerTml).toHaveBeenCalled();
270
+ });
271
+ it('should handle invalid JSON in event data', async () => {
272
+ const eventData = {
273
+ data: 'invalid-json'
274
+ };
275
+ await apiIntercept.handleInterceptEvent({
276
+ eventData,
277
+ executeEvent,
278
+ viewConfig,
279
+ getUnsavedAnswerTml
280
+ });
281
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.Error, { error: 'Error parsing api intercept body' });
282
+ expect(mockLogger.error).toHaveBeenCalled();
283
+ });
284
+ it('should handle init with non-JSON body', async () => {
285
+ const eventData = {
286
+ data: JSON.stringify({
287
+ input: '/api/test',
288
+ init: {
289
+ method: 'POST',
290
+ body: 'plain-text-body'
291
+ }
292
+ })
293
+ };
294
+ await apiIntercept.handleInterceptEvent({
295
+ eventData,
296
+ executeEvent,
297
+ viewConfig,
298
+ getUnsavedAnswerTml
299
+ });
300
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.ApiIntercept, expect.objectContaining({
301
+ init: expect.objectContaining({
302
+ body: 'plain-text-body'
303
+ })
304
+ }));
305
+ });
306
+ it('should handle malformed event data structure with property access error', async () => {
307
+ // Create an object with a getter that throws when accessing 'input'
308
+ global.JSON.parse = jest.fn().mockImplementationOnce((str) => {
309
+ // Return an object with a getter that throws
310
+ return new Proxy({}, {
311
+ get(target, prop) {
312
+ if (prop === 'input') {
313
+ throw new Error('Property access error');
314
+ }
315
+ return undefined;
316
+ }
317
+ });
318
+ });
319
+ const eventData = {
320
+ data: JSON.stringify({ input: '/test', init: {} })
321
+ };
322
+ await apiIntercept.handleInterceptEvent({
323
+ eventData,
324
+ executeEvent,
325
+ viewConfig,
326
+ getUnsavedAnswerTml
327
+ });
328
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.Error, { error: 'Error parsing api intercept body' });
329
+ expect(mockLogger.error).toHaveBeenCalled();
330
+ // Explicitly restore for this test
331
+ global.JSON.parse = originalJsonParse;
332
+ });
333
+ it('should determine urlType as ALL for unknown URLs', async () => {
334
+ const eventData = {
335
+ data: JSON.stringify({
336
+ input: '/unknown/endpoint',
337
+ init: { method: 'GET' }
338
+ })
339
+ };
340
+ await apiIntercept.handleInterceptEvent({
341
+ eventData,
342
+ executeEvent,
343
+ viewConfig,
344
+ getUnsavedAnswerTml
345
+ });
346
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.ApiIntercept, expect.objectContaining({
347
+ urlType: InterceptedApiType.ALL
348
+ }));
349
+ });
350
+ it('should determine urlType as LiveboardData for liveboard URLs', async () => {
351
+ const eventData = {
352
+ data: JSON.stringify({
353
+ input: '/prism/?op=LoadContextBook',
354
+ init: { method: 'POST' }
355
+ })
356
+ };
357
+ await apiIntercept.handleInterceptEvent({
358
+ eventData,
359
+ executeEvent,
360
+ viewConfig,
361
+ getUnsavedAnswerTml
362
+ });
363
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.ApiIntercept, expect.objectContaining({
364
+ urlType: InterceptedApiType.LiveboardData
365
+ }));
366
+ });
367
+ it('should handle event data with missing init', async () => {
368
+ const eventData = {
369
+ data: JSON.stringify({
370
+ input: '/prism/?op=GetChartWithData'
371
+ })
372
+ };
373
+ await apiIntercept.handleInterceptEvent({
374
+ eventData,
375
+ executeEvent,
376
+ viewConfig,
377
+ getUnsavedAnswerTml
378
+ });
379
+ // When init is missing, accessing init.body throws an error
380
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.Error, { error: 'Error parsing api intercept body' });
381
+ });
382
+ it('should handle event data with missing body', async () => {
383
+ const eventData = {
384
+ data: JSON.stringify({
385
+ input: '/prism/?op=GetChartWithData',
386
+ init: {}
387
+ })
388
+ };
389
+ await apiIntercept.handleInterceptEvent({
390
+ eventData,
391
+ executeEvent,
392
+ viewConfig,
393
+ getUnsavedAnswerTml
394
+ });
395
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.ApiIntercept, expect.any(Object));
396
+ });
397
+ it('should handle event data with missing variables in body', async () => {
398
+ const eventData = {
399
+ data: JSON.stringify({
400
+ input: '/prism/?op=GetChartWithData',
401
+ init: {
402
+ body: JSON.stringify({})
403
+ }
404
+ })
405
+ };
406
+ await apiIntercept.handleInterceptEvent({
407
+ eventData,
408
+ executeEvent,
409
+ viewConfig,
410
+ getUnsavedAnswerTml
411
+ });
412
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.ApiIntercept, expect.any(Object));
413
+ });
414
+ it('should handle event data with missing session in variables', async () => {
415
+ const eventData = {
416
+ data: JSON.stringify({
417
+ input: '/prism/?op=GetChartWithData',
418
+ init: {
419
+ body: JSON.stringify({
420
+ variables: {}
421
+ })
422
+ }
423
+ })
424
+ };
425
+ await apiIntercept.handleInterceptEvent({
426
+ eventData,
427
+ executeEvent,
428
+ viewConfig,
429
+ getUnsavedAnswerTml
430
+ });
431
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.ApiIntercept, expect.any(Object));
432
+ });
433
+ });
434
+ describe('processApiInterceptResponse', () => {
435
+ it('should process legacy format with error', () => {
436
+ const legacyPayload = {
437
+ data: {
438
+ error: {
439
+ errorText: 'Test Error',
440
+ errorDescription: 'Test Description'
441
+ },
442
+ execute: false
443
+ }
444
+ };
445
+ const result = apiIntercept.processApiInterceptResponse(legacyPayload);
446
+ expect(result).toEqual({
447
+ data: {
448
+ execute: false,
449
+ response: {
450
+ body: {
451
+ errors: [
452
+ {
453
+ title: 'Test Error',
454
+ description: 'Test Description',
455
+ isUserError: true,
456
+ },
457
+ ],
458
+ data: {},
459
+ },
460
+ },
461
+ }
462
+ });
463
+ });
464
+ it('should pass through new format unchanged', () => {
465
+ const newPayload = {
466
+ execute: true,
467
+ response: {
468
+ body: { data: 'test' }
469
+ }
470
+ };
471
+ const result = apiIntercept.processApiInterceptResponse(newPayload);
472
+ expect(result).toEqual(newPayload);
473
+ });
474
+ it('should handle payload without data property', () => {
475
+ const payload = {
476
+ execute: true
477
+ };
478
+ const result = apiIntercept.processApiInterceptResponse(payload);
479
+ expect(result).toEqual(payload);
480
+ });
481
+ it('should handle payload with data but no error', () => {
482
+ const payload = {
483
+ data: {
484
+ execute: true,
485
+ someOtherProperty: 'value'
486
+ }
487
+ };
488
+ const result = apiIntercept.processApiInterceptResponse(payload);
489
+ expect(result).toEqual(payload);
490
+ });
491
+ it('should handle null payload', () => {
492
+ const result = apiIntercept.processApiInterceptResponse(null);
493
+ expect(result).toBeNull();
494
+ });
495
+ it('should handle undefined payload', () => {
496
+ const result = apiIntercept.processApiInterceptResponse(undefined);
497
+ expect(result).toBeUndefined();
498
+ });
499
+ it('should handle payload with null data', () => {
500
+ const payload = {
501
+ data: null
502
+ };
503
+ const result = apiIntercept.processApiInterceptResponse(payload);
504
+ expect(result).toEqual(payload);
505
+ });
506
+ it('should handle payload with data.error set to null', () => {
507
+ const payload = {
508
+ data: {
509
+ error: null,
510
+ execute: true
511
+ }
512
+ };
513
+ const result = apiIntercept.processApiInterceptResponse(payload);
514
+ expect(result).toEqual(payload);
515
+ });
516
+ it('should handle payload with data.error set to undefined', () => {
517
+ const payload = {
518
+ data: {
519
+ error: undefined,
520
+ execute: true
521
+ }
522
+ };
523
+ const result = apiIntercept.processApiInterceptResponse(payload);
524
+ expect(result).toEqual(payload);
525
+ });
526
+ it('should handle payload with data.error set to false', () => {
527
+ const payload = {
528
+ data: {
529
+ error: false,
530
+ execute: true
531
+ }
532
+ };
533
+ const result = apiIntercept.processApiInterceptResponse(payload);
534
+ expect(result).toEqual(payload);
535
+ });
536
+ it('should handle payload with data.error set to 0', () => {
537
+ const payload = {
538
+ data: {
539
+ error: 0,
540
+ execute: true
541
+ }
542
+ };
543
+ const result = apiIntercept.processApiInterceptResponse(payload);
544
+ expect(result).toEqual(payload);
545
+ });
546
+ it('should handle payload with data.error set to empty string', () => {
547
+ const payload = {
548
+ data: {
549
+ error: '',
550
+ execute: true
551
+ }
552
+ };
553
+ const result = apiIntercept.processApiInterceptResponse(payload);
554
+ expect(result).toEqual(payload);
555
+ });
556
+ });
557
+ describe('processLegacyInterceptResponse', () => {
558
+ it('should convert legacy error format to new format', () => {
559
+ const legacyPayload = {
560
+ data: {
561
+ error: {
562
+ errorText: 'Custom Error',
563
+ errorDescription: 'Custom Description'
564
+ },
565
+ execute: false
566
+ }
567
+ };
568
+ const result = apiIntercept.processLegacyInterceptResponse(legacyPayload);
569
+ expect(result).toEqual({
570
+ data: {
571
+ execute: false,
572
+ response: {
573
+ body: {
574
+ errors: [
575
+ {
576
+ title: 'Custom Error',
577
+ description: 'Custom Description',
578
+ isUserError: true,
579
+ },
580
+ ],
581
+ data: {},
582
+ },
583
+ },
584
+ }
585
+ });
586
+ });
587
+ it('should handle missing error properties', () => {
588
+ const legacyPayload = {
589
+ data: {
590
+ error: {},
591
+ execute: true
592
+ }
593
+ };
594
+ const result = apiIntercept.processLegacyInterceptResponse(legacyPayload);
595
+ expect(result.data.response.body.errors[0]).toEqual({
596
+ title: undefined,
597
+ description: undefined,
598
+ isUserError: true,
599
+ });
600
+ });
601
+ it('should handle missing execute property', () => {
602
+ const legacyPayload = {
603
+ data: {
604
+ error: {
605
+ errorText: 'Error',
606
+ errorDescription: 'Description'
607
+ }
608
+ }
609
+ };
610
+ const result = apiIntercept.processLegacyInterceptResponse(legacyPayload);
611
+ expect(result.data.execute).toBeUndefined();
612
+ });
613
+ it('should always include empty data object', () => {
614
+ const legacyPayload = {
615
+ data: {
616
+ error: {
617
+ errorText: 'Error',
618
+ errorDescription: 'Description'
619
+ },
620
+ execute: false
621
+ }
622
+ };
623
+ const result = apiIntercept.processLegacyInterceptResponse(legacyPayload);
624
+ expect(result.data.response.body.data).toEqual({});
625
+ });
626
+ it('should always set isUserError to true', () => {
627
+ const legacyPayload = {
628
+ data: {
629
+ error: {
630
+ errorText: 'Error',
631
+ errorDescription: 'Description'
632
+ },
633
+ execute: false
634
+ }
635
+ };
636
+ const result = apiIntercept.processLegacyInterceptResponse(legacyPayload);
637
+ expect(result.data.response.body.errors[0].isUserError).toBe(true);
638
+ });
639
+ it('should handle payload with null data', () => {
640
+ const legacyPayload = {
641
+ data: null
642
+ };
643
+ const result = apiIntercept.processLegacyInterceptResponse(legacyPayload);
644
+ expect(result.data.execute).toBeUndefined();
645
+ expect(result.data.response.body.errors[0].title).toBeUndefined();
646
+ expect(result.data.response.body.errors[0].description).toBeUndefined();
647
+ });
648
+ it('should handle payload with null error', () => {
649
+ const legacyPayload = {
650
+ data: {
651
+ error: null,
652
+ execute: true
653
+ }
654
+ };
655
+ const result = apiIntercept.processLegacyInterceptResponse(legacyPayload);
656
+ expect(result.data.execute).toBe(true);
657
+ expect(result.data.response.body.errors[0].title).toBeUndefined();
658
+ expect(result.data.response.body.errors[0].description).toBeUndefined();
659
+ });
660
+ it('should handle payload with undefined properties', () => {
661
+ const legacyPayload = {};
662
+ const result = apiIntercept.processLegacyInterceptResponse(legacyPayload);
663
+ expect(result.data.execute).toBeUndefined();
664
+ expect(result.data.response.body.errors[0].title).toBeUndefined();
665
+ expect(result.data.response.body.errors[0].description).toBeUndefined();
666
+ });
667
+ });
668
+ });
669
+ //# sourceMappingURL=api-intercept.spec.js.map