quickbase-js 0.1.0-beta.8 → 0.1.0-beta.9

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 (52) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +46 -130
  3. package/dist/esm/quickbase.d.ts +822 -119
  4. package/dist/esm/quickbase.js +373 -236
  5. package/dist/esm/quickbase.js.map +1 -1
  6. package/dist/esm/quickbase.min.js +1 -1
  7. package/dist/esm/quickbase.min.js.map +1 -1
  8. package/dist/umd/quickbase.umd.js +373 -236
  9. package/dist/umd/quickbase.umd.js.map +1 -1
  10. package/dist/umd/quickbase.umd.min.js +1 -1
  11. package/dist/umd/quickbase.umd.min.js.map +1 -1
  12. package/open-api/generate-unified-interface.ts +97 -17
  13. package/open-api/utils/generateJsDoc.ts +96 -0
  14. package/package.json +3 -1
  15. package/src/ThrottleBucket.ts +17 -12
  16. package/src/authorizationStrategy.ts +246 -0
  17. package/src/generated-unified/QuickbaseClient.ts +809 -119
  18. package/src/invokeMethod.ts +150 -265
  19. package/src/quickbaseClient.ts +85 -58
  20. package/src/rateLimiter.ts +25 -0
  21. package/src/tokenCache.ts +10 -26
  22. package/tests/vitest/qb/auth/mockQuickbaseServer.ts +60 -0
  23. package/tests/vitest/qb/auth/retryUserToken401.test.ts +59 -42
  24. package/tests/vitest/qb/auth/ssoTokenIntegrationWithServer.test.ts +65 -0
  25. package/tests/vitest/qb/fields/getFieldUsage.test.ts +58 -150
  26. package/tests/vitest/qb/formulas/runFormula.test.ts +96 -0
  27. package/tests/vitest/qb/tables/createRelationship.test.ts +102 -0
  28. package/tests/vitest/qb/tables/deleteRelationship.test.ts +143 -0
  29. package/tests/vitest/qb/tables/updateRelationship.test.ts +118 -145
  30. package/tests/vitest/unit/ThrottleBucket.test.ts +95 -0
  31. package/tests/vitest/unit/apps/copyApp.test.ts +133 -40
  32. package/tests/vitest/unit/apps/updateApp.test.ts +42 -11
  33. package/tests/vitest/unit/auth/fetchTempToken401.test.ts +3 -2
  34. package/tests/vitest/unit/auth/getTempToken.test.ts +42 -18
  35. package/tests/vitest/unit/auth/retryTempToken401.test.ts +46 -64
  36. package/tests/vitest/unit/auth/retryTempTokenMaxRetries.test.ts +235 -0
  37. package/tests/vitest/unit/auth/retryUserToken401.test.ts +56 -43
  38. package/tests/vitest/unit/auth/ssoTokenRefresh.test.ts +325 -0
  39. package/tests/vitest/unit/fields/createField.test.ts +180 -116
  40. package/tests/vitest/unit/fields/getFieldUsage.test.ts +17 -3
  41. package/tests/vitest/unit/fields/updateField.test.ts +12 -7
  42. package/tests/vitest/unit/formulas/runFormula.test.ts +205 -0
  43. package/tests/vitest/unit/index.ts +2 -1
  44. package/tests/vitest/unit/inferHttpMethod.test.ts +131 -0
  45. package/tests/vitest/unit/rateLimit.test.ts +4 -2
  46. package/tests/vitest/unit/tables/createRelationship.test.ts +212 -0
  47. package/tests/vitest/unit/tables/deleteRelationship.test.ts +97 -0
  48. package/tests/vitest/unit/tables/updateRelationship.test.ts +12 -10
  49. package/tests/vitest/unit/tokenLifespan.test.ts +149 -83
  50. package/tools/log-gen.ts +14 -5
  51. package/tools/log-gen.yaml +710 -268
  52. package/tests/vitest/unit/auth/retryTempTokenTwo401.test.ts +0 -81
@@ -2,11 +2,11 @@ import { describe, it, expect, beforeEach, vi } from "vitest";
2
2
  import {
3
3
  createClient,
4
4
  mockFetch,
5
+ QB_TABLE_ID_1,
5
6
  QB_REALM,
6
7
  QB_USER_TOKEN,
7
- QB_TABLE_ID_1,
8
8
  } from "@tests/setup.ts";
