WhatapClient.test.ts•7.56 kB
/**
* WhatapClient Unit Tests (Mock-based)
*
* Tests WhatapClient with mocked HTTP responses
*/
import MockAdapter from 'axios-mock-adapter';
import axios from 'axios';
import * as fs from 'fs/promises';
import * as path from 'path';
import * as os from 'os';
import { WhatapClient } from '../../../src/core/client/WhatapClient';
import { AuthManager } from '../../../src/core/auth/AuthManager';
import { SessionStore } from '../../../src/core/auth/SessionStore';
import { ApiError } from '../../../src/core/types';
import type { Session, Project } from '../../../src/core/types';
describe('WhatapClient (Unit Tests)', () => {
let testDir: string;
let sessionStore: SessionStore;
let authManager: AuthManager;
let whatapClient: WhatapClient;
let mock: MockAdapter;
const mockSession: Session = {
email: 'test@whatap.io',
accountId: 12345,
cookies: { wa: 'test-wa-cookie', jsessionid: 'test-jsessionid' },
apiToken: 'test-api-token',
serviceUrl: 'https://test.whatap.io',
createdAt: new Date(),
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
};
beforeEach(async () => {
// Create temporary test directory
testDir = path.join(os.tmpdir(), `whatap-test-${Date.now()}`);
await fs.mkdir(testDir, { recursive: true });
sessionStore = new SessionStore(testDir);
// Setup axios mock BEFORE creating AuthManager
mock = new MockAdapter(axios, { onNoMatch: 'throwException' });
// Save mock session
await sessionStore.save(mockSession);
// Create AuthManager and load session
authManager = new AuthManager(sessionStore);
await authManager.loadSession();
// Create WhatapClient
whatapClient = new WhatapClient(authManager);
});
afterEach(async () => {
// Clean up
mock.restore();
try {
await fs.rm(testDir, { recursive: true, force: true });
} catch (error) {
// Ignore cleanup errors
}
});
describe('executeMxql', () => {
test('should execute MXQL query successfully', async () => {
const mockData = [
{ time: 1234567890, value: 100 },
{ time: 1234567900, value: 200 },
];
mock.onPost('https://test.whatap.io/yard/api/flush').reply(200, mockData);
const result = await whatapClient.executeMxql({
pcode: 12345,
mql: 'SELECT * FROM app_counter',
stime: Date.now() - 3600000,
etime: Date.now(),
limit: 100,
});
expect(result.ok).toBe(true);
expect(result.code).toBe(200);
expect(result.data).toEqual(mockData);
});
test('should use default time range if not provided', async () => {
mock.onPost('https://test.whatap.io/yard/api/flush').reply((config) => {
const data = JSON.parse(config.data);
expect(data.params.stime).toBeDefined();
expect(data.params.etime).toBeDefined();
expect(data.params.limit).toBe(100);
return [200, []];
});
await whatapClient.executeMxql({
pcode: 12345,
mql: 'SELECT * FROM app_counter',
});
});
test('should throw ApiError when MXQL execution fails', async () => {
mock.onPost('https://test.whatap.io/yard/api/flush').reply(500, {
error: 'Internal Server Error',
});
await expect(
whatapClient.executeMxql({
pcode: 12345,
mql: 'INVALID QUERY',
})
).rejects.toThrow(ApiError);
});
test('should send correct MXQL request format', async () => {
mock.onPost('https://test.whatap.io/yard/api/flush').reply((config) => {
const data = JSON.parse(config.data);
expect(data.type).toBe('mxql');
expect(data.pcode).toBe(12345);
expect(data.params.mql).toBe('SELECT * FROM app_counter');
expect(data.path).toBe('text');
return [200, []];
});
await whatapClient.executeMxql({
pcode: 12345,
mql: 'SELECT * FROM app_counter',
stime: 1234567890,
etime: 1234567900,
limit: 50,
});
});
});
describe('getProjects', () => {
test('should get list of projects', async () => {
const mockProjects: Project[] = [
{
pcode: 12345,
name: 'Test Project 1',
type: 'apm',
status: 'active',
},
{
pcode: 67890,
name: 'Test Project 2',
type: 'server',
status: 'active',
},
];
mock.onGet('https://test.whatap.io/v2/project').reply(200, mockProjects);
const projects = await whatapClient.getProjects();
expect(projects).toEqual(mockProjects);
expect(projects).toHaveLength(2);
expect(projects[0].pcode).toBe(12345);
});
test('should throw ApiError when getting projects fails', async () => {
mock.onGet('https://test.whatap.io/v2/project').reply(500);
await expect(whatapClient.getProjects()).rejects.toThrow(ApiError);
});
});
describe('getProject', () => {
test('should get project details', async () => {
const mockProject: Project = {
pcode: 12345,
name: 'Test Project',
type: 'apm',
status: 'active',
createTime: 1234567890,
};
mock
.onGet('https://test.whatap.io/v2/project/12345')
.reply(200, mockProject);
const project = await whatapClient.getProject(12345);
expect(project).toEqual(mockProject);
expect(project.pcode).toBe(12345);
expect(project.name).toBe('Test Project');
});
test('should throw ApiError when project not found', async () => {
mock.onGet('https://test.whatap.io/v2/project/99999').reply(404);
await expect(whatapClient.getProject(99999)).rejects.toThrow(ApiError);
});
});
describe('generic HTTP methods', () => {
test('should execute generic GET request', async () => {
const mockData = { result: 'success' };
mock.onGet('https://test.whatap.io/test/endpoint').reply(200, mockData);
const result = await whatapClient.get('/test/endpoint');
expect(result.ok).toBe(true);
expect(result.code).toBe(200);
expect(result.data).toEqual(mockData);
});
test('should execute generic POST request', async () => {
const requestData = { query: 'test' };
const mockData = { result: 'created' };
mock
.onPost('https://test.whatap.io/test/endpoint', requestData)
.reply(200, mockData);
const result = await whatapClient.post('/test/endpoint', requestData);
expect(result.ok).toBe(true);
expect(result.code).toBe(200);
expect(result.data).toEqual(mockData);
});
test('should throw ApiError on GET failure', async () => {
mock.onGet('https://test.whatap.io/test/endpoint').reply(500);
await expect(whatapClient.get('/test/endpoint')).rejects.toThrow(
ApiError
);
});
test('should throw ApiError on POST failure', async () => {
mock.onPost('https://test.whatap.io/test/endpoint').reply(500);
await expect(whatapClient.post('/test/endpoint', {})).rejects.toThrow(
ApiError
);
});
});
describe('authentication', () => {
test('should include authentication cookies in requests', async () => {
mock.onGet('https://test.whatap.io/test').reply((config) => {
expect(config.headers?.Cookie).toContain('WHATAP=');
expect(config.headers?.Cookie).toContain('JSESSIONID=');
return [200, {}];
});
await whatapClient.get('/test');
});
});
});