Here is my NodeJs Controller for which I am writing tests. I have mocked the prisma ORM using the guide at https://www.prisma.io/docs/orm/prisma-client/testing/unit-testing#mocking-the-prisma-client.
Here is the NodeJS Controller :
import { Response } from 'express';
import prisma from '../connections/prisma';
import logger from '../utils/logger';
import { CustomError, TRequest } from '../utils/inferfaces';
import * as crypto from 'crypto';
export const fetchApiAccessToken = async (req: TRequest, res: Response) => {
const { clientId } = req;
logger.log(
'info',
`fetchApiAccessToken API - Initiated
Request Body (clientId):
clientId : ${clientId}`,
);
try {
const resData = await prisma.access_tokens.findFirst({
where: {
client_id: clientId,
},
});
if (!resData) {
const error: CustomError = new Error('Access Token not found');
error.code = 404;
throw error;
}
const token =
resData.token.slice(0, 4) +
'***************************' +
resData.token.slice(-4);
logger.log(
'info',
`fetchApiAccessToken API - Completed -
clientId : ${clientId} `,
);
return res.status(200).send({
status: 'sucess',
message: 'Access Token fetched successfully',
data: { ...resData, token },
});
} catch (error) {
const message = error.message || 'internal server error';
let statusCode = 500;
if (
error.code &&
typeof error.code === 'number' &&
error.code >= 400 &&
error.code < 600
) {
statusCode = error.code;
}
logger.log(
'error',
`fetchApiAccessToken API - Terminated - error: ${error}`,
);
return res.status(statusCode).send({
status: 'failed',
message,
});
}
};
export const updateApiAccessToken = async (req: TRequest, res: Response) => {
const { clientId } = req;
const allowed_hosts = req.body.allowedHosts ?? '*';
logger.log(
'info',
`fetchApiAccessToken API - Initiated
Request Body (clientId):
clientId : ${clientId}, allowed_hosts : ${allowed_hosts}`,
);
try {
const token = crypto.randomBytes(32).toString('hex');
const data = await prisma.access_tokens.upsert({
where: {
client_id: clientId,
},
update: {
allowed_hosts: allowed_hosts,
token: token,
created_ts: new Date(),
},
create: {
client_id: clientId,
allowed_hosts: allowed_hosts,
token: token,
},
});
logger.log(
'info',
`updateApiAccessToken API - Completed - clientId : ${clientId} `,
);
return res.status(200).send({
status: 'sucess',
message: 'Access Token updated successfully',
data,
});
} catch (error) {
const message = error.message || 'internal server error';
let statusCode = 500;
if (
error.code &&
typeof error.code === 'number' &&
error.code >= 400 &&
error.code < 600
) {
statusCode = error.code;
}
logger.log(
'error',
`fetchApiAccessToken API - Terminated - error: ${error}`,
);
return res.status(statusCode).send({
status: 'failed',
message,
});
}
};
Here is the Winston Logger Util File :
import winston from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';
const logger = winston.createLogger({
level: 'debug',
format: winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.printf(
({ timestamp, level, message }) =>
`${timestamp} \n ${level}: \n ${message}`,
),
),
transports: [
new winston.transports.Console(),
new DailyRotateFile({
filename: 'logs/app-%DATE%.log',
datePattern: 'YYYY-MM-DD',
zippedArchive: false,
maxSize: '10m',
maxFiles: '14d',
level: 'info',
auditFile: null,
}),
],
});
export default logger;
Here is the Jest Test case I have written :
import { fetchApiAccessToken } from '../controller/accessManagement';
import { prismaMock } from '../connections/__mocks__/prismaMock'
describe('fectchAPIAccessToken Unit Testing', ()=> {
it('successfully fetches access token', async () => {
// Setup
const mockReq = { clientId: 1 };
const mockRes = {
status: jest.fn().mockReturnThis(),
send: jest.fn(),
};
prismaMock.access_tokens.findFirst.mockResolvedValue({
client_id: 1,
token: 'abcd1234567890efghijklmnopqrstuv',
allowed_hosts: "*",
created_ts: new Date()
});
// Action
await fetchApiAccessToken(mockReq as any, mockRes as any);
// Assert
expect(mockRes.status).toHaveBeenCalledWith(200);
expect(mockRes.send).toHaveBeenCalledWith(expect.objectContaining({
status: 'sucess',
message: 'Access Token fetched successfully',
}));
});
});
And Here is the Error I am facing : FAIL src/test/accessManagement.test.ts ● Test suite failed to run
TypeError: Cannot read properties of undefined (reading 'createLogger')
2 | import DailyRotateFile from 'winston-daily-rotate-file';
3 |
> 4 | const logger = winston.createLogger({
| ^
5 | level: 'debug',
6 | format: winston.format.combine(
7 | winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
at Object.<anonymous> (src/utils/logger.ts:4:24)
at Object.<anonymous> (src/controller/accessManagement.ts:3:1)
at Object.<anonymous> (src/test/accessManagement.test.ts:1:1)
I want to understand why this error is happening and what code should I write to fix this issue.