This repository has been archived on 2025-08-03. You can view files and clone it, but cannot push or open issues or pull requests.
anonpenguin 64ed9e82a7 Add integration tests for blog workflow and supporting infrastructure
- Implemented comprehensive integration tests for user management, category management, content publishing, comment system, performance, scalability, and network resilience.
- Created DockerNodeManager to manage Docker containers for testing.
- Developed ApiClient for API interactions and health checks.
- Introduced SyncWaiter for synchronizing node states and ensuring data consistency.
- Enhanced test reliability with increased timeouts and detailed logging.
2025-06-21 11:15:33 +03:00

123 lines
3.0 KiB
TypeScript

import fetch from 'node-fetch';
export interface ApiResponse<T = any> {
data?: T;
error?: string;
status: number;
}
export class ApiClient {
constructor(private baseUrl: string) {}
async get<T = any>(path: string): Promise<ApiResponse<T>> {
try {
const response = await fetch(`${this.baseUrl}${path}`);
const data = await response.json();
return {
data: response.ok ? data : undefined,
error: response.ok ? undefined : data.error || 'Request failed',
status: response.status
};
} catch (error) {
return {
error: error.message,
status: 0
};
}
}
async post<T = any>(path: string, body: any): Promise<ApiResponse<T>> {
try {
const response = await fetch(`${this.baseUrl}${path}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
});
const data = await response.json();
return {
data: response.ok ? data : undefined,
error: response.ok ? undefined : data.error || 'Request failed',
status: response.status
};
} catch (error) {
return {
error: error.message,
status: 0
};
}
}
async put<T = any>(path: string, body: any): Promise<ApiResponse<T>> {
try {
const response = await fetch(`${this.baseUrl}${path}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
});
const data = await response.json();
return {
data: response.ok ? data : undefined,
error: response.ok ? undefined : data.error || 'Request failed',
status: response.status
};
} catch (error) {
return {
error: error.message,
status: 0
};
}
}
async delete<T = any>(path: string): Promise<ApiResponse<T>> {
try {
const response = await fetch(`${this.baseUrl}${path}`, {
method: 'DELETE'
});
const data = response.status === 204 ? {} : await response.json();
return {
data: response.ok ? data : undefined,
error: response.ok ? undefined : data.error || 'Request failed',
status: response.status
};
} catch (error) {
return {
error: error.message,
status: 0
};
}
}
async health(): Promise<ApiResponse<{ status: string; nodeId: string; peers: number }>> {
return this.get('/health');
}
async waitForHealth(timeout: number = 30000): Promise<boolean> {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
try {
const response = await this.health();
if (response.status === 200 && response.data?.status === 'healthy') {
return true;
}
} catch (error) {
// Continue waiting
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
return false;
}
}