React+TypeScript+firebaseで作成しているアプリのユニットテストを行おうとしているのですが、テストしようとしているコンポーネントがFirebaseと何らかのやりとりをしている場合に、テストがうまくいかずFirebaseError
となります。
テストについていろいろと調べていたところ、APIなどの外部との通信を行うアプリをテストする場合、コンポーネントをモック化してテストコードの中にどの様なデータが帰ってくるかなどを予め記述しておいてテストを行うというのが良さそうだと気づきました。
しかしながらいろいろと調べても、自分の理解力が乏しいのか、うまくいく様なテストコードを記述することができなかったので、質問させていただきます。
実現したいこと
firebaseとの通信をするハンドラを含む関数コンポーネント内で様々なテストを行える様にしたい
質問
① API通信などを含むreactの関数コンポーネントをテストするときはどの様にmockすればいいのか
② そもそもmockするという考え方は間違っていて、別のやり方があるのかどうか
ソースコード
以下はLogin.tsx
です。
Login.tsx
1export default function Login() { 2 const classes = useStyles(); 3 const emailRef = useRef(); 4 const passwordRef = useRef(); 5 const { login }: any = useAuth(); 6 const [error, setError] = useState(""); 7 const [loading, setLoading] = useState(false); 8 const [email, setEmail] = useState(""); 9 const [password, setPassword] = useState(""); 10 const history = useHistory(); 11 12 const inputEmail = useCallback( 13 (event) => { 14 setEmail(event.target.value); 15 }, 16 [setEmail] 17 ); 18 19 const inputPassword = useCallback( 20 (event) => { 21 setPassword(event.target.value); 22 }, 23 [setPassword] 24 ); 25 26 async function handleSubmit(e: any) { 27 e.preventDefault(); 28 29 setError(""); 30 setLoading(true); 31 return login(email, password) 32 .then(() => { 33 history.push("/"); 34 }) 35 .catch((error: any) => { 36 setError("failed!!"); 37 }) 38 .finally(() => { 39 setLoading(false); 40 }); 41 } 42 43 const onClickGuestButton = () => { 44 setError(""); 45 setLoading(true); 46 return login("guest@example.com", "password") 47 .then(() => { 48 history.push("/"); 49 }) 50 .catch((error: any) => { 51 setError("failed!!"); 52 }) 53 .finally(() => { 54 setLoading(false); 55 }); 56 }; 57 58 return( 59 {/*少し長いので省略しています。*/} 60 )
以下はLogin.test.tsx
です。
Login.test.tsx
1import * as React from "react"; 2import Login from "../Login"; 3import { configure, mount, shallow } from "enzyme"; 4import Adapter from "enzyme-adapter-react-16"; 5// import { Login as mockLogin } from "../Login"; 6import ReactDOM from "react-dom"; 7 8configure({ adapter: new Adapter() }); 9 10jest.mock("../Login", () => { 11 return login("fake@example.com", "password"){ 12 return Promise.resolve(fakeUser) 13 } 14}); 15 16describe("Login", () => { 17 18 it("should return currect user", () => { 19 // const wrapper = shallow(<Login />); 20 // expect(wrapper.find("button").length).toBe(2); 21 const fakeUser = { 22 username: "FakeMan", 23 email: "fake@example.com", 24 uid: "KN8qXkuYmPf2i9kvzC2mQylZQPo1", 25 }; 26 jest.spyOn(global, "fetch").mockImplementation((): any => 27 Promise.resolve({ 28 json: () => Promise.resolve(fakeUser), 29 }) 30 ); 31 }); 32});
jest.mock()
でコンポーネントや関数などをモック化することができそうというのはわかったのですが、今回の場合どの様にすればいいのかわかりません。
また、Firebaseとの通信を行わないコンポーネントでテストを実行してみると、(当たり前ですが)FirebaseError
は起こらず、普通にテストがpassしました。
このことから、Firebaseとの通信がテストに何らか影響しているのは確かだと思っています。
[Jest+TypeScript] クラスと関数のモック化
を参考にしてみましたが、結局よくわからず...
何かいい解決策はありますでしょうか?
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。