9
- import { CreateFieldRequest, CreateField200Response } from "@/generated/models";
9
+ import { CreateFieldRequest } from "@/generated/models";
10
10
 
11
11
  describe("QuickbaseClient Unit - createField", () => {
12
12
  let client: ReturnType<typeof createClient>;
@@ -21,52 +21,43 @@ describe("QuickbaseClient Unit - createField", () => {
21
21
  expect(typeof client.createField).toBe("function");
22
22
  });
23
23
 
24
- it("creates a field successfully with user token", async () => {
24
+ it("creates field successfully with user token", async () => {
25
25
  client = createClient(mockFetch, { debug: true });
26
26
 
27
27
  const request: CreateFieldRequest = {
28
- label: "TestField",
28
+ label: "NewField",
29
29
  fieldType: "text",
30
- fieldHelp: "A test field",
31
- addToForms: true,
32
- permissions: [
33
- { role: "Viewer", permissionType: "View", roleId: 10 },
34
- { role: "Administrator", permissionType: "Modify", roleId: 12 },
35
- ],
36
30
  };
37
31
 
38
- const mockResponse: CreateField200Response = {
39
- id: 100,
40
- label: "TestField",
32
+ const mockResponse = {
33
+ id: 101,
34
+ label: "NewField",
41
35
  fieldType: "text",
42
- mode: "",
43
- noWrap: false,
44
- bold: false,
45
- required: false,
46
36
  appearsByDefault: true,
47
- findEnabled: true,
48
- unique: false,
49
- doesDataCopy: false,
50
- fieldHelp: "A test field",
51
37
  audited: false,
38
+ bold: false,
39
+ doesDataCopy: false,
40
+ fieldHelp: "",
41
+ findEnabled: true,
42
+ mode: "",
43
+ noWrap: false,
44
+ permissions: [],
52
45
  properties: {
53
- primaryKey: false,
54
- foreignKey: false,
55
- numLines: 1,
56
- maxLength: 0,
57
- appendOnly: false,
58
46
  allowHTML: false,
59
47
  allowMentions: false,
60
- sortAsGiven: false,
61
- carryChoices: true,
62
48
  allowNewChoices: false,
63
- formula: "",
49
+ appendOnly: false,
50
+ carryChoices: true,
64
51
  defaultValue: "",
52
+ foreignKey: false,
53
+ formula: "",
54
+ maxLength: 0,
55
+ numLines: 1,
56
+ primaryKey: false,
57
+ sortAsGiven: false,
65
58
  },
66
- permissions: [
67
- { permissionType: "View", role: "Viewer", roleId: 10 },
68
- { permissionType: "Modify", role: "Administrator", roleId: 12 },
69
- ],
59
+ required: false,
60
+ unique: false,
70
61
  };
71
62
 
72
63
  mockFetch.mockResolvedValueOnce({
@@ -81,25 +72,22 @@ describe("QuickbaseClient Unit - createField", () => {
81
72
  });
82
73
 
83
74
  expect(result).toEqual(mockResponse);
84
- const callArgs = mockFetch.mock.calls[0];
85
- console.log("Raw fetch call (user token):", callArgs);
86
- const receivedBody = JSON.parse(callArgs[1].body as string);
87
- expect(receivedBody).toEqual(request);
88
75
  expect(mockFetch).toHaveBeenCalledWith(
89
76
  `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`,
90
- expect.objectContaining({
77
+ {
91
78
  method: "POST",
92
- headers: expect.objectContaining({
79
+ body: JSON.stringify(request),
80
+ headers: {
93
81
  "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
94
82
  Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
95
83
  "Content-Type": "application/json",
96
- }),
97
- body: JSON.stringify(request),
98
- })
84
+ },
85
+ credentials: "omit",
86
+ }
99
87
  );
100
88
  });
101
89
 
102
- it("creates a field successfully with temp token", async () => {
90
+ it("creates field successfully with temp token", async () => {
103
91
  client = createClient(mockFetch, { useTempTokens: true, debug: true });
104
92
 
105
93
  const request: CreateFieldRequest = {
@@ -108,35 +96,35 @@ describe("QuickbaseClient Unit - createField", () => {
108
96
  addToForms: false,
109
97
  };
110
98
 
111
- const mockResponse: CreateField200Response = {
112
- id: 101,
99
+ const mockResponse = {
100
+ id: 102,
113
101
  label: "TempField",
114
102
  fieldType: "numeric",
115
- mode: "",
116
- noWrap: false,
103
+ appearsByDefault: false,
104
+ audited: false,
117
105
  bold: false,
118
- required: false,
119
- appearsByDefault: true,
120
- findEnabled: true,
121
- unique: false,
122
106
  doesDataCopy: false,
123
107
  fieldHelp: "",
124
- audited: false,
108
+ findEnabled: true,
109
+ mode: "",
110
+ noWrap: false,
111
+ permissions: [],
125
112
  properties: {
126
- primaryKey: false,
127
- foreignKey: false,
128
- numLines: 1,
129
- maxLength: 0,
130
- appendOnly: false,
131
113
  allowHTML: false,
132
114
  allowMentions: false,
133
- sortAsGiven: false,
134
- carryChoices: true,
135
115
  allowNewChoices: false,
136
- formula: "",
116
+ appendOnly: false,
117
+ carryChoices: true,
137
118
  defaultValue: "",
119
+ foreignKey: false,
120
+ formula: "",
121
+ maxLength: 0,
122
+ numLines: 1,
123
+ primaryKey: false,
124
+ sortAsGiven: false,
138
125
  },
139
- permissions: [],
126
+ required: false,
127
+ unique: false,
140
128
  };
141
129
 
142
130
  mockFetch
@@ -161,29 +149,21 @@ describe("QuickbaseClient Unit - createField", () => {
161
149
  expect(mockFetch).toHaveBeenNthCalledWith(
162
150
  1,
163
151
  `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
164
- expect.objectContaining({
165
- method: "GET",
166
- headers: expect.objectContaining({
167
- "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
168
- "Content-Type": "application/json",
169
- }),
170
- credentials: "include",
171
- })
152
+ expect.any(Object)
172
153
  );
173
- const callArgs = mockFetch.mock.calls[1];
174
- console.log("Raw fetch call (temp token):", callArgs);
175
154
  expect(mockFetch).toHaveBeenNthCalledWith(
176
155
  2,
177
156
  `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`,
178
- expect.objectContaining({
157
+ {
179
158
  method: "POST",
180
- headers: expect.objectContaining({
181
- "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
159
+ body: JSON.stringify(request),
160
+ headers: {
182
161
  Authorization: "QB-TEMP-TOKEN temp_token",
183
162
  "Content-Type": "application/json",
184
- }),
185
- body: JSON.stringify(request),
186
- })
163
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
164
+ },
165
+ credentials: "omit",
166
+ }
187
167
  );
188
168
  });
189
169
 
@@ -195,35 +175,35 @@ describe("QuickbaseClient Unit - createField", () => {
195
175
  fieldType: "checkbox",
196
176
  };
197
177
 
198
- const mockResponse: CreateField200Response = {
178
+ const mockResponse = {
199
179
  id: 102,
200
180
  label: "RetryField",
201
181
  fieldType: "checkbox",
202
- mode: "",
203
- noWrap: false,
204
- bold: false,
205
- required: false,
206
182
  appearsByDefault: true,
207
- findEnabled: true,
208
- unique: false,
183
+ audited: false,
184
+ bold: false,
209
185
  doesDataCopy: false,
210
186
  fieldHelp: "",
211
- audited: false,
187
+ findEnabled: true,
188
+ mode: "",
189
+ noWrap: false,
190
+ permissions: [],
212
191
  properties: {
213
- primaryKey: false,
214
- foreignKey: false,
215
- numLines: 1,
216
- maxLength: 0,
217
- appendOnly: false,
218
192
  allowHTML: false,
219
193
  allowMentions: false,
220
- sortAsGiven: false,
221
- carryChoices: true,
222
194
  allowNewChoices: false,
223
- formula: "",
195
+ appendOnly: false,
196
+ carryChoices: true,
224
197
  defaultValue: "",
198
+ foreignKey: false,
199
+ formula: "",
200
+ maxLength: 0,
201
+ numLines: 1,
202
+ primaryKey: false,
203
+ sortAsGiven: false,
225
204
  },
226
- permissions: [],
205
+ required: false,
206
+ unique: false,
227
207
  };
228
208
 
229
209
  mockFetch
@@ -237,6 +217,7 @@ describe("QuickbaseClient Unit - createField", () => {
237
217
  ok: false,
238
218
  status: 401,
239
219
  json: () => Promise.resolve({ message: "Unauthorized" }),
220
+ text: () => Promise.resolve("Unauthorized"),
240
221
  })
241
222
  .mockResolvedValueOnce({
242
223
  ok: true,
@@ -265,11 +246,16 @@ describe("QuickbaseClient Unit - createField", () => {
265
246
  expect(mockFetch).toHaveBeenNthCalledWith(
266
247
  2,
267
248
  `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`,
268
- expect.objectContaining({
269
- headers: expect.objectContaining({
249
+ {
250
+ method: "POST",
251
+ body: JSON.stringify(request),
252
+ headers: {
270
253
  Authorization: "QB-TEMP-TOKEN initial_token",
271
- }),
272
- })
254
+ "Content-Type": "application/json",
255
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
256
+ },
257
+ credentials: "omit",
258
+ }
273
259
  );
274
260
  expect(mockFetch).toHaveBeenNthCalledWith(
275
261
  3,
@@ -279,18 +265,22 @@ describe("QuickbaseClient Unit - createField", () => {
279
265
  expect(mockFetch).toHaveBeenNthCalledWith(
280
266
  4,
281
267
  `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`,
282
- expect.objectContaining({
283
- headers: expect.objectContaining({
268
+ {
269
+ method: "POST",
270
+ body: JSON.stringify(request),
271
+ headers: {
284
272
  Authorization: "QB-TEMP-TOKEN new_token",
285
- }),
286
- })
273
+ "Content-Type": "application/json",
274
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
275
+ },
276
+ credentials: "omit",
277
+ }
287
278
  );
288
279
  expect(consoleSpy).toHaveBeenCalledWith(
289
- "Authorization error for createField (temp token), refreshing token:",
290
- expect.any(String)
280
+ "Authorization error for createField (temp token), refreshing token:"
291
281
  );
292
282
  expect(consoleSpy).toHaveBeenCalledWith(
293
- "Retrying createField with temp token"
283
+ "[createField] Retrying with token: new_token..."
294
284
  );
295
285
  consoleSpy.mockRestore();
296
286
  });
@@ -299,7 +289,7 @@ describe("QuickbaseClient Unit - createField", () => {
299
289
  client = createClient(mockFetch, { debug: true });
300
290
 
301
291
  const request: CreateFieldRequest = {
302
- label: "", // Invalid: label is required
292
+ label: "", // Invalid: empty label
303
293
  fieldType: "text",
304
294
  };
305
295
 
@@ -307,6 +297,7 @@ describe("QuickbaseClient Unit - createField", () => {
307
297
  ok: false,
308
298
  status: 400,
309
299
  json: () => Promise.resolve({ message: "Label is required" }),
300
+ text: () => Promise.resolve("Label is required"),
310
301
  });
311
302
 
312
303
  await expect(
@@ -315,15 +306,16 @@ describe("QuickbaseClient Unit - createField", () => {
315
306
 
316
307
  expect(mockFetch).toHaveBeenCalledWith(
317
308
  `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`,
318
- expect.objectContaining({
309
+ {
319
310
  method: "POST",
320
- headers: expect.objectContaining({
311
+ body: JSON.stringify(request),
312
+ headers: {
321
313
  "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
322
314
  Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
323
315
  "Content-Type": "application/json",
324
- }),
325
- body: JSON.stringify(request),
326
- })
316
+ },
317
+ credentials: "omit",
318
+ }
327
319
  );
328
320
  });
329
321
 
@@ -346,19 +338,49 @@ describe("QuickbaseClient Unit - createField", () => {
346
338
  ok: false,
347
339
  status: 401,
348
340
  json: () => Promise.resolve({ message: "Unauthorized" }),
341
+ text: () => Promise.resolve("Unauthorized"),
342
+ })
343
+ .mockResolvedValueOnce({
344
+ ok: true,
345
+ status: 200,
346
+ json: () => Promise.resolve({ temporaryAuthorization: "token_2" }),
347
+ })
348
+ .mockResolvedValueOnce({
349
+ ok: false,
350
+ status: 401,
351
+ json: () => Promise.resolve({ message: "Unauthorized again" }),
352
+ text: () => Promise.resolve("Unauthorized again"),
353
+ })
354
+ .mockResolvedValueOnce({
355
+ ok: true,
356
+ status: 200,
357
+ json: () => Promise.resolve({ temporaryAuthorization: "token_3" }),
358
+ })
359
+ .mockResolvedValueOnce({
360
+ ok: false,
361
+ status: 401,
362
+ json: () => Promise.resolve({ message: "Unauthorized again" }),
363
+ text: () => Promise.resolve("Unauthorized again"),
364
+ })
365
+ .mockResolvedValueOnce({
366
+ ok: true,
367
+ status: 200,
368
+ json: () => Promise.resolve({ temporaryAuthorization: "token_4" }),
349
369
  })
350
370
  .mockResolvedValueOnce({
351
371
  ok: false,
352
372
  status: 401,
353
- json: () => Promise.resolve({ message: "Temp token fetch failed" }),
373
+ json: () => Promise.resolve({ message: "Unauthorized again" }),
374
+ text: () => Promise.resolve("Unauthorized again"),
354
375
  });
355
376
 
356
377
  const consoleSpy = vi.spyOn(console, "log");
378
+
357
379
  await expect(
358
380
  client.createField({ tableId: QB_TABLE_ID_1, body: request })
359
- ).rejects.toThrow("API Error: Temp token fetch failed (Status: 401)");
381
+ ).rejects.toThrow("API Error: Unauthorized again (Status: 401)");
360
382
 
361
- expect(mockFetch).toHaveBeenCalledTimes(3);
383
+ expect(mockFetch).toHaveBeenCalledTimes(8);
362
384
  expect(mockFetch).toHaveBeenNthCalledWith(
363
385
  1,
364
386
  `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
@@ -368,6 +390,7 @@ describe("QuickbaseClient Unit - createField", () => {
368
390
  2,
369
391
  `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`,
370
392
  expect.objectContaining({
393
+ method: "POST",
371
394
  headers: expect.objectContaining({
372
395
  Authorization: "QB-TEMP-TOKEN initial_token",
373
396
  }),
@@ -378,10 +401,51 @@ describe("QuickbaseClient Unit - createField", () => {
378
401
  `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
379
402
  expect.any(Object)
380
403
  );
404
+ expect(mockFetch).toHaveBeenNthCalledWith(
405
+ 4,
406
+ `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`,
407
+ expect.objectContaining({
408
+ method: "POST",
409
+ headers: expect.objectContaining({
410
+ Authorization: "QB-TEMP-TOKEN token_2",
411
+ }),
412
+ })
413
+ );
414
+ expect(mockFetch).toHaveBeenNthCalledWith(
415
+ 5,
416
+ `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
417
+ expect.any(Object)
418
+ );
419
+ expect(mockFetch).toHaveBeenNthCalledWith(
420
+ 6,
421
+ `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`,
422
+ expect.objectContaining({
423
+ method: "POST",
424
+ headers: expect.objectContaining({
425
+ Authorization: "QB-TEMP-TOKEN token_3",
426
+ }),
427
+ })
428
+ );
429
+ expect(mockFetch).toHaveBeenNthCalledWith(
430
+ 7,
431
+ `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
432
+ expect.any(Object)
433
+ );
434
+ expect(mockFetch).toHaveBeenNthCalledWith(
435
+ 8,
436
+ `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`,
437
+ expect.objectContaining({
438
+ method: "POST",
439
+ headers: expect.objectContaining({
440
+ Authorization: "QB-TEMP-TOKEN token_4",
441
+ }),
442
+ })
443
+ );
444
+
381
445
  expect(consoleSpy).toHaveBeenCalledWith(
382
- "Authorization error for createField (temp token), refreshing token:",
383
- expect.any(String)
446
+ "Authorization error for createField (temp token), refreshing token:"
384
447
  );
448
+
385
449
  consoleSpy.mockRestore();
386
450
  });
387
451
  });
@@ -113,8 +113,22 @@ describe("QuickbaseClient Unit - getFieldUsage", () => {
113
113
  });
114
114
 
115
115
  it("handles persistent 401 error for field usage retrieval", async () => {
116
- // Simulate a persistent 401 error (initial and retry attempts fail)
116
+ // Simulate persistent 401 errors to exhaust retries
117
117
  mockFetch
118
+ .mockResolvedValueOnce(
119
+ new Response(JSON.stringify({ message: "Unauthorized" }), {
120
+ status: 401,
121
+ statusText: "Unauthorized",
122
+ headers: { "Content-Type": "application/json" },
123
+ })
124
+ )
125
+ .mockResolvedValueOnce(
126
+ new Response(JSON.stringify({ message: "Unauthorized" }), {
127
+ status: 401,
128
+ statusText: "Unauthorized",
129
+ headers: { "Content-Type": "application/json" },
130
+ })
131
+ )
118
132
  .mockResolvedValueOnce(
119
133
  new Response(JSON.stringify({ message: "Unauthorized" }), {
120
134
  status: 401,
@@ -137,7 +151,7 @@ describe("QuickbaseClient Unit - getFieldUsage", () => {
137
151
  })
138
152
  ).rejects.toThrow("API Error: Unauthorized (Status: 401)");
139
153
 
140
- expect(mockFetch).toHaveBeenCalledTimes(2); // Initial call + 1 retry
154
+ expect(mockFetch).toHaveBeenCalledTimes(4); // Initial + 3 retries
141
155
  expect(mockFetch).toHaveBeenNthCalledWith(
142
156
  1,
143
157
  `https://api.quickbase.com/v1/fields/usage/6?tableId=${QB_TABLE_ID_1}`,
@@ -151,7 +165,7 @@ describe("QuickbaseClient Unit - getFieldUsage", () => {
151
165
  })
152
166
  );
153
167
  expect(mockFetch).toHaveBeenNthCalledWith(
154
- 2,
168
+ 4,
155
169
  `https://api.quickbase.com/v1/fields/usage/6?tableId=${QB_TABLE_ID_1}`,
156
170
  expect.objectContaining({
157
171
  method: "GET",
@@ -1,4 +1,3 @@
1
- // tests/vitest/unit/fields/updateField.test.ts
2
1
  import { describe, it, expect, beforeEach } from "vitest";
3
2
  import {
4
3
  createClient,
@@ -53,7 +52,7 @@ describe("QuickbaseClient Unit - updateField", () => {
53
52
  comments: "Updated field settings",
54
53
  doesTotal: false,
55
54
  defaultValue: "Initial text",
56
- choices: ["Option1", "Option2"], // Still valid for properties
55
+ choices: ["Option1", "Option2"],
57
56
  },
58
57
  permissions: [
59
58
  { role: "Viewer", permissionType: "View", roleId: 10 },
@@ -65,7 +64,7 @@ describe("QuickbaseClient Unit - updateField", () => {
65
64
  const mockResponse: UpdateField200Response = {
66
65
  id: fieldId,
67
66
  label: "Field1",
68
- fieldType: "text", // Returned by API, not updated
67
+ fieldType: "text",
69
68
  mode: "",
70
69
  noWrap: false,
71
70
  bold: false,
@@ -120,10 +119,12 @@ describe("QuickbaseClient Unit - updateField", () => {
120
119
  Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
121
120
  "Content-Type": "application/json",
122
121
  }),
123
- body: JSON.stringify(request),
122
+ body: expect.any(String),
124
123
  credentials: "omit",
125
124
  })
126
125
  );
126
+ const [_, callOptions] = mockFetch.mock.calls[0];
127
+ expect(JSON.parse(callOptions.body)).toEqual(request);
127
128
  });
128
129
 
129
130
  it("updates field successfully with temp token", async () => {
@@ -153,7 +154,7 @@ describe("QuickbaseClient Unit - updateField", () => {
153
154
  const mockResponse: UpdateField200Response = {
154
155
  id: fieldId,
155
156
  label: "Field1",
156
- fieldType: "text-multiple-choice", // Returned by API, not updated
157
+ fieldType: "text-multiple-choice",
157
158
  mode: "",
158
159
  noWrap: false,
159
160
  bold: false,
@@ -226,10 +227,12 @@ describe("QuickbaseClient Unit - updateField", () => {
226
227
  Authorization: "QB-TEMP-TOKEN temp_token",
227
228
  "Content-Type": "application/json",
228
229
  }),
229
- body: JSON.stringify(request),
230
+ body: expect.any(String),
230
231
  credentials: "omit",
231
232
  })
232
233
  );
234
+ const [_, callOptions] = mockFetch.mock.calls[1];
235
+ expect(JSON.parse(callOptions.body)).toEqual(request);
233
236
  });
234
237
 
235
238
  it("handles 400 error for invalid field update", async () => {
@@ -272,9 +275,11 @@ describe("QuickbaseClient Unit - updateField", () => {
272
275
  Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
273
276
  "Content-Type": "application/json",
274
277
  }),
275
- body: JSON.stringify(request),
278
+ body: expect.any(String),
276
279
  credentials: "omit",
277
280
  })
278
281
  );
282
+ const [_, callOptions] = mockFetch.mock.calls[0];
283
+ expect(JSON.parse(callOptions.body)).toEqual(request);
279
284
  });
280
285
  });