# React Testing Library - [React Testing Library 是什麼?](https://hackmd.io/dsF4WVq1RUCZjVSCmeG9PA?view#Jest-%E6%98%AF%E4%BB%80%E9%BA%BC%EF%BC%9F) - [初始設定](https://hackmd.io/AZ-6Gx0HSkSPFyS_7XV0zQ?both#%E5%88%9D%E5%A7%8B%E8%A8%AD%E5%AE%9A) - [撰寫流程](https://hackmd.io/AZ-6Gx0HSkSPFyS_7XV0zQ?both#%E6%92%B0%E5%AF%AB%E6%B5%81%E7%A8%8B) - [常見使用方法](https://hackmd.io/AZ-6Gx0HSkSPFyS_7XV0zQ?both#%E5%B8%B8%E8%A6%8B%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95%EF%BC%9A) - 常用方法(getBy、findBy ...) - 如何選取 (ByText、ByRole ...) - screen.debug --- #### React Testing Library 是什麼? React Testing Library 是一套 DOM Testing Library 工具,希望我們能更**關注在用戶的使用操作**上,因此提供許多在模擬使用者查詢 DOM 節點的方法,讓開發者針對 DOM 與使用者的操作行為進行測試。 但是 React Testing Library 本身無法運行測試,以及測試是否有通過,需**仰賴 Jest 的協作**。並且可與 Jest 搭配在不透過瀏覽器的情況下模擬使用者的操作行為(e.g. 點擊按鈕、下拉選單)。 - 常用方法: - Type of Query:`getBy`, `queryBy`, `findBy` - Multiple Elements:`getAllBy`, `queryAllBy`, `findAllBy` - 渲染 React 元件:`render`, `screen`, `getBy` --- #### 初始設定 如果是使用 `create-react-app` 建立的專案,通常在建立時就會幫你安裝好 `React Testing Library` 套件。 可以在 `package.json` 檔案裡找到: ```jsx! "dependencies": { ... "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", ... } ``` `jest-dom`, `user-event` 皆為在測試時會一起使用的輔助工具。 若專案中沒有 `create-react-app` 套件,也可以自行執行 npm 指令進行安裝。 ```jsx! npm install --save-dev @testing-library/react ``` --- #### 撰寫流程 使用`React Testing Library` 搭配來撰寫測試時,我們可以針對程式碼結構進行思考,如何渲染、模擬行為、驗證結果是否符合預期。 1. 可以先使用 render 呈現我們要測試的元件 2. 找到該元件中元素的所在位子 3. 觀察或模擬使用者在該元素上的操作行為 4. 搭配 jest 函式庫來導入方法 5. 驗證結果是否和預期相同 --- #### 常見使用方法: React Testing Library 提供很多方法可以讓我們像使用者一樣選取網頁上的 DOM 元素,讓我們在測試時更切合實際。 ![React Testing Library 提供的表格](https://i.imgur.com/dTChCwk.png) - `getBy`: - 在沒有匹配到(No Match)或是匹配到多個(1 + Match)的情況下,都會報錯(throw)。 - 不適用於一開始不會顯示的情況。 - e.g. 某些元素需要在**用戶有操作**的情況下才會顯示的情形。 - `getAllBy`: - 可以選取多個匹配的元素 - 匹配到一個(1 Match)、多個(1 + Match)⇒ 回傳 Array - `findBy`: - 可用來處理**非同步、**或一開始**不會顯示在頁面上**,需執行**對應動作**重新渲染後才會顯示的畫面。 - `findAllBy`: - 與 `getAllBy`一樣可以選取多個匹配的元素,適合用來選取非同步操作後顯示的元素。 - `queryBy`: - 適用於比對**是否沒有某個元素**時 - 沒有比對到元素時不會報錯,而是會回傳 `null` - 因不會直接報錯,不建議拿來選取存在的元素 - 適合與 `not` 一起搭配使用 ```jsx expect(screen.queryByRole('button')).not.toBeInTheDocument(); ``` - `queryAllBy` : - 適合用在比對**是否沒有某個元素** - 沒有匹配的情況下會回傳**空陣列** -- 如何選取: - `ByText`: - 尋找 document 內符合的文字內容 - `ByRole`:(需注意套件設定的 Role) - 可以透過標籤的角色去尋找想要的元素,角色可以透過此方式去觀看: - 叫出開發者工具後在 Elements 底下原先預設 Styles 的地方點擊最右側小箭頭 >> 圖示後選取 **Accessibility** 。 ![選取 Accessibility ](https://i.imgur.com/cbiQHkR.png) - 選取對應的 element 後底下會顯示 Role 角色! ![選取對應的 element 後底下會顯示 Role 角色](https://i.imgur.com/btwqjoD.png) - 以按鈕舉例可以這樣選取: ```JSX! screen.getByRole('button'); ``` - 如果有多顆按鈕的情況,可以在按鈕上添加 aria-label 屬性後透過 name 去指定: ```JSX! <button aria-label='first-button'>第一顆按鈕</button> ``` ```JSX! // 透過 aria-label 指定名稱 screen.debug(screen.getByRole('button', { name: /first-button/i })); ``` 這邊透過 Antd 的素材庫去舉例,也要特別提醒,如果是透過套件去渲染的元件,套件可能會有多個層級,此時要特別留意要做測試的層級,按照 Select 舉例該 input 可能包在很內層,input 內也有去設定 role 角色: ![role 角色](https://i.imgur.com/56GkZjp.png) - `ByLabelText` : - 尋找 label 屬性的文字內容。 - `ByPlaceholderText`: - 尋找 Placeholder 屬性的文字內容。 - `ByDisplayValue`: - 尋找 value :如 input 、 select 等等的顯示值。 - `ByAltText`: - 尋找 img 標籤的 Alt 屬性。 - `ByTitle`: - 尋找有設定 title 屬性的元素。 - `ByTestId` - 可以找出 `data-testid` 屬性,`data-testid` 要提前埋在標籤內: ```jsx <div data-testid="test" /> // 選取埋藏的 id screen.getByTestId('test'); ```` -- 選取之前須先觀看頁面上可供選擇的元素 - `screen.debug()` : - 能幫我們印出現有的 DOM 元素,讓我們更方便去選去元素,也可以帶入參數,帶入參數後可單獨印出該元素。 ```jsx // 會帶出所有目前頁面上的 dom 元素 screen.debug() // 帶入參數選取想看的 dom 元素 screen.debug(screen.getByText('test')); ```