Skip to content

Commit

Permalink
fix: don't patch console.error for pure imports
Browse files Browse the repository at this point in the history
Added RHTL_DISABLE_ERROR_FILTERING environment variable toggle to globally disable console filtering.

Fixes #546
  • Loading branch information
mpeyper committed Jan 18, 2021
1 parent 68460e4 commit 36e5a27
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 4 deletions.
1 change: 1 addition & 0 deletions disable-error-filtering.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
process.env.RHTL_DISABLE_ERROR_FILTERING = true
49 changes: 48 additions & 1 deletion docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ route: '/reference/api'
- [`cleanup`](/reference/api#cleanup)
- [`addCleanup`](/reference/api#addcleanup)
- [`removeCleanup`](/reference/api#removecleanup)
- [`console.error`](/reference/api#consoleerror)

---

Expand Down Expand Up @@ -154,7 +155,7 @@ module.exports = {
```

Alternatively, you can change your test to import from `@testing-library/react-hooks/pure` instead
of the regular imports. This applys to any of our export methods documented in
of the regular imports. This applies to any of our export methods documented in
[Rendering](/installation#being-specific).

```diff
Expand Down Expand Up @@ -270,3 +271,49 @@ Interval checking is disabled if `interval` is not provided as a `falsy`.
_Default: 1000_

The maximum amount of time in milliseconds (ms) to wait.

---

## `console.error`

In order to catch errors that are produced in all parts of the hook's lifecycle, the test harness
used to wrap the hook call includes an
[Error Boundary](https://reactjs.org/docs/error-boundaries.html) which causes a
[significant amount of output noise](https://reactjs.org/docs/error-boundaries.html#component-stack-traces)
in tests.

To keep test output clean, we patch `console.error` when `renderHook` is called to filter out the
unnecessary logging and restore the original version during cleanup. This side-effect can affect
tests that also patch `console.error` (e.g. to assert a specific error message get logged) by
replacing their custom implementation as well.

### Disabling `console.error` filtering

Importing `@testing-library/react-hooks/disable-error-filtering.js` in test setup files disable the
error filtering feature and not patch `console.error` in any way.

For example, in [Jest](https://jestjs.io/) this can be added to your
[Jest config](https://jestjs.io/docs/configuration):

```js
module.exports = {
setupFilesAfterEnv: [
'@testing-library/react-hooks/disable-error-filtering.js'
// other setup files
]
}
```

Alternatively, you can change your test to import from `@testing-library/react-hooks/pure` instead
of the regular imports. This applies to any of our export methods documented in
[Rendering](/installation#being-specific).

```diff
- import { renderHook, cleanup, act } from '@testing-library/react-hooks'
+ import { renderHook, cleanup, act } from '@testing-library/react-hooks/pure'
```

If neither of these approaches are suitable, setting the `RHTL_DISABLE_ERROR_FILTERING` environment
variable to `true` before importing `@testing-library/react-hooks` will also disable this feature.

> Please note that this may result is a significant amount of additional logging in you test output.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"native",
"server",
"pure",
"disable-error-filtering.js",
"dont-cleanup-after-each.js"
],
"author": "Michael Peyper <mpeyper7@gmail.com>",
Expand Down
39 changes: 39 additions & 0 deletions src/dom/__tests__/errorSuppression.disabled.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { renderHook } from '..'

describe('error output suppression (disabled) tests', () => {
function useError(throwError?: boolean) {
if (throwError) {
throw new Error('expected')
}
return true
}

const originalConsoleError = console.error
const mockConsoleError = jest.fn()

beforeAll(() => {
process.env.RHTL_DISABLE_ERROR_FILTERING = 'true'
})

beforeEach(() => {
console.error = mockConsoleError
})

afterEach(() => {
console.error = originalConsoleError
})

test('should not suppress error output', () => {
const { result } = renderHook(() => useError(true))

expect(result.error).toEqual(Error('expected'))
expect(mockConsoleError).toBeCalledWith(
expect.stringMatching(/^Error: Uncaught \[Error: expected\]/),
expect.any(Error)
)
expect(mockConsoleError).toBeCalledWith(
expect.stringMatching(/^The above error occurred in the <TestComponent> component:/)
)
expect(mockConsoleError).toBeCalledTimes(2)
})
})
35 changes: 35 additions & 0 deletions src/dom/__tests__/errorSuppression.pure.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { renderHook } from '../pure'

describe('error output suppression (pure) tests', () => {
function useError(throwError?: boolean) {
if (throwError) {
throw new Error('expected')
}
return true
}

const originalConsoleError = console.error
const mockConsoleError = jest.fn()

beforeEach(() => {
console.error = mockConsoleError
})

afterEach(() => {
console.error = originalConsoleError
})

test('should not suppress error output', () => {
const { result } = renderHook(() => useError(true))

expect(result.error).toEqual(Error('expected'))
expect(mockConsoleError).toBeCalledWith(
expect.stringMatching(/^Error: Uncaught \[Error: expected\]/),
expect.any(Error)
)
expect(mockConsoleError).toBeCalledWith(
expect.stringMatching(/^The above error occurred in the <TestComponent> component:/)
)
expect(mockConsoleError).toBeCalledTimes(2)
})
})
2 changes: 2 additions & 0 deletions src/dom/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { autoRegisterCleanup } from '../core/cleanup'
import { enableErrorOutputSuppression } from '../helpers/console'

autoRegisterCleanup()
enableErrorOutputSuppression()

export * from './pure'
12 changes: 11 additions & 1 deletion src/helpers/console.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import filterConsole from 'filter-console'

let errorOutputSuppressionEnabled = false

function enableErrorOutputSuppression() {
errorOutputSuppressionEnabled = true
}

function suppressErrorOutput() {
if (!errorOutputSuppressionEnabled || process.env.RHTL_DISABLE_ERROR_FILTERING) {
return () => {}
}

// The error output from error boundaries is notoriously difficult to suppress. To save
// our users from having to work it out, we crudely suppress the output matching the patterns
// below. For more information, see these issues:
Expand All @@ -19,4 +29,4 @@ function suppressErrorOutput() {
)
}

export { suppressErrorOutput }
export { enableErrorOutputSuppression, suppressErrorOutput }
4 changes: 2 additions & 2 deletions src/helpers/promises.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ async function callAfter(callback: () => void, ms: number) {
callback()
}

function isPromise<T>(value: unknown): boolean {
return value !== undefined && typeof (value as PromiseLike<T>).then === 'function'
function isPromise(value: unknown): boolean {
return value !== undefined && typeof (value as PromiseLike<unknown>).then === 'function'
}

export { resolveAfter, callAfter, isPromise }
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { autoRegisterCleanup } from './core/cleanup'
import { enableErrorOutputSuppression } from './helpers/console'

autoRegisterCleanup()
enableErrorOutputSuppression()

export * from './pure'
2 changes: 2 additions & 0 deletions src/native/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { autoRegisterCleanup } from '../core/cleanup'
import { enableErrorOutputSuppression } from '../helpers/console'

autoRegisterCleanup()
enableErrorOutputSuppression()

export * from './pure'
2 changes: 2 additions & 0 deletions src/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { autoRegisterCleanup } from '../core/cleanup'
import { enableErrorOutputSuppression } from '../helpers/console'

autoRegisterCleanup()
enableErrorOutputSuppression()

export * from './pure'

0 comments on commit 36e5a27

Please sign in to comment.