quickbase-js 0.1.0-beta.10

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 (165) hide show
  1. package/CHANGELOG.md +211 -0
  2. package/LICENSE +21 -0
  3. package/README.md +179 -0
  4. package/api-examples.md +49 -0
  5. package/build-common.js +131 -0
  6. package/build-esm.js +71 -0
  7. package/build-umd.js +69 -0
  8. package/dist/esm/quickbase.d.ts +8081 -0
  9. package/dist/esm/quickbase.js +7928 -0
  10. package/dist/esm/quickbase.js.map +1 -0
  11. package/dist/esm/quickbase.min.js +2 -0
  12. package/dist/esm/quickbase.min.js.map +1 -0
  13. package/dist/umd/quickbase.umd.js +8504 -0
  14. package/dist/umd/quickbase.umd.js.map +1 -0
  15. package/dist/umd/quickbase.umd.min.js +2 -0
  16. package/dist/umd/quickbase.umd.min.js.map +1 -0
  17. package/docs/.vitepress/cache/deps/@theme_index.js +275 -0
  18. package/docs/.vitepress/cache/deps/@theme_index.js.map +7 -0
  19. package/docs/.vitepress/cache/deps/_metadata.json +40 -0
  20. package/docs/.vitepress/cache/deps/chunk-5A67QEFC.js +12542 -0
  21. package/docs/.vitepress/cache/deps/chunk-5A67QEFC.js.map +7 -0
  22. package/docs/.vitepress/cache/deps/chunk-7D4P4MMP.js +9719 -0
  23. package/docs/.vitepress/cache/deps/chunk-7D4P4MMP.js.map +7 -0
  24. package/docs/.vitepress/cache/deps/package.json +3 -0
  25. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4504 -0
  26. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  27. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +583 -0
  28. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  29. package/docs/.vitepress/cache/deps/vue.js +343 -0
  30. package/docs/.vitepress/cache/deps/vue.js.map +7 -0
  31. package/docs/.vitepress/config.mts +26 -0
  32. package/docs/api-examples.md +49 -0
  33. package/docs/index.md +59 -0
  34. package/docs/markdown-examples.md +85 -0
  35. package/docs-data/api-docs.json +4143 -0
  36. package/examples/quicbase-jsCDN.html +36 -0
  37. package/examples/react.js +48 -0
  38. package/examples/vanillajs.html +47 -0
  39. package/index.md +25 -0
  40. package/markdown-examples.md +85 -0
  41. package/open-api/fix-spec-main.ts +133 -0
  42. package/open-api/generate-unified-interface.ts +104 -0
  43. package/open-api/generateDocsJson.ts +24 -0
  44. package/open-api/output/quickbase-fixed.json +11191 -0
  45. package/open-api/post-process-generated.ts +226 -0
  46. package/open-api/regenerate-client.ts +117 -0
  47. package/open-api/schema/enhance-general.ts +111 -0
  48. package/open-api/schema/fix-arrays.ts +68 -0
  49. package/open-api/schema/tags/apps.ts +90 -0
  50. package/open-api/schema/tags/fields.ts +471 -0
  51. package/open-api/schema/tags/groups.ts +51 -0
  52. package/open-api/schema/tags/index.ts +66 -0
  53. package/open-api/schema/tags/records.ts +115 -0
  54. package/open-api/schema/tags/tables.ts +211 -0
  55. package/open-api/schema/tags/users.ts +47 -0
  56. package/open-api/types/spec.ts +42 -0
  57. package/open-api/utils/common.ts +29 -0
  58. package/open-api/utils/generateJsDoc.ts +74 -0
  59. package/open-api/utils/infer-schema.ts +40 -0
  60. package/open-api/utils/naming.ts +10 -0
  61. package/open-api/utils/sharedUtils.ts +352 -0
  62. package/package.json +96 -0
  63. package/playwright.config.ts +37 -0
  64. package/rollup.config.js +114 -0
  65. package/specs/QuickBase_RESTful_API_2025-03-04T06_22_39.725Z.json +46878 -0
  66. package/specs/split/apps.json +1315 -0
  67. package/specs/split/auth.json +191 -0
  68. package/specs/split/fields.json +3869 -0
  69. package/specs/split/records.json +754 -0
  70. package/specs/split/reports.json +619 -0
  71. package/specs/split/tables.json +1605 -0
  72. package/src/RateLimitError.ts +12 -0
  73. package/src/ThrottleBucket.ts +41 -0
  74. package/src/authorizationStrategy.ts +283 -0
  75. package/src/generated-unified/QuickbaseClient.ts +1135 -0
  76. package/src/generated-unified/missing-types-report.json +3 -0
  77. package/src/index.ts +1 -0
  78. package/src/invokeMethod.ts +245 -0
  79. package/src/quickbaseClient.ts +194 -0
  80. package/src/rateLimiter.ts +25 -0
  81. package/src/tokenCache.ts +35 -0
  82. package/src/utils.ts +50 -0
  83. package/tests/playwright/qb/auth/cacheSwitching.test.ts +159 -0
  84. package/tests/playwright/qb/auth/fetchTempToken401.test.ts +219 -0
  85. package/tests/playwright/qb/auth/getAppWithTempToken.test.ts +162 -0
  86. package/tests/playwright/qb/auth/getAppWithUserToken.test.ts +153 -0
  87. package/tests/playwright/qb/auth/getTempToken.test.ts +152 -0
  88. package/tests/playwright/qb/auth/tempTokenPrefetch.test.ts +179 -0
  89. package/tests/playwright/qb/auth/tempTokenRenewal.test.ts +133 -0
  90. package/tests/setup.ts +53 -0
  91. package/tests/vitest/qb/apps/copyApp.test.ts +76 -0
  92. package/tests/vitest/qb/apps/createApp.test.ts +64 -0
  93. package/tests/vitest/qb/apps/deleteApp.test.ts +76 -0
  94. package/tests/vitest/qb/apps/getApp.test.ts +44 -0
  95. package/tests/vitest/qb/apps/getAppEvents.test.ts +67 -0
  96. package/tests/vitest/qb/apps/updateApp.test.ts +58 -0
  97. package/tests/vitest/qb/auth/mockQuickbaseServer.ts +60 -0
  98. package/tests/vitest/qb/auth/retryUserToken401.test.ts +73 -0
  99. package/tests/vitest/qb/auth/ssoTokenIntegrationWithServer.test.ts +65 -0
  100. package/tests/vitest/qb/fields/createField.test.ts +77 -0
  101. package/tests/vitest/qb/fields/deleteFields.test.ts +83 -0
  102. package/tests/vitest/qb/fields/getField.test.ts +85 -0
  103. package/tests/vitest/qb/fields/getFieldUsage.test.ts +82 -0
  104. package/tests/vitest/qb/fields/getFields.test.ts +232 -0
  105. package/tests/vitest/qb/fields/getFieldsUsage.test.ts +77 -0
  106. package/tests/vitest/qb/fields/updateField.test.ts +93 -0
  107. package/tests/vitest/qb/formulas/runFormula.test.ts +96 -0
  108. package/tests/vitest/qb/index.ts +29 -0
  109. package/tests/vitest/qb/records/deleteRecords.test.ts +110 -0
  110. package/tests/vitest/qb/records/runQuery.test.ts +146 -0
  111. package/tests/vitest/qb/records/upsert.test.ts +102 -0
  112. package/tests/vitest/qb/tables/createRelationship.test.ts +102 -0
  113. package/tests/vitest/qb/tables/createTable.test.ts +55 -0
  114. package/tests/vitest/qb/tables/deleteRelationship.test.ts +143 -0
  115. package/tests/vitest/qb/tables/deleteTable.test.ts +50 -0
  116. package/tests/vitest/qb/tables/getAppTables.test.ts +46 -0
  117. package/tests/vitest/qb/tables/getRelationships.test.ts +80 -0
  118. package/tests/vitest/qb/tables/getTable.test.ts +26 -0
  119. package/tests/vitest/qb/tables/updateRelationship.test.ts +250 -0
  120. package/tests/vitest/qb/tables/updateTable.test.ts +48 -0
  121. package/tests/vitest/unit/ThrottleBucket.test.ts +95 -0
  122. package/tests/vitest/unit/apps/copyApp.test.ts +581 -0
  123. package/tests/vitest/unit/apps/createApp.test.ts +186 -0
  124. package/tests/vitest/unit/apps/deleteApp.test.ts +216 -0
  125. package/tests/vitest/unit/apps/getApp.test.ts +128 -0
  126. package/tests/vitest/unit/apps/getAppEvents.test.ts +193 -0
  127. package/tests/vitest/unit/apps/updateApp.test.ts +412 -0
  128. package/tests/vitest/unit/auth/fetchTempToken401.test.ts +63 -0
  129. package/tests/vitest/unit/auth/getTempToken.test.ts +119 -0
  130. package/tests/vitest/unit/auth/retryTempToken401.test.ts +95 -0
  131. package/tests/vitest/unit/auth/retryTempTokenMaxRetries.test.ts +206 -0
  132. package/tests/vitest/unit/auth/retryUserToken401.test.ts +69 -0
  133. package/tests/vitest/unit/auth/ssoTokenRefresh.test.ts +325 -0
  134. package/tests/vitest/unit/fields/createField.test.ts +451 -0
  135. package/tests/vitest/unit/fields/deleteFields.test.ts +141 -0
  136. package/tests/vitest/unit/fields/getField.test.ts +189 -0
  137. package/tests/vitest/unit/fields/getFieldUsage.test.ts +180 -0
  138. package/tests/vitest/unit/fields/getFields.test.ts +122 -0
  139. package/tests/vitest/unit/fields/getFieldsUsage.test.ts +160 -0
  140. package/tests/vitest/unit/fields/updateField.test.ts +285 -0
  141. package/tests/vitest/unit/formulas/runFormula.test.ts +205 -0
  142. package/tests/vitest/unit/index.ts +34 -0
  143. package/tests/vitest/unit/quickbaseClientHttpMethods.test.ts +139 -0
  144. package/tests/vitest/unit/rateLimit.test.ts +191 -0
  145. package/tests/vitest/unit/records/deleteRecords.test.ts +112 -0
  146. package/tests/vitest/unit/records/runQuery.test.ts +102 -0
  147. package/tests/vitest/unit/records/upsert.test.ts +234 -0
  148. package/tests/vitest/unit/tables/createRelationship.test.ts +212 -0
  149. package/tests/vitest/unit/tables/createTable.test.ts +70 -0
  150. package/tests/vitest/unit/tables/deleteRelationship.test.ts +97 -0
  151. package/tests/vitest/unit/tables/deleteTable.test.ts +77 -0
  152. package/tests/vitest/unit/tables/getAppTables.test.ts +85 -0
  153. package/tests/vitest/unit/tables/getRelationships.test.ts +259 -0
  154. package/tests/vitest/unit/tables/getTable.test.ts +233 -0
  155. package/tests/vitest/unit/tables/updateRelationship.test.ts +307 -0
  156. package/tests/vitest/unit/tables/updateTable.test.ts +80 -0
  157. package/tests/vitest/unit/tokenLifespan.test.ts +204 -0
  158. package/tests/vitest/unit/umd.test.ts +8 -0
  159. package/tools/log-gen.ts +251 -0
  160. package/tools/log-gen.yaml +4777 -0
  161. package/tools/openapi-jars/openapi-generator-cli-7.12.0.jar +0 -0
  162. package/tsconfig.build.json +17 -0
  163. package/tsconfig.json +32 -0
  164. package/versionrc.json +9 -0
  165. package/vitest.config.ts +27 -0
