js-tests-results-collector
Version:
Universal test results collector for Jest, Jasmine, Mocha, Cypress, and Playwright that sends results to Buddy Works API
153 lines (126 loc) • 5 kB
JavaScript
const axios = require('axios');
const Logger = require('../utils/logger');
class ApiClient {
constructor(config) {
this.config = config;
this.logger = new Logger('ApiClient');
this.baseUrl = config.getBaseUrl();
this.headers = config.getHeaders();
// Log configuration for debugging
this.logger.debug('ApiClient initialized with config:', {
baseUrl: this.baseUrl,
headers: this.headers
});
this.axiosInstance = axios.create({
baseURL: this.baseUrl,
timeout: 10000,
headers: this.headers
});
// Add request interceptor for debugging
this.axiosInstance.interceptors.request.use(
config => {
if (this.config.debugEnabled) {
this.logger.info('=== API REQUEST ===');
this.logger.info(`Method: ${config.method?.toUpperCase()}`);
this.logger.info(`URL: ${config.url}`);
this.logger.info(`Full URL: ${config.baseURL}${config.url}`);
this.logger.info(`Headers:`, JSON.stringify(config.headers, null, 2));
if (config.data) {
this.logger.info('Payload:', JSON.stringify(config.data, null, 2));
}
this.logger.info('=== END REQUEST ===');
}
return config;
},
error => {
this.logger.error('Request interceptor error:', error);
return Promise.reject(error);
}
);
// Add response interceptor for debugging and error handling
this.axiosInstance.interceptors.response.use(
response => {
if (this.config.debugEnabled) {
this.logger.info('=== API RESPONSE ===');
this.logger.info(`Status: ${response.status} ${response.statusText}`);
this.logger.info(`Headers:`, JSON.stringify(response.headers, null, 2));
this.logger.info(`Data:`, JSON.stringify(response.data, null, 2));
this.logger.info('=== END RESPONSE ===');
}
return response;
},
error => {
const errorDetails = {
message: error.message,
status: error.response?.status,
statusText: error.response?.statusText,
url: error.config?.url,
method: error.config?.method?.toUpperCase(),
requestHeaders: error.config?.headers,
requestPayload: error.config?.data,
responseHeaders: error.response?.headers,
responseData: error.response?.data
};
this.logger.error('API request failed:', errorDetails);
return Promise.reject(error);
}
);
}
async createSession() {
try {
this.logger.debug('Creating new test session');
const sessionPayload = this.config.getSessionPayload();
this.logger.debug('Session creation details:', {
endpoint: '/unit-tests/sessions',
payload: sessionPayload
});
const response = await this.axiosInstance.post('/unit-tests/sessions', sessionPayload);
const sessionId = response.data.id;
this.logger.info(`Created session with ID: ${sessionId}`);
return sessionId;
} catch (error) {
this.logger.error('Failed to create session', error);
throw error;
}
}
async reopenSession(sessionId) {
try {
this.logger.debug(`Reopening test session: ${sessionId}`);
const response = await this.axiosInstance.post(`/unit-tests/sessions/${sessionId}/reopen`, {});
this.logger.info(`Reopened session with ID: ${response.data.id}`);
return response.data.id;
} catch (error) {
this.logger.error(`Failed to reopen session: ${sessionId}`, error);
throw error;
}
}
async submitTestCase(sessionId, testCase) {
try {
this.logger.debug(`Submitting test case: ${testCase.name}`);
await this.axiosInstance.put(`/unit-tests/sessions/${sessionId}/cases`, testCase);
this.logger.debug(`Successfully submitted test case: ${testCase.name}`);
} catch (error) {
this.logger.error(`Failed to submit test case: ${testCase.name}`, error);
// Don't throw - we don't want to break the test runner
}
}
async submitTestCases(sessionId, testCases) {
const promises = testCases.map(testCase =>
this.submitTestCase(sessionId, testCase)
);
await Promise.allSettled(promises);
}
async closeSession(sessionId, status = 'SUCCESS') {
try {
this.logger.debug(`Closing test session: ${sessionId} with status: ${status}`);
// Send status information in the payload
const payload = { status: status };
await this.axiosInstance.post(`/unit-tests/sessions/${sessionId}/close`, payload);
this.logger.info(`Successfully closed session: ${sessionId} with status: ${status}`);
} catch (error) {
this.logger.error(`Failed to close session: ${sessionId}`, error);
// Don't throw - we don't want to break if session close fails
}
}
}
module.exports = ApiClient;