Facing a Type Error Cannot read properties of undefined (reading 'createLogger') in winston logger when runnning unit tests using Jest

20 views Asked by At

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.

0

There are 0 answers