We want to hear from you!Take our 2021 Community Survey!
This site is no longer updated.Go to react.dev

ํ…Œ์ŠคํŒ… ๋„๊ตฌ

Importing

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

๊ฐœ์š”

ReactTestUtils๋Š” ์—ฌ๋Ÿฌ๋ถ„์ด ์„ ํƒํ•œ ํ…Œ์ŠคํŒ… ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์‰ฝ๊ฒŒ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด ์ค๋‹ˆ๋‹ค. Facebook์—์„œ๋Š” Jest๋ฅผ ์ด์šฉํ•ด ๋”์šฑ ์‰ฝ๊ฒŒ JavaScript ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Jest ์›น์‚ฌ์ดํŠธ์˜ React ์ž์Šต์„œ ๋ฌธ์„œ๋ฅผ ํ†ตํ•ด Jest๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์„ธ์š”.

์ฃผ์˜

Facebook์—์„œ๋Š” React Testing Library ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

React v16 ์ดํ•˜์—์„œ๋Š” Enzyme์„ ํ†ตํ•ด React ์ปดํฌ๋„ŒํŠธ์˜ ์ถœ๋ ฅ์„ ์‰ฝ๊ฒŒ ๊ฒ€์ฆํ•˜๊ณ  ์กฐ์ž‘ํ•˜๊ณ  ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ์กฐ์‚ฌํ•ญ

act()

์ปดํฌ๋„ŒํŠธ์˜ ์ง„๋‹จ์„ ์ค€๋น„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ๊ฐฑ์‹ ํ•ด์ฃผ๋Š” ์ฝ”๋“œ๋ฅผ act()๋ฅผ ํ˜ธ์ถœํ•œ ๊ฒƒ์˜ ์•ˆ์— ๋„ฃ์–ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด React๋ฅผ ๋ธŒ๋ผ์šฐ์ € ๋‚ด์—์„œ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•œ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์˜

react-test-renderer๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ๋˜‘๊ฐ™์ด ์ž‘๋™ํ•˜๋Š” act export๊ฐ€ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ 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/client';
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', () => {
  // ์ฒซ render์™€ componentDidMount๋ฅผ ํ…Œ์ŠคํŠธ
  act(() => {    ReactDOM.createRoot(container).render(<Counter />);  });  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');

  // ๋‘ ๋ฒˆ์งธ render์™€ 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');
});
  • DOM ์ด๋ฒคํŠธ ๋ฐœํ–‰์€ DOM ์ปจํ…Œ์ด๋„ˆ๊ฐ€ document ๊ฐ์ฒด์— ์ถ”๊ฐ€๋˜์—ˆ์„ ๋•Œ๋งŒ ์ž‘๋™ํ•œ๋‹ค๋Š” ์ ์„ ์žŠ์ง€๋งˆ์„ธ์š”. ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ฐ˜๋ณต ๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด์„œ react-testing-library์™€ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ• ๋ฌธ์„œ์— act()์˜ ๋™์ž‘ ๋ฐฉ์‹์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์ด ์˜ˆ์‹œ์™€ ์‚ฌ์šฉ๋ฒ•๊ณผ ํ•จ๊ป˜ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

mockComponent()

mockComponent(
  componentClass,
  [mockTagName]
)

๋ชจ์˜ ์ปดํฌ๋„ŒํŠธ ๋ชจ๋“ˆ์„ ์ด ๋ฉ”์„œ๋“œ์— ๋„˜๊ฒจ ์œ ์šฉํ•œ ๋ฉ”์„œ๋“œ๋“ค์„ ๋ถ™์—ฌ ์ฆ๊ฐ•ํ•ด ๋”๋ฏธ React ์ปดํฌ๋„ŒํŠธ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณดํ†ต์˜ ๊ฒฝ์šฐ์ฒ˜๋Ÿผ ๋ Œ๋”๋ง ํ•˜์ง€ ์•Š๊ณ  ๊ทธ ๋Œ€์‹  ์ปดํฌ๋„ŒํŠธ๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ <div> ํƒœ๊ทธ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. mockTagName๊ฐ’์„ ๋„˜๊ฒจ์ค€๋‹ค๋ฉด <div>๋Œ€์‹  ๋‹ค๋ฅธ ํƒœ๊ทธ๋กœ ๋งŒ๋“ค์–ด ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์˜

mockComponent()๋Š” ๋” ์ด์ƒ ์“ฐ์ด์ง€ ์•Š๋Š” API์ž…๋‹ˆ๋‹ค. jest.mock() ์‚ฌ์šฉ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.


isElement()

isElement(element)

element๊ฐ€ React์˜ element๋ผ๋ฉด true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.


isElementOfType()

isElementOfType(
  element,
  componentClass
)

element๊ฐ€ componentClass ํƒ€์ž…์˜ React element๋ผ๋ฉด true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.


isDOMComponent()

isDOMComponent(instance)

