@databiosphere/findable-ui 50.6.0 → 50.6.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 (72) hide show
  1. package/package.json +6 -1
  2. package/.eslintignore +0 -5
  3. package/.eslintrc.json +0 -79
  4. package/.github/copilot-instructions.md +0 -176
  5. package/.github/workflows/release-please.yml +0 -49
  6. package/.github/workflows/run-checks.yml +0 -57
  7. package/.husky/commit-msg +0 -18
  8. package/.husky/pre-commit +0 -43
  9. package/.prettierignore +0 -19
  10. package/.prettierrc.json +0 -1
  11. package/.release-please-manifest.json +0 -3
  12. package/.storybook/main.ts +0 -10
  13. package/.storybook/preview-head.html +0 -4
  14. package/.storybook/preview.js +0 -6
  15. package/CHANGELOG.md +0 -1117
  16. package/CLAUDE.md +0 -214
  17. package/backend/README.md +0 -64
  18. package/backend/__init__.py +0 -0
  19. package/backend/controllers/__init__.py +0 -0
  20. package/backend/controllers/facets_controller.py +0 -16
  21. package/backend/controllers/models.py +0 -11
  22. package/backend/main.py +0 -8
  23. package/backend/requirements.txt +0 -4
  24. package/backend/services/__init__.py +0 -0
  25. package/backend/services/facets_service.py +0 -68
  26. package/backend/services/models.py +0 -43
  27. package/commitlint.config.js +0 -1
  28. package/docs/TRUSTED_PUBLISHING.md +0 -132
  29. package/jest.config.js +0 -6
  30. package/release-please-config.json +0 -23
  31. package/tests/azulFileDownload.test.tsx +0 -96
  32. package/tests/buildCategoryViews.test.ts +0 -282
  33. package/tests/buildRequestFilters.test.ts +0 -60
  34. package/tests/buildRequestManifest.test.ts +0 -103
  35. package/tests/chart.test.tsx +0 -274
  36. package/tests/chartSortUtils.test.ts +0 -119
  37. package/tests/chartView.test.tsx +0 -48
  38. package/tests/dataDictionaryColumnFilters.test.tsx +0 -101
  39. package/tests/dataDictionary_utils.test.ts +0 -153
  40. package/tests/fetchApi.test.ts +0 -93
  41. package/tests/filter.test.tsx +0 -100
  42. package/tests/filterMenu.test.ts +0 -100
  43. package/tests/filterRange.test.tsx +0 -372
  44. package/tests/filterSortUtils.test.ts +0 -180
  45. package/tests/filters.test.tsx +0 -61
  46. package/tests/getFacetedMinMaxValues.test.ts +0 -166
  47. package/tests/getFilterSortType.test.ts +0 -45
  48. package/tests/getProfileStatus.test.ts +0 -290
  49. package/tests/linkCell.test.tsx +0 -89
  50. package/tests/markdownCell.test.tsx +0 -52
  51. package/tests/provider.test.tsx +0 -189
  52. package/tests/research.chatState.test.ts +0 -463
  53. package/tests/research.fetchResponse.test.ts +0 -164
  54. package/tests/research.queryProvider.test.ts +0 -321
  55. package/tests/research.useKeyShortCuts.test.ts +0 -256
  56. package/tests/rowSelectionValidation.test.ts +0 -282
  57. package/tests/setup.ts +0 -19
  58. package/tests/stepIcon.test.tsx +0 -42
  59. package/tests/tableFilter.test.tsx +0 -90
  60. package/tests/terraProfileProvider.test.tsx +0 -117
  61. package/tests/theme.test.ts +0 -465
  62. package/tests/toggleButtonGroupProvider.test.tsx +0 -125
  63. package/tests/transformRoute.test.ts +0 -21
  64. package/tests/tsconfig.json +0 -8
  65. package/tests/useFileLocation.test.ts +0 -36
  66. package/tests/useRequestManifest.test.ts +0 -201
  67. package/tests/useRouteHistory.test.ts +0 -97
  68. package/tests/useSessionActive.test.ts +0 -106
  69. package/tests/useWindowResize.test.ts +0 -130
  70. package/tests/viewModelBuilders_utils.test.ts +0 -58
  71. package/tests/viewToggle.test.tsx +0 -54
  72. package/tsconfig.json +0 -25
