Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e4b0aa3

Browse files
authored
feat: Remove node specific dependencies and code to better support testing in browser environments
* feat: removed filter-console dependency and fallback if process.env is not available (#624) * fix: protect import helpers for setting env variables and comment why try/catch is being used BREAKING CHANGE: `suppressErrorOutput` will now work when explicitly called, even if the `RHTL_DISABLE_ERROR_FILTERING` env variable has been set Fixes #617
1 parent e11b63a commit e4b0aa3

25 files changed

+559
-188
lines changed

‎disable-error-filtering.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
process.env.RHTL_DISABLE_ERROR_FILTERING = true
1+
try {
2+
process.env.RHTL_DISABLE_ERROR_FILTERING = true
3+
} catch {
4+
// falling back in the case that process.env.RHTL_DISABLE_ERROR_FILTERING cannot be accessed (e.g. browser environment)
5+
console.warn(
6+
'Could not disable error filtering as process.env.RHTL_DISABLE_ERROR_FILTERING could not be accessed.'
7+
)
8+
}

‎dont-cleanup-after-each.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
process.env.RHTL_SKIP_AUTO_CLEANUP = true
1+
try {
2+
process.env.RHTL_SKIP_AUTO_CLEANUP = true
3+
} catch {
4+
// falling back in the case that process.env.RHTL_SKIP_AUTO_CLEANUP cannot be accessed (e.g. browser environment)
5+
console.warn(
6+
'Could not skip auto cleanup as process.env.RHTL_SKIP_AUTO_CLEANUP could not be accessed.'
7+
)
8+
}

‎package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
"@types/react": ">=16.9.0",
5151
"@types/react-dom": ">=16.9.0",
5252
"@types/react-test-renderer": ">=16.9.0",
53-
"filter-console": "^0.1.1",
5453
"react-error-boundary": "^3.1.0"
5554
},
5655
"devDependencies": {

‎src/core/cleanup.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,18 @@ function removeCleanup(callback: CleanupCallback) {
1818
cleanupCallbacks = cleanupCallbacks.filter((cb) => cb !== callback)
1919
}
2020

21+
function skipAutoCleanup() {
22+
try {
23+
return !!process.env.RHTL_SKIP_AUTO_CLEANUP
24+
} catch {
25+
// falling back in the case that process.env.RHTL_SKIP_AUTO_CLEANUP cannot be accessed (e.g. browser environment)
26+
return false
27+
}
28+
}
29+
2130
function autoRegisterCleanup() {
2231
// Automatically registers cleanup in supported testing frameworks
23-
if (typeof afterEach === 'function' && !process.env.RHTL_SKIP_AUTO_CLEANUP) {
32+
if (typeof afterEach === 'function' && !skipAutoCleanup()) {
2433
afterEach(async () => {
2534
await cleanup()
2635
})

‎src/core/console.ts

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,41 @@
1-
import filterConsole from 'filter-console'
1+
const consoleFilters = [
2+
/^Theaboveerroroccurredinthe<.*?>component:/, // error boundary output
3+
/^Error:Uncaught.+/ // jsdom output
4+
]
25

36
function suppressErrorOutput() {
4-
if (process.env.RHTL_DISABLE_ERROR_FILTERING) {
5-
return () => {}
6-
}
7+
const originalError = console.error
78

8-
return filterConsole(
9-
[
10-
/^Theaboveerroroccurredinthe<TestComponent>component:/, // error boundary output
11-
/^Error:Uncaught.+/ // jsdom output
12-
],
13-
{
14-
methods: ['error']
9+
const error = (...args: Parameters<typeof originalError>) => {
10+
const message = typeof args[0] === 'string' ? args[0] : null
11+
if (!message || !consoleFilters.some((filter) => filter.test(message))) {
12+
originalError(...args)
1513
}
16-
)
14+
}
15+
16+
console.error = error
17+
18+
return () => {
19+
console.error = originalError
20+
}
21+
}
22+
23+
function errorFilteringDisabled() {
24+
try {
25+
return !!process.env.RHTL_DISABLE_ERROR_FILTERING
26+
} catch {
27+
// falling back in the case that process.env.RHTL_DISABLE_ERROR_FILTERING cannot be accessed (e.g. browser environment)
28+
return false
29+
}
1730
}
1831

1932
function enableErrorOutputSuppression() {
2033
// Automatically registers console error suppression and restoration in supported testing frameworks
21-
if (typeof beforeEach === 'function' && typeof afterEach === 'function') {
34+
if (
35+
typeof beforeEach === 'function' &&
36+
typeof afterEach === 'function' &&
37+
!errorFilteringDisabled()
38+
) {
2239
let restoreConsole!: () => void
2340

2441
beforeEach(() => {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { useEffect } from 'react'
2+
3+
import { ReactHooksRenderer } from '../../types/react'
4+
5+
// This verifies that if process.env is unavailable
6+
// then we still auto-wire up the afterEach for folks
7+
describe('skip auto cleanup (no process.env) tests', () => {
8+
const originalEnv = process.env
9+
let cleanupCalled = false
10+
let renderHook: ReactHooksRenderer['renderHook']
11+
12+
beforeAll(() => {
13+
process.env = {
14+
...process.env,
15+
get RHTL_SKIP_AUTO_CLEANUP(): string | undefined {
16+
throw new Error('expected')
17+
}
18+
}
19+
renderHook = (require('..') as ReactHooksRenderer).renderHook
20+
})
21+
22+
afterAll(() => {
23+
process.env = originalEnv
24+
})
25+
26+
test('first', () => {
27+
const hookWithCleanup = () => {
28+
useEffect(() => {
29+
return () => {
30+
cleanupCalled = true
31+
}
32+
})
33+
}
34+
renderHook(() => hookWithCleanup())
35+
})
36+
37+
test('second', () => {
38+
expect(cleanupCalled).toBe(true)
39+
})
40+
})

‎src/dom/__tests__/errorHook.test.ts

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -142,51 +142,4 @@ describe('error hook tests', () => {
142142
expect(result.error).toBe(undefined)
143143
})
144144
})
145-
146-
describe('error output suppression', () => {
147-
test('should allow console.error to be mocked', async () => {
148-
const consoleError = console.error
149-
console.error = jest.fn()
150-
151-
try {
152-
const { rerender, unmount } = renderHook(
153-
(stage) => {
154-
useEffect(() => {
155-
console.error(`expected in effect`)
156-
return () => {
157-
console.error(`expected in unmount`)
158-
}
159-
}, [])
160-
console.error(`expected in ${stage}`)
161-
},
162-
{
163-
initialProps: 'render'
164-
}
165-
)
166-
167-
act(() => {
168-
console.error('expected in act')
169-
})
170-
171-
await act(async () => {
172-
await new Promise((resolve) => setTimeout(resolve, 100))
173-
console.error('expected in async act')
174-
})
175-
176-
rerender('rerender')
177-
178-
unmount()
179-
180-
expect(console.error).toBeCalledWith('expected in render')
181-
expect(console.error).toBeCalledWith('expected in effect')
182-
expect(console.error).toBeCalledWith('expected in act')
183-
expect(console.error).toBeCalledWith('expected in async act')
184-
expect(console.error).toBeCalledWith('expected in rerender')
185-
expect(console.error).toBeCalledWith('expected in unmount')
186-
expect(console.error).toBeCalledTimes(6)
187-
} finally {
188-
console.error = consoleError
189-
}
190-
})
191-
})
192145
})
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// This verifies that if process.env is unavailable
2+
// then we still auto-wire up the afterEach for folks
3+
describe('error output suppression (no process.env) tests', () => {
4+
const originalEnv = process.env
5+
const originalConsoleError = console.error
6+
7+
beforeAll(() => {
8+
process.env = {
9+
...process.env,
10+
get RHTL_DISABLE_ERROR_FILTERING(): string | undefined {
11+
throw new Error('expected')
12+
}
13+
}
14+
require('..')
15+
})
16+
17+
afterAll(() => {
18+
process.env = originalEnv
19+
})
20+
21+
test('should not patch console.error', () => {
22+
expect(console.error).not.toBe(originalConsoleError)
23+
})
24+
})
25+
26+
export {}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { useEffect } from 'react'
2+
3+
import { ReactHooksRenderer } from '../../types/react'
4+
5+
describe('error output suppression tests', () => {
6+
test('should not suppress relevant errors', () => {
7+
const consoleError = console.error
8+
console.error = jest.fn()
9+
10+
const { suppressErrorOutput } = require('..') as ReactHooksRenderer
11+
12+
try {
13+
const restoreConsole = suppressErrorOutput()
14+
15+
console.error('expected')
16+
console.error(new Error('expected'))
17+
console.error('expected with args', new Error('expected'))
18+
19+
restoreConsole()
20+
21+
expect(console.error).toBeCalledWith('expected')
22+
expect(console.error).toBeCalledWith(new Error('expected'))
23+
expect(console.error).toBeCalledWith('expected with args', new Error('expected'))
24+
expect(console.error).toBeCalledTimes(3)
25+
} finally {
26+
console.error = consoleError
27+
}
28+
})
29+
30+
test('should allow console.error to be mocked', async () => {
31+
const { renderHook, act } = require('..') as ReactHooksRenderer
32+
const consoleError = console.error
33+
console.error = jest.fn()
34+
35+
try {
36+
const { rerender, unmount } = renderHook(
37+
(stage) => {
38+
useEffect(() => {
39+
console.error(`expected in effect`)
40+
return () => {
41+
console.error(`expected in unmount`)
42+
}
43+
}, [])
44+
console.error(`expected in ${stage}`)
45+
},
46+
{
47+
initialProps: 'render'
48+
}
49+
)
50+
51+
act(() => {
52+
console.error('expected in act')
53+
})
54+
55+
await act(async () => {
56+
await new Promise((resolve) => setTimeout(resolve, 100))
57+
console.error('expected in async act')
58+
})
59+
60+
rerender('rerender')
61+
62+
unmount()
63+
64+
expect(console.error).toBeCalledWith('expected in render')
65+
expect(console.error).toBeCalledWith('expected in effect')
66+
expect(console.error).toBeCalledWith('expected in act')
67+
expect(console.error).toBeCalledWith('expected in async act')
68+
expect(console.error).toBeCalledWith('expected in rerender')
69+
expect(console.error).toBeCalledWith('expected in unmount')
70+
expect(console.error).toBeCalledTimes(6)
71+
} finally {
72+
console.error = consoleError
73+
}
74+
})
75+
})

‎src/dom/pure.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import ReactDOM from 'react-dom'
1+
import *asReactDOM from 'react-dom'
22
import { act } from 'react-dom/test-utils'
33

44
import { RendererProps, RendererOptions } from '../types/react'

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /