systems-obscure/posts/suppressing-logs-errors-jest.md

61 lines
1.8 KiB
Markdown

---
title: "Suppressing logs and errors in Jest"
slug: /suppressing-logs-errors-jest/
date: 2024-09-10
tags: ["javascript", "unit-testing"]
---
It annoys me when I am working on a project and a previous developer has left
logs and/or thrown errors in their unit tests. To be clear: I mean when the
developer is testing that an error is thrown in the right circumstances, not a
test failure arising from regression. The former makes the latter harder to
detect by polluting the output.
This can be so easily prevented.
Take the following function:
```js
function sillyFunction(int) {
console.info(`Now handling ${int}`)
if (int > 2) throw new Error(`Error: int ${int} is greater than two`)
else return
}
```
To avoid pointlessly logging to the console and to confirm the error without
actually throwing it:
```js
import { jest } from "@jest/globals"
describe("sillyFunction", () => {
beforeEach(() => {
jest.spyOn(console, "info").mockImplementation(() => {})
})
afterEach(() => {
console.info.mockRestore()
})
it("throws error if `int` is less than 2", () => {
expect(() => {
sillyFunction(3)
}).toThrow("Error: int 3 is greater than two")
})
})
```
The `spyOn` method silences the output of `console.error` by returning nothing.
If we wish, we can still confirm that the log is acting as expected during the
runtime of the test by again using a spy:
```js
const consoleInfoSpy = jest.spyOn(console, "info")
expect(consoleInfoSpy).toHaveBeenCalledWith("Now handling x")
```
The `toThrow` method catches the error before it hits the console and allows us
to interrogate it. If it was an asynchronous function under test, we would need
to use the matcher `rejects.toThrow`. This waits for the promise to resolve
before checking if it has been rejected.