NISHIO Hirokazu[Translate]
Jestメモ Day3
Jestメモ Day3
--- day 3
MissingAPIError: indexedDB API missing
Firestoreの時と同様にIndexeDBに触れるコードも分離してモックで置き換える必要がある
前回、Firestoreから値を取った後のコードを下記のように切り出してエクスポートし、これを直接呼び出すPromiseでgetNewTalkIDを置き換える、というモックをした
ts
// exported for test export const _gotNewTalkID = (text: string) => { return localDB.talks .orderBy("id") .reverse() .limit(1) .toArray() .then((x) => { const previousTalkID = x[0]?.TalkID; if (previousTalkID !== undefined) { setGlobal({ TalkID: text, previousTalkID: x[0].TalkID }); } else { setGlobal({ TalkID: text, previousTalkID: "" }); } localDB.talks.add({ TalkID: text }); }); };
Promiseの型を明記しつつ読み出し、利用、書き込みの3つの関数に分割
Jestのモックは同一モジュール内の呼び出しに影響を与えないから、IndexedDBに触れるところだけ別モジュールにくくり出してモックしよう
ユーザーモジュールのモック doc
なるほど
でも2通りの実装が欲しいな
__mocks__/managePreviousTalkID.ts
// no previoud id export const getPreviousTalkID = (): Promise<string> => { return Promise.resolve(""); }; export const MOCK_PREVIOUS_ID_EXISTS = (): Promise<string> => { return Promise.resolve("test"); }; export const updatePreviousTalkID = (currentTalkID: string): void => {};
トップ画面の描画テストは動くようになった
jest.mockをテストケースの中ではなくトップレベルに置かないと期待通りにモックされない、なぜ?
複数のモックの挙動を切り替えてテストしたいのだが…
>jest.mockをテストケースの中ではなくトップレベルに置かないと期待通りにモックされない、なぜ?
>docs: ES module importsを使用している場合、通常はテストファイルの先頭でimport宣言を書くことが多いでしょう。 しかしモジュールがそれらを使用するのに先立ち、Jestにモックを使用するよう指示する必要があります。 このため、Jestは自動的にjest.mockコールを自動的にモジュールの先頭に(importを行う前に)移動します。
「先におかないといけないのでは?」と思ったがESLintが "Import in body of module; reorder to top." と文句を言うので後に置いてた。
後においても動くのでmockのタイミングでインポート済みのものを置き換えるのかなと思ってたがそういうことではないようだ。
spyOnなら確実にそのタイミングでの差し替えを行うので、重ねてspyOnすることにしてみた
previousTalkIDが存在するかどうかでメニューの表示が異なる、というテストが一応動いた
しかし(1)の部分、メニューが実際に存在しないのか、まだ非同期の再描画が終わってないのか判断がつかないと思う
タイムアウトするまで待てば判断つくけど、テストが遅くなるから嫌だし
ts
const { container } = render(<App />); expect(container).toMatchSnapshot(); fireEvent.click(screen.getByLabelText("menu")); expect(screen.queryByText("Re-enter to Last Talk")).toBeNull(); // (1) jest .spyOn(managePreviousTalkIDModule, "getPreviousTalkID") .mockResolvedValue("test"); render(<App />); await waitFor(() => screen.getByText("Re-enter to Last Talk")); expect(screen.queryByText("Re-enter to Last Talk")).not.toBeNull();



次回「useStateをモックで置き換えたらいいのでは?」

"Engineer's way of creating knowledge" the English version of my book is now available on [Engineer's way of creating knowledge]

(C)NISHIO Hirokazu / Converted from [Scrapbox] at [Edit]