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.
- package/CHANGELOG.md +29 -0
- package/README.md +46 -130
- package/dist/esm/quickbase.d.ts +822 -119
- package/dist/esm/quickbase.js +373 -236
- package/dist/esm/quickbase.js.map +1 -1
- package/dist/esm/quickbase.min.js +1 -1
- package/dist/esm/quickbase.min.js.map +1 -1
- package/dist/umd/quickbase.umd.js +373 -236
- package/dist/umd/quickbase.umd.js.map +1 -1
- package/dist/umd/quickbase.umd.min.js +1 -1
- package/dist/umd/quickbase.umd.min.js.map +1 -1
- package/open-api/generate-unified-interface.ts +97 -17
- package/open-api/utils/generateJsDoc.ts +96 -0
- package/package.json +3 -1
- package/src/ThrottleBucket.ts +17 -12
- package/src/authorizationStrategy.ts +246 -0
- package/src/generated-unified/QuickbaseClient.ts +809 -119
- package/src/invokeMethod.ts +150 -265
- package/src/quickbaseClient.ts +85 -58
- package/src/rateLimiter.ts +25 -0
- package/src/tokenCache.ts +10 -26
- package/tests/vitest/qb/auth/mockQuickbaseServer.ts +60 -0
- package/tests/vitest/qb/auth/retryUserToken401.test.ts +59 -42
- package/tests/vitest/qb/auth/ssoTokenIntegrationWithServer.test.ts +65 -0
- package/tests/vitest/qb/fields/getFieldUsage.test.ts +58 -150
- package/tests/vitest/qb/formulas/runFormula.test.ts +96 -0
- package/tests/vitest/qb/tables/createRelationship.test.ts +102 -0
- package/tests/vitest/qb/tables/deleteRelationship.test.ts +143 -0
- package/tests/vitest/qb/tables/updateRelationship.test.ts +118 -145
- package/tests/vitest/unit/ThrottleBucket.test.ts +95 -0
- package/tests/vitest/unit/apps/copyApp.test.ts +133 -40
- package/tests/vitest/unit/apps/updateApp.test.ts +42 -11
- package/tests/vitest/unit/auth/fetchTempToken401.test.ts +3 -2
- package/tests/vitest/unit/auth/getTempToken.test.ts +42 -18
- package/tests/vitest/unit/auth/retryTempToken401.test.ts +46 -64
- package/tests/vitest/unit/auth/retryTempTokenMaxRetries.test.ts +235 -0
- package/tests/vitest/unit/auth/retryUserToken401.test.ts +56 -43
- package/tests/vitest/unit/auth/ssoTokenRefresh.test.ts +325 -0
- package/tests/vitest/unit/fields/createField.test.ts +180 -116
- package/tests/vitest/unit/fields/getFieldUsage.test.ts +17 -3
- package/tests/vitest/unit/fields/updateField.test.ts +12 -7
- package/tests/vitest/unit/formulas/runFormula.test.ts +205 -0
- package/tests/vitest/unit/index.ts +2 -1
- package/tests/vitest/unit/inferHttpMethod.test.ts +131 -0
- package/tests/vitest/unit/rateLimit.test.ts +4 -2
- package/tests/vitest/unit/tables/createRelationship.test.ts +212 -0
- package/tests/vitest/unit/tables/deleteRelationship.test.ts +97 -0
- package/tests/vitest/unit/tables/updateRelationship.test.ts +12 -10
- package/tests/vitest/unit/tokenLifespan.test.ts +149 -83
- package/tools/log-gen.ts +14 -5
- package/tools/log-gen.yaml +710 -268
- 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
|
|
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
|
|
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: "
|
|
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
|
|
39
|
-
id:
|
|
40
|
-
label: "
|
|
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
|
-
|
|
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
|
-
|
|
67
|
-
|
|
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
|
-
|
|
77
|
+
{
|
|
91
78
|
method: "POST",
|
|
92
|
-
|
|
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
|
-
|
|
98
|
-
}
|
|
84
|
+
},
|
|
85
|
+
credentials: "omit",
|
|
86
|
+
}
|
|
99
87
|
);
|
|
100
88
|
});
|
|
101
89
|
|
|
102
|
-
it("creates
|
|
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
|
|
112
|
-
id:
|
|
99
|
+
const mockResponse = {
|
|
100
|
+
id: 102,
|
|
113
101
|
label: "TempField",
|
|
114
102
|
fieldType: "numeric",
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
157
|
+
{
|
|
179
158
|
method: "POST",
|
|
180
|
-
|
|
181
|
-
|
|
159
|
+
body: JSON.stringify(request),
|
|
160
|
+
headers: {
|
|
182
161
|
Authorization: "QB-TEMP-TOKEN temp_token",
|
|
183
162
|
"Content-Type": "application/json",
|
|
184
|
-
|
|
185
|
-
|
|
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
|
|
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
|
-
|
|
208
|
-
|
|
183
|
+
audited: false,
|
|
184
|
+
bold: false,
|
|
209
185
|
doesDataCopy: false,
|
|
210
186
|
fieldHelp: "",
|
|
211
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
269
|
-
|
|
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
|
-
|
|
283
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
309
|
+
{
|
|
319
310
|
method: "POST",
|
|
320
|
-
|
|
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
|
-
|
|
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: "
|
|
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:
|
|
381
|
+
).rejects.toThrow("API Error: Unauthorized again (Status: 401)");
|
|
360
382
|
|
|
361
|
-
expect(mockFetch).toHaveBeenCalledTimes(
|
|
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
|
|
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(
|
|
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
|
-
|
|
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"],
|
|
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",
|
|
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:
|
|
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",
|
|
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:
|
|
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:
|
|
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
|
});
|