我写了一个简单的 React 钩子,想用react-hooks-testing-library
.
这个钩子调用一个异步函数一次provider
和domain
变量,然后一旦它被解决,就会将数据置于状态并返回它。
我在任何地方都找不到如何测试异步钩子,但发现了这个:How to test custom async/await hook with react-hooks-testing-library。这个问题没有答案,但至少我发现我需要调用waitForNextUpdate
w/ 进行测试useEffect
。
我的测试的问题是它只运行一次钩子(在挂载时),而不是在设置提供者和域时。所以它总是挂在默认值上。如何让它重新触发钩子以实际调用getENS
和设置数据?
这是钩子的样子:
import { useEffect, useState } from 'react'
import { getENS, ResolvedENS } from 'get-ens'
import type { Provider } from '@ethersproject/providers'
const ac = new AbortController()
export const useENS = (provider: Provider, domain: string): ResolvedENS => {
const [data, set] = useState<ResolvedENS>({ address: null, owner: null, records: { web: {} } })
useEffect(() => {
const load = async () => {
const data = await getENS(provider)(domain, { signal: ac.signal })
set(data)
}
if (provider && domain) load()
return () => ac.abort()
}, [domain, provider])
return data
}
这就是我的测试的样子:
import { describe, it, jest } from '@jest/globals'
import { renderHook } from '@testing-library/react-hooks'
import { useENS } from '../packages/use-ens/src/index'
import { providers } from 'ethers'
import fetch from 'fetch-mock'
jest.setTimeout(30000)
describe('use-ens', () => {
it('should return resolved data for a domain', async () => {
fetch.mock('*', {
data: {
domains: [
{
resolvedAddress: { id: '0xf75ed978170dfa5ee3d71d95979a34c91cd7042e' },
resolver: {
texts: ['avatar', 'color', 'description', 'email', 'url', 'com.github', 'com.instagram', 'com.twitter']
},
owner: { id: '0xf75ed978170dfa5ee3d71d95979a34c91cd7042e' }
}
]
}
})
const provider = new providers.InfuraProvider('homestead', 'INFURA_API_KEY')
const { result, waitForNextUpdate } = renderHook<[providers.BaseProvider, string], ReturnType<typeof useENS>>(() =>
useENS(provider, 'foda.eth')
)
console.log(result.current)
await waitForNextUpdate()
console.log(result.current)
})
})
当我运行测试时,我收到此错误:
> NODE_OPTIONS=--experimental-vm-modules pnpx jest tests
console.log
{ address: null, owner: null, records: { web: {} } }
at Object.<anonymous> (tests/use-ens.test.ts:30:13)
FAIL tests/use-ens.test.ts
use-ens
✕ should return resolved data for a domain (1049 ms)
● use-ens › should return resolved data for a domain
Timed out in waitForNextUpdate after 1000ms.
30 | console.log(result.current)
31 |
> 32 | await waitForNextUpdate()
| ^
33 |
34 | console.log(result.current)
35 | })
at waitForNextUpdate (node_modules/.pnpm/@testing-library+react-hooks@7.0.1_react-dom@17.0.2+react@17.0.2/node_modules/@testing-library/react-hooks/lib/core/asyncUtils.js:102:13)
at Object.<anonymous> (tests/use-ens.test.ts:32:5)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 5.215 s
Ran all test suites matching /tests/i.
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
console.error
Warning: An update to TestComponent inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
at TestComponent (/home/v1rtl/Coding/proj/node_modules/.pnpm/@testing-library+react-hooks@7.0.1_react-dom@17.0.2+react@17.0.2/node_modules/@testing-library/react-hooks/lib/helpers/createTestHarness.js:22:5)
13 | export const useENS = (provider: Provider, domain: string): ResolvedENS => {
14 | const [data, set] = useState<ResolvedENS>({ address: null, owner: null, records: { web: {} } })
> 15 |
| ^
16 | useEffect(() => {
17 | const load = async () => {
18 | const data = await getENS(provider)(domain, { signal: ac.signal })
console.error
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
at TestComponent (/home/v1rtl/Coding/proj/node_modules/.pnpm/@testing-library+react-hooks@7.0.1_react-dom@17.0.2+react@17.0.2/node_modules/@testing-library/react-hooks/lib/helpers/createTestHarness.js:22:5)
13 | export const useENS = (provider: Provider, domain: string): ResolvedENS => {
14 | const [data, set] = useState<ResolvedENS>({ address: null, owner: null, records: { web: {} } })
> 15 |
| ^
16 | useEffect(() => {
17 | const load = async () => {
18 | const data = await getENS(provider)(domain, { signal: ac.signal })
at printWarning (node_modules/.pnpm/react-dom@17.0.2_react@17.0.2/node_modules/react-dom/cjs/react-dom.development.js:67:30)
ERROR Test failed. See above for more details.
我还创建了一个包含 Jest 配置文件的要点:https ://gist.github.com/talentlessguy/aad20875b1e4406024e454485a73b1f9
这里也是get-ens
我导入的库的来源:https ://github.com/talentlessguy/get-ens