iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
自我挑戰組

<< 測試魔法 >> 這能動嗎?不然就測測看好了!系列 第 20

情境練習:使用 Context 報錯情境

  • 分享至 

  • xImage
  •  

今天來紀錄下遇過的問題,在元件中遇到透過 useContext 取值時可能會遇到的問題及解決方法!

接下來來介紹可能遇到的兩種報錯情形:

情況一: Context value 傳送單一值

首先來看範例程式碼,透過在 App 層級創建 Context 並包覆子層級 TodoList ,後傳入單一值 todoData ,並於子層級將 todoData 取出來使用後渲染列表:

父層級

import React, { useState, useEffect } from "react";
import "./App.css";
import TodoList from "./Loading";
import axios from "axios";

export const TodoDataContext = React.createContext();

const App = () => {
  const [todoData, setTodoData] = useState(null);

  const fetchData = async () => {
    const response = await axios.get(
      `https://jsonplaceholder.typicode.com/todos`
    );
    setTodoData(response.data);
  };

  useEffect(() => {
    fetchData();
  }, []);

  return (
    <>
      <TodoDataContext.Provider value={todoData}>
        <TodoList />
      </TodoDataContext.Provider>
    </>
  );
};

export default App;

子層級

import React, { useContext } from "react";
import { TodoDataContext } from "./App.js";

const TodoList = () => {
  const todoData = useContext(TodoDataContext);

  return (
    <>
      <ul>
        {todoData &&
          todoData.map((item) => <li key={item.id}>{item.title}</li>)}
      </ul>
    </>
  );
};
export default TodoList;

在撰寫測試時會發現即使透過 waitFor 非同步等待回傳值,依然無法成功等到值:

測試

import { render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import TodoList from "./Loading";

// delectus aut autem 為 api 回傳值
test("Test get value from Context", async () => {
  render(<TodoList />);
  await waitFor(() => {
    expect(screen.getByText("delectus aut autem")).toBeInTheDocument();
  });
});

https://ithelp.ithome.com.tw/upload/images/20221005/20139066aKkp8FlpWc.png

情況二:Context value 傳送物件

修改一下上方的範例程式碼,將傳送的從純值,改成傳送物件,物件內放入一個函式 fetchData ,再於子層級將 fetchData 拿出來使用!

父層級

import React from "react";
import "./App.css";
import TodoList from "./Loading";
import axios from "axios";

export const TodoDataContext = React.createContext();

const App = () => {

  const fetchData = async () => {
    const response = await axios.get(
      `https://jsonplaceholder.typicode.com/todos`
    );
    return response.data;
  };

  return (
    <>
      <TodoDataContext.Provider value={{fetchData}}>
        <TodoList />
      </TodoDataContext.Provider>
    </>
  );
};

export default App;

子層級

import React, { useContext, useEffect, useState } from "react";
import { TodoDataContext } from "./App.js";

const TodoList = () => {
  const { fetchData } = useContext(TodoDataContext);
  const [todoData, setTodoData] = useState(null);
  const init = async () => {
    const data = await fetchData();
    setTodoData(data);
  };
  useEffect(() => {
    init();
  }, []);

  return (
    <>
      <ul>
        {todoData &&
          todoData.map((item) => <li key={item.id}>{item.title}</li>)}
      </ul>
    </>
  );
};
export default TodoList;

測試的部分程式碼與問題一相同,但能觀察到報不一樣的錯誤:

import { render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import TodoList from "./Loading";

// delectus aut autem 為 api 回傳值
test("Test get value from Context", async () => {
  render(<TodoList />);
  await waitFor(() => {
    expect(screen.getByText("delectus aut autem")).toBeInTheDocument();
  });
});

https://ithelp.ithome.com.tw/upload/images/20221005/20139066z2eTRnyXVy.png

解決方法

判斷測試 render 時無法取得從 Context 取得的值,所以透過引入 TodoDataContext 於 render 時包覆元件,並傳入 mock 的 fetchData 解決報錯。

import { render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import { TodoDataContext } from "./App.js";
import TodoList from "./Loading";

test("Test get value from Context", async () => {
  const fetchData = jest
    .fn()
    .mockReturnValue([{ id: "test", title: "delectus aut autem" }]);
  render(
    <TodoDataContext.Provider value={{ fetchData }}>
      <TodoList />
    </TodoDataContext.Provider>
  );

  await waitFor(() => {
    expect(screen.getByText("delectus aut autem")).toBeInTheDocument();
  });
});

可以發現測試順利運行通過:
https://ithelp.ithome.com.tw/upload/images/20221006/20139066JidwaPq9p9.png
之前常常卡在 Context 取得的資料上透過這個方法就能成功運行測試了!


上一篇
關於測試的學習小總結篇
下一篇
情境練習:透過 Mock 模擬 Module
系列文
<< 測試魔法 >> 這能動嗎?不然就測測看好了!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言