@@ -0,0 +1,189 @@
1
+ // tests/vitest/unit/fields/getField.test.ts
2
+ import { describe, it, expect, beforeEach } from "vitest";
3
+ import {
4
+ createClient,
5
+ mockFetch,
6
+ QB_REALM,
7
+ QB_USER_TOKEN,
8
+ QB_TABLE_ID_1,
9
+ } from "@tests/setup.ts";
10
+ import { Field } from "@/generated/models";
11
+
12
+ describe("QuickbaseClient Unit - getField", () => {
13
+ let client: ReturnType<typeof createClient>;
14
+
15
+ beforeEach(() => {
16
+ mockFetch.mockClear();
17
+ client = createClient(mockFetch, { debug: true });
18
+ });
19
+
20
+ it("initializes without errors and has getField method", () => {
21
+ expect(client).toBeDefined();
22
+ expect(typeof client.getField).toBe("function");
23
+ });
24
+
25
+ it("calls getField successfully with user token", async () => {
26
+ const mockResponse: Field = {
27
+ id: 123,
28
+ label: "Field1",
29
+ fieldType: "text",
30
+ mode: "",
31
+ noWrap: false,
32
+ bold: false,
33
+ required: false,
34
+ appearsByDefault: false,
35
+ findEnabled: false,
36
+ unique: false,
37
+ doesDataCopy: false,
38
+ fieldHelp: "field help",
39
+ audited: false,
40
+ properties: {
41
+ primaryKey: false,
42
+ foreignKey: false,
43
+ numLines: 1,
44
+ maxLength: 0,
45
+ appendOnly: false,
46
+ allowHTML: false,
47
+ allowMentions: false,
48
+ sortAsGiven: false,
49
+ carryChoices: true,
50
+ allowNewChoices: false,
51
+ formula: "",
52
+ defaultValue: "",
53
+ },
54
+ permissions: [
55
+ { permissionType: "View", role: "Viewer", roleId: 10 },
56
+ { permissionType: "None", role: "Participant", roleId: 11 },
57
+ { permissionType: "Modify", role: "Administrator", roleId: 12 },
58
+ ],
59
+ };
60
+
61
+ mockFetch.mockResolvedValueOnce({
62
+ ok: true,
63
+ status: 200,
64
+ json: () => Promise.resolve(mockResponse),
65
+ });
66
+
67
+ const result = await client.getField({
68
+ fieldId: 123,
69
+ tableId: QB_TABLE_ID_1,
70
+ includeFieldPerms: true,
71
+ });
72
+
73
+ expect(result).toEqual(mockResponse);
74
+ expect(mockFetch).toHaveBeenCalledWith(
75
+ `https://api.quickbase.com/v1/fields/123?tableId=${QB_TABLE_ID_1}&includeFieldPerms=true`,
76
+ expect.objectContaining({
77
+ method: "GET",
78
+ headers: expect.objectContaining({
79
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
80
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
81
+ "Content-Type": "application/json",
82
+ }),
83
+ })
84
+ );
85
+ });
86
+
87
+ it("calls getField successfully with temp token", async () => {
88
+ client = createClient(mockFetch, { useTempTokens: true, debug: true });
89
+
90
+ const mockResponse: Field = {
91
+ id: 123,
92
+ label: "Field1",
93
+ fieldType: "text",
94
+ mode: "",
95
+ noWrap: false,
96
+ bold: false,
97
+ required: false,
98
+ appearsByDefault: false,
99
+ findEnabled: false,
100
+ unique: false,
101
+ doesDataCopy: false,
102
+ fieldHelp: "field help",
103
+ audited: false,
104
+ properties: {
105
+ primaryKey: false,
106
+ foreignKey: false,
107
+ numLines: 1,
108
+ maxLength: 0,
109
+ appendOnly: false,
110
+ allowHTML: false,
111
+ allowMentions: false,
112
+ sortAsGiven: false,
113
+ carryChoices: true,
114
+ allowNewChoices: false,
115
+ formula: "",
116
+ defaultValue: "",
117
+ },
118
+ permissions: [],
119
+ };
120
+
121
+ mockFetch
122
+ .mockResolvedValueOnce({
123
+ ok: true,
124
+ status: 200,
125
+ json: () => Promise.resolve({ temporaryAuthorization: "temp_token" }),
126
+ })
127
+ .mockResolvedValueOnce({
128
+ ok: true,
129
+ status: 200,
130
+ json: () => Promise.resolve(mockResponse),
131
+ });
132
+
133
+ const result = await client.getField({
134
+ fieldId: 123,
135
+ tableId: QB_TABLE_ID_1,
136
+ });
137
+
138
+ expect(result).toEqual(mockResponse);
139
+ expect(mockFetch).toHaveBeenCalledTimes(2);
140
+ expect(mockFetch).toHaveBeenNthCalledWith(
141
+ 1,
142
+ `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
143
+ expect.objectContaining({
144
+ method: "GET",
145
+ headers: expect.objectContaining({
146
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
147
+ "Content-Type": "application/json",
148
+ }),
149
+ credentials: "include",
150
+ })
151
+ );
152
+ expect(mockFetch).toHaveBeenNthCalledWith(
153
+ 2,
154
+ `https://api.quickbase.com/v1/fields/123?tableId=${QB_TABLE_ID_1}`,
155
+ expect.objectContaining({
156
+ method: "GET",
157
+ headers: expect.objectContaining({
158
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
159
+ Authorization: "QB-TEMP-TOKEN temp_token",
160
+ "Content-Type": "application/json",
161
+ }),
162
+ })
163
+ );
164
+ });
165
+
166
+ it("handles 404 error for non-existent field", async () => {
167
+ mockFetch.mockResolvedValueOnce({
168
+ ok: false,
169
+ status: 404,
170
+ json: () => Promise.resolve({ message: "Field not found" }),
171
+ });
172
+
173
+ await expect(
174
+ client.getField({ fieldId: 999, tableId: QB_TABLE_ID_1 })
175
+ ).rejects.toThrow("API Error: Field not found (Status: 404)");
176
+
177
+ expect(mockFetch).toHaveBeenCalledWith(
178
+ `https://api.quickbase.com/v1/fields/999?tableId=${QB_TABLE_ID_1}`,
179
+ expect.objectContaining({
180
+ method: "GET",
181
+ headers: expect.objectContaining({
182
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
183
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
184
+ "Content-Type": "application/json",
185
+ }),
186
+ })
187
+ );
188
+ });
189
+ });
@@ -0,0 +1,180 @@
1
+ import { describe, it, expect, beforeEach } from "vitest";
2
+ import {
3
+ createClient,
4
+ mockFetch,
5
+ QB_REALM,
6
+ QB_USER_TOKEN,
7
+ QB_TABLE_ID_1,
8
+ } from "@tests/setup.ts";
9
+ import { FieldUsage } from "@/generated/models";
10
+
11
+ describe("QuickbaseClient Unit - getFieldUsage", () => {
12
+ let client: ReturnType<typeof createClient>;
13
+
14
+ beforeEach(() => {
15
+ mockFetch.mockClear();
16
+ client = createClient(mockFetch, { realm: QB_REALM, debug: true });
17
+ });
18
+
19
+ it("initializes without errors and has getFieldUsage method", () => {
20
+ expect(client).toBeDefined();
21
+ expect(typeof client.getFieldUsage).toBe("function");
22
+ });
23
+
24
+ it("calls getFieldUsage successfully with user token", async () => {
25
+ const mockResponse: FieldUsage = {
26
+ field: {
27
+ id: 6,
28
+ name: "name",
29
+ type: "text",
30
+ },
31
+ usage: {
32
+ actions: { count: 0 },
33
+ appHomePages: { count: 0 },
34
+ dashboards: { count: 2 },
35
+ defaultReports: { count: 1 },
36
+ exactForms: { count: 0 },
37
+ fields: { count: 0 },
38
+ forms: { count: 1 },
39
+ notifications: { count: 0 },
40
+ personalReports: { count: 0 },
41
+ pipelines: { count: 1 },
42
+ relationships: { count: 0 },
43
+ reminders: { count: 0 },
44
+ reports: { count: 2 },
45
+ roles: { count: 2 },
46
+ tableImports: { count: 2 },
47
+ tableRules: { count: 1 },
48
+ webhooks: { count: 0 },
49
+ },
50
+ };
51
+
52
+ mockFetch.mockResolvedValueOnce(
53
+ new Response(JSON.stringify([mockResponse]), {
54
+ status: 200,
55
+ statusText: "OK",
56
+ headers: { "Content-Type": "application/json" },
57
+ })
58
+ );
59
+
60
+ const result = await client.getFieldUsage({
61
+ fieldId: 6,
62
+ tableId: QB_TABLE_ID_1,
63
+ });
64
+
65
+ expect(result).toBeInstanceOf(Array);
66
+ expect(result).toHaveLength(1);
67
+ const fieldUsage = result[0];
68
+
69
+ expect(fieldUsage).toEqual(mockResponse);
70
+ expect(mockFetch).toHaveBeenCalledWith(
71
+ `https://api.quickbase.com/v1/fields/usage/6?tableId=${QB_TABLE_ID_1}`,
72
+ expect.objectContaining({
73
+ method: "GET",
74
+ headers: expect.objectContaining({
75
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
76
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
77
+ "Content-Type": "application/json",
78
+ }),
79
+ })
80
+ );
81
+ expect(fieldUsage.field.id).toBe(6);
82
+ expect(fieldUsage.field.name).toBe("name");
83
+ expect(fieldUsage.usage.dashboards.count).toBe(2);
84
+ });
85
+
86
+ it("handles 404 error for non-existent field", async () => {
87
+ mockFetch.mockResolvedValueOnce(
88
+ new Response(JSON.stringify({ message: "Field not found" }), {
89
+ status: 404,
90
+ statusText: "Not Found",
91
+ headers: { "Content-Type": "application/json" },
92
+ })
93
+ );
94
+
95
+ await expect(
96
+ client.getFieldUsage({
97
+ fieldId: 999,
98
+ tableId: QB_TABLE_ID_1,
99
+ })
100
+ ).rejects.toThrow("API Error: Field not found (Status: 404)");
101
+
102
+ expect(mockFetch).toHaveBeenCalledWith(
103
+ `https://api.quickbase.com/v1/fields/usage/999?tableId=${QB_TABLE_ID_1}`,
104
+ expect.objectContaining({
105
+ method: "GET",
106
+ headers: expect.objectContaining({
107
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
108
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
109
+ "Content-Type": "application/json",
110
+ }),
111
+ })
112
+ );
113
+ });
114
+
115
+ it("handles persistent 401 error for field usage retrieval", async () => {
116
+ // Simulate persistent 401 errors to exhaust retries
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
+ )
132
+ .mockResolvedValueOnce(
133
+ new Response(JSON.stringify({ message: "Unauthorized" }), {
134
+ status: 401,
135
+ statusText: "Unauthorized",
136
+ headers: { "Content-Type": "application/json" },
137
+ })
138
+ )
139
+ .mockResolvedValueOnce(
140
+ new Response(JSON.stringify({ message: "Unauthorized" }), {
141
+ status: 401,
142
+ statusText: "Unauthorized",
143
+ headers: { "Content-Type": "application/json" },
144
+ })
145
+ );
146
+
147
+ await expect(
148
+ client.getFieldUsage({
149
+ fieldId: 6,
150
+ tableId: QB_TABLE_ID_1,
151
+ })
152
+ ).rejects.toThrow("API Error: Unauthorized (Status: 401)");
153
+
154
+ expect(mockFetch).toHaveBeenCalledTimes(4); // Initial + 3 retries
155
+ expect(mockFetch).toHaveBeenNthCalledWith(
156
+ 1,
157
+ `https://api.quickbase.com/v1/fields/usage/6?tableId=${QB_TABLE_ID_1}`,
158
+ expect.objectContaining({
159
+ method: "GET",
160
+ headers: expect.objectContaining({
161
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
162
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
163
+ "Content-Type": "application/json",
164
+ }),
165
+ })
166
+ );
167
+ expect(mockFetch).toHaveBeenNthCalledWith(
168
+ 4,
169
+ `https://api.quickbase.com/v1/fields/usage/6?tableId=${QB_TABLE_ID_1}`,
170
+ expect.objectContaining({
171
+ method: "GET",
172
+ headers: expect.objectContaining({
173
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
174
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
175
+ "Content-Type": "application/json",
176
+ }),
177
+ })
178
+ );
179
+ });
180
+ });
@@ -0,0 +1,122 @@
1
+ // tests/vitest/unit/fields/getFields.test.ts
2
+ import { describe, it, expect } from "vitest";
3
+ import {
4
+ createClient,
5
+ mockFetch,
6
+ QB_REALM,
7
+ QB_USER_TOKEN,
8
+ QB_TABLE_ID_1,
9
+ } from "@tests/setup.ts";
10
+
11
+ describe("QuickbaseClient Unit - getFields", () => {
12
+ it("calls getFields successfully", async () => {
13
+ mockFetch.mockImplementation((url: string, options: any) => {
14
+ console.log("Mock fetch for getFields:", url, options);
15
+ return Promise.resolve({
16
+ ok: true,
17
+ status: 200,
18
+ json: () =>
19
+ Promise.resolve([
20
+ {
21
+ id: 1,
22
+ label: "Field1",
23
+ fieldType: "text",
24
+ noWrap: false,
25
+ bold: false,
26
+ required: false,
27
+ appearsByDefault: false,
28
+ findEnabled: false,
29
+ unique: false,
30
+ doesDataCopy: false,
31
+ fieldHelp: "field help",
32
+ audited: false,
33
+ properties: {
34
+ primaryKey: false,
35
+ foreignKey: false,
36
+ numLines: 1,
37
+ maxLength: 0,
38
+ appendOnly: false,
39
+ allowHTML: false,
40
+ allowMentions: false,
41
+ sortAsGiven: false,
42
+ carryChoices: true,
43
+ allowNewChoices: false,
44
+ formula: "",
45
+ defaultValue: "",
46
+ },
47
+ permissions: [
48
+ { permissionType: "View", role: "Viewer", roleId: 10 },
49
+ { permissionType: "None", role: "Participant", roleId: 11 },
50
+ { permissionType: "Modify", role: "Administrator", roleId: 12 },
51
+ ],
52
+ },
53
+ ]),
54
+ } as Response);
55
+ });
56
+
57
+ const client = createClient(mockFetch, { debug: true }); // Add debug: true for consistency
58
+ const result = await client.getFields({
59
+ tableId: QB_TABLE_ID_1,
60
+ includeFieldPerms: true,
61
+ });
62
+ console.log("getFields response:", result);
63
+ expect(result).toEqual(
64
+ expect.arrayContaining([
65
+ expect.objectContaining({
66
+ id: 1,
67
+ label: "Field1",
68
+ fieldType: "text",
69
+ noWrap: false,
70
+ bold: false,
71
+ required: false,
72
+ appearsByDefault: false,
73
+ findEnabled: false,
74
+ unique: false,
75
+ doesDataCopy: false,
76
+ fieldHelp: "field help",
77
+ audited: false,
78
+ properties: expect.objectContaining({
79
+ primaryKey: false,
80
+ foreignKey: false,
81
+ numLines: 1,
82
+ maxLength: 0,
83
+ appendOnly: false,
84
+ allowHTML: false,
85
+ allowMentions: false,
86
+ sortAsGiven: false,
87
+ carryChoices: true,
88
+ allowNewChoices: false,
89
+ formula: "",
90
+ defaultValue: "",
91
+ }),
92
+ permissions: expect.arrayContaining([
93
+ expect.objectContaining({
94
+ permissionType: "View",
95
+ role: "Viewer",
96
+ roleId: 10,
97
+ }),
98
+ expect.objectContaining({
99
+ permissionType: "None",
100
+ role: "Participant",
101
+ roleId: 11,
102
+ }),
103
+ expect.objectContaining({
104
+ permissionType: "Modify",
105
+ role: "Administrator",
106
+ roleId: 12,
107
+ }),
108
+ ]),
109
+ }),
110
+ ])
111
+ );
112
+ expect(mockFetch).toHaveBeenCalledWith(
113
+ `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}&includeFieldPerms=true`,
114
+ expect.objectContaining({
115
+ headers: expect.objectContaining({
116
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
117
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
118
+ }),
119
+ })
120
+ );
121
+ });
122
+ });
@@ -0,0 +1,160 @@
1
+ // tests/vitest/unit/fields/getFieldsUsage.test.ts
2
+ import { describe, it, expect, beforeEach } from "vitest";
3
+ import {
4
+ createClient,
5
+ mockFetch,
6
+ QB_REALM,
7
+ QB_TABLE_ID_1,
8
+ QB_USER_TOKEN,
9
+ } from "@tests/setup.ts";
10
+ import { FieldUsage } from "@/generated/models";
11
+
12
+ describe("QuickbaseClient Unit - getFieldsUsage", () => {
13
+ let client: ReturnType<typeof createClient>;
14
+
15
+ beforeEach(() => {
16
+ mockFetch.mockClear();
17
+ client = createClient(mockFetch, { debug: true });
18
+ });
19
+
20
+ it("initializes without errors and has getFieldsUsage method", () => {
21
+ expect(client).toBeDefined();
22
+ expect(typeof client.getFieldsUsage).toBe("function");
23
+ });
24
+
25
+ it("calls getFieldsUsage successfully with user token", async () => {
26
+ const mockResponse: FieldUsage[] = [
27
+ {
28
+ field: {
29
+ id: 6,
30
+ name: "name",
31
+ type: "Text",
32
+ },
33
+ usage: {
34
+ actions: { count: 0 },
35
+ appHomePages: { count: 0 },
36
+ dashboards: { count: 2 },
37
+ defaultReports: { count: 1 },
38
+ exactForms: { count: 0 },
39
+ fields: { count: 0 },
40
+ forms: { count: 1 },
41
+ notifications: { count: 0 },
42
+ personalReports: { count: 0 },
43
+ pipelines: { count: 1 },
44
+ relationships: { count: 0 },
45
+ reminders: { count: 0 },
46
+ reports: { count: 2 },
47
+ roles: { count: 2 },
48
+ tableImports: { count: 3 },
49
+ tableRules: { count: 1 },
50
+ webhooks: { count: 0 },
51
+ },
52
+ },
53
+ ];
54
+
55
+ mockFetch.mockResolvedValueOnce({
56
+ ok: true,
57
+ status: 200,
58
+ json: () => Promise.resolve(mockResponse),
59
+ });
60
+
61
+ const result = await client.getFieldsUsage({
62
+ tableId: QB_TABLE_ID_1,
63
+ });
64
+
65
+ expect(result).toEqual(mockResponse);
66
+ expect(mockFetch).toHaveBeenCalledWith(
67
+ `https://api.quickbase.com/v1/fields/usage?tableId=${QB_TABLE_ID_1}`,
68
+ expect.objectContaining({
69
+ method: "GET",
70
+ headers: expect.objectContaining({
71
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
72
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
73
+ "Content-Type": "application/json",
74
+ }),
75
+ })
76
+ );
77
+ });
78
+
79
+ it("calls getFieldsUsage with skip and top parameters", async () => {
80
+ const mockResponse: FieldUsage[] = [
81
+ {
82
+ field: {
83
+ id: 7,
84
+ name: "priority",
85
+ type: "Text",
86
+ },
87
+ usage: {
88
+ actions: { count: 1 },
89
+ appHomePages: { count: 0 },
90
+ dashboards: { count: 0 },
91
+ defaultReports: { count: 0 },
92
+ exactForms: { count: 0 },
93
+ fields: { count: 1 },
94
+ forms: { count: 0 },
95
+ notifications: { count: 0 },
96
+ personalReports: { count: 0 },
97
+ pipelines: { count: 0 },
98
+ relationships: { count: 0 },
99
+ reminders: { count: 0 },
100
+ reports: { count: 1 },
101
+ roles: { count: 1 },
102
+ tableImports: { count: 0 },
103
+ tableRules: { count: 0 },
104
+ webhooks: { count: 0 },
105
+ },
106
+ },
107
+ ];
108
+
109
+ mockFetch.mockResolvedValueOnce({
110
+ ok: true,
111
+ status: 200,
112
+ json: () => Promise.resolve(mockResponse),
113
+ });
114
+
115
+ const result = await client.getFieldsUsage({
116
+ tableId: QB_TABLE_ID_1,
117
+ skip: 1,
118
+ top: 1,
119
+ });
120
+
121
+ expect(result).toEqual(mockResponse);
122
+ expect(mockFetch).toHaveBeenCalledWith(
123
+ `https://api.quickbase.com/v1/fields/usage?tableId=${QB_TABLE_ID_1}&skip=1&top=1`,
124
+ expect.objectContaining({
125
+ method: "GET",
126
+ headers: expect.objectContaining({
127
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
128
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
129
+ "Content-Type": "application/json",
130
+ }),
131
+ })
132
+ );
133
+ });
134
+
135
+ it("handles 404 error for non-existent table", async () => {
136
+ const nonExistentTableId = "nonexistent_dbid";
137
+
138
+ mockFetch.mockResolvedValueOnce({
139
+ ok: false,
140
+ status: 404,
141
+ json: () => Promise.resolve({ message: "Table not found" }),
142
+ });
143
+
144
+ await expect(
145
+ client.getFieldsUsage({ tableId: nonExistentTableId })
146
+ ).rejects.toThrow("API Error: Table not found (Status: 404)");
147
+
148
+ expect(mockFetch).toHaveBeenCalledWith(
149
+ `https://api.quickbase.com/v1/fields/usage?tableId=${nonExistentTableId}`,
150
+ expect.objectContaining({
151
+ method: "GET",
152
+ headers: expect.objectContaining({
153
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
154
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
155
+ "Content-Type": "application/json",
156
+ }),
157
+ })
158
+ );
159
+ });
160
+ });