@objectql/sdk 4.1.0 → 4.2.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +36 -0
- package/README.md +1 -1
- package/dist/index.d.ts +15 -17
- package/dist/index.js +17 -17
- package/dist/index.js.map +1 -1
- package/package.json +11 -4
- package/src/index.test.ts +760 -0
- package/src/index.ts +21 -21
- package/test/remote-driver.test.ts +52 -48
- package/tsconfig.json +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/jest.config.js +0 -23
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Data, System as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
type
|
|
1
|
+
import { Data, System as _SystemSpec } from '@objectstack/spec';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { QueryAST } from '@objectql/types';
|
|
4
|
+
type _DriverInterface = z.infer<typeof Data.DriverInterface>;
|
|
5
5
|
/**
|
|
6
6
|
* ObjectQL
|
|
7
7
|
* Copyright (c) 2026-present ObjectStack Inc.
|
|
@@ -336,7 +336,7 @@ export class RemoteDriver implements Driver {
|
|
|
336
336
|
try {
|
|
337
337
|
await this.checkHealth();
|
|
338
338
|
} catch (error) {
|
|
339
|
-
throw new
|
|
339
|
+
throw new ObjectQLError({ code: 'DRIVER_CONNECTION_FAILED', message: `Failed to connect to remote server: ${(error as Error).message}` });
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
342
|
|
|
@@ -358,7 +358,7 @@ export class RemoteDriver implements Driver {
|
|
|
358
358
|
})
|
|
359
359
|
});
|
|
360
360
|
return res.ok;
|
|
361
|
-
} catch (
|
|
361
|
+
} catch (_error) {
|
|
362
362
|
return false;
|
|
363
363
|
}
|
|
364
364
|
}
|
|
@@ -389,7 +389,7 @@ export class RemoteDriver implements Driver {
|
|
|
389
389
|
* });
|
|
390
390
|
* ```
|
|
391
391
|
*/
|
|
392
|
-
async executeQuery(ast: QueryAST,
|
|
392
|
+
async executeQuery(ast: QueryAST, _options?: any): Promise<{ value: any[]; count?: number }> {
|
|
393
393
|
return this.retryWithBackoff(async () => {
|
|
394
394
|
const endpoint = this.buildEndpoint(this.queryPath);
|
|
395
395
|
this.log('executeQuery', { endpoint, ast });
|
|
@@ -478,7 +478,7 @@ export class RemoteDriver implements Driver {
|
|
|
478
478
|
* });
|
|
479
479
|
* ```
|
|
480
480
|
*/
|
|
481
|
-
async executeCommand(command: Command,
|
|
481
|
+
async executeCommand(command: Command, _options?: any): Promise<CommandResult> {
|
|
482
482
|
return this.retryWithBackoff(async () => {
|
|
483
483
|
const endpoint = this.buildEndpoint(this.commandPath);
|
|
484
484
|
this.log('executeCommand', { endpoint, command });
|
|
@@ -545,19 +545,19 @@ export class RemoteDriver implements Driver {
|
|
|
545
545
|
* @example
|
|
546
546
|
* ```typescript
|
|
547
547
|
* // Execute a custom workflow
|
|
548
|
-
* const result = await driver.
|
|
548
|
+
* const result = await driver.executeCustomEndpoint('/api/workflows/approve', {
|
|
549
549
|
* workflowId: 'wf_123',
|
|
550
550
|
* comment: 'Approved'
|
|
551
551
|
* });
|
|
552
552
|
*
|
|
553
553
|
* // Use default execute endpoint
|
|
554
|
-
* const result = await driver.
|
|
554
|
+
* const result = await driver.executeCustomEndpoint(undefined, {
|
|
555
555
|
* action: 'calculateMetrics',
|
|
556
556
|
* params: { year: 2024 }
|
|
557
557
|
* });
|
|
558
558
|
* ```
|
|
559
559
|
*/
|
|
560
|
-
async
|
|
560
|
+
async executeCustomEndpoint(endpoint?: string, payload?: any, _options?: any): Promise<any> {
|
|
561
561
|
return this.retryWithBackoff(async () => {
|
|
562
562
|
const targetEndpoint = endpoint
|
|
563
563
|
? this.buildEndpoint(endpoint)
|
|
@@ -617,7 +617,7 @@ export class RemoteDriver implements Driver {
|
|
|
617
617
|
const json = await res.json();
|
|
618
618
|
|
|
619
619
|
if (json.error) {
|
|
620
|
-
throw new
|
|
620
|
+
throw new ObjectQLError({ code: 'DRIVER_QUERY_FAILED', message: json.error.message });
|
|
621
621
|
}
|
|
622
622
|
|
|
623
623
|
return json.data;
|
|
@@ -630,40 +630,40 @@ export class RemoteDriver implements Driver {
|
|
|
630
630
|
* QueryAST format uses 'top' for limit, while UnifiedQuery uses 'limit'.
|
|
631
631
|
* QueryAST sort is array of {field, order}, while UnifiedQuery is array of [field, order].
|
|
632
632
|
*/
|
|
633
|
-
async find(objectName: string, query: any,
|
|
633
|
+
async find(objectName: string, query: any, _options?: any): Promise<any[]> {
|
|
634
634
|
return this.request('find', objectName, query);
|
|
635
635
|
}
|
|
636
636
|
|
|
637
|
-
async findOne(objectName: string, id: string | number, query?: any,
|
|
637
|
+
async findOne(objectName: string, id: string | number, query?: any, _options?: any): Promise<any> {
|
|
638
638
|
return this.request('findOne', objectName, { id, query });
|
|
639
639
|
}
|
|
640
640
|
|
|
641
|
-
async create(objectName: string, data: any,
|
|
641
|
+
async create(objectName: string, data: any, _options?: any): Promise<any> {
|
|
642
642
|
return this.request('create', objectName, data);
|
|
643
643
|
}
|
|
644
644
|
|
|
645
|
-
async update(objectName: string, id: string | number, data: any,
|
|
645
|
+
async update(objectName: string, id: string | number, data: any, _options?: any): Promise<any> {
|
|
646
646
|
// args for update: { id, data } based on server code: repo.update(req.args.id, req.args.data)
|
|
647
647
|
return this.request('update', objectName, { id, data });
|
|
648
648
|
}
|
|
649
649
|
|
|
650
|
-
async delete(objectName: string, id: string | number,
|
|
650
|
+
async delete(objectName: string, id: string | number, _options?: any): Promise<any> {
|
|
651
651
|
return this.request('delete', objectName, { id });
|
|
652
652
|
}
|
|
653
653
|
|
|
654
|
-
async count(objectName: string, filters: any,
|
|
654
|
+
async count(objectName: string, filters: any, _options?: any): Promise<number> {
|
|
655
655
|
return this.request('count', objectName, filters);
|
|
656
656
|
}
|
|
657
657
|
|
|
658
|
-
async createMany(objectName: string, data: any[],
|
|
658
|
+
async createMany(objectName: string, data: any[], _options?: any): Promise<any> {
|
|
659
659
|
return this.request('createMany', objectName, data);
|
|
660
660
|
}
|
|
661
661
|
|
|
662
|
-
async updateMany(objectName: string, filters: any, data: any,
|
|
662
|
+
async updateMany(objectName: string, filters: any, data: any, _options?: any): Promise<any> {
|
|
663
663
|
return this.request('updateMany', objectName, { filters, data });
|
|
664
664
|
}
|
|
665
665
|
|
|
666
|
-
async deleteMany(objectName: string, filters: any,
|
|
666
|
+
async deleteMany(objectName: string, filters: any, _options?: any): Promise<any> {
|
|
667
667
|
return this.request('deleteMany', objectName, { filters });
|
|
668
668
|
}
|
|
669
669
|
}
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { RemoteDriver } from '../src/index';
|
|
10
|
+
import { vi, Mock } from 'vitest';
|
|
10
11
|
|
|
11
12
|
// Mock fetch globally
|
|
12
|
-
global.fetch =
|
|
13
|
+
global.fetch = vi.fn();
|
|
13
14
|
|
|
14
15
|
describe('RemoteDriver', () => {
|
|
15
16
|
let driver: RemoteDriver;
|
|
@@ -17,7 +18,7 @@ describe('RemoteDriver', () => {
|
|
|
17
18
|
|
|
18
19
|
beforeEach(() => {
|
|
19
20
|
driver = new RemoteDriver(baseUrl);
|
|
20
|
-
|
|
21
|
+
vi.clearAllMocks();
|
|
21
22
|
});
|
|
22
23
|
|
|
23
24
|
describe('Constructor', () => {
|
|
@@ -41,7 +42,7 @@ describe('RemoteDriver', () => {
|
|
|
41
42
|
]
|
|
42
43
|
};
|
|
43
44
|
|
|
44
|
-
(global.fetch as
|
|
45
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
45
46
|
json: async () => mockResponse
|
|
46
47
|
});
|
|
47
48
|
|
|
@@ -65,7 +66,7 @@ describe('RemoteDriver', () => {
|
|
|
65
66
|
it('should handle empty result', async () => {
|
|
66
67
|
const mockResponse = { data: [] };
|
|
67
68
|
|
|
68
|
-
(global.fetch as
|
|
69
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
69
70
|
json: async () => mockResponse
|
|
70
71
|
});
|
|
71
72
|
|
|
@@ -78,7 +79,7 @@ describe('RemoteDriver', () => {
|
|
|
78
79
|
error: { message: 'Object not found' }
|
|
79
80
|
};
|
|
80
81
|
|
|
81
|
-
(global.fetch as
|
|
82
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
82
83
|
json: async () => mockResponse
|
|
83
84
|
});
|
|
84
85
|
|
|
@@ -94,7 +95,7 @@ describe('RemoteDriver', () => {
|
|
|
94
95
|
data: { _id: '1', name: 'Alice', email: 'alice@example.com' }
|
|
95
96
|
};
|
|
96
97
|
|
|
97
|
-
(global.fetch as
|
|
98
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
98
99
|
json: async () => mockResponse
|
|
99
100
|
});
|
|
100
101
|
|
|
@@ -116,7 +117,7 @@ describe('RemoteDriver', () => {
|
|
|
116
117
|
it('should return null when record not found', async () => {
|
|
117
118
|
const mockResponse = { data: null };
|
|
118
119
|
|
|
119
|
-
(global.fetch as
|
|
120
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
120
121
|
json: async () => mockResponse
|
|
121
122
|
});
|
|
122
123
|
|
|
@@ -129,7 +130,7 @@ describe('RemoteDriver', () => {
|
|
|
129
130
|
data: { _id: 123, name: 'Test' }
|
|
130
131
|
};
|
|
131
132
|
|
|
132
|
-
(global.fetch as
|
|
133
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
133
134
|
json: async () => mockResponse
|
|
134
135
|
});
|
|
135
136
|
|
|
@@ -156,7 +157,7 @@ describe('RemoteDriver', () => {
|
|
|
156
157
|
data: { _id: '3', ...newData }
|
|
157
158
|
};
|
|
158
159
|
|
|
159
|
-
(global.fetch as
|
|
160
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
160
161
|
json: async () => mockResponse
|
|
161
162
|
});
|
|
162
163
|
|
|
@@ -181,7 +182,7 @@ describe('RemoteDriver', () => {
|
|
|
181
182
|
error: { message: 'Validation failed: email is required' }
|
|
182
183
|
};
|
|
183
184
|
|
|
184
|
-
(global.fetch as
|
|
185
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
185
186
|
json: async () => mockResponse
|
|
186
187
|
});
|
|
187
188
|
|
|
@@ -198,7 +199,7 @@ describe('RemoteDriver', () => {
|
|
|
198
199
|
data: { _id: '1', name: 'Alice Updated', email: 'alice@example.com' }
|
|
199
200
|
};
|
|
200
201
|
|
|
201
|
-
(global.fetch as
|
|
202
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
202
203
|
json: async () => mockResponse
|
|
203
204
|
});
|
|
204
205
|
|
|
@@ -222,7 +223,7 @@ describe('RemoteDriver', () => {
|
|
|
222
223
|
error: { message: 'Record not found' }
|
|
223
224
|
};
|
|
224
225
|
|
|
225
|
-
(global.fetch as
|
|
226
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
226
227
|
json: async () => mockResponse
|
|
227
228
|
});
|
|
228
229
|
|
|
@@ -236,7 +237,7 @@ describe('RemoteDriver', () => {
|
|
|
236
237
|
data: { _id: 123, name: 'Updated' }
|
|
237
238
|
};
|
|
238
239
|
|
|
239
|
-
(global.fetch as
|
|
240
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
240
241
|
json: async () => mockResponse
|
|
241
242
|
});
|
|
242
243
|
|
|
@@ -259,7 +260,7 @@ describe('RemoteDriver', () => {
|
|
|
259
260
|
it('should delete a record', async () => {
|
|
260
261
|
const mockResponse = { data: 1 };
|
|
261
262
|
|
|
262
|
-
(global.fetch as
|
|
263
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
263
264
|
json: async () => mockResponse
|
|
264
265
|
});
|
|
265
266
|
|
|
@@ -283,7 +284,7 @@ describe('RemoteDriver', () => {
|
|
|
283
284
|
error: { message: 'Record not found' }
|
|
284
285
|
};
|
|
285
286
|
|
|
286
|
-
(global.fetch as
|
|
287
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
287
288
|
json: async () => mockResponse
|
|
288
289
|
});
|
|
289
290
|
|
|
@@ -295,7 +296,7 @@ describe('RemoteDriver', () => {
|
|
|
295
296
|
it('should handle numeric id in delete', async () => {
|
|
296
297
|
const mockResponse = { data: 1 };
|
|
297
298
|
|
|
298
|
-
(global.fetch as
|
|
299
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
299
300
|
json: async () => mockResponse
|
|
300
301
|
});
|
|
301
302
|
|
|
@@ -318,7 +319,7 @@ describe('RemoteDriver', () => {
|
|
|
318
319
|
it('should count records', async () => {
|
|
319
320
|
const mockResponse = { data: 42 };
|
|
320
321
|
|
|
321
|
-
(global.fetch as
|
|
322
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
322
323
|
json: async () => mockResponse
|
|
323
324
|
});
|
|
324
325
|
|
|
@@ -340,7 +341,7 @@ describe('RemoteDriver', () => {
|
|
|
340
341
|
it('should count all records when no filters', async () => {
|
|
341
342
|
const mockResponse = { data: 100 };
|
|
342
343
|
|
|
343
|
-
(global.fetch as
|
|
344
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
344
345
|
json: async () => mockResponse
|
|
345
346
|
});
|
|
346
347
|
|
|
@@ -351,7 +352,7 @@ describe('RemoteDriver', () => {
|
|
|
351
352
|
it('should return 0 for empty collection', async () => {
|
|
352
353
|
const mockResponse = { data: 0 };
|
|
353
354
|
|
|
354
|
-
(global.fetch as
|
|
355
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
355
356
|
json: async () => mockResponse
|
|
356
357
|
});
|
|
357
358
|
|
|
@@ -362,7 +363,7 @@ describe('RemoteDriver', () => {
|
|
|
362
363
|
|
|
363
364
|
describe('Error Handling', () => {
|
|
364
365
|
it('should handle network errors', async () => {
|
|
365
|
-
(global.fetch as
|
|
366
|
+
(global.fetch as Mock).mockRejectedValueOnce(new Error('Network error'));
|
|
366
367
|
|
|
367
368
|
await expect(driver.find('user', {}))
|
|
368
369
|
.rejects
|
|
@@ -370,7 +371,7 @@ describe('RemoteDriver', () => {
|
|
|
370
371
|
});
|
|
371
372
|
|
|
372
373
|
it('should handle invalid JSON response', async () => {
|
|
373
|
-
(global.fetch as
|
|
374
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
374
375
|
json: async () => { throw new Error('Invalid JSON'); }
|
|
375
376
|
});
|
|
376
377
|
|
|
@@ -387,7 +388,7 @@ describe('RemoteDriver', () => {
|
|
|
387
388
|
}
|
|
388
389
|
};
|
|
389
390
|
|
|
390
|
-
(global.fetch as
|
|
391
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
391
392
|
json: async () => mockResponse
|
|
392
393
|
});
|
|
393
394
|
|
|
@@ -402,7 +403,7 @@ describe('RemoteDriver', () => {
|
|
|
402
403
|
const driverWithSlash = new RemoteDriver('http://example.com/');
|
|
403
404
|
const mockResponse = { data: [] };
|
|
404
405
|
|
|
405
|
-
(global.fetch as
|
|
406
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
406
407
|
json: async () => mockResponse
|
|
407
408
|
});
|
|
408
409
|
|
|
@@ -418,7 +419,7 @@ describe('RemoteDriver', () => {
|
|
|
418
419
|
const httpsDriver = new RemoteDriver('https://secure.example.com');
|
|
419
420
|
const mockResponse = { data: [] };
|
|
420
421
|
|
|
421
|
-
(global.fetch as
|
|
422
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
422
423
|
json: async () => mockResponse
|
|
423
424
|
});
|
|
424
425
|
|
|
@@ -434,7 +435,7 @@ describe('RemoteDriver', () => {
|
|
|
434
435
|
const customPortDriver = new RemoteDriver('http://localhost:8080');
|
|
435
436
|
const mockResponse = { data: [] };
|
|
436
437
|
|
|
437
|
-
(global.fetch as
|
|
438
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
438
439
|
json: async () => mockResponse
|
|
439
440
|
});
|
|
440
441
|
|
|
@@ -470,7 +471,7 @@ describe('RemoteDriver', () => {
|
|
|
470
471
|
count: 2
|
|
471
472
|
};
|
|
472
473
|
|
|
473
|
-
(global.fetch as
|
|
474
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
474
475
|
ok: true,
|
|
475
476
|
json: async () => mockResponse
|
|
476
477
|
});
|
|
@@ -502,7 +503,7 @@ describe('RemoteDriver', () => {
|
|
|
502
503
|
fields: ['name']
|
|
503
504
|
};
|
|
504
505
|
|
|
505
|
-
(global.fetch as
|
|
506
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
506
507
|
ok: true,
|
|
507
508
|
json: async () => ({ value: [], count: 0 })
|
|
508
509
|
});
|
|
@@ -524,7 +525,7 @@ describe('RemoteDriver', () => {
|
|
|
524
525
|
const queryAST = { object: 'users' };
|
|
525
526
|
|
|
526
527
|
// Test data response format
|
|
527
|
-
(global.fetch as
|
|
528
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
528
529
|
ok: true,
|
|
529
530
|
json: async () => ({ data: [{ id: 1 }] })
|
|
530
531
|
});
|
|
@@ -533,7 +534,7 @@ describe('RemoteDriver', () => {
|
|
|
533
534
|
expect(result.value).toEqual([{ id: 1 }]);
|
|
534
535
|
|
|
535
536
|
// Test direct array response
|
|
536
|
-
(global.fetch as
|
|
537
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
537
538
|
ok: true,
|
|
538
539
|
json: async () => [{ id: 2 }]
|
|
539
540
|
});
|
|
@@ -545,7 +546,7 @@ describe('RemoteDriver', () => {
|
|
|
545
546
|
it('should handle errors in executeQuery', async () => {
|
|
546
547
|
const queryAST = { object: 'users' };
|
|
547
548
|
|
|
548
|
-
(global.fetch as
|
|
549
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
549
550
|
ok: false,
|
|
550
551
|
status: 404,
|
|
551
552
|
statusText: 'Not Found',
|
|
@@ -577,7 +578,7 @@ describe('RemoteDriver', () => {
|
|
|
577
578
|
affected: 1
|
|
578
579
|
};
|
|
579
580
|
|
|
580
|
-
(global.fetch as
|
|
581
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
581
582
|
ok: true,
|
|
582
583
|
json: async () => mockResponse
|
|
583
584
|
});
|
|
@@ -612,7 +613,7 @@ describe('RemoteDriver', () => {
|
|
|
612
613
|
affected: 2
|
|
613
614
|
};
|
|
614
615
|
|
|
615
|
-
(global.fetch as
|
|
616
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
616
617
|
ok: true,
|
|
617
618
|
json: async () => mockResponse
|
|
618
619
|
});
|
|
@@ -630,7 +631,7 @@ describe('RemoteDriver', () => {
|
|
|
630
631
|
data: { name: 'Test' }
|
|
631
632
|
};
|
|
632
633
|
|
|
633
|
-
(global.fetch as
|
|
634
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
634
635
|
ok: true,
|
|
635
636
|
json: async () => ({
|
|
636
637
|
error: {
|
|
@@ -653,7 +654,7 @@ describe('RemoteDriver', () => {
|
|
|
653
654
|
id: '999'
|
|
654
655
|
};
|
|
655
656
|
|
|
656
|
-
(global.fetch as
|
|
657
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
657
658
|
ok: false,
|
|
658
659
|
status: 404,
|
|
659
660
|
statusText: 'Not Found',
|
|
@@ -682,12 +683,12 @@ describe('RemoteDriver', () => {
|
|
|
682
683
|
result: { total: 1000 }
|
|
683
684
|
};
|
|
684
685
|
|
|
685
|
-
(global.fetch as
|
|
686
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
686
687
|
ok: true,
|
|
687
688
|
json: async () => mockResponse
|
|
688
689
|
});
|
|
689
690
|
|
|
690
|
-
const result = await driver.
|
|
691
|
+
const result = await driver.executeCustomEndpoint('/api/custom', payload);
|
|
691
692
|
|
|
692
693
|
expect(global.fetch).toHaveBeenCalledWith(
|
|
693
694
|
'http://localhost:3000/api/custom',
|
|
@@ -702,12 +703,12 @@ describe('RemoteDriver', () => {
|
|
|
702
703
|
it('should use default execute endpoint when not specified', async () => {
|
|
703
704
|
const payload = { action: 'test' };
|
|
704
705
|
|
|
705
|
-
(global.fetch as
|
|
706
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
706
707
|
ok: true,
|
|
707
708
|
json: async () => ({ success: true })
|
|
708
709
|
});
|
|
709
710
|
|
|
710
|
-
await driver.
|
|
711
|
+
await driver.executeCustomEndpoint(undefined, payload);
|
|
711
712
|
|
|
712
713
|
expect(global.fetch).toHaveBeenCalledWith(
|
|
713
714
|
'http://localhost:3000/api/execute',
|
|
@@ -716,7 +717,7 @@ describe('RemoteDriver', () => {
|
|
|
716
717
|
});
|
|
717
718
|
|
|
718
719
|
it('should handle errors in execute', async () => {
|
|
719
|
-
(global.fetch as
|
|
720
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
720
721
|
ok: false,
|
|
721
722
|
status: 500,
|
|
722
723
|
statusText: 'Internal Server Error',
|
|
@@ -728,7 +729,7 @@ describe('RemoteDriver', () => {
|
|
|
728
729
|
})
|
|
729
730
|
});
|
|
730
731
|
|
|
731
|
-
await expect(driver.
|
|
732
|
+
await expect(driver.executeCustomEndpoint('/api/test', {}))
|
|
732
733
|
.rejects
|
|
733
734
|
.toThrow('Server error');
|
|
734
735
|
});
|
|
@@ -741,7 +742,7 @@ describe('RemoteDriver', () => {
|
|
|
741
742
|
token: 'my-secret-token'
|
|
742
743
|
});
|
|
743
744
|
|
|
744
|
-
(global.fetch as
|
|
745
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
745
746
|
ok: true,
|
|
746
747
|
json: async () => ({ value: [], count: 0 })
|
|
747
748
|
});
|
|
@@ -764,7 +765,7 @@ describe('RemoteDriver', () => {
|
|
|
764
765
|
apiKey: 'my-api-key'
|
|
765
766
|
});
|
|
766
767
|
|
|
767
|
-
(global.fetch as
|
|
768
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
768
769
|
ok: true,
|
|
769
770
|
json: async () => ({ value: [], count: 0 })
|
|
770
771
|
});
|
|
@@ -788,7 +789,7 @@ describe('RemoteDriver', () => {
|
|
|
788
789
|
apiKey: 'my-api-key'
|
|
789
790
|
});
|
|
790
791
|
|
|
791
|
-
(global.fetch as
|
|
792
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
792
793
|
ok: true,
|
|
793
794
|
json: async () => ({ value: [], count: 0 })
|
|
794
795
|
});
|
|
@@ -809,11 +810,11 @@ describe('RemoteDriver', () => {
|
|
|
809
810
|
|
|
810
811
|
describe('Retry Logic', () => {
|
|
811
812
|
beforeEach(() => {
|
|
812
|
-
|
|
813
|
+
vi.useFakeTimers();
|
|
813
814
|
});
|
|
814
815
|
|
|
815
816
|
afterEach(() => {
|
|
816
|
-
|
|
817
|
+
vi.useRealTimers();
|
|
817
818
|
});
|
|
818
819
|
|
|
819
820
|
it('should retry on network errors when enabled', async () => {
|
|
@@ -824,7 +825,7 @@ describe('RemoteDriver', () => {
|
|
|
824
825
|
});
|
|
825
826
|
|
|
826
827
|
// First two attempts fail, third succeeds
|
|
827
|
-
(global.fetch as
|
|
828
|
+
(global.fetch as Mock)
|
|
828
829
|
.mockRejectedValueOnce(new Error('Network error'))
|
|
829
830
|
.mockRejectedValueOnce(new Error('Network error'))
|
|
830
831
|
.mockResolvedValueOnce({
|
|
@@ -835,7 +836,10 @@ describe('RemoteDriver', () => {
|
|
|
835
836
|
const promise = driverWithRetry.executeQuery({ object: 'users' });
|
|
836
837
|
|
|
837
838
|
// Fast-forward through retries
|
|
838
|
-
|
|
839
|
+
// We need to advance time multiple times for each retry
|
|
840
|
+
for (let i = 0; i < 2; i++) {
|
|
841
|
+
await vi.runAllTimersAsync();
|
|
842
|
+
}
|
|
839
843
|
|
|
840
844
|
const result = await promise;
|
|
841
845
|
|
|
@@ -850,7 +854,7 @@ describe('RemoteDriver', () => {
|
|
|
850
854
|
maxRetries: 3
|
|
851
855
|
});
|
|
852
856
|
|
|
853
|
-
(global.fetch as
|
|
857
|
+
(global.fetch as Mock).mockResolvedValueOnce({
|
|
854
858
|
ok: false,
|
|
855
859
|
status: 400,
|
|
856
860
|
statusText: 'Bad Request',
|