instance๊ฐ€ <div>๋‚˜ <span>๊ฐ™์€ DOM ์ปดํฌ๋„ŒํŠธ๋ผ๋ฉด 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
)

๋ Œ๋”๋ง ๋œ ํŠธ๋ฆฌ์—์„œ ์กฐ๊ฑด className์— ๋งŒ์กฑํ•˜๋Š” class๋ช…์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” DOM ์ปดํฌ๋„ŒํŠธ์˜ DOM ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ชจ๋‘ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.


findRenderedDOMComponentWithClass()

findRenderedDOMComponentWithClass(
  tree,
  className
)

scryRenderedDOMComponentsWithClass()์™€ ๊ธฐ๋Šฅ์ด ์œ ์‚ฌํ•˜๋‚˜ ๊ฒฐ๊ณผ๊ฐ’์ด ํ•˜๋‚˜๋ผ๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๊ฐ’๋งŒ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๊ฐœ ์ด์ƒ์˜ ๊ฒฐ๊ณผ๊ฐ’์ด ์žˆ๋‹ค๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.


scryRenderedDOMComponentsWithTag()

scryRenderedDOMComponentsWithTag(
  tree,
  tagName
)

๋ Œ๋”๋ง ๋œ ํŠธ๋ฆฌ ๋‚ด์—์„œ ์กฐ๊ฑด tagName์— ๋งŒ์กฑํ•˜๋Š” tag๋ช…์„ ๊ฐ€์ง„ DOM ์ปดํฌ๋„ŒํŠธ์˜ DOM ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ชจ๋‘ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.


findRenderedDOMComponentWithTag()

findRenderedDOMComponentWithTag(
  tree,
  tagName
)

scryRenderedDOMComponentsWithTag()์™€ ๊ธฐ๋Šฅ์ด ์œ ์‚ฌํ•˜๋‚˜ ๊ฒฐ๊ณผ๊ฐ’์ด ํ•˜๋‚˜๋ผ๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๊ฐ’๋งŒ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๊ฐœ ์ด์ƒ์˜ ๊ฒฐ๊ณผ๊ฐ’์ด ์žˆ๋‹ค๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฑ‰์Šต๋‹ˆ๋‹ค.


scryRenderedComponentsWithType()

scryRenderedComponentsWithType(
  tree,
  componentClass
)

componentClass ํƒ€์ž…์„ ๊ฐ€์ง„ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.


findRenderedComponentWithType()

findRenderedComponentWithType(
  tree,
  componentClass
)

scryRenderedComponentsWithType()์™€ ๊ธฐ๋Šฅ์ด ์œ ์‚ฌํ•˜๋‚˜ ๊ฒฐ๊ณผ๊ฐ’์ด ํ•˜๋‚˜๋ผ๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๊ฐ’๋งŒ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๊ฐœ ์ด์ƒ์˜ ๊ฒฐ๊ณผ๊ฐ’์ด ์žˆ๋‹ค๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฑ‰์Šต๋‹ˆ๋‹ค.


renderIntoDocument()

renderIntoDocument(element)

React ์—˜๋ฆฌ๋จผํŠธ๋ฅผ document๋‚ด์˜ ๋–จ์–ด์ ธ ์žˆ๋Š” DOM ๋…ธ๋“œ์— ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ์“ฐ๋ ค๋ฉด DOM์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋‹ค์Œ ์ฝ”๋“œ์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•ฉ๋‹ˆ๋‹ค.

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

์ฃผ์˜

window, window.document์™€ window.document.createElement๋Š” React๋ฅผ ๊ฐ€์ ธ์™€์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์—๋„ ์ „์—ญ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด React๋Š” DOM์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ๊ฐ„์ฃผํ•  ๊ฒƒ์ด๋ฉฐ setState์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋“ค์ด ์ž‘๋™ํ•˜์ง€ ์•Š์„ ๊ฒƒ ์ž…๋‹ˆ๋‹ค.


๋‹ค๋ฅธ ํ…Œ์ŠคํŒ… ๋„๊ตฌ๋“ค

Simulate

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

์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ์ธ eventData๋ฅผ ์˜ต์…˜์œผ๋กœ ์ค€ DOM ๋…ธ๋“œ์— ๋ถ™์ด๋Š” ์ด๋ฒคํŠธ๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ดํŒ…ํ•ฉ๋‹ˆ๋‹ค.

Simulate๋Š” React๊ฐ€ ์ดํ•ดํ•˜๋Š” ๋ชจ๋“  ์ด๋ฒคํŠธ๋ฅผ ์œ„ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

์—˜๋ฆฌ๋จผํŠธ ํด๋ฆญ

// <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์™€ ๊ฐ™์€ ์ด๋ฒคํŠธ ํ”„๋กœํผํ‹ฐ๋Š” ๋ณ„๋„๋กœ ์ œ๊ณตํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. React์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์ด๋ฒคํŠธ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


Is this page useful?Edit this page