跳转到内容

Testing

我们认同 Testing Library 的指导原则

  • “你的测试越贴近软件的实际使用方式,就越能给你信心。”

我们鼓励你像用户与原子和组件交互那样编写测试,将 Jotai 视为实现细节。

以下是使用 React Testing Library 的示例:

Counter.tsx

import { atom, useAtom } from 'jotai'
export const countAtom = atom(0)
export function Counter() {
const [count, setCount] = useAtom(countAtom)
return (
<h1>
<p>{count}</p>
<button onClick={() => setCount((c) => c + 1)}>one up</button>
</h1>
)
}

Counter.test.ts

import React from 'react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Counter } from './Counter'
test('should increment counter', () => {
// Arrange
render(<Counter />)
const counter = screen.getByText('0')
const incrementButton = screen.getByText('one up')
// Act
await userEvent.click(incrementButton)
// Assert
expect(counter.textContent).toEqual('1')
})

你可能希望在开始测试前为原子注入任意值。例如,假设计数器的上限为 100,我们来测试它在达到 100 后是否不再递增。为此,只需使用 Provider,并导出你的原子以便注入值。

import React from 'react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { useHydrateAtoms } from 'jotai/utils'
import { countAtom, Counter } from './Counter'
import { Provider } from 'jotai'
const HydrateAtoms = ({ initialValues, children }) => {
useHydrateAtoms(initialValues)
return children
}
const TestProvider = ({ initialValues, children }) => (
<Provider>
<HydrateAtoms initialValues={initialValues}>{children}</HydrateAtoms>
</Provider>
)
const CounterProvider = () => {
return (
<TestProvider initialValues={[[countAtom, 100]]}>
<Counter />
</TestProvider>
)
}
test('should not increment on max (100)', () => {
render(<CounterProvider />)
const counter = screen.getByText('100')
const incrementButton = screen.getByText('one up')
await userEvent.click(incrementButton)
expect(counter.textContent).toEqual('100')
})

如果你有复杂的原子,有时你可能希望单独测试它们。

为此,可以使用 React Hooks Testing Library。以下是一个示例:

countAtom.ts

import { useAtom } from 'jotai'
import { atomWithReducer } from 'jotai/utils'
const reducer = (state: number, action?: 'INCREASE' | 'DECREASE') => {
switch (action) {
case 'INCREASE':
return state + 1
case 'DECREASE':
return state - 1
case undefined:
return state
}
}
export const countAtom = atomWithReducer(0, reducer)

countAtom.test.ts

import { renderHook, act } from '@testing-library/react-hooks'
import { useAtom } from 'jotai'
import { countAtom } from './countAtom'
test('should increment counter', () => {
const { result } = renderHook(() => useAtom(countAtom))
act(() => {
result.current[1]('INCREASE')
})
expect(result.current[0]).toBe(1)
})

当然,你也可以用同样的方式测试 React Native 组件,无论是否使用 Provider。

import React from 'react'
import { render, fireEvent } from '@testing-library/react-native'
import { Counter } from './counter'
test('should increment counter', () => {
// Arrange
const { getByText } = render(<Counter />)
const counter = getByText('0')
const incrementButton = getByText('one up')
// Act
fireEvent.press(incrementButton)
// Assert
expect(counter.props.children.toString()).toEqual('1')
})