ابزارهای تست

ایمپورت کردن

import ReactTestUtils from 'react-dom/test-utils'; // ES6
var ReactTestUtils = require('react-dom/test-utils'); // ES5 with npm

بررسی اجمالی

ReactTestUtils عملیات تست کامپوننت‌های ری‌اکت را در فریموورک موردنظرتان ساده می‌کند. ما در فیسبوک از Jest برای تست کردن جاوااسکریپتی بدون دردسر استفاده می‌کنیم. برای اینکه یاد بگیرید از کجا شروع کنید از React Tutorial سایت Jest استفاده نمایید.

نکته:

ما استفاده از React Testing Library را پیش‌نهاد می‌کنیم، از آن‌جا که طراحی آن با هدف قادر ساختن و تشویق شما به نوشتن تست‌ به گونه‌ای است که کاربر نهایی کامپوننت شما را استفاده می‌کند.

به عنوان جایگزین، Airbnb یک ابزار تست به نام Enzyme منتشر کرده‌است که بررسی، دستکاری و ارزیابی خروجی کامپوننت‌های ری‌اکت شما را ساده می‌کند.

مرجع

act()

برای آماده‌سازی یک کامپوننت برای اثبات، کدی که آن را رندر و به‌روز رسانی می‌کند را درون یک فراخوانی act() قرار دهید. این‌کار باعث می‌شود تست شما به روش کارکرد ری‌اکت در مرورگر نزدیک‌تر شود.

نکته

اگر از react-test-renderer استفاده می‌کنید، یک خروجی act که به همین شکل رفتار می‌کند برایتان فراهم می‌کند.

برای مثال، اجازه دهید بگوییم این کامپوننت Counter را داریم:

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: 0};
    this.handleClick = this.handleClick.bind(this);
  }
  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }
  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }
  handleClick() {
    this.setState(state => ({
      count: state.count + 1,
    }));
  }
  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={this.handleClick}>
          Click me
        </button>
      </div>
    );
  }
}

به این شکل آن را تست می‌کنیم:

import React from 'react';
import ReactDOM from 'react-dom';
import { act } from 'react-dom/test-utils';import Counter from './Counter';

let container;

beforeEach(() => {
  container = document.createElement('div');
  document.body.appendChild(container);
});

afterEach(() => {
  document.body.removeChild(container);
  container = null;
});

it('can render and update a counter', () => {
  // Test first render and componentDidMount
  act(() => {    ReactDOM.render(<Counter />, container);  });  const button = container.querySelector('button');
  const label = container.querySelector('p');
  expect(label.textContent).toBe('You clicked 0 times');
  expect(document.title).toBe('You clicked 0 times');

  // Test second render and componentDidUpdate
  act(() => {    button.dispatchEvent(new MouseEvent('click', {bubbles: true}));  });  expect(label.textContent).toBe('You clicked 1 times');
  expect(document.title).toBe('You clicked 1 times');
});
  • فراموش نکنید که توضیع (dispatch) رویداد‌های DOM تنها زمانی که DOM container به document اضافه شده‌باشد کار می‌کند. شما می‌توانید از یک کتابخانه مانند React Testing Library برای کاهش کدهای تکراری (boilerplate) استفاده کنید.
  • سند دستورالعمل‌ها شامل اطلاعات بیشتری در مورد چگونگی رفتار act()، با مثال‌ها و کاربردها می‌باشد.

mockComponent()

mockComponent(
  componentClass,
  [mockTagName]
)

یک ماژول کامپوننت mock شده به این متد پاس دهید تا آن را به متدهای سودمندی که به آن اجازه می‌دهند که به عنوان یک کامپوننت ساختگی ری‌اکت استفاده شود تبدیل کنید. به جای این‌که مثل همیشه رندر شود، کامپوننت یک <div> ساده (یا تگ دیگری اگر mockTagName فراهم شده باشد) خواهد شد که هر فرزندی را که فراهم شده‌‌باشد، دربر می‌گیرد.

نکته:

mockComponent() یک API قدیمی است. ما استفاده از jest.mock() را به عنوان جایگزین پیشنهاد می‌کنیم.


isElement()

isElement(element)

اگر element هر المنت ری‌اکتی باشد true برمی‌گرداند.


isElementOfType()

isElementOfType(
  element,
  componentClass
)

اگر element یک المنت ری‌اکت که از نوع componentClass ری‌اکت است باشد، true بازمی‌گرداند.


isDOMComponent()

isDOMComponent(instance)

