react测试库,如何在useEffect中测试setState



我写了一个组件,它做两件事:

  1. 显示一条横幅:当netInfo.isConnected变化为false或当netInfo.isInternetReachable变化为3 seconds后仍为false
  2. 隐藏横幅:当netInfo.isConnectednetInfo.isInternetReachable更改为true

For(1)在3秒后隐藏是可能的,通过创建一个ref,可以在3秒后读取

(2)是非常直接的,一个简单的useEffect可以帮助我做到这一点,我的组件看起来像这样:

export function OfflineModeContainer({ children }: { children: ReactNode }) {
const netInfo = useNetInfo()
const [show, setShow] = useState(!netInfo.isConnected)
const isInternetReachable = useRef(netInfo.isInternetReachable)
useEffect(() => {
setShow(!netInfo.isConnected)
}, [netInfo.isConnected])
useEffect(() => {
isInternetReachable.current = netInfo.isInternetReachable
let timer: number | undefined
if (!isInternetReachable.current) {
timer = setTimeout(() => {
if (!isInternetReachable.current) {
setShow(true)
}
}, 3000)
} else {
setShow(false)
}
return () => {
if (timer) {
clearInterval(timer)
}
}
}, [netInfo.isInternetReachable])
return (
<View>
<View>{children}</View>
{show ? (
<View>
<View>{t`aucune connexion internet.`}</<View>
</<View>
) : null}
</View>
)
}

这很好。我现在想测试两个useEffect使用React测试库。

  • 当其中一个值切换到true时,我如何测试第一个useEffect和第二个useEffect的隐藏功能?我认为这里的困难是在测试期间过了一段时间后触发钩子
  • 如何测试setTimeout异步操作?如何测试clearTimer

现场演示再现

https://codesandbox.io/s/react-native-test-forked-7nc5zc

不幸的是,由于已知的jest.mock开放问题,我不能在codesandbox中使用mock,直到2018年仍然开放https://github.com/codesandbox/codesandbox-client/issues/513

由于这个原因,我在这里添加了测试日志:
$ TZ=UTC JEST=true jest --forceExit /home/dka/workspace/github.com/pass-culture/pass-culture-app-native/src/libs/network/__tests__/OfflineModeContainer.test.tsx
FAIL  src/libs/network/__tests__/OfflineModeContainer.test.tsx (5.178 s)
<OfflineModeContainer />
✓ should render children and show banner when offline at init when isConnected is false (36 ms)
✓ should render children and not show banner when offline at init when isConnected is true (5 ms)
✕ should not show "aucune connexion internet." at init, then show when isConnected is false, then hide when isConnected switch back to true (558 ms)
● <OfflineModeContainer /> › should not show "aucune connexion internet." at init, then show when isConnected is false, then hide when isConnected switch back to true
expect(received).toBeFalsy()
Received: {"_fiber": {"_debugHookTypes": null, "_debugID": 163, "_debugNeedsRemount": false, "_debugOwner": [FiberNode], "_debugSource": null, "actualDuration": 0, "actualStartTime": -1, "alternate": null, "child": [FiberNode], "childLanes": 0, "dependencies": null, "elementType": [Function Component], "firstEffect": null, "flags": 1, "index": 0, "key": null, "lanes": 0, "lastEffect": null, "memoizedProps": [Object], "memoizedState": null, "mode": 0, "nextEffect": null, "pendingProps": [Object], "ref": null, "return": [FiberNode], "selfBaseDuration": 0, "sibling": null, "stateNode": [Component], "tag": 1, "treeBaseDuration": 0, "type": [Function Component], "updateQueue": [Object]}}
50 |       </OfflineModeContainer>
51 |     )
> 52 |     expect(await renderAPI.queryByText('aucune connexion internet.')).toBeFalsy()
|                                                                       ^
53 |   })
54 | })
55 |

我是这样解决这个问题的:

import React from 'react'
import { View, Text } from 'react-native'
import { useNetInfoContext as useNetInfoContextDefault } from 'libs/network/NetInfoWrapper'
import { OfflineModeContainer } from 'libs/network/OfflineModeContainer'
import { render } from '@testing-library/react-native'
jest.mock('libs/network/useNetInfo', () => jest.requireMock('@react-native-community/netinfo'))
const mockUseNetInfoContext = useNetInfoContextDefault as jest.Mock
describe('<OfflineModeContainer />', () => {
mockUseNetInfoContext.mockImplementation(() => ({ isConnected: false }))
it('should not show "aucune connexion internet." at init, then show when isConnected is false, then hide when isConnected switch back to true', () => {
mockUseNetInfoContext.mockImplementationOnce(() => ({
isConnected: true,
isInternetReachable: true,
}))
const renderAPI = renderOfflineModeContainer()
expect(renderAPI.queryByText('aucune connexion internet.')).toBeFalsy()
mockUseNetInfoContext.mockImplementationOnce(() => ({
isConnected: false,
isInternetReachable: false,
}))
renderAPI.rerender(getJsx())
expect(renderAPI.queryByText('aucune connexion internet.')).toBeTruthy()
})
})
// for rerender, it cannot be static, it has to be new
const getJsx = () => (
<OfflineModeContainer>
<View>
<Text>Hello World</Text>
</View>
</OfflineModeContainer>
)
function renderOfflineModeContainer() {
return render(getJsx())
}

最新更新