'jest winston format.errors is not a function

I have an app that uses winston for logging. I am trying to setup a jest test for a function, that calls another function, etc., and the test for the function eventually fails at an attempt to use winston exported functions:

services\__tests__>jest search.test.js
 FAIL  ./search.test.js
  ● Test suite failed to run

    TypeError: format.errors is not a function

      26 | const logger = createLogger({
      27 |   level: config.logging.level,
    > 28 |   format: format.combine(format.errors({ stack: true }), errorStackFormat(), config.logging.logFormat()),
         |                                 ^
      29 |   transports: [
      30 |     new transports.Console({
      31 |       stderrLevels: ['error', 'critical'],

      at Object.<anonymous> (helpers/logger.js:28:33)
      at Object.<anonymous> (db/connection/connection.js:2:16)

/search.test.js

jest.mock('winston', () => ({
  format: jest.fn(() => ({
    errors: jest.fn(),
    combine: jest.fn(),
    apply: jest.fn(),
  })),
  createLogger: jest.fn().mockImplementation(() => ({
    info: jest.fn(),
    warn: jest.fn(),
    error: jest.fn(),
  })),
  transports: {
    Console: jest.fn(),
  },
}));

const search = require('../search');
process.env.NODE_ENV = 'development';

describe('services/search.js', () => {
  it('searches ', async () => {
    const query = {
      mpn: '5555555555',
    };

    expect(
      await search(query).then((result) => {
        console.log('result', result);
        return result;
      })
    ).toEqual(['000']);
  });
});

helpers/logger.js

const { createLogger, format, transports } = require('winston');
const config = require('../config');
require('express-async-errors');

const errorStackFormat = format((info) => {
  if (info.level === 'error') {
    if (!/^{.*?}$/.test(info.message)) return info;

    const { code, reason, status, message } = JSON.parse(info.message);
    return {
      ...info,
      code,
      reason,
      status,
      message,
    };
  }

  return info;
});

const logger = createLogger({
  level: config.logging.level,
  format: format.combine(format.errors({ stack: true }), errorStackFormat(), config.logging.logFormat()),
  transports: [
    new transports.Console({
      stderrLevels: ['error', 'critical'],
    }),
  ],
  exceptionHandlers: [new transports.Console(config.logging.format)],
  exitOnError: true,
});

module.exports = logger;

If I try to only have format as an object, it fails the test on const errorStackFormat = format((info) because it's looking for format to be a function, so the mock needs to have format as a function, and also have properties (like errors) that are functions as well.

How can I get format.errors to work in the mock? I'm not doing something right, please help me figure out what I am doing wrong :) Thanks!



Solution 1:[1]

Well I figured it out, at least it's not complaining anymore about the original error. I needed to use my logger function that uses winston, like so:

jest.mock('../../helpers/logger', () => jest.fn());
const logger = require('../../helpers/logger');

logger.mockImplementation(() => () => ({
  format: jest.fn(() => ({
    errors: jest.fn(),
    combine: jest.fn(),
    apply: jest.fn(),
  })),
  createLogger: jest.fn().mockImplementation(() => ({
    info: jest.fn(),
    warn: jest.fn(),
    error: jest.fn(),
  })),
  transports: {
    Console: jest.fn(),
  },
}));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Kris Nelson