اگر instance یک کامپوننت DOM باشد (مانند یک <div> یا <span>) مقدار true برمی‌گرداند.


isCompositeComponent()

isCompositeComponent(instance)

اگر instance یک کامپوننت تعریف شده توسط کاربر مانند یک کلاس یا یک تابع باشد، مقدار true را برمی‌گرداند.


isCompositeComponentWithType()

isCompositeComponentWithType(
  instance,
  componentClass
)

اگر instance یک کامپوننت از نوع componentClass ری‌اکت باشد مقدار true را برمی‌گرداند.


findAllInRenderedTree()

findAllInRenderedTree(
  tree,
  test
)

از تمامی کامپوننت ها در tree عبور می‌کند و تمام کامپوننت‌هایی که test(component) آن‌ها مقدار true دارد را ذخیره می‌کند. به تنهایی کاربردی ندارد، اما به عنوان یک قدم اولیه برای دیگر ابزارهای تست استفاده می‌شود.


scryRenderedDOMComponentsWithClass()

scryRenderedDOMComponentsWithClass(
  tree,
  className
)

تمامی المنت‌های DOM در کامپوننت‌های درخت رندر شده را که کامپوننت‌هایی هستند که نام کلاسشان با className برابر است را پیدا می‌کند.


findRenderedDOMComponentWithClass()

findRenderedDOMComponentWithClass(
  tree,
  className
)

شبیه scryRenderedDOMComponentsWithClass() است اما انتظار دارد که تنها یک نتیجه وجود داشته باشد، یا اگر هر تعدادی به غیر از یک نتیجه پیدا کند یک خطا می‌اندازد.


scryRenderedDOMComponentsWithTag()

scryRenderedDOMComponentsWithTag(
  tree,
  tagName
)

تمامی المنت‌های DOM در کامپوننت‌های درخت رندر شده را که کامپوننت‌هایی هستند که نام تگشان با tagName برابر است را پیدا می‌کند.


findRenderedDOMComponentWithTag()

findRenderedDOMComponentWithTag(
  tree,
  tagName
)

شبیه scryRenderedDOMComponentsWithTag() است اما انتظار دارد که تنها یک نتیجه وجود داشته باشد، یا اگر هر تعدادی به غیر از یک نتیجه پیدا کند یک خطا می‌اندازد.


scryRenderedComponentsWithType()

scryRenderedComponentsWithType(
  tree,
  componentClass
)

تمامی instance های کامپوننت‌ها با نوع componentClass را پیدا می‌کند.


findRenderedComponentWithType()

findRenderedComponentWithType(
  tree,
  componentClass
)

مانند scryRenderedComponentsWithType() است اما انتظار دارد که تنها یک نتیجه وجود داشته باشد، یا اگر هر تعدادی به غیر از یک نتیجه پیدا کند یک خطا باز می‌گرداند.


renderIntoDocument()

renderIntoDocument(element)

یک المنت ری‌اکت را در یک نود DOM جدا شده در document رندر می‌کند. این تابع یک DOM نیاز دارد. معادل است با:

const domContainer = document.createElement('div');
ReactDOM.render(element, domContainer);

نکته:

شما به window، window.document و window.document.createElement قبل از اینکه React را ایمپورت کنید و با دسترسی عمومی نیاز خواهید داشت. در غیر اینصورت ری‌اکت فکر می‌کند که نمی‌تواند به DOM دسترسی پیدا کند و متدهایی مانند setState کار نخواهند کرد.


دیگر ابزارها

Simulate

Simulate.{eventName}(
  element,
  [eventData]
)

توزیع یک رویداد روی یک نود DOM با eventData داده اختیاری برای رویداد شبیه‌سازی می‌کند.

Simulate یک متد برای هر رویدادی که ری‌اکت می‌فهمد دارد.

کلیک کردن روی یک المنت

// <button ref={(node) => this.button = node}>...</button>
const node = this.button;
ReactTestUtils.Simulate.click(node);

تغییر مقدار یک فیلد ورودی و سپس فشردن ENTER.

// <input ref={(node) => this.textInput = node} />
const node = this.textInput;
node.value = 'giraffe';
ReactTestUtils.Simulate.change(node);
ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});

نکته

شما باید هرگونه ویژگی رویدادی که در کامپوننتان استفاه می‌کنید (مانند keyCode, which, etc…) را فراهم کنید چرا که ری‌اکت هیچ یک از ان‌ها را برای شما ایجاد نمی‌کند.