@@ -1,463 +0,0 @@
1
- import { chatReducer } from "../src/views/ResearchView/state/reducer";
2
- import { setErrorAction } from "../src/views/ResearchView/state/actions/setError/action";
3
- import { setError } from "../src/views/ResearchView/state/actions/setError/dispatch";
4
- import { setMessageAction } from "../src/views/ResearchView/state/actions/setMessage/action";
5
- import { setMessage } from "../src/views/ResearchView/state/actions/setMessage/dispatch";
6
- import { setQueryAction } from "../src/views/ResearchView/state/actions/setQuery/action";
7
- import { setQuery } from "../src/views/ResearchView/state/actions/setQuery/dispatch";
8
- import { setStatusAction } from "../src/views/ResearchView/state/actions/setStatus/action";
9
- import { setStatus } from "../src/views/ResearchView/state/actions/setStatus/dispatch";
10
- import { ChatActionKind } from "../src/views/ResearchView/state/actions/types";
11
- import {
12
- ChatState,
13
- MESSAGE_TYPE,
14
- MessageResponse,
15
- SUGGESTION_VARIANT,
16
- } from "../src/views/ResearchView/state/types";
17
- import { initializer } from "../src/views/ResearchView/state/initializer/initializer";
18
- import { INITIAL_STATE } from "../src/views/ResearchView/state/constants";
19
-
20
- /**
21
- * Creates a mock MessageResponse for testing.
22
- * @param message - Optional message override.
23
- * @returns A mock MessageResponse object.
24
- */
25
- const mockResponse = (message: string | null = null): MessageResponse => ({
26
- intent: "auto",
27
- message,
28
- query: {
29
- mentions: [],
30
- message: null,
31
- },
32
- timing: {
33
- lookupMs: 0,
34
- pipelineMs: 0,
35
- totalMs: 0,
36
- },
37
- });
38
-
39
- describe("setError action creator", () => {
40
- it("should return correct action shape", () => {
41
- const action = setError({ error: "Something went wrong" });
42
-
43
- expect(action).toEqual({
44
- payload: { error: "Something went wrong" },
45
- type: ChatActionKind.SetError,
46
- });
47
- });
48
- });
49
-
50
- describe("setErrorAction", () => {
51
- it("should append error to empty array", () => {
52
- const state: ChatState = { messages: [], status: { loading: false } };
53
- const result = setErrorAction(state, { error: "Network error" });
54
-
55
- expect(result.messages).toEqual([
56
- {
57
- createdAt: expect.any(Number),
58
- error: "Network error",
59
- type: MESSAGE_TYPE.ERROR,
60
- },
61
- ]);
62
- });
63
-
64
- it("should append error to existing messages", () => {
65
- const response = mockResponse("Response");
66
- const state: ChatState = {
67
- messages: [
68
- { createdAt: 1000, text: "Query", type: MESSAGE_TYPE.USER },
69
- { createdAt: 2000, response, type: MESSAGE_TYPE.ASSISTANT },
70
- ],
71
- status: { loading: false },
72
- };
73
- const result = setErrorAction(state, { error: "Request failed" });
74
-
75
- expect(result.messages).toEqual([
76
- { createdAt: 1000, text: "Query", type: MESSAGE_TYPE.USER },
77
- { createdAt: 2000, response, type: MESSAGE_TYPE.ASSISTANT },
78
- {
79
- createdAt: expect.any(Number),
80
- error: "Request failed",
81
- type: MESSAGE_TYPE.ERROR,
82
- },
83
- ]);
84
- });
85
-
86
- it("should not mutate original state", () => {
87
- const state: ChatState = {
88
- messages: [
89
- { createdAt: 1000, text: "Original", type: MESSAGE_TYPE.USER },
90
- ],
91
- status: { loading: false },
92
- };
93
- const result = setErrorAction(state, { error: "Error" });
94
-
95
- expect(state.messages).toEqual([
96
- { createdAt: 1000, text: "Original", type: MESSAGE_TYPE.USER },
97
- ]);
98
- expect(result).not.toBe(state);
99
- expect(result.messages).not.toBe(state.messages);
100
- });
101
- });
102
-
103
- describe("setMessage action creator", () => {
104
- it("should return correct action shape", () => {
105
- const response = mockResponse("Hello");
106
- const action = setMessage({ response });
107
-
108
- expect(action).toEqual({
109
- payload: { response },
110
- type: ChatActionKind.SetMessage,
111
- });
112
- });
113
- });
114
-
115
- describe("setMessageAction", () => {
116
- it("should append message to empty array", () => {
117
- const state: ChatState = { messages: [], status: { loading: false } };
118
- const response = mockResponse("First response");
119
- const result = setMessageAction(state, { response });
120
-
121
- expect(result.messages).toEqual([
122
- {
123
- createdAt: expect.any(Number),
124
- response,
125
- type: MESSAGE_TYPE.ASSISTANT,
126
- },
127
- ]);
128
- });
129
-
130
- it("should append message to existing messages", () => {
131
- const existingResponse = mockResponse("Second");
132
- const state: ChatState = {
133
- messages: [
134
- { createdAt: 1000, text: "First", type: MESSAGE_TYPE.USER },
135
- {
136
- createdAt: 2000,
137
- response: existingResponse,
138
- type: MESSAGE_TYPE.ASSISTANT,
139
- },
140
- ],
141
- status: { loading: false },
142
- };
143
- const newResponse = mockResponse("Third");
144
- const result = setMessageAction(state, { response: newResponse });
145
-
146
- expect(result.messages).toEqual([
147
- { createdAt: 1000, text: "First", type: MESSAGE_TYPE.USER },
148
- {
149
- createdAt: 2000,
150
- response: existingResponse,
151
- type: MESSAGE_TYPE.ASSISTANT,
152
- },
153
- {
154
- createdAt: expect.any(Number),
155
- response: newResponse,
156
- type: MESSAGE_TYPE.ASSISTANT,
157
- },
158
- ]);
159
- });
160
-
161
- it("should not mutate original state", () => {
162
- const state: ChatState = {
163
- messages: [
164
- { createdAt: 1000, text: "Original", type: MESSAGE_TYPE.USER },
165
- ],
166
- status: { loading: false },
167
- };
168
- const response = mockResponse("New");
169
- const result = setMessageAction(state, { response });
170
-
171
- expect(state.messages).toEqual([
172
- { createdAt: 1000, text: "Original", type: MESSAGE_TYPE.USER },
173
- ]);
174
- expect(result).not.toBe(state);
175
- expect(result.messages).not.toBe(state.messages);
176
- });
177
- });
178
-
179
- describe("setQuery action creator", () => {
180
- it("should return correct action shape", () => {
181
- const action = setQuery({ query: "What studies are available?" });
182
-
183
- expect(action).toEqual({
184
- payload: { query: "What studies are available?" },
185
- type: ChatActionKind.SetQuery,
186
- });
187
- });
188
- });
189
-
190
- describe("setQueryAction", () => {
191
- it("should append query to empty array", () => {
192
- const state: ChatState = { messages: [], status: { loading: false } };
193
- const result = setQueryAction(state, { query: "First query" });
194
-
195
- expect(result.messages).toEqual([
196
- {
197
- createdAt: expect.any(Number),
198
- text: "First query",
199
- type: MESSAGE_TYPE.USER,
200
- },
201
- ]);
202
- });
203
-
204
- it("should append query to existing messages", () => {
205
- const existingResponse = mockResponse("Response");
206
- const state: ChatState = {
207
- messages: [
208
- { createdAt: 1000, text: "First", type: MESSAGE_TYPE.USER },
209
- {
210
- createdAt: 2000,
211
- response: existingResponse,
212
- type: MESSAGE_TYPE.ASSISTANT,
213
- },
214
- ],
215
- status: { loading: false },
216
- };
217
- const result = setQueryAction(state, { query: "Second query" });
218
-
219
- expect(result.messages).toEqual([
220
- { createdAt: 1000, text: "First", type: MESSAGE_TYPE.USER },
221
- {
222
- createdAt: 2000,
223
- response: existingResponse,
224
- type: MESSAGE_TYPE.ASSISTANT,
225
- },
226
- {
227
- createdAt: expect.any(Number),
228
- text: "Second query",
229
- type: MESSAGE_TYPE.USER,
230
- },
231
- ]);
232
- });
233
-
234
- it("should not mutate original state", () => {
235
- const response = mockResponse("Original response");
236
- const state: ChatState = {
237
- messages: [{ createdAt: 1000, response, type: MESSAGE_TYPE.ASSISTANT }],
238
- status: { loading: false },
239
- };
240
- const result = setQueryAction(state, { query: "New query" });
241
-
242
- expect(state.messages).toEqual([
243
- { createdAt: 1000, response, type: MESSAGE_TYPE.ASSISTANT },
244
- ]);
245
- expect(result).not.toBe(state);
246
- expect(result.messages).not.toBe(state.messages);
247
- });
248
- });
249
-
250
- describe("setStatus action creator", () => {
251
- it("should return correct action shape", () => {
252
- const action = setStatus({ loading: true });
253
-
254
- expect(action).toEqual({
255
- payload: { loading: true },
256
- type: ChatActionKind.SetStatus,
257
- });
258
- });
259
- });
260
-
261
- describe("setStatusAction", () => {
262
- it("should set loading to true", () => {
263
- const state: ChatState = { messages: [], status: { loading: false } };
264
- const result = setStatusAction(state, { loading: true });
265
-
266
- expect(result.status.loading).toBe(true);
267
- });
268
-
269
- it("should set loading to false", () => {
270
- const state: ChatState = { messages: [], status: { loading: true } };
271
- const result = setStatusAction(state, { loading: false });
272
-
273
- expect(result.status.loading).toBe(false);
274
- });
275
-
276
- it("should preserve messages when setting loading", () => {
277
- const response = mockResponse("Test");
278
- const state: ChatState = {
279
- messages: [
280
- { createdAt: 1000, text: "Query", type: MESSAGE_TYPE.USER },
281
- { createdAt: 2000, response, type: MESSAGE_TYPE.ASSISTANT },
282
- ],
283
- status: { loading: false },
284
- };
285
- const result = setStatusAction(state, { loading: true });
286
-
287
- expect(result.messages).toEqual(state.messages);
288
- });
289
-
290
- it("should not mutate original state", () => {
291
- const state: ChatState = { messages: [], status: { loading: false } };
292
- const result = setStatusAction(state, { loading: true });
293
-
294
- expect(state.status.loading).toBe(false);
295
- expect(result).not.toBe(state);
296
- });
297
- });
298
-
299
- describe("chatReducer", () => {
300
- it("should return initial state for unknown action", () => {
301
- const state: ChatState = { messages: [], status: { loading: false } };
302
- const unknownAction = { payload: {}, type: "UNKNOWN" } as never;
303
-
304
- const result = chatReducer(state, unknownAction);
305
-
306
- expect(result).toBe(state);
307
- });
308
-
309
- it("should handle SetMessage action", () => {
310
- const state: ChatState = { messages: [], status: { loading: false } };
311
- const response = mockResponse("Test response");
312
- const action = setMessage({ response });
313
-
314
- const result = chatReducer(state, action);
315
-
316
- expect(result.messages).toEqual([
317
- {
318
- createdAt: expect.any(Number),
319
- response,
320
- type: MESSAGE_TYPE.ASSISTANT,
321
- },
322
- ]);
323
- });
324
-
325
- it("should handle SetQuery action", () => {
326
- const state: ChatState = { messages: [], status: { loading: false } };
327
- const action = setQuery({ query: "Test query" });
328
-
329
- const result = chatReducer(state, action);
330
-
331
- expect(result.messages).toEqual([
332
- {
333
- createdAt: expect.any(Number),
334
- text: "Test query",
335
- type: MESSAGE_TYPE.USER,
336
- },
337
- ]);
338
- });
339
-
340
- it("should return new state reference on SetMessage", () => {
341
- const state: ChatState = { messages: [], status: { loading: false } };
342
- const response = mockResponse("Test");
343
- const action = setMessage({ response });
344
-
345
- const result = chatReducer(state, action);
346
-
347
- expect(result).not.toBe(state);
348
- });
349
-
350
- it("should return new state reference on SetQuery", () => {
351
- const state: ChatState = { messages: [], status: { loading: false } };
352
- const action = setQuery({ query: "Test" });
353
-
354
- const result = chatReducer(state, action);
355
-
356
- expect(result).not.toBe(state);
357
- });
358
-
359
- it("should handle SetStatus action", () => {
360
- const state: ChatState = { messages: [], status: { loading: false } };
361
- const action = setStatus({ loading: true });
362
-
363
- const result = chatReducer(state, action);
364
-
365
- expect(result.status.loading).toBe(true);
366
- });
367
-
368
- it("should return new state reference on SetStatus", () => {
369
- const state: ChatState = { messages: [], status: { loading: false } };
370
- const action = setStatus({ loading: true });
371
-
372
- const result = chatReducer(state, action);
373
-
374
- expect(result).not.toBe(state);
375
- });
376
-
377
- it("should handle SetError action", () => {
378
- const state: ChatState = { messages: [], status: { loading: false } };
379
- const action = setError({ error: "Test error" });
380
-
381
- const result = chatReducer(state, action);
382
-
383
- expect(result.messages).toEqual([
384
- {
385
- createdAt: expect.any(Number),
386
- error: "Test error",
387
- type: MESSAGE_TYPE.ERROR,
388
- },
389
- ]);
390
- });
391
-
392
- it("should return new state reference on SetError", () => {
393
- const state: ChatState = { messages: [], status: { loading: false } };
394
- const action = setError({ error: "Test error" });
395
-
396
- const result = chatReducer(state, action);
397
-
398
- expect(result).not.toBe(state);
399
- });
400
- });
401
-
402
- describe("initializer", () => {
403
- it("should return initial state when no args provided", () => {
404
- const result = initializer();
405
-
406
- expect(result).toBe(INITIAL_STATE);
407
- });
408
-
409
- it("should return initial state when undefined is passed", () => {
410
- const result = initializer(undefined);
411
-
412
- expect(result).toBe(INITIAL_STATE);
413
- });
414
-
415
- it("should inject a prompt message when initialArgs is provided", () => {
416
- const result = initializer({ text: "Welcome to the assistant" });
417
-
418
- expect(result.messages).toEqual([
419
- expect.objectContaining({
420
- initial: true,
421
- text: "Welcome to the assistant",
422
- type: MESSAGE_TYPE.PROMPT,
423
- }),
424
- ]);
425
- expect(result.messages[0]).toHaveProperty("createdAt");
426
- });
427
-
428
- it("should include all initialArgs properties in the prompt message", () => {
429
- const result = initializer({
430
- inputPlaceholder: "Ask about datasets",
431
- suggestions: [
432
- {
433
- label: "GLP-1",
434
- query: "GLP-1 studies",
435
- variant: SUGGESTION_VARIANT.CHIP,
436
- },
437
- ],
438
- text: "How can I help?",
439
- });
440
-
441
- expect(result.messages).toHaveLength(1);
442
- expect(result.messages[0]).toEqual(
443
- expect.objectContaining({
444
- inputPlaceholder: "Ask about datasets",
445
- suggestions: [
446
- {
447
- label: "GLP-1",
448
- query: "GLP-1 studies",
449
- variant: SUGGESTION_VARIANT.CHIP,
450
- },
451
- ],
452
- text: "How can I help?",
453
- type: MESSAGE_TYPE.PROMPT,
454
- }),
455
- );
456
- });
457
-
458
- it("should preserve default status when initialArgs is provided", () => {
459
- const result = initializer({ text: "Welcome" });
460
-
461
- expect(result.status).toEqual({ loading: false });
462
- });
463
- });
@@ -1,164 +0,0 @@
1
- import { jest } from "@jest/globals";
2
- import fetchMock from "jest-fetch-mock";
3
- import { ERROR_MESSAGE } from "../src/views/ResearchView/query/constants";
4
- import { fetchResponse } from "../src/views/ResearchView/query/fetch";
5
-
6
- beforeAll(() => {
7
- fetchMock.enableMocks();
8
- });
9
-
10
- beforeEach(() => {
11
- fetchMock.resetMocks();
12
- });
13
-
14
- describe("fetchResponse", () => {
15
- const mockCallbacks = (): {
16
- onError: jest.Mock;
17
- onSettled: jest.Mock;
18
- onSuccess: jest.Mock;
19
- } => ({
20
- onError: jest.fn(),
21
- onSettled: jest.fn(),
22
- onSuccess: jest.fn(),
23
- });
24
-
25
- it("should call onSuccess with data on successful response", async () => {
26
- const mockData = { results: ["study1", "study2"] };
27
- fetchMock.mockResponseOnce(JSON.stringify(mockData));
28
-
29
- const controller = new AbortController();
30
- const callbacks = mockCallbacks();
31
-
32
- await fetchResponse("https://api.example.com/search", "diabetes", {
33
- controller,
34
- ...callbacks,
35
- });
36
-
37
- expect(callbacks.onSuccess).toHaveBeenCalledWith(mockData);
38
- expect(callbacks.onError).not.toHaveBeenCalled();
39
- expect(callbacks.onSettled).toHaveBeenCalled();
40
- });
41
-
42
- it("should call onError on rate limit (429)", async () => {
43
- fetchMock.mockResponseOnce("", { status: 429 });
44
-
45
- const controller = new AbortController();
46
- const callbacks = mockCallbacks();
47
-
48
- await fetchResponse("https://api.example.com/search", "diabetes", {
49
- controller,
50
- ...callbacks,
51
- });
52
-
53
- expect(callbacks.onError).toHaveBeenCalledWith(
54
- new Error(ERROR_MESSAGE.RATE_LIMITED),
55
- );
56
- expect(callbacks.onSuccess).not.toHaveBeenCalled();
57
- expect(callbacks.onSettled).toHaveBeenCalled();
58
- });
59
-
60
- it("should call onError on non-ok response", async () => {
61
- fetchMock.mockResponseOnce("", { status: 500 });
62
-
63
- const controller = new AbortController();
64
- const callbacks = mockCallbacks();
65
-
66
- await fetchResponse("https://api.example.com/search", "diabetes", {
67
- controller,
68
- ...callbacks,
69
- });
70
-
71
- expect(callbacks.onError).toHaveBeenCalledWith(
72
- new Error(`${ERROR_MESSAGE.REQUEST_FAILED} (500)`),
73
- );
74
- expect(callbacks.onSuccess).not.toHaveBeenCalled();
75
- expect(callbacks.onSettled).toHaveBeenCalled();
76
- });
77
-
78
- it("should not call onError when request is aborted", async () => {
79
- const controller = new AbortController();
80
- controller.abort();
81
-
82
- fetchMock.mockRejectOnce(new DOMException("Aborted", "AbortError"));
83
-
84
- const callbacks = mockCallbacks();
85
-
86
- await fetchResponse("https://api.example.com/search", "diabetes", {
87
- controller,
88
- ...callbacks,
89
- });
90
-
91
- expect(callbacks.onError).not.toHaveBeenCalled();
92
- expect(callbacks.onSuccess).not.toHaveBeenCalled();
93
- expect(callbacks.onSettled).toHaveBeenCalled();
94
- });
95
-
96
- it("should call onSettled after success", async () => {
97
- const mockData = { results: [] };
98
- fetchMock.mockResponseOnce(JSON.stringify(mockData));
99
-
100
- const controller = new AbortController();
101
- const callbacks = mockCallbacks();
102
-
103
- await fetchResponse("https://api.example.com/search", "diabetes", {
104
- controller,
105
- ...callbacks,
106
- });
107
-
108
- expect(callbacks.onSuccess).toHaveBeenCalledTimes(1);
109
- expect(callbacks.onSettled).toHaveBeenCalledTimes(1);
110
- });
111
-
112
- it("should call onSettled after error", async () => {
113
- fetchMock.mockResponseOnce("", { status: 500 });
114
-
115
- const controller = new AbortController();
116
- const callbacks = mockCallbacks();
117
-
118
- await fetchResponse("https://api.example.com/search", "diabetes", {
119
- controller,
120
- ...callbacks,
121
- });
122
-
123
- expect(callbacks.onError).toHaveBeenCalledTimes(1);
124
- expect(callbacks.onSettled).toHaveBeenCalledTimes(1);
125
- });
126
-
127
- it("should send POST request with correct body and headers", async () => {
128
- fetchMock.mockResponseOnce(JSON.stringify({}));
129
-
130
- const controller = new AbortController();
131
- const callbacks = mockCallbacks();
132
-
133
- await fetchResponse("https://api.example.com/search", "cancer studies", {
134
- controller,
135
- ...callbacks,
136
- });
137
-
138
- expect(fetchMock).toHaveBeenCalledWith(
139
- "https://api.example.com/search",
140
- expect.objectContaining({
141
- body: JSON.stringify({ query: "cancer studies" }),
142
- headers: { "Content-Type": "application/json" },
143
- method: "POST",
144
- }),
145
- );
146
- });
147
-
148
- it("should call onError with unknown error message for non-Error throws", async () => {
149
- fetchMock.mockRejectOnce("string error" as unknown as Error);
150
-
151
- const controller = new AbortController();
152
- const callbacks = mockCallbacks();
153
-
154
- await fetchResponse("https://api.example.com/search", "diabetes", {
155
- controller,
156
- ...callbacks,
157
- });
158
-
159
- expect(callbacks.onError).toHaveBeenCalledWith(
160
- new Error(ERROR_MESSAGE.UNKNOWN),
161
- );
162
- expect(callbacks.onSettled).toHaveBeenCalled();
163
- });
164
- });