Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.2.1] Calling failOnConsole() via setupFilesAfterEnv now fails with "Test did not tear down console.error mock properly" #13

Closed
caugner opened this issue Feb 10, 2022 · 12 comments · Fixed by #14

Comments

@caugner
Copy link

caugner commented Feb 10, 2022

We call failOnConsole() in a jest.setup.js script that we have configured in jest.config.js using the setupFilesAfterEnv config option.

// jest.setup.js

import failOnConsole from 'jest-fail-on-console'

failOnConsole({
  silenceMessage(message) {
    if (
      message.startsWith('[BootstrapVue warn]') ||
      message.startsWith('[Vue warn]: Injection "Symbol(pinia)" not found')
    ) {
      return true
    }
    return false
  },
})

Dependabot opened a MR today to bump jest-fail-on-console from 2.1.1 to 2.2.1, but unfortunately this causes all tests to fail with the following error message:

    Test did not tear down console.error mock properly.
        If you are trying to disable the "fail on console" mechanism, you should use beforeEach/afterEach
        instead of beforeAll/afterAll
          
      at flushUnexpectedConsoleCalls (node_modules/jest-fail-on-console/index.js:50:13)
      at Object.flushAllUnexpectedConsoleCalls (node_modules/jest-fail-on-console/index.js:97:7)

The changelog doesn't explain this change in behaviour, and it is working as expected with 2.1.1, despite not using any {before,after}* methods, so I'm wondering if this is intended.

@ValentinH
Copy link
Owner

Thank you for the report and sorry for the inconvenience.

Are you able to reproduce this issue with a simple example please?

@ValentinH
Copy link
Owner

Moreover, could you try with the 2.2.0 version?

@ValentinH
Copy link
Owner

Lastly, could you try to change this line in your node_modules: https://github.com/ricardo-ch/jest-fail-on-console/blob/main/index.js#L42

By:

return newMethod

@caugner
Copy link
Author

caugner commented Feb 10, 2022

2.2.0 is working fine, and changing that line to return newMethod resolves the isue with 2.2.1 as well.

@ValentinH
Copy link
Owner

Perfect, I'll publish a fix ASAP then.

@caugner
Copy link
Author

caugner commented Feb 10, 2022

Awesome, thanks a lot for the quick resolution! 🚀

@ValentinH
Copy link
Owner

Hmm, actually, if I try this on one of my project, I start getting the same error as you. 🤔

What version of Jest are you using?

@caugner
Copy link
Author

caugner commented Feb 10, 2022

What version of Jest are you using?

24.9.0 (via @vue/cli-plugin-unit-jest)

@ValentinH
Copy link
Owner

ValentinH commented Feb 10, 2022

Ok this is probably why. I'm using v27.

I did a quite heavy refactor that also simplify the logic, could you try it please?

const util = require('util')
const chalk = require('chalk')

const defaultErrorMessage = (methodName, bold) =>
  `Expected test not to call ${bold(`console.${methodName}()`)}.\n\n` +
  `If the ${methodName} is expected, test for it explicitly by mocking it out using ${bold(
    'jest.spyOn'
  )}(console, '${methodName}').mockImplementation() and test that the warning occurs.`

const init = ({
  silenceMessage,
  shouldFailOnWarn = true,
  shouldFailOnError = true,
  shouldFailOnLog = false,
  errorMessage = defaultErrorMessage,
} = {}) => {
  const flushUnexpectedConsoleCalls = (methodName, unexpectedConsoleCallStacks) => {
    if (unexpectedConsoleCallStacks.length > 0) {
      const messages = unexpectedConsoleCallStacks.map(([stack, message]) => {
        const stackLines = stack.split('\n')
        return (
          `${chalk.red(message)}\n` +
          `${stackLines
            .map((line, index) => {
              if (index === stackLines.length - 1) {
                return chalk.white(line)
              }
              return chalk.gray(line)
            })
            .join('\n')}`
        )
      })

      const message = errorMessage(methodName, chalk.bold)

      throw new Error(`${message}\n\n${messages.join('\n\n')}`)
    }
  }

  const patchConsoleMethod = (methodName) => {
    const unexpectedConsoleCallStacks = []

    const newMethod = (format, ...args) => {
      const message = util.format(format, ...args)
      if (silenceMessage && silenceMessage(message, methodName)) {
        return
      }

      // Capture the call stack now so we can warn about it later.
      // The call stack has helpful information for the test author.
      // Don't throw yet though b'c it might be accidentally caught and suppressed.
      const { stack } = new Error()
      if (stack) {
        unexpectedConsoleCallStacks.push([stack.substr(stack.indexOf('\n') + 1), message])
      }
    }

    let originalMethod = console[methodName]

    beforeEach(() => {
      console[methodName] = newMethod // eslint-disable-line no-console
      unexpectedConsoleCallStacks.length = 0
    })

    afterEach(() => {
      flushUnexpectedConsoleCalls(methodName, unexpectedConsoleCallStacks)
      console[methodName] = originalMethod
    })
  }

  if (shouldFailOnError) {
    patchConsoleMethod('error')
  }
  if (shouldFailOnWarn) {
    patchConsoleMethod('warn')
  }
  if (shouldFailOnLog) {
    patchConsoleMethod('log')
  }
}

module.exports = init

@ValentinH
Copy link
Owner

The code in the above PR is published as 2.2.2-alpha.0 if you want to try it.

@ValentinH
Copy link
Owner

A fix was published in v2.2.2

@caugner
Copy link
Author

caugner commented Feb 15, 2022

Sorry for the late response, and thank you! v2.2.2 is working like a charme. 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants