JotaiでAtomの挙動をテストする方法
Jotaiを用いてReact開発している際、作ったAtomの挙動をテストしたいことがあるかと思います。調べてみると思いの外参考になる情報が無かったので、簡単なテスト方法を紹介します。
ロジック部分を別関数に切り分け、その関数単体でテストを行う方針も考えられますので、そちらを検討してみるのも良いかもしれません。
テスト方法
store
のget
メソッドやset
メソッドを用いてテストを用いるのが良いです。useAtom
・useAtomValue
・useSetValue
などはHookなので基本的にはReactコンポーネント内で使用します。そのため、Atomがちゃんと値を計算してくれるかなどをJestでお手軽にテストするのには向きません。
JotaiにおいてAtomは大きく分けて2つあります。primitive atomとderived atomです。derived atomはprimitive atomを用いて計算されるatomになります(Recoilのselectorに近いかも)。derived atomは以下の3つに区分出来ます。
- Read-only Atom
- Write-only Atom
- Read-Write Atom
テストの観点から言うとRead-Write Atomは先2つと同じなのでこの記事では割愛します。
Read-only Atomのテスト
Read-only AtomはAtomの値を読み取るAtomです。例えば以下のdoubledNumberAtom
はread-only atomです。
const numberAtom = atom(0); // primitive atom
const doubledNumberAtom = atom((get) => get(numberAtom) * 2);
このAtomはstore
を用いて以下のようにテストすることが出来ます。
test("should add 1", () => {
const store = createStore();
store.set(numberAtom, 1); // numberAtomの初期値を設定
const newNumber = store.get(doubledNumberAtom); // doubledNumberAtomの値を読み出す
expect(newNumber).toBe(2);
})
Write-only Atomのテスト
Write-only Atomは文字通りAtomの値を更新するだけのAtomです。もちろんreadすることは出来ません。例えば以下のようなWrite-only Atomを考えます。
const numberAtom = atom(0); // primitive atom
const addNumberAtom = atom(
null,
(get, set, num: number) => set(numberAtom, get(countAtom) + num)
);
addNumberAtom
はnumberAtom
の更新を行うだけのAtomです。read関数を持たずcountAtom
などの値を読むわけではありません。例えば以下のようにコンポーネント内で用います。
const Component = () => {
const setAddNumberAtom = useSetAtom(addNumberAtom);
return (
<button onClick={() => setAddNumberAtom(1)}>increment</button>
)
}
こちらも以下のようにstore
を用いてテストすることが出来ます。
test("should add 1", () => {
const store = createStore();
store.set(numberAtom, 1); // numberAtomの初期値を設定
store.set(addNumberAtom, 1); // addNumberAtomとその引数を渡す
const newNumber = store.get(numberAtom); // 更新されたnumberAtomの値を読み出す
expect(newNumber).toBe(2);
})
引数を受け取らないWrite-only Atomの場合はset
で引数を渡さなくて大丈夫です。
const incrementNumberAtom = atom(
null,
(get, set) => set(numberAtom, get(countAtom) + 1)
);
test("should add 1", () => {
const store = createStore();
store.set(numberAtom, 1);
store.set(addNumberAtom); // 引数無しでOK
const newNumber = store.get(numberAtom);
expect(newNumber).toBe(2);
})
Discussion