iT邦幫忙

2022 iThome 鐵人賽

DAY 10
1
自我挑戰組

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

用 User Event 模擬使用者操作

  • 分享至 

  • xImage
  •  

前情提要

「好,今天來學怎麼模擬一些對陣法的操作行為!」艾草道。

「嗯嗯。」

「為什麼要模擬操作陣法的行為呢?可以更容易看出哪些操作的情況下,陣法會有一些疏漏。」艾草忘我的補充。

「嗯嗯嗯。」

「咦,你今天怎麼這麼配合?」艾草回過神來,往我看了過來。

「嗯嗯嗯嗯。總之我們開始學習吧!」我心虛的停止了手邊對陣法的瘋狂操作行為。

「啊啊啊,沒有要進行壓力測驗呀!你在幹嘛啊啊啊~~~」

https://ithelp.ithome.com.tw/upload/images/20220925/20139066d4r0cXLlkT.png


昨天的情境練習有使用到 React Testing Library 的 fireEvent 來執行 click 事件,今天要來使用 user event 來改寫 fireEvent 。

User Event 的好處

為什麼要使用 user event 呢?

fireEvent 雖然一樣能調用事件,但 use event 可以更容易模擬使用者與瀏覽器的交互行為,官方文件上有舉例:

For example, when a user types into a text box, the element has to be focused, and then keyboard and input events are fired and the selection and value on the element are manipulated as they type.

用戶輸入文字框時會有一連串的交互行為,包含一開始文字框的 focus 後續會觸發鍵盤的輸入事件再輸入內容時也同時在操作元素的值。

User Event 的使用

認識完 user event 後來了解如何使用:

在使用 creat-react-app 建立專案的情況下,已經幫我們安裝好 user event 了,而安裝好的版本是 v13 ,目前 user event 已更新至 v14 版本,但文章還是會先按照 v13 版本進行解釋。

如果專案還沒有安裝 user event ,可以透過底下指令安裝:

npm install --save-dev @testing-library/user-event @testing-library/dom

接下來來認識 user event 好用的幾種操作行為吧!

Click 、 dblClick

首先從常用的 click 開始:

以下程式碼取自官方文件,在使用之前記得先引入 userEvent 後,直接透過 userEvent.click 並帶入要點選的對象:

import React from 'react'
import {render, screen} from '@testing-library/react'
// 記得引入 userEvent 
import userEvent from '@testing-library/user-event'

test('click', () => {
  render(
    <div>
      <label htmlFor="checkbox">Check</label>
      <input id="checkbox" type="checkbox" />
    </div>,
  )

  userEvent.click(screen.getByText('Check'))
  expect(screen.getByLabelText('Check')).toBeChecked()
})

除此之外跟 click 相關的還有 dblClick 可以透過此方式判斷點擊 checkbox 兩次後是否不是打勾狀態:

test('click', () => {
  render(
    <div>
      <label htmlFor="checkbox">Check</label>
      <input id="checkbox" type="checkbox" />
    </div>,
  )

  userEvent.dblClick(screen.getByText('Check'))
  expect(screen.getByLabelText('Check')).not.toBeChecked()
})

type

type(element, text, [options]) 該方法可以使用在 input 或 textarea,透過 React Testing Library 選取該 input 或 textarea 後可以輸入要顯示的數字,會模擬使用者操作時點擊 input 的行為後再去做輸入。

假設今天有一個元件 Input 如下:

import { useState } from "react";

const Input = () => {
  const [value, setValue] = useState('');
  const changeValue = (value) => setValue(value);

  return (
    <>
      <input
        value={value}
        onChange={(e) => changeValue(e.target.value)}
      />
      <h1>{value}</h1>
    </>
  );
};

export default Input;

可透過 type 去模擬使用者輸入進行測試:

import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import Input from "./TestInput";

test("type", () => {
  render(<Input />);
  userEvent.type(screen.getByRole("textbox"), 'Hello');
  expect(screen.getByText('Hello')).toBeInTheDocument();
});

且除了輸入文字內容外,也可以輸入一些特殊符號,如下圖(圖片取自官方文件):

https://ithelp.ithome.com.tw/upload/images/20220925/20139066tEutr17RfX.png

使用方式只要像這樣直接加進去:

test("type", () => {
  render(<Input />);
  userEvent.type(screen.getByRole("textbox"), 'Helli{backspace}o');
  expect(screen.getByText('Hello')).toBeInTheDocument();
});

其他還有很多方法像是:

  • keyboard :輸入的鍵盤事件,與 type 相似但並沒有單擊行為
  • upload :用於檔案上傳的測試
  • selectOptions :選擇 selet 的選項

都可以參閱官方文件唷!

透過 User Event 改寫昨天範例

這是昨天 form 表單要測試打勾後是否將按鈕改為可點擊狀態的程式碼:

import "jest";
import React from 'react';
import { render, fireEvent, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import Form from "./test";

describe('Click the checkbox to change the disabled property of the button', () => {
  test('Unable to press the button at first' ,() => {
    render(<Form />);
    expect(screen.getByRole('button')).toBeDisabled();
  })
  test('The button can be turned on when the checkbox is checked' ,() => {
    render(<Form />);
    fireEvent.click(screen.getByRole('checkbox'));
    expect(screen.getByRole('button')).toBeEnabled();
  })
  test('Clicking the checkbox twice disables the button',() => {
    render(<Form />);
    fireEvent.click(screen.getByRole('checkbox'));
    expect(screen.getByRole('button')).not.toBeDisabled();
    fireEvent.click(screen.getByRole('checkbox'));
    expect(screen.getByRole('button')).toBeDisabled();
  })
})

要改寫這段程式碼只需要兩個步驟:

  1. 引入 user event 套件
  2. fireEvent 的地方改寫成 userEvent

來看看改完後的程式碼:

import "jest";
import React from 'react';
import userEvent from '@testing-library/user-event'
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import Form from "./test";

describe('Click the checkbox to change the disabled property of the button', () => {
  test('Unable to press the button at first' ,() => {
    render(<Form />);
    expect(screen.getByRole('button')).toBeDisabled();
  })
  test('The button can be turned on when the checkbox is checked' ,() => {
    render(<Form />);
    userEvent.click(screen.getByRole('checkbox'));
    expect(screen.getByRole('button')).toBeEnabled();
  })
  test('Clicking the checkbox twice disables the button',() => {
    render(<Form />);
    userEvent.click(screen.getByRole('checkbox'));
    expect(screen.getByRole('button')).not.toBeDisabled();
    userEvent.click(screen.getByRole('checkbox'));
    expect(screen.getByRole('button')).toBeDisabled();
  })
})

幾個步驟修改後,可以讓測試更貼近使用者的操作行為!


參考文章

https://testing-library.com/docs/ecosystem-user-event
https://testing-library.com/docs/user-event/intro/


上一篇
情境練習:打勾才能按確認按鈕
下一篇
Unit Test 觀念學習 - 3A Pattern、名詞 (SUT、DOC)
系列文
<< 測試魔法 >> 這能動嗎?不然就測測看好了!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言