I have a test file whose objective is to test the main function, inside the main function there are several endpoints that I mock using jest framework. And the mock actually works and instead of giving me the result of the real endpoint it uses the mock data that I’ve built, the bad thing is while the test is running it keeps putting these messages in the terminal for every endpoint:
Error >>fetching projects: AxiosError {
port: 8055,
address: '10.20.10.68',
syscall: 'connect',
code: 'ETIMEDOUT',
errno: -4039,
message: 'connect ETIMEDOUT 10.20.10.68:8055',
name: 'Error',
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [ 'xhr', 'http', 'fetch' ],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: { FormData: [Function [FormData]], Blob: [class Blob] },
validateStatus: [Function: validateStatus],
headers: Object [AxiosHeaders] {
Accept: 'application/json, text/plain, */*',
'Content-Type': undefined,
'User-Agent': 'axios/1.9.0',
'Accept-Encoding': 'gzip, compress, deflate, br'
},
baseURL: 'http://10.20.10.68:8055/xpand-api',
auth: { username: 'revenueassurance', password: '8#XL$K0>10XOs£kS' },
method: 'get',
url: '/services/bi/revenue-assurance/project/get',
allowAbsoluteUrls: true,
data: undefined
},
request: <ref *1> Writable {
_events: {
close: undefined,
error: [Function: handleRequestError],
prefinish: undefined,
finish: undefined,
drain: undefined,
response: [Function: handleResponse],
socket: [Function: handleRequestSocket]
},
_writableState: WritableState {
highWaterMark: 16384,
length: 0,
corked: 0,
onwrite: [Function: bound onwrite],
writelen: 0,
bufferedIndex: 0,
pendingcb: 0,
[Symbol(kState)]: 17580812,
[Symbol(kBufferedValue)]: null
},
_maxListeners: undefined,
_options: {
maxRedirects: 21,
maxBodyLength: Infinity,
protocol: 'http:',
path: '/xpand-api/services/bi/revenue-assurance/project/get',
method: 'GET',
headers: [Object: null prototype],
agents: [Object],
auth: 'revenueassurance:8#XL$K0>10XOs£kS',
family: undefined,
beforeRedirect: [Function: dispatchBeforeRedirect],
beforeRedirects: [Object],
hostname: '10.20.10.68',
port: '8055',
agent: undefined,
nativeProtocols: [Object],
pathname: '/xpand-api/services/bi/revenue-assurance/project/get'
},
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 0,
_requestBodyBuffers: [],
_eventsCount: 3,
_onNativeResponse: [Function (anonymous)],
_currentRequest: ClientRequest {
_events: [Object: null prototype],
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: false,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: true,
maxRequestsOnConnectionReached: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
strictContentLength: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
_closed: false,
_header: 'GET /xpand-api/services/bi/revenue-assurance/project/get HTTP/1.1rn' +
'Accept: application/json, text/plain, */*rn' +
'User-Agent: axios/1.9.0rn' +
'Accept-Encoding: gzip, compress, deflate, brrn' +
'Host: 10.20.10.68:8055rn' +
'Authorization: Basic cmV2ZW51ZWFzc3VyYW5jZTo4I1hMJEswPjEwWE9zwqNrUw==rn' +
'Connection: keep-alivern' +
'rn',
_keepAliveTimeout: 0,
_onPendingData: [Function: nop],
agent: [Agent],
socketPath: undefined,
method: 'GET',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
joinDuplicateHeaders: undefined,
path: '/xpand-api/services/bi/revenue-assurance/project/get',
_ended: false,
res: null,
aborted: false,
timeoutCb: [Function: emitRequestTimeout],
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: false,
host: '10.20.10.68',
protocol: 'http:',
_redirectable: [Circular *1],
[Symbol(shapeMode)]: false,
[Symbol(kCapture)]: false,
[Symbol(kBytesWritten)]: 0,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kChunkedBuffer)]: [],
[Symbol(kChunkedLength)]: 0,
[Symbol(kSocket)]: [Socket],
[Symbol(kOutHeaders)]: [Object: null prototype],
[Symbol(errored)]: null,
[Symbol(kHighWaterMark)]: 16384,
[Symbol(kRejectNonStandardBodyWrites)]: false,
[Symbol(kUniqueHeaders)]: null
},
_currentUrl: 'http://revenueassurance:8%23XL%24K0%3E10XOs%C2%[email protected]:8055/xpand-api/services/bi/revenue-assurance/project/get',
[Symbol(shapeMode)]: true,
[Symbol(kCapture)]: false
},
cause: Error: connect ETIMEDOUT 10.20.10.68:8055
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1636:16) {
errno: -4039,
code: 'ETIMEDOUT',
syscall: 'connect',
address: '10.20.10.68',
port: 8055
}
}
I assume this happens because although the endpoint is being properly mocked the code still tries to access the real endpoint.
This is my test code:
import { axiosInstance as axioInstanceProject } from '../src/data/projects';
import { axiosInstance as axioInstanceRoleValue } from '../src/data/roleValue';
import { axiosInstance as axioInstanceTask } from '../src/data/tasks';
import { axiosInstance as axioInstanceTeam } from '../src/data/team';
import { axiosInstance as axioInstancePlannedExecution } from '../src/data/planned';
import { axiosInstance as axioInstanceMonthExecution } from '../src/data/execution';
import { axiosInstance as axioInstanceMultiplier } from '../src/data/multiplier';
import { axiosInstance as axioInstanceTimesheet } from '../src/services/timesheetService';
import { main, axiosInstancePost as axioInstancePostOutput } from '../src/services/computeOutput';
import { mockPostEndpoint } from './postDataMock';
import { mockGetEndpoints } from './getDataMock'
import { loadMockData, createMockAdapters } from './utils';
import { beforeEach, describe, expect, it, jest } from '@jest/globals';
import MockDate from 'mockdate'
const axiosInstance = {
Project: axioInstanceProject,
RoleValue: axioInstanceRoleValue,
Team: axioInstanceTeam,
Task: axioInstanceTask,
PlannedExecution: axioInstancePlannedExecution,
MonthExecution: axioInstanceMonthExecution,
Multiplier: axioInstanceMultiplier,
Timesheet: axioInstanceTimesheet,
PostOutput: axioInstancePostOutput
};
describe('basicTk', () => {
let mockAdapters;
beforeEach(() => {
mockAdapters = createMockAdapters(axiosInstance);
});
afterEach(() => {
Object.values(mockAdapters).forEach(mock => mock.restore());
});
it('basicTk success', async () => {
const mockData = loadMockData('basicTk');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
});
it('basicTk fail', async () => {
const mockData = loadMockData('basicTk', true);
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).rejects.toThrowError();
});
});
describe('basicTm', () => {
let mockAdapters;
beforeEach(() => {
mockAdapters = createMockAdapters(axiosInstance);
});
afterEach(() => {
Object.values(mockAdapters).forEach( mock => mock.restore());
});
it('basicTm success', async () => {
const mockData = loadMockData('basicTm');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
});
it('basicTm fail', async () => {
const mockData = loadMockData('basicTm', true);
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).rejects.toThrowError();
});
});
describe('snapshot', () => {
let mockAdapters;
beforeEach(() => {
mockAdapters = createMockAdapters(axiosInstance);
});
afterEach(() => {
Object.values(mockAdapters).forEach(mock => mock.restore());
jest.restoreAllMocks();
MockDate.reset();
});;
it('snapshot success', async () => {
const mockDate = new Date('2025-05-19T08:00:00Z');
MockDate.set(mockDate)
const mockData = loadMockData('snapshot');
mockGetEndpoints(mockAdapters, mockData)
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
});
it('snapshot fail', async () => {
const mockDate = new Date('2025-03-04T08:00:00Z');
MockDate.set(mockDate)
const mockData = loadMockData('snapshot');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).rejects.toThrowError();
});
})
describe('tm with multiplier', () => {
let mockAdapters;
beforeEach(() => {
mockAdapters = createMockAdapters(axiosInstance);
});
afterEach(() => {
Object.values(mockAdapters).forEach(mock => mock.restore());
});
it('tm with multiplier success', async () => {
const mockData = loadMockData('tmWithMultiplier');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
});
it('tm with multiplier fail', async () => {
const mockData = loadMockData('tmWithMultiplier');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
});
});
describe('tm with fixed fee', () => {
let mockAdapters;
beforeEach(() => {
mockAdapters = createMockAdapters(axiosInstance);
});
afterEach(() => {
Object.values(mockAdapters).forEach(mock => mock.restore());
});
it('basic tm with one fixed fee per project add success', async () => {
const mockDate = new Date('2025-03-03T08:00:00Z');
MockDate.set(mockDate)
const mockData = loadMockData('tmWithOneFixedFeeAdd');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
});
it('basic tm with more than one fixed fee per project add success', async () => {
const mockDate = new Date('2025-03-03T08:00:00Z');
MockDate.set(mockDate)
const mockData = loadMockData('tmWithMoreThanOneFixedFeeAdd');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
});
it('basic tm with one fixed fee per project replace success', async () => {
const mockDate = new Date('2025-03-03T08:00:00Z');
MockDate.set(mockDate)
const mockData = loadMockData('tmWithOneFixedFeeReplace');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
});
it('basic tm with more than one fixed fee per project replace success', async () => {
const mockDate = new Date('2025-03-03T08:00:00Z');
MockDate.set(mockDate)
const mockData = loadMockData('tmWithMoreThanOneFixedFeeReplace');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
});
});
describe('tm with expired date', () => {
let mockAdapters;
beforeEach(() => {
mockAdapters = createMockAdapters(axiosInstance);
});
afterEach(() => {
Object.values(mockAdapters).forEach(mock => mock.restore());
});
it('tm with expired date success', async () => {
const mockDate = new Date('2025-12-12T08:00:00Z');
MockDate.set(mockDate)
const mockData = loadMockData('tmWithExpiredDate');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
})
})
describe('tk + tm for work types', () => {
let mockAdapters;
beforeEach(() => {
mockAdapters = createMockAdapters(axiosInstance);
});
afterEach(() => {
Object.values(mockAdapters).forEach(mock => mock.restore());
});
it('tk + tm for work types success', async () => {
const mockDate = new Date('2025-12-12T08:00:00Z');
MockDate.set(mockDate)
const mockData = loadMockData('tk+tmWorkType');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
})
})
/*describe('tm with po', () => {
let mockAdapters;
beforeEach(() => {
mockAdapters = createMockAdapters(axiosInstance);
});
afterEach(() => {
Object.values(mockAdapters).forEach(mock => mock.restore());
});
it('tmWithPoPo success', async () => {
const mockData = loadMockData('tmWithPo');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
});
});*/
describe('preset plan', () => {
let mockAdapters;
beforeEach(() => {
mockAdapters = createMockAdapters(axiosInstance);
});
afterEach(() => {
Object.values(mockAdapters).forEach(mock => mock.restore());
});
it('preset plan success', async () => {
const mockData = loadMockData('presetPlan');
mockGetEndpoints(mockAdapters, mockData);
mockPostEndpoint(mockAdapters.PostOutput, mockData.expectedOutput);
await expect(main()).resolves.toBeUndefined();
});
})
this is postdatamock:
import fs from 'fs';
import deepDiff from 'deep-diff'
import { config } from 'dotenv';
function snakeToCamel(str) {
return str.replace(/_([a-z])/g, (_, char) => char.toUpperCase());
}
function convertAndStrip(obj) {
return recursiveStrip(obj);
}
function recursiveStrip(item) {
if (Array.isArray(item)) {
return item.map((element) => recursiveStrip(element));
}
if (item !== null && typeof item === 'object') {
return Object.entries(item).reduce((acc, [key, value]) => {
if (
key === "output_id" || key === "outputId" ||
key === "timestamp_local" || key === "timestamp_utc" ||
key === "timeStampLocal" || key === "timeStampUtc"
) {
return acc;
}
const camelKey = snakeToCamel(key);
acc[camelKey] = recursiveStrip(value);
return acc;
}, {});
}
if (typeof item === 'string') {
return item.trim();
}
return item;
}
function canonicalize(obj) {
if (Array.isArray(obj)) {
return obj.map(canonicalize);
}
if (obj !== null && typeof obj === "object") {
const sorted = {};
Object.keys(obj)
.sort()
.forEach((key) => {
sorted[key] = canonicalize(obj[key]);
});
return sorted;
}
return obj;
}
function sortData(data) {
data.sort((a, b) => {
return a.projectCode.localeCompare(b.projectCode) ||
a.yearMonth.localeCompare(b.yearMonth) ||
a.roleName.localeCompare(b.roleName) ||
a.billable.localeCompare(b.billable) ||
a.workType.localeCompare(b.workType) ||
a.po.localeCompare(b.po) ||
a.type.localeCompare(b.type);
});
const cleaned = data.map(item => {
const {
timeStampLocal,
timeStampUtc,
entryStartDate,
entryEndDate,
isActive,
...rest
} = item;
return rest;
});
return cleaned;
}
function createKey(record) {
return [
record.billable,
record.workType,
record.yearMonth,
record.projectCode,
record.po,
record.engagementManagement,
record.type,
record.roleName
].join("|");
}
function checkDuplicates(data) {
const seen = new Map();
const duplicates = [];
const unique_records = [];
for (const record of data) {
const key = createKey(record);
if (seen.has(key)) {
duplicates.push(record);
} else {
seen.set(key, true);
unique_records.push(record);
}
}
console.log("Duplicates found: " + duplicates.length);
if (duplicates.length > 0) {
fs.writeFileSync('duplicates', JSON.stringify(duplicates, null, 2));
fs.writeFileSync('uniqueRecords', JSON.stringify(unique_records, null, 2));
}
}
export function mockPostEndpoint(mockAdapterPost, expectedOutput) {
mockAdapterPost.onPost().reply(config => {
console.log("Post Mock start..")
const actualOutput = typeof config.data === 'string' ? JSON.parse(config.data) : config.data;
console.log("Convert And Strip start");
const csExpectedOutput = convertAndStrip(expectedOutput);
const csActualData = convertAndStrip(actualOutput);
console.log("Canonicalize start");
const cnExpectedOutput = canonicalize(csExpectedOutput);
const cnActualData = canonicalize(csActualData);
console.log("Sort start")
const expectedString_ = sortData(cnExpectedOutput);
const actualString_ = sortData(cnActualData);
console.log("Check Duplicates start");
checkDuplicates(actualString_);
console.log("PRESTES A ESCREVER")
fs.writeFileSync('actualFileeeee', JSON.stringify(actualString_, null, 2));
const diff = deepDiff.diff(actualString_, expectedString_);
if (diff === undefined) {
return [200, { code: 200, payload: { message: 'Success' } }];
} else {
return [400, { code: 400, payload: { message: 'Output mismatch', diff } }];
}
});
}
export {
snakeToCamel,
convertAndStrip,
canonicalize,
sortData
};
this is getdatamock.js:
export function mockGetEndpoints(mockAdapters, mockData) {
mockAdapters.Project.onGet().reply(200, mockData.project);
mockAdapters.RoleValue.onGet().reply(200, mockData.roleValue);
mockAdapters.Team.onGet().reply(200, mockData.team);
mockAdapters.Task.onGet().reply(200, mockData.task);
mockAdapters.PlannedExecution.onGet().reply(200, mockData.plannedExecution);
mockAdapters.MonthExecution.onGet().reply(200, mockData.monthExecution);
mockAdapters.Multiplier.onGet().reply(200, mockData.multiplier);
mockAdapters.Timesheet.onGet().reply(200, mockData.timesheet);
mockAdapters.PostOutput.onGet().reply(200, mockData.postOutput);
}
How can I fix this?