簡體   English   中英

如何在笑話和酶中為 useState Hook 設置初始狀態值?

[英]How to set initial state value for useState Hook in jest and enzyme?

我知道這里已經有人問過這個問題: How to set initial state for useState Hook in jest andase?

const [state, setState] = useState([]);

我完全同意Jimmy's Answer從測試文件中模擬 useState 函數,但我有這個問題的一些擴展版本,“如果我有多個 useState 語句進入鈎子,我如何測試它們並為它們分配相應的自定義值?”

我有一些帶有鈎子狀態值條件的 JSX 渲染,並且取決於JSX正在渲染的狀態值。

如何通過將這些 JSX 放入我的測試用例代碼的wrapper來測試它們?

根據您鏈接的答案,您可以為模擬函數的每次調用返回不同的值:

let myMock = jest.fn();

myMock
  .mockReturnValueOnce(10)
  .mockReturnValueOnce('x')
  .mockReturnValue(true);

在我看來,這仍然很脆弱。 您可以稍后修改組件並添加另一個狀態,並且您會得到令人困惑的結果。

測試 React 組件的另一種方法是像用戶一樣通過單擊事物並在輸入上設置值來測試它。 這將觸發組件的事件處理程序,而 React 將像在實際配置中一樣更新狀態。 您可能無法進行淺層渲染,或者您可能需要 模擬子組件

如果您更喜歡淺層渲染,可以像這樣從 props 讀取初始狀態值:

function FooComponent({initialStateValue}) {
  const [state, setState] = useState(initialStateValue ?? []);
}

如果您真的不需要測試狀態但是狀態對孩子的影響,您應該(如某些評論所述)然后測試副作用並將狀態視為不透明的實現細節。 如果您不使用淺層渲染或不進行某種異步初始化(例如在效果中獲取數據或其他可能需要更多工作),這將起作用。

如果您不能執行上述操作,您可以考慮將狀態完全從組件中移除並使其完全正常運行。 這樣你需要的任何狀態,你都可以將它注入到組件中。 您可以將所有鈎子包裝到一個“控制器”類型的鈎子中,該鈎子封裝了組件或域的行為。 下面是一個示例,說明如何使用<Todos />做到這一點。 這段代碼是 0% 測試的,它只是為了展示一個概念。

const useTodos = (state = {}) => {
  const [todos, setTodos] = useState(state.todos);
  const id = useRef(Date.now());
  
  const addTodo = useCallback((task) => {
    setTodos((current) => [...current, { id: id.current++, completed: false, task }]);
  }, []);

  const removeTodo = useCallback((id) => {
    setTodos((current) => current.filter((t) => t.id !== id));
  }, []);
  
  const completeTodo = useCallback((id) => {
    setTodos((current) => current.map((t) => {
      let next = t;
      
        if (t.id === id) {
        next = { ...t, completed: true };
      }
      
      return next;
    }))
  }, []);

  return { todos, addTodo, removeTodo, completeTodo };
};


const Todos = (props) => {
  const { todos, onAdd, onRemove, onComplete } = props;
  
  const onSubmit = (e) => {
    e.preventDefault();
    onAdd({ task: e.currentTarget.elements['todo'].value });
  }
  
  return (
    <div classname="todos">
      <ul className="todos-list">
        {todos.map((todo) => (
          <Todo key={todo.id} onRemove={onRemove} onComplete={onComplete} />
        )}
      </ul>
      <form className="todos-form" onSubmit={onSubmit}>
        <input name="todo" />
        <button>Add</button>
      </form>
    </div>
  );
};

所以現在父組件向<Todos />注入了待辦事項和回調。 這對於測試、SSR 等很有用。 你的組件可以只需要一個待辦事項列表和一些處理程序,更重要的是你可以簡單地測試兩者。 對於<Todos />您可以傳遞useTodos和已知狀態,對於useTodos您只需調用方法並確保狀態反映預期的內容。

您可能會想,這將問題提升了一個級別,確實如此,但您現在可以測試組件/邏輯並增加測試覆蓋率。 如果圍繞這個組件進行任何測試,膠水層將需要最少的測試,除非你真的想確保 props 被傳遞到組件中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM