在Jest中访问捕获的stderr输出

cnjp1d6j  于 2023-09-28  发布在  Jest
关注(0)|答案(2)|浏览(131)

Jest捕获stdout和stderr输出。是否可以在测试中访问此捕获的信息?
问候,尼德基尔

2jcobegt

2jcobegt1#

我的方法不对。我没有使用spy/mock,而是尝试直接拦截stdout/stderr。我用下面的函数解决了这个问题。

/* eslint-disable no-undef */
export function spyConsole() {
  let spy = {}

  beforeEach(() => {
    spy.console = jest.spyOn(console, 'error').mockImplementation(() => {})
  })

  afterEach(() => {
    spy.console.mockClear()
  })

  afterAll(() => {
    spy.console.mockRestore()
  })

  return spy
}

它的使用方式如下:

import { createLocalVue, mount } from '@vue/test-utils'
import { spyConsole } from '@tst/helpers/test-utils'
import Vuetify from 'vuetify'
import VBtnPlus from '@/components/common/VBtnPlus.vue'

describe('VStatsCard.vue', () => {
  let localVue = null

  beforeEach(() => {
    localVue = createLocalVue()
    localVue.use(Vuetify)
  })

  describe('test prop warnings', () => {
    let spy = spyConsole()

    it('displays warning messages when both label and icon are not specified', () => {
      mount(VBtnPlus, {
        localVue: localVue
      })
      expect(console.error).toHaveBeenCalledTimes(1)
      expect(spy.console.mock.calls[0][0]).toContain(
        '[Vue warn]: Missing required prop, specify at least one of the following: "label" or "icon"'
      )
    })
  })
})
vngu2lb8

vngu2lb82#

如果您看到这篇文章试图测试pino日志记录,我可以通过执行以下操作来测试我的pino配置(感谢How to use Jest to test that pino debug log is written to stdout when load a module in a test?

import { streamSym } from 'pino/lib/symbols'
import logger from './logger' // where my pino config is

describe('Logger default configuration', () => {
  beforeEach(() => {
    jest.resetAllMocks()
    jest.restoreAllMocks()
  })
  it('Logs an error', () => {
    const spyOnLoggerError = jest.spyOn(logger, 'error')
    const spyOnLoggerStreamWrite = jest.spyOn(logger[streamSym], 'write')
    const myTestError = new Error('My test error')
    logger.error(myTestError)
    expect(spyOnLoggerError).toBeCalledWith(myTestError) // verify logger.error called
    expect(spyOnLoggerStreamWrite).toBeCalledTimes(1) // verify that logger.error was only called once
    expect(spyOnLoggerStreamWrite).toBeCalledWith(expect.stringContaining('"level":50')) // validate log level of message
    expect(spyOnLoggerStreamWrite).toBeCalledWith(expect.stringContaining('"message":"My test error"')) // validate that message contains error message
  })
})

在测试时,请确保pino配置中的log level设置为实际记录结果的值。例如,我的默认level设置为'error',这就是测试通过的原因。但是,如果需要测试logger.trace(new Error('Some trace error')),我需要模拟设置level的环境变量。
更新:请注意,我以前尝试使用jest.spyOn((global.console as any)._stdout, 'write'),但这被证明是不可靠的,当我运行所有测试时都失败了。
以下是我的pino配置(./logger.ts):

// logger.ts
import { isPlainObject } from 'lodash'
import pino, { Logger } from 'pino'
import pinoCaller from 'pino-caller'
import pinoStdSerializers from 'pino-std-serializers'

const normalSerializer = (value): string => {
  if (typeof value === 'object') return JSON.stringify(value)
  if (typeof value === 'undefined') return 'undefined'
  return value
}

const isError = (value): boolean => value instanceof Error

const appName = 'myAppName'
const logLevel = process.env.LOG_LEVEL || 'error'

const pinoLogger = pino({
  name: `${appName}`,
  level: logLevel,
  hooks: {
    logMethod(args, method): void {
      const arrayArgs = Array.from(args)
      arrayArgs.forEach(arg => {
        const isArgError = isError(arg)
        const doesArgContainErrorValue = isPlainObject(arg) && Object.values(arg).some(val => isError(val))
        const isErrorFoundInArg = isArgError || doesArgContainErrorValue // use the error serializer if the argument is an instance of error or prop value is instance of error
        const serializer = isErrorFoundInArg ? pinoStdSerializers.err : normalSerializer
        method.apply(this, [serializer(arg)])
      })
    },
  },
  prettyPrint: process.env.ENABLE_PRETTY_LOG === 'true',
})

/**
 * Accepted logger arguments are as follows:
 * logger.trace(err) // where the argument err is an instance of Error
 * logger.info({ err, myCtx: {prop1: 'some value'} }) // where the argument is an object with err being an instanceof Error and myCtx being some arbitrary context object
 * logger.warn({prop1: 1, prop2: 2}) // where the argument is an arbitrary object
 * logger.error('My String')
 */
const logger = process.env.ENABLE_LOG_CALL_DETAILS === 'true' ? pinoCaller(pinoLogger) : pinoLogger

export default logger

相关问题