Tudor Stanciu 9ad0d9be93 feat: update version to 1.2.0 and refactor backend structure
- Changed main entry point from `index.js` to `server.js` in package.json.
- Created a new `app.ts` file to encapsulate Express app configuration.
- Removed old `index.ts` file and moved server logic to `server.ts`.
- Updated nodemon configurations to point to the new `server.ts`.
- Added new middleware for API key authentication with public endpoint support.
- Modified validators to accept any string for IPs, allowing handlers to determine validity.
- Added integration tests for batch lookup and health endpoints.
- Implemented unit tests for error handling and validation middleware.
- Updated `tsup` and `vitest` configurations to reflect new entry points and testing setup.
2025-10-13 01:14:37 +03:00

126 lines
3.7 KiB
TypeScript

// Copyright (c) 2025 Tudor Stanciu
import { describe, it, expect } from 'vitest';
import {
apiRequest,
TEST_API_KEY,
VALID_IPV4,
VALID_IPV6,
PRIVATE_IP,
INVALID_IP,
} from '../setup';
describe('Batch Lookup Endpoint', () => {
describe('POST /api/lookup/batch', () => {
it('should return results for valid IPs', async () => {
const response = await (
await apiRequest()
)
.post('/api/lookup/batch')
.set('X-API-Key', TEST_API_KEY)
.send({ ips: [VALID_IPV4, VALID_IPV6] })
.expect(200);
expect(response.body).toHaveProperty('succeeded');
expect(response.body).toHaveProperty('failed');
expect(Array.isArray(response.body.succeeded)).toBe(true);
expect(Array.isArray(response.body.failed)).toBe(true);
expect(response.body.succeeded.length).toBeGreaterThan(0);
});
it('should separate succeeded and failed results', async () => {
const response = await (
await apiRequest()
)
.post('/api/lookup/batch')
.set('X-API-Key', TEST_API_KEY)
.send({ ips: [VALID_IPV4, INVALID_IP] })
.expect(200);
expect(response.body.succeeded.length).toBeGreaterThan(0);
expect(response.body.failed.length).toBeGreaterThan(0);
expect(response.body.succeeded[0]).toHaveProperty('ip', VALID_IPV4);
expect(response.body.failed[0]).toHaveProperty('ip', INVALID_IP);
expect(response.body.failed[0]).toHaveProperty('error');
});
it('should filter out private IPs', async () => {
const response = await (
await apiRequest()
)
.post('/api/lookup/batch')
.set('X-API-Key', TEST_API_KEY)
.send({ ips: [VALID_IPV4, PRIVATE_IP] })
.expect(200);
const privateIpError = response.body.failed.find(
(f: any) => f.ip === PRIVATE_IP
);
expect(privateIpError).toBeDefined();
expect(privateIpError.error).toContain('Private IP');
});
it('should return all failures for invalid IPs', async () => {
const response = await (
await apiRequest()
)
.post('/api/lookup/batch')
.set('X-API-Key', TEST_API_KEY)
.send({ ips: ['invalid-1', 'invalid-2'] })
.expect(200);
expect(response.body.succeeded.length).toBe(0);
expect(response.body.failed.length).toBe(2);
});
it('should return 400 when ips array is missing', async () => {
const response = await apiRequest()
.post('/api/lookup/batch')
.set('X-API-Key', TEST_API_KEY)
.send({})
.expect(400);
expect(response.body).toHaveProperty('error', 'Bad Request');
});
it('should return 400 when ips array is empty', async () => {
const response = await apiRequest()
.post('/api/lookup/batch')
.set('X-API-Key', TEST_API_KEY)
.send({ ips: [] })
.expect(400);
expect(response.body).toHaveProperty('error', 'Bad Request');
});
it('should handle IPv4 and IPv6 mix', async () => {
const response = await (
await apiRequest()
)
.post('/api/lookup/batch')
.set('X-API-Key', TEST_API_KEY)
.send({ ips: [VALID_IPV4, VALID_IPV6] })
.expect(200);
expect(response.body.succeeded.length).toBe(2);
const ipv4Result = response.body.succeeded.find(
(r: any) => r.ip === VALID_IPV4
);
const ipv6Result = response.body.succeeded.find(
(r: any) => r.ip === VALID_IPV6
);
expect(ipv4Result).toBeDefined();
expect(ipv6Result).toBeDefined();
});
it('should reject request without API key', async () => {
await (
await apiRequest()
)
.post('/api/lookup/batch')
.send({ ips: [VALID_IPV4] })
.expect(401);
});
});
});