222 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { tap, expect } from '@git.zone/tstest/tapbundle';
 | |
| 
 | |
| import { SmartRequest } from '../ts/client/index.js';
 | |
| 
 | |
| tap.test('client: should request a html document over https', async () => {
 | |
|   const response = await SmartRequest.create()
 | |
|     .url('https://encrypted.google.com/')
 | |
|     .get();
 | |
| 
 | |
|   expect(response).not.toBeNull();
 | |
|   expect(response).toHaveProperty('status');
 | |
|   expect(response.status).toBeGreaterThan(0);
 | |
|   const text = await response.text();
 | |
|   expect(text.length).toBeGreaterThan(0);
 | |
| });
 | |
| 
 | |
| tap.test('client: should request a JSON document over https', async () => {
 | |
|   const response = await SmartRequest.create()
 | |
|     .url('https://jsonplaceholder.typicode.com/posts/1')
 | |
|     .get();
 | |
| 
 | |
|   const body = await response.json();
 | |
|   expect(body).toHaveProperty('id');
 | |
|   expect(body.id).toEqual(1);
 | |
| });
 | |
| 
 | |
| tap.test('client: should post a JSON document over http', async () => {
 | |
|   const testData = { title: 'example_text', body: 'test body', userId: 1 };
 | |
|   const response = await SmartRequest.create()
 | |
|     .url('https://jsonplaceholder.typicode.com/posts')
 | |
|     .json(testData)
 | |
|     .post();
 | |
| 
 | |
|   const body = await response.json();
 | |
|   expect(body).toHaveProperty('title');
 | |
|   expect(body.title).toEqual('example_text');
 | |
|   expect(body).toHaveProperty('id'); // jsonplaceholder returns an id for created posts
 | |
| });
 | |
| 
 | |
| tap.test('client: should set headers correctly', async () => {
 | |
|   const customHeader = 'X-Custom-Header';
 | |
|   const headerValue = 'test-value';
 | |
| 
 | |
|   const response = await SmartRequest.create()
 | |
|     .url('https://echo.zuplo.io/')
 | |
|     .header(customHeader, headerValue)
 | |
|     .get();
 | |
| 
 | |
|   const body = await response.json();
 | |
|   expect(body).toHaveProperty('headers');
 | |
| 
 | |
|   // Check if the header exists (headers might be lowercase)
 | |
|   const headers = body.headers;
 | |
|   const headerFound =
 | |
|     headers[customHeader] ||
 | |
|     headers[customHeader.toLowerCase()] ||
 | |
|     headers['x-custom-header'];
 | |
|   expect(headerFound).toEqual(headerValue);
 | |
| });
 | |
| 
 | |
| tap.test('client: should handle query parameters', async () => {
 | |
|   const params = { userId: '1' };
 | |
| 
 | |
|   const response = await SmartRequest.create()
 | |
|     .url('https://jsonplaceholder.typicode.com/posts')
 | |
|     .query(params)
 | |
|     .get();
 | |
| 
 | |
|   const body = await response.json();
 | |
|   expect(Array.isArray(body)).toBeTrue();
 | |
|   // Check that we got posts for userId 1
 | |
|   if (body.length > 0) {
 | |
|     expect(body[0]).toHaveProperty('userId');
 | |
|     expect(body[0].userId).toEqual(1);
 | |
|   }
 | |
| });
 | |
| 
 | |
| tap.test('client: should handle timeout configuration', async () => {
 | |
|   // This test just verifies that the timeout method doesn't throw
 | |
|   const client = SmartRequest.create()
 | |
|     .url('https://jsonplaceholder.typicode.com/posts/1')
 | |
|     .timeout(5000);
 | |
| 
 | |
|   const response = await client.get();
 | |
|   expect(response).toHaveProperty('ok');
 | |
|   expect(response.ok).toBeTrue();
 | |
| 
 | |
|   // Consume the body to prevent socket hanging
 | |
|   await response.text();
 | |
| });
 | |
| 
 | |
| tap.test('client: should handle retry configuration', async () => {
 | |
|   // This test just verifies that the retry method doesn't throw
 | |
|   const client = SmartRequest.create()
 | |
|     .url('https://jsonplaceholder.typicode.com/posts/1')
 | |
|     .retry(1);
 | |
| 
 | |
|   const response = await client.get();
 | |
|   expect(response).toHaveProperty('ok');
 | |
|   expect(response.ok).toBeTrue();
 | |
| 
 | |
|   // Consume the body to prevent socket hanging
 | |
|   await response.text();
 | |
| });
 | |
| 
 | |
