quickbase-js 1.1.0-beta.0 → 1.1.0-beta.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.
@@ -1,11 +1,19 @@
1
+ // tests/vitest/unit/apps/getApp.test.ts
1
2
  import { describe, it, expect, beforeEach } from "vitest";
2
- import { createClient, mockFetch } from "@tests/setup.ts";
3
+ import {
4
+ createClient,
5
+ mockFetch,
6
+ QB_APP_ID,
7
+ QB_REALM,
8
+ QB_USER_TOKEN,
9
+ } from "@tests/setup.ts";
3
10
 
4
- describe("QuickbaseClient - getApp (Unit)", () => {
5
- const client = createClient(mockFetch);
11
+ describe("QuickbaseClient Unit - getApp", () => {
12
+ let client: ReturnType<typeof createClient>;
6
13
 
7
14
  beforeEach(() => {
8
15
  mockFetch.mockClear();
16
+ client = createClient(mockFetch, { debug: true }); // Add debug: true for consistency
9
17
  });
10
18
 
11
19
  it("initializes without errors", () => {
@@ -24,7 +32,7 @@ describe("QuickbaseClient - getApp (Unit)", () => {
24
32
  status: 200,
25
33
  json: () =>
26
34
  Promise.resolve({
27
- id: process.env.QB_APP_ID,
35
+ id: QB_APP_ID,
28
36
  name: "qb-copy",
29
37
  created: "2025-02-13T18:22:33Z",
30
38
  updated: "2025-03-04T04:25:51Z",
@@ -45,12 +53,9 @@ describe("QuickbaseClient - getApp (Unit)", () => {
45
53
  } as Response);
46
54
  });
47
55
 
48
- const getAppId = process.env.QB_APP_ID;
49
- if (!getAppId) throw new Error("QB_APP_ID is not defined in .env");
50
- console.log("Test appId:", getAppId);
51
- const result = await client.getApp({ appId: getAppId });
56
+ const result = await client.getApp({ appId: QB_APP_ID });
52
57
  expect(result).toEqual({
53
- id: getAppId,
58
+ id: QB_APP_ID,
54
59
  name: "qb-copy",
55
60
  created: new Date("2025-02-13T18:22:33Z"),
56
61
  updated: new Date("2025-03-04T04:25:51Z"),
@@ -69,11 +74,11 @@ describe("QuickbaseClient - getApp (Unit)", () => {
69
74
  },
70
75
  });
71
76
  expect(mockFetch).toHaveBeenCalledWith(
72
- `https://api.quickbase.com/v1/apps/${getAppId}`,
77
+ `https://api.quickbase.com/v1/apps/${QB_APP_ID}`,
73
78
  expect.objectContaining({
74
79
  headers: expect.objectContaining({
75
- Authorization: `QB-USER-TOKEN ${process.env.QB_USER_TOKEN}`,
76
- "QB-Realm-Hostname": `${process.env.QB_REALM}.quickbase.com`,
80
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
81
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
77
82
  }),
78
83
  })
79
84
  );
@@ -1,7 +1,13 @@
1
+ // tests/vitest/unit/auth/fetchTempToken401.test.ts
1
2
  import { describe, it, expect, beforeEach, vi } from "vitest";
2
- import { createClient, mockFetch } from "@tests/setup.ts";
3
+ import {
4
+ createClient,
5
+ mockFetch,
6
+ QB_REALM,
7
+ QB_TABLE_ID_1,
8
+ } from "@tests/setup.ts";
3
9
 
4
- describe("QuickbaseClient - 401 with fetchTempToken 401", () => {
10
+ describe("QuickbaseClient Unit - 401 with fetchTempToken 401", () => {
5
11
  let client: ReturnType<typeof createClient>;
6
12
 
7
13
  beforeEach(() => {
@@ -10,7 +16,6 @@ describe("QuickbaseClient - 401 with fetchTempToken 401", () => {
10
16
  });
11
17
 
12
18
  it("fails without infinite loop when fetchTempToken returns 401 after initial 401", async () => {
13
- const mockDbid = "mockDbid123";
14
19
  let callCount = 0;
15
20
 
16
21
  mockFetch.mockImplementation((url) => {
@@ -43,11 +48,31 @@ describe("QuickbaseClient - 401 with fetchTempToken 401", () => {
43
48
  });
44
49
 
45
50
  const consoleSpy = vi.spyOn(console, "log");
46
- await expect(client.getFields({ tableId: mockDbid })).rejects.toThrow(
51
+ await expect(client.getFields({ tableId: QB_TABLE_ID_1 })).rejects.toThrow(
47
52
  "API Error: Unauthorized in fetchTempToken (Status: 401)"
48
53
  );
49
54
 
50
55
  expect(mockFetch).toHaveBeenCalledTimes(3);
56
+ expect(mockFetch).toHaveBeenNthCalledWith(
57
+ 1,
58
+ `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
59
+ expect.any(Object)
60
+ );
61
+ expect(mockFetch).toHaveBeenNthCalledWith(
62
+ 2,
63
+ `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`, // Removed &includeFieldPerms=false
64
+ expect.objectContaining({
65
+ headers: expect.objectContaining({
66
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
67
+ }),
68
+ })
69
+ );
70
+ expect(mockFetch).toHaveBeenNthCalledWith(
71
+ 3,
72
+ `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
73
+ expect.any(Object)
74
+ );
75
+
51
76
  expect(consoleSpy).toHaveBeenCalledWith(
52
77
  "Authorization error for getFields, refreshing token:",
53
78
  expect.any(String)
@@ -1,7 +1,13 @@
1
+ // tests/vitest/unit/auth/getTempTokenDBID.test.ts
1
2
  import { describe, it, expect, beforeEach } from "vitest";
2
- import { createClient, mockFetch } from "@tests/setup.ts";
3
+ import {
4
+ createClient,
5
+ mockFetch,
6
+ QB_REALM,
7
+ QB_TABLE_ID_1,
8
+ } from "@tests/setup.ts";
3
9
 
4
- describe("QuickbaseClient - getTempTokenDBID (Unit)", () => {
10
+ describe("QuickbaseClient Unit - getTempTokenDBID", () => {
5
11
  let client: ReturnType<typeof createClient>;
6
12
 
7
13
  beforeEach(() => {
@@ -18,7 +24,6 @@ describe("QuickbaseClient - getTempTokenDBID (Unit)", () => {
18
24
  });
19
25
 
20
26
  it("fetches and caches temp token on first call", async () => {
21
- const mockDbid = "mockDbid123";
22
27
  const mockToken = "b123xyz_temp_token";
23
28
 
24
29
  mockFetch.mockResolvedValueOnce({
@@ -27,14 +32,14 @@ describe("QuickbaseClient - getTempTokenDBID (Unit)", () => {
27
32
  json: () => Promise.resolve({ temporaryAuthorization: mockToken }),
28
33
  });
29
34
 
30
- const result = await client.getTempTokenDBID({ dbid: mockDbid });
35
+ const result = await client.getTempTokenDBID({ dbid: QB_TABLE_ID_1 });
31
36
  expect(result).toEqual({ temporaryAuthorization: mockToken });
32
37
  expect(mockFetch).toHaveBeenCalledWith(
33
- `https://api.quickbase.com/v1/auth/temporary/${mockDbid}`,
38
+ `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
34
39
  expect.objectContaining({
35
40
  method: "GET",
36
41
  headers: expect.objectContaining({
37
- "QB-Realm-Hostname": `${process.env.QB_REALM}.quickbase.com`,
42
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
38
43
  "Content-Type": "application/json",
39
44
  }),
40
45
  credentials: "include",
@@ -43,7 +48,6 @@ describe("QuickbaseClient - getTempTokenDBID (Unit)", () => {
43
48
  });
44
49
 
45
50
  it("reuses cached temp token on second call", async () => {
46
- const mockDbid = "mockDbid123";
47
51
  const mockToken = "b123xyz_temp_token";
48
52
 
49
53
  mockFetch.mockResolvedValueOnce({
@@ -52,31 +56,40 @@ describe("QuickbaseClient - getTempTokenDBID (Unit)", () => {
52
56
  json: () => Promise.resolve({ temporaryAuthorization: mockToken }),
53
57
  });
54
58
 
55
- const firstResult = await client.getTempTokenDBID({ dbid: mockDbid });
59
+ const firstResult = await client.getTempTokenDBID({ dbid: QB_TABLE_ID_1 });
56
60
  expect(firstResult).toEqual({ temporaryAuthorization: mockToken });
57
61
  expect(mockFetch).toHaveBeenCalledTimes(1);
58
62
 
59
63
  mockFetch.mockClear();
60
- const secondResult = await client.getTempTokenDBID({ dbid: mockDbid });
64
+ const secondResult = await client.getTempTokenDBID({ dbid: QB_TABLE_ID_1 });
61
65
  expect(secondResult).toEqual({ temporaryAuthorization: mockToken });
62
66
  expect(mockFetch).not.toHaveBeenCalled();
63
67
  });
64
68
 
65
69
  it("handles API error", async () => {
66
- const mockDbid = "mockDbid123";
67
-
68
70
  mockFetch.mockResolvedValueOnce({
69
71
  ok: false,
70
72
  status: 401,
71
73
  json: () => Promise.resolve({ message: "Unauthorized" }),
72
74
  });
73
75
 
74
- await expect(client.getTempTokenDBID({ dbid: mockDbid })).rejects.toSatisfy(
75
- (error: Error) => {
76
- expect(error).toBeInstanceOf(Error);
77
- expect(error.message).toBe("API Error: Unauthorized (Status: 401)");
78
- return true;
79
- }
76
+ await expect(
77
+ client.getTempTokenDBID({ dbid: QB_TABLE_ID_1 })
78
+ ).rejects.toSatisfy((error: Error) => {
79
+ expect(error).toBeInstanceOf(Error);
80
+ expect(error.message).toBe("API Error: Unauthorized (Status: 401)");
81
+ return true;
82
+ });
83
+ expect(mockFetch).toHaveBeenCalledWith(
84
+ `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
85
+ expect.objectContaining({
86
+ method: "GET",
87
+ headers: expect.objectContaining({
88
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
89
+ "Content-Type": "application/json",
90
+ }),
91
+ credentials: "include",
92
+ })
80
93
  );
81
94
  });
82
95
  });
@@ -1,7 +1,13 @@
1
+ // tests/vitest/unit/auth/retryOn401.test.ts
1
2
  import { describe, it, expect, beforeEach, vi } from "vitest";
2
- import { createClient, mockFetch } from "@tests/setup.ts";
3
+ import {
4
+ createClient,
5
+ mockFetch,
6
+ QB_REALM,
7
+ QB_TABLE_ID_1,
8
+ } from "@tests/setup.ts";
3
9
 
4
- describe("QuickbaseClient - 401 Retry Creates New Token", () => {
10
+ describe("QuickbaseClient Unit - 401 Retry Creates New Token", () => {
5
11
  let client: ReturnType<typeof createClient>;
6
12
 
7
13
  beforeEach(() => {
@@ -10,7 +16,6 @@ describe("QuickbaseClient - 401 Retry Creates New Token", () => {
10
16
  });
11
17
 
12
18
  it("creates a new token on 401 and retries successfully", async () => {
13
- const mockDbid = "mockDbid123";
14
19
  const mockToken = "new_token_456";
15
20
  const mockFields = [{ id: 1, label: "Field1" }];
16
21
  let callCount = 0;
@@ -51,16 +56,45 @@ describe("QuickbaseClient - 401 Retry Creates New Token", () => {
51
56
  });
52
57
 
53
58
  const consoleSpy = vi.spyOn(console, "log");
54
- const result = await client.getFields({ tableId: mockDbid });
59
+ const result = await client.getFields({ tableId: QB_TABLE_ID_1 });
55
60
 
56
61
  expect(result).toEqual(mockFields);
57
62
  expect(mockFetch).toHaveBeenCalledTimes(4);
63
+ expect(mockFetch).toHaveBeenNthCalledWith(
64
+ 1,
65
+ `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
66
+ expect.any(Object)
67
+ );
68
+ expect(mockFetch).toHaveBeenNthCalledWith(
69
+ 2,
70
+ `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`, // Removed &includeFieldPerms=false
71
+ expect.objectContaining({
72
+ headers: expect.objectContaining({
73
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
74
+ }),
75
+ })
76
+ );
77
+ expect(mockFetch).toHaveBeenNthCalledWith(
78
+ 3,
79
+ `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
80
+ expect.any(Object)
81
+ );
82
+ expect(mockFetch).toHaveBeenNthCalledWith(
83
+ 4,
84
+ `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}`, // Removed &includeFieldPerms=false
85
+ expect.objectContaining({
86
+ headers: expect.objectContaining({
87
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
88
+ }),
89
+ })
90
+ );
91
+
58
92
  expect(consoleSpy).toHaveBeenCalledWith(
59
93
  "Authorization error for getFields, refreshing token:",
60
94
  expect.any(String)
61
95
  );
62
96
  expect(consoleSpy).toHaveBeenCalledWith(
63
- "Fetched and cached new token for dbid: mockDbid123",
97
+ `Fetched and cached new token for dbid: ${QB_TABLE_ID_1}`,
64
98
  mockToken + "_retry",
65
99
  expect.any(String)
66
100
  );
@@ -1,7 +1,14 @@
1
+ // tests/vitest/unit/fields/getFields.test.ts
1
2
  import { describe, it, expect } from "vitest";
2
- import { createClient, mockFetch } from "@tests/setup.ts";
3
+ import {
4
+ createClient,
5
+ mockFetch,
6
+ QB_REALM,
7
+ QB_USER_TOKEN,
8
+ QB_TABLE_ID_1,
9
+ } from "@tests/setup.ts";
3
10
 
4
- describe("QuickbaseClient - getFields (Unit)", () => {
11
+ describe("QuickbaseClient Unit - getFields", () => {
5
12
  it("calls getFields successfully", async () => {
6
13
  mockFetch.mockImplementation((url: string, options: any) => {
7
14
  console.log("Mock fetch for getFields:", url, options);
@@ -47,9 +54,9 @@ describe("QuickbaseClient - getFields (Unit)", () => {
47
54
  } as Response);
48
55
  });
49
56
 
50
- const client = createClient(mockFetch);
57
+ const client = createClient(mockFetch, { debug: true }); // Add debug: true for consistency
51
58
  const result = await client.getFields({
52
- tableId: "dummyTableId",
59
+ tableId: QB_TABLE_ID_1,
53
60
  includeFieldPerms: true,
54
61
  });
55
62
  console.log("getFields response:", result);
@@ -103,11 +110,11 @@ describe("QuickbaseClient - getFields (Unit)", () => {
103
110
  ])
104
111
  );
105
112
  expect(mockFetch).toHaveBeenCalledWith(
106
- `https://api.quickbase.com/v1/fields?tableId=dummyTableId&includeFieldPerms=true`,
113
+ `https://api.quickbase.com/v1/fields?tableId=${QB_TABLE_ID_1}&includeFieldPerms=true`,
107
114
  expect.objectContaining({
108
115
  headers: expect.objectContaining({
109
- Authorization: `QB-USER-TOKEN ${process.env.QB_USER_TOKEN}`,
110
- "QB-Realm-Hostname": `${process.env.QB_REALM}.quickbase.com`,
116
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
117
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
111
118
  }),
112
119
  })
113
120
  );
@@ -1,18 +1,22 @@
1
1
  // tests/vitest/unit/records/deleteRecords.test.ts
2
- import { describe, expect, test, beforeEach } from "vitest"; // Added 'describe'
3
- import { createClient, mockFetch } from "@tests/setup.ts";
2
+ import { describe, expect, test, 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
+
11
+ describe("QuickbaseClient Unit - deleteRecords", () => {
12
+ let qb: ReturnType<typeof createClient>;
4
13
 
5
- describe("QuickbaseClient - deleteRecords (Unit)", () => {
6
14
  beforeEach(() => {
7
- mockFetch.mockClear(); // Clear mock state between tests
15
+ mockFetch.mockClear();
16
+ qb = createClient(mockFetch, { debug: true }); // Use debug: true for consistency with other tests
8
17
  });
9
18
 
10
- test("deleteRecords - sends correct DELETE request and handles success", async () => {
11
- const qb = createClient(mockFetch, {
12
- realm: "test-realm",
13
- userToken: "test-token",
14
- });
15
-
19
+ test("sends correct DELETE request and handles success", async () => {
16
20
  mockFetch.mockResolvedValueOnce({
17
21
  ok: true,
18
22
  status: 200,
@@ -21,7 +25,7 @@ describe("QuickbaseClient - deleteRecords (Unit)", () => {
21
25
 
22
26
  const result = await qb.deleteRecords({
23
27
  body: {
24
- from: "test-table-id",
28
+ from: QB_TABLE_ID_1,
25
29
  where: "{3.EX.'5'}", // Simulate deleting Record ID 5
26
30
  },
27
31
  });
@@ -31,22 +35,17 @@ describe("QuickbaseClient - deleteRecords (Unit)", () => {
31
35
  expect.objectContaining({
32
36
  method: "DELETE",
33
37
  headers: expect.objectContaining({
34
- "QB-Realm-Hostname": "test-realm.quickbase.com",
35
- Authorization: "QB-USER-TOKEN test-token",
38
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
39
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
36
40
  "Content-Type": "application/json",
37
41
  }),
38
- body: JSON.stringify({ from: "test-table-id", where: "{3.EX.'5'}" }),
42
+ body: JSON.stringify({ from: QB_TABLE_ID_1, where: "{3.EX.'5'}" }),
39
43
  })
40
44
  );
41
45
  expect(result).toEqual({ numberDeleted: 1 });
42
46
  });
43
47
 
44
- test("deleteRecords - handles no records deleted", async () => {
45
- const qb = createClient(mockFetch, {
46
- realm: "test-realm",
47
- userToken: "test-token",
48
- });
49
-
48
+ test("handles no records deleted", async () => {
50
49
  mockFetch.mockResolvedValueOnce({
51
50
  ok: true,
52
51
  status: 200,
@@ -55,7 +54,7 @@ describe("QuickbaseClient - deleteRecords (Unit)", () => {
55
54
 
56
55
  const result = await qb.deleteRecords({
57
56
  body: {
58
- from: "test-table-id",
57
+ from: QB_TABLE_ID_1,
59
58
  where: "{3.EX.'999999'}", // Non-existent Record ID
60
59
  },
61
60
  });
@@ -65,12 +64,12 @@ describe("QuickbaseClient - deleteRecords (Unit)", () => {
65
64
  expect.objectContaining({
66
65
  method: "DELETE",
67
66
  headers: expect.objectContaining({
68
- "QB-Realm-Hostname": "test-realm.quickbase.com",
69
- Authorization: "QB-USER-TOKEN test-token",
67
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
68
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
70
69
  "Content-Type": "application/json",
71
70
  }),
72
71
  body: JSON.stringify({
73
- from: "test-table-id",
72
+ from: QB_TABLE_ID_1,
74
73
  where: "{3.EX.'999999'}",
75
74
  }),
76
75
  })
@@ -78,12 +77,7 @@ describe("QuickbaseClient - deleteRecords (Unit)", () => {
78
77
  expect(result).toEqual({ numberDeleted: 0 });
79
78
  });
80
79
 
81
- test("deleteRecords - throws error on API failure", async () => {
82
- const qb = createClient(mockFetch, {
83
- realm: "test-realm",
84
- userToken: "test-token",
85
- });
86
-
80
+ test("throws error on API failure", async () => {
87
81
  mockFetch.mockResolvedValueOnce({
88
82
  ok: false,
89
83
  status: 400,
@@ -93,7 +87,7 @@ describe("QuickbaseClient - deleteRecords (Unit)", () => {
93
87
  await expect(() =>
94
88
  qb.deleteRecords({
95
89
  body: {
96
- from: "test-table-id",
90
+ from: QB_TABLE_ID_1,
97
91
  where: "{3.EX.'invalid'}",
98
92
  },
99
93
  })
@@ -104,12 +98,12 @@ describe("QuickbaseClient - deleteRecords (Unit)", () => {
104
98
  expect.objectContaining({
105
99
  method: "DELETE",
106
100
  headers: expect.objectContaining({
107
- "QB-Realm-Hostname": "test-realm.quickbase.com",
108
- Authorization: "QB-USER-TOKEN test-token",
101
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
102
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
109
103
  "Content-Type": "application/json",
110
104
  }),
111
105
  body: JSON.stringify({
112
- from: "test-table-id",
106
+ from: QB_TABLE_ID_1,
113
107
  where: "{3.EX.'invalid'}",
114
108
  }),
115
109
  })
@@ -0,0 +1,102 @@
1
+ // tests/vitest/unit/records/runQuery.test.ts
2
+ import { describe, test, 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 { RunQueryRequest, RunQueryResponse } from "@/generated";
11
+
12
+ describe("QuickbaseClient Unit - runQuery", () => {
13
+ let client: ReturnType<typeof createClient>;
14
+
15
+ beforeEach(() => {
16
+ mockFetch.mockClear();
17
+ client = createClient(mockFetch, { debug: true });
18
+ });
19
+
20
+ test("sends correct POST request and handles successful query response", async () => {
21
+ const queryRequest: RunQueryRequest = {
22
+ from: QB_TABLE_ID_1,
23
+ select: [3, 6, 7],
24
+ where: "{6.EX.'Task 1'}",
25
+ sortBy: [{ fieldId: 6, order: "ASC" }],
26
+ groupBy: [{ fieldId: 7, grouping: "equal-values" }],
27
+ options: { skip: 0, top: 100, compareWithAppLocalTime: false },
28
+ };
29
+
30
+ const mockResponse: RunQueryResponse = {
31
+ data: [
32
+ { "3": { value: 1 }, "6": { value: "Task 1" }, "7": { value: "High" } },
33
+ ],
34
+ fields: [
35
+ { id: 3, label: "Record ID#", type: "recordid" },
36
+ { id: 6, label: "Task Name", type: "text" },
37
+ { id: 7, label: "Priority", type: "text" },
38
+ ],
39
+ metadata: {
40
+ numFields: 3,
41
+ numRecords: 1,
42
+ skip: 0,
43
+ top: 100,
44
+ totalRecords: 1,
45
+ },
46
+ };
47
+
48
+ mockFetch.mockResolvedValueOnce({
49
+ ok: true,
50
+ status: 200,
51
+ json: () => Promise.resolve(mockResponse),
52
+ });
53
+
54
+ const result = await client.runQuery({ body: queryRequest });
55
+
56
+ expect(mockFetch).toHaveBeenCalledWith(
57
+ "https://api.quickbase.com/v1/records/query",
58
+ expect.objectContaining({
59
+ method: "POST",
60
+ headers: expect.objectContaining({
61
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
62
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
63
+ "Content-Type": "application/json",
64
+ }),
65
+ body: JSON.stringify(queryRequest),
66
+ })
67
+ );
68
+
69
+ expect(result).toEqual(mockResponse);
70
+ });
71
+
72
+ test("handles API error with invalid query", async () => {
73
+ const invalidQueryRequest = {
74
+ from: QB_TABLE_ID_1,
75
+ select: [3],
76
+ where: "{999.EX.'Invalid'}", // Invalid field ID
77
+ };
78
+
79
+ mockFetch.mockResolvedValueOnce({
80
+ ok: false,
81
+ status: 400,
82
+ json: () => Promise.resolve({ message: "Invalid query" }),
83
+ });
84
+
85
+ await expect(
86
+ client.runQuery({ body: invalidQueryRequest })
87
+ ).rejects.toThrow("API Error: Invalid query (Status: 400)");
88
+
89
+ expect(mockFetch).toHaveBeenCalledWith(
90
+ "https://api.quickbase.com/v1/records/query",
91
+ expect.objectContaining({
92
+ method: "POST",
93
+ headers: expect.objectContaining({
94
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
95
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
96
+ "Content-Type": "application/json",
97
+ }),
98
+ body: JSON.stringify(invalidQueryRequest),
99
+ })
100
+ );
101
+ });
102
+ });