首先製作一個簡單的useCounter
我們希望他會有三個功能,加一、減一、重置到初始值,並且也要回傳count值、與可以自己設定的setCount,我們也能設定初始值
// useCounter.ts
import React, { useState } from "react";
export function useCounter(initialValue?: number) {
const [count, setCount] = useState(initialValue || 0);
// Increase 1
function increment() {
setCount((prevCount: number) => prevCount + 1);
}
// decrease 1
function decrement() {
setCount((prevCount: number) => prevCount - 1);
}
// reset to initValue or 0
function reset() {
setCount(initialValue || 0);
}
return { count, setCount, increment, decrement, reset };
}
// 想使用的地方
const { count, setCount, increment, decrement, reset } = useCounter(1);
稍微解釋一下,我們可以在useCounter()中放入一個參數,我們設定是initialValue?: number,?:代表他是選填的,並不是必要傳入的參數,reset如果有設定初始值,就會變成初始值,不然就會變成0
那接下來我們要開始寫測試了,首先我們要思考我們可能會需要哪些測試->
// useCounter.test.ts
import { useCounter } from "../src";
import { renderHook, act } from "@testing-library/react";
// describe 用於對一組相關的測試用例進行分組
// 它接受兩個參數:
// 字串(描述該測試組的目的或主題)。
// 一個包含一組測試用例的回調函數。
describe("useCounter custom hook", () => {
// 測試放在這裡面
// it 用於定義單一的測試用例, 參數與describe一樣
// 測試如果沒有填入初始值,count預設會是0
it("should use default initial value", () => {
// 1. 使用renderHook 來測試我們剛剛做的useCounter,renderHook裡面放的就是你寫的custom hook function,result則是代表回傳的值
const { result } = renderHook(() => useCounter());
// result.current 會指向你回傳的{ count, setCount, increment, decrement, reset }
// 底下這行expect 是指你期望的,所以包這個裡面就是你想測的變數,toBe類似= 裡面就的就是你期望的值
// 簡單來說,可以把這行想成 result.current.count 期望要=0,如果跟你期望的一樣,那就是Pass,如果沒有如同期望值,就會導致test fail
expect(result.current.count).toBe(0);
});
// 測試如果有填入初始值,count預設會是初始值
it("should use initial value", () => {
const { result } = renderHook(() => useCounter(5));
// 這邊跟上面一樣,因為有填入初始值,所以我們期望count = 5
expect(result.current.count).toBe(5);
});
// 測試是否有加一
it("should increment counter", () => {
const { result } = renderHook(() => useCounter(5));
// act 主要用於包裹會導致 React 組件狀態變化或具有副作用的代碼片段。使用 act 可以確保測試過程中組件的渲染行為與實際瀏覽器環境中的行為更加一致,並且能夠避免一些不必要的測試警告。
// 上面寫的act解釋簡單來說就是模擬人操作,他可以在裡面放你想執行的function,主要目的是為了模擬你實際執行increment function
act(() => {
result.current.increment();
});
// 因為他+1了,所以我們期望他從5+1變成6
expect(result.current.count).toBe(6);
});
// 測試是否有減一
it("should decrement counter", () => {
const { result } = renderHook(() => useCounter(5));
act(() => {
result.current.decrement();
});
expect(result.current.count).toBe(4);
});
// 測試是否有重置為初始值
it("should reset counter to initial value", () => {
// renderHook接受兩個參數
// 1.測試的 Hook 函數(必須):這是你想要測試的實際 hook 函數或一個封裝該 hook 的函數。這個函數的返回值會被包裝在 result 對象中,以便後續進行檢查。
// 2.選項對象(可選):一個包含各種選項的object。其中最常用的選項可能是 initialProps,這個選項允許我們為這個custom hook提供初始的 props,但記得這樣
const { result, rerender } = renderHook((props) => useCounter(props), {
initialProps: 5,
});
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(6);
act(() => {
result.current.reset();
});
expect(result.current.count).toBe(5);
// 初始的 useCounter hook 是用一個初始值 5 渲染的。
// 之後,rerender(10) 被調用,意味著這個 hook 會以新的初始值 10 進行重新渲染
// 所以,rerender 主要是用於:
// 1.模擬 prop 值的變化。
// 2.檢查 hook 是否能正確地響應這些變化。
rerender(10);
act(() => {
result.current.reset();
});
expect(result.current.count).toBe(10);
});
});
接下來跑npm test吧
成功畫面應該會長得像底下這樣
Pass底下的useCounter custom hook就是我們剛剛寫的describe的第一個參數,描述測試大綱
✓ should use default initial value (9 ms)
✓ should use initial value (2 ms)
✓ should increment counter (3 ms)
✓ should decrement counter (2 ms)
✓ should reset counter to initial value (2 ms)
底下這五個則是我們剛剛寫的It的第一個參數,描述測試內容
今天可能比較多東西,但因為custom hook比較簡單,所以直接把custom hook與測試放一起,接下來應該是一天custom hook,隔一天講解測試,目前安排了11個實例,有什麼希望也可以講解的測試或想了解的custom hook都可以在下面留言。
有什麼不會、不了解的也歡迎下面提問,有什麼我寫錯的也歡迎指正,太趕或任何問題都可以在下面提出喔.
你們的觀看就是我繼續的動力,謝謝大家~