| tap.test(
 | |
|   'client: should support keepAlive option for connection reuse',
 | |
|   async () => {
 | |
|     // Simple test
 | |
|     const response = await SmartRequest.create()
 | |
|       .url('https://jsonplaceholder.typicode.com/posts/1')
 | |
|       .options({ keepAlive: true })
 | |
|       .get();
 | |
| 
 | |
|     expect(response.ok).toBeTrue();
 | |
|     await response.text();
 | |
|   },
 | |
| );
 | |
| 
 | |
| tap.test(
 | |
|   'client: should handle 429 rate limiting with default config',
 | |
|   async () => {
 | |
|     // Test that handle429Backoff can be configured without errors
 | |
|     const client = SmartRequest.create()
 | |
|       .url('https://jsonplaceholder.typicode.com/posts/1')
 | |
|       .handle429Backoff();
 | |
| 
 | |
|     const response = await client.get();
 | |
|     expect(response.status).toEqual(200);
 | |
| 
 | |
|     // Consume the body to prevent socket hanging
 | |
|     await response.text();
 | |
|   },
 | |
| );
 | |
| 
 | |
| tap.test('client: should handle 429 with custom config', async () => {
 | |
|   let rateLimitCallbackCalled = false;
 | |
|   let attemptCount = 0;
 | |
|   let waitTimeReceived = 0;
 | |
| 
 | |
|   const client = SmartRequest.create()
 | |
|     .url('https://jsonplaceholder.typicode.com/posts/1')
 | |
|     .handle429Backoff({
 | |
|       maxRetries: 2,
 | |
|       fallbackDelay: 500,
 | |
|       maxWaitTime: 5000,
 | |
|       onRateLimit: (attempt, waitTime) => {
 | |
|         rateLimitCallbackCalled = true;
 | |
|         attemptCount = attempt;
 | |
|         waitTimeReceived = waitTime;
 | |
|       },
 | |
|     });
 | |
| 
 | |
|   const response = await client.get();
 | |
|   expect(response.status).toEqual(200);
 | |
| 
 | |
|   // The callback should not have been called for a 200 response
 | |
|   expect(rateLimitCallbackCalled).toBeFalse();
 | |
| 
 | |
|   // Consume the body to prevent socket hanging
 | |
|   await response.text();
 | |
| });
 | |
| 
 | |
| tap.test(
 | |
|   'client: should respect Retry-After header format (seconds)',
 | |
|   async () => {
 | |
|     // Test the configuration works - actual 429 testing would require a mock server
 | |
|     const client = SmartRequest.create()
 | |
|       .url('https://jsonplaceholder.typicode.com/posts/1')
 | |
|       .handle429Backoff({
 | |
|         maxRetries: 1,
 | |
|         respectRetryAfter: true,
 | |
|       });
 | |
| 
 | |
|     const response = await client.get();
 | |
|     expect(response.ok).toBeTrue();
 | |
| 
 | |
|     // Consume the body to prevent socket hanging
 | |
|     await response.text();
 | |
|   },
 | |
| );
 | |
| 
 | |
| tap.test(
 | |
|   'client: should handle rate limiting with exponential backoff',
 | |
|   async () => {
 | |
|     // Test exponential backoff configuration
 | |
|     const client = SmartRequest.create()
 | |
|       .url('https://jsonplaceholder.typicode.com/posts/1')
 | |
|       .handle429Backoff({
 | |
|         maxRetries: 3,
 | |
|         fallbackDelay: 100,
 | |
|         backoffFactor: 2,
 | |
|         maxWaitTime: 1000,
 | |
|       });
 | |
| 
 | |
|     const response = await client.get();
 | |
|     expect(response.status).toEqual(200);
 | |
| 
 | |
|     // Consume the body to prevent socket hanging
 | |
|     await response.text();
 | |
|   },
 | |
| );
 | |
| 
 | |
| tap.test(
 | |
|   'client: should not retry non-429 errors with rate limit handler',
 | |
|   async () => {
 | |
|     // Test that 404 errors are not retried by rate limit handler
 | |
|     const client = SmartRequest.create()
 | |
|       .url('https://jsonplaceholder.typicode.com/posts/999999')
 | |
|       .handle429Backoff();
 | |
| 
 | |
|     const response = await client.get();
 | |
|     expect(response.status).toEqual(404);
 | |
|     expect(response.ok).toBeFalse();
 | |
| 
 | |
|     // Consume the body to prevent socket hanging
 | |
|     await response.text();
 | |
|   },
 | |
| );
 | |
| 
 | |
| tap.start();
 |