Airbnb의 효소, Jest, Babel을 사용하여 반응 테스트를 진행하다

여보세요, 점원들, 안녕하세요!


네, 점원들, 우선 Jest를 처음부터 시작하는 효소를 설정해야 합니다.그래서 당신은 우리가 어떤 모듈이나 소프트웨어 패키지를 사용할지 알 수 있습니다.
데스크톱의 명령줄에서 이 작업을 수행합니다.
  md testing-with-enzyme && cd testing-with-enzyme
md testing with enzyme - testing with enzyme의 이름을 포함하는 디렉터리를 만듭니다.
&&- 첫 번째 명령이 오류를 일으키지 않으면 두 번째 명령을 실행합니다
cd 효소 테스트 - 현재 디렉터리를 효소 테스트로 변경
  npm init --y && npm i -D @babel/preset-env @babel/preset-react 
  @babel/plugin-proposal-class-properties @types/jest jest
  enzyme enzyme-adapter-react-16 && npm i -P react react-dom
좋아, 나는 이 모든 패키지를 설명하지 않겠지만, 우리는 이 패키지들을 효소와 농담과 함께 일할 것이다.
 type nul > babel.config.js && type nul > jest.config.js && md Tests && md components
Windows OS용 nul을 입력합니다.터치는 UNIX 시스템에 적용됩니다.
우리 바베타.구성js 파일.
module.exports = {
  presets: ['@babel/preset-env', '@babel/preset-react'],
  plugins: ['@babel/plugin-proposal-class-properties']
}
우리 농담.구성js 파일.
module.exports = {
  rootDir: '.',
  displayName: {
    name: 'enzyme-setup',
    color: 'blue'
  },
  runner: 'jest-runner',
  verbose: true,
  errorOnDeprecated: true,
  roots: ['./Tests'],
  moduleFileExtensions: ['js', 'jsx'],
  setupFilesAfterEnv: ['<rootDir>Tests/setupTest.js']
}
테스트 폴더에서 setupTest 를 수행합니다.js 파일.
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

configure({
  adapter: new Adapter()
})
우리의 소포.json 파일.

components 폴더에 4개의 파일을 만듭니다.
  type nul > App.js && type nul > Form.js && type nul > Header.js && type nul > List.js
우리의 제목.js 파일.
import React from 'react'

export default function Header({ message, handleToggleTheme, theme }) {
  return (
    <div className="header">
      <h1>{message}</h1>
      <button className="right" onClick={handleToggleTheme}>
        <i className={theme}></i>
      </button>
    </div>
  )
}
우리 표.js 파일.
import React from 'react'

export default function Form({ handleChange, value, handleClick }) {
  return (
    <div className="form">
      <input
        className="form-control"
        type="text"
        onChange={handleChange}
        value={value}
      />
      <button className="btn" onClick={handleClick}>
        Submit
      </button>
    </div>
  )
}
우리 명단.js 파일.
import React from 'react'

export default function List({ items }) {
  return (
    <ul className="list">
      {items.map(item => (
        <li className="list-item" key={item}>{item}</li>
      ))}
    </ul>
  )
}
우리의 응용 프로그램.js 파일.
import React, { Component } from 'react'
import Header from './Header'
import List from './List'
import Form from './Form'

export default class App extends Component {

  state = {
    listItem: '',
    items: [],
    isDarkTheme: false
  }



  handleChange = ({ target: { value } }) => {
    this.setState({
      listItem: value
    })
  }

  handleClick = () => {
    this.setState({
      items: [...this.state.items, this.state.listItem],
      listItem: ''
    })
  }


  handleToggleTheme = () => {
    this.setState({
      isDarkTheme: !this.state.isDarkTheme
    })
  }

  render() {
    const theme = this.state.isDarkTheme ? 'dark' : 'light'
    return (
      <div className={theme}>
        <Header
          theme={theme}
          message={this.props.message}
          handleToggleTheme={this.state.handleToggleTheme}
        />
        <Form
          handleChange={this.state.handleChange}
          value={this.state.listItem}
          handleClick={this.state.handleClick}
        />
        <List items={this.state.items} />
      </div>
    )
  }

}

App.defaultProps = {
  message: 'Hello World'
}
Tests 폴더에 색인을 작성합니다.테스트js 파일.
import React from 'react'
import App from '../components/App'
import Header from '../components/Header'
import Form from '../components/Form'
import List from '../components/List'
import { shallow, mount } from 'enzyme'

describe('Test App component', () => {
  let wrapper;

  beforeAll(() => {
    wrapper = shallow(<App />)
  })

  it('should not return an error', () => {
    expect(wrapper).toMatchSnapshot()
    console.log(wrapper.debug())
  })
})
그리고 터미널에서 이 명령을 실행합니다
 npm t
만약 그것이 잘못을 던지고 통과하지 않았다면, 너는 갈 수 있었을 것이다.
얕은 렌더링과 전체 설치 렌더링 사이에는 어떤 차이가 있습니까?
shallow와 mount는 매우 유용한 디버깅 방법을 제공합니다.
색인을 업데이트해 보십시오.테스트js 파일이 이렇게 보입니다.
import React from 'react'
import App from '../components/App'
import Header from '../components/Header'
import Form from '../components/Form'
import List from '../components/List'
import { shallow, mount } from 'enzyme'

describe('Test App component', () => {
  let shallowWrapper, mountWrapper;

  beforeAll(() => {
    shallowWrapper = shallow(<App />)
    mountWrapper = mount(<App />)

    console.log(shallowWrapper)
    console.log(mountWrapper)
  })

})

디버깅 방법을 사용하여 구성합니다.


첫 번째 컨트롤러.일지는 이렇게 보인다.
 console.log Tests/index.test.js:12
    <div className="light">
      <Header theme="light" message="Hello World" handleToggleTheme={[Function]} 
        />
      <Form handleChange={[Function]} value="" handleClick={[Function]} />
      <List items={{...}} />
    </div>
두 번째 콘솔.일지는 이렇게 보인다.
  console.log Tests/index.test.js:13
    <App message="Hello World">
      <div className="light">
        <Header theme="light" message="Hello World" handleToggleTheme={[Function]}>
          <div className="header">
            <h1>
              Hello World
            </h1>
            <button className="right" onClick={[Function]}>
              <i className="light" />
            </button>
          </div>
        </Header>
        <Form handleChange={[Function]} value="" handleClick={[Function]}>
          <div className="form">
            <input className="form-control" type="text" onChange={[Function]} value="" />
            <button className="btn" onClick={[Function]} />
          </div>
        </Form>
        <List items={{...}}>
          <ul className="list" />
        </List>
      </div>
    </App>
디버깅 방법은 기본적으로 우리에게 구성 요소의 구조를 제공했다.우리가 shallow에서 그것을 사용할 때, 이것은 우리 구성 요소의 완전한 구조를 제공하지 않습니다. 제목, 표, 목록 구성 요소의 JSX 구조를 볼 수 없지만, 우리가 mount에서 그것을 사용할 때, 그것은 우리 구성 요소의 완전한 구조를 제공합니다. 우리 하위 구성 요소가 사용하는 모든 JSX 요소까지.
효소가 우리에게 제공하는 유용한 방법.

at(인덱스: 번호)


주어진 색인에 따라 포장기 요소를 되돌려줍니다.
우리 프로그램 구성 요소에서shallow와mount의 차이를 사용합니다.
  it('should have an "App" component "at" index of 0', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.at(0).type()).toBe(App);
  });

  it('should return an App', () => {
    let wrapper = mount(<App />);
    expect(wrapper.at(0).type()).toBe(App)
  });

첫 번째 테스트는 실패했지만 두 번째 테스트는 통과했습니다. 왜냐하면 우리의 얕은 구성 요소 중 색인 0곳의 요소 유형은 앱이 아니라 div이지만 우리의 mountend 구성 요소는 앱이기 때문입니다. 구조 부분을 참고하십시오. 얕은 테스트에서 앱을 div로 변경하면 테스트가 통과됩니다.

childAt(인덱스: 숫자)


지정된 인덱스에서 하위 레벨의 새 패키지를 되돌려줍니다.
  it('should have a child component of type "Header" at "index" of 0', () => {
    let wrapper = shallow(<App />);
    expect(wrapper.childAt(0).type()).toBe(Header);
  });

  it('should have a child element of type "div" at "index" of 0', () => {
    let wrapper = mount(<App />);
    expect(wrapper.childAt(0).type()).toBe('div')
  });
우리의 얕은 응용 프로그램의 구조에 따라 첫 번째 하위 항목은 Header이고, 우리가 설치한 응용 프로그램에서 첫 번째 하위 항목은div이어야 한다. 이 두 가지 테스트는 통과해야 한다.

찾기(선택기: EnzymeSelector)


기본적으로 주어진 선택기와 일치하는 모든 노드를 찾습니다.
선택기.

  • find ('div') = 현재 포장에 있는 모든'div'요소를 찾습니다.

  • find ('div.something') = 현재 패키지에서'something'클래스가 있는'div'요소를 찾습니다.
  • find('div[title='오키나와') = 각 속성이'title'이고 값이'오키나와'인'div'요소를 찾습니다.
  • find('#okinawa') = id가'okinawa'인 모든 요소를 찾습니다.
  • find(".okinawa") ="okinawa"류가 있는 모든 요소를 찾습니다.
  • find('div#okinawa>span')=
    오키나와의'div'의 직계 자녀
  • find('div.okinawa+span') ='okinawa'클래스를 가진'div'원소 뒤에 놓인'span'원소를 찾습니다
  • find('div.okinawa span') ='okinawa'로 분류되는'div'원소 내의 각각'span'원소를 찾습니다
  • find(SomeComponent) = SomeComponent 컨트롤러가 있는 각 요소 찾기
  •    function App({ children }){
         return (
           <div>
               {children}
            </div>
         )
       }   
    
    
       function SomeComponent(){
          return (
            <div>
             <h1>
                Hi!
             </h1>
            </div>
          )
       }
    
    
       it('should have length of "1" when finding "SomeComponent" comp', () => {
        const wrapper = shallow(<App>
             <SomeComponent />
         </App>
         )
        expect(wrapper.find(SomeComponent)).toHaveLength(1);
       });
    
    
    모든 유효한 선택기here를 찾을 수 있습니다.

    최근(선택기: EnzymeSelector)


    선택기와 일치하는 최근 상위 레벨을 찾습니다.그것은 자신부터 모든 노드를 두루 돌아다닌다.
    
      it('should have an h1 with a text of "Hello World"', () => {
        let wrapper = shallow(<App />);
        expect(wrapper.find(Header).closest('div.light')).toHaveLength(1);
      });
    
    
      it('should have a parent element of "div" with a class of "light"', () => {
        let wrapper = mount(<App />);
        expect(wrapper.find(Header).closest('div.light')).toHaveLength(1);
      })
    
    
    이 두 가지 테스트는 반드시 통과해야 한다.

    포함 (노드: 노드 | 노드 [])


    포함된 패키지에 일치하는 하위 항목이 있는지 테스트합니다.
       it('should have a node of <Header /> and the right props', () => {
        let wrapper = shallow(<App />);
        expect(wrapper.contains(
          <Header theme="light" message="Hello World" handleToggleTheme= 
               {wrapper.instance().handleToggleTheme} />
        )).toBeTruthy();
      });
    
    
    
      it('should contain these two nodes', () => {
        const wrapper = mount(<App />);
        expect(wrapper.contains([
          <h1>Hi</h1>,
          <button className="right" onClick={wrapper.instance().handleToggleTheme}>
            <i className="light" />
          </button>
        ])).toBeTruthy();
      })
    
    
    우리는 instance () 방법을 사용하여 이 구성 요소의 실례에서handleToggleTheme 함수의 인용을 가져옵니다.잠시 후 실례 방법을 상세하게 소개할 것이다.이 테스트들은 반드시 통과해야 한다.

    일치하는 모든 요소 포함 (노드: 노드 [])


    현재 포장의 모든 노드와 일치해야 합니다.
     it('should have these two nodes when shallow mounting', () => {
       let wrapper = shallow(<App />);
        wrapper.setState({ listItem: '1' })
        expect(wrapper.containsAllMatchingElements(
          [
            <Form handleChange={wrapper.instance().handleChange} value="1" handleClick={wrapper.instance().handleClick} />,
            <Header theme="light" message="Hello World" handleToggleTheme={wrapper.instance().handleToggleTheme} />
          ]
        )).toBeTruthy();
      });
    
      it('should have these two nodes when mounting', () => {
        let wrapper = mount(<App />);
        expect(wrapper.containsAllMatchingElements([
          <h1>Hi</h1>,
          <button className="right" onClick={wrapper.instance().handleToggleTheme}>
            <i className="light" />
          </button>
        ])).toBeTruthy();
      })
    
    
    
    setState 업데이트 상태의 속성 값을 사용하고 있습니다.작업 원리는 React의 setState와 같습니다.this.setState({property: newValue}) . 이 테스트들은 반드시 통과해야 한다.

    containsAnyMatchingElements(노드: 노드 [])


    현재 포장의 최소 노드와 일치해야 합니다.
      it('should this Form with the right props', () => {
        expect(wrapper.containsAnyMatchingElements(
          [
            <Form handleChange={wrapper.instance().handleChange} value="1" handleClick={wrapper.instance().handleClick} />,
          ]
        )).toBeTruthy();
      });
    
      it('should return true because the "i" element is right while "div" element is not the right structure', () =>{
        expect(wrapper.containsAnyMatchingElements([
          <div className="form">
          </div>,
          <i className="light" />
        ])).toBeTruthy();
      });
    
    
    왜 우리가 얕은 부분에서 "1"이라는 값을 가지고 있는지 알고 싶습니다. 이것은 우리가 이전 절에서 setState를 사용하고 목록 항목을 값 1로 업데이트했기 때문입니다.이 테스트들은 반드시 통과해야 한다.

    첫 번째 ()


    동작은 (0)refer와 유사합니다.

    hasClass (클래스: 문자열)


    현재 노드에 className 속성이 있는지 확인하고 값을 확인하십시오.
    
       it('should have a class of "light"', () => {
        let wrapper = shallow(<App />);
        expect(wrapper.hasClass('light')).toBeTruthy();
       });
    
       it('should have a class of "form-control"', () => 
         wrapper = mount(<App />);  
        {
        expect(wrapper.find(Form).find('#form').childAt(0).hasClass('form-control')).toBeTruthy();
      })
    
    
    이 테스트들은 반드시 통과해야 한다.

    html()


    현재 포장된 원시 html 문자열을 되돌려줍니다.
       it('should return the correct string', () => {
        let wrapper = shallow(<App >);
        expect(wrapper.childAt(2).html()).toBe('<ul class="list"></ul>')
      });
    
      it('should have an element with an id of "form"', () => {
        let wrapper = mount(<App >);
        wrapper.setProps({ message: 'Hi' });
        expect(wrapper.find('h1').html()).toBe('<h1>Hi</h1>')
      })
    
    
    이런 테스트도 통과해야 한다.

    인스턴스()


    현재 패키지의 현재 클래스를 되돌려줍니다. 기능 구성 요소에서 사용할 때null을 되돌려줍니다.실례 방법은 루트 노드에서만 사용할 수 있다.
    
       it('should be an instance of App', () => {
        let wrapper = shallow(<App />);
        expect(wrapper.instance()).toBeInstanceOf(App);
      });
    
    
      it('should be an instance of App', () => {
        let wrapper = mount(<App />);
        expect(wrapper.instance()).toBeInstanceOf(App);
      });
    
    이 테스트들은 반드시 통과해야 한다.

    호출(functionPropName)(...매개 변수)


    
      it('should have a prop of "value" with a value of "12344"', () => {
        let wrapper = shallow(<App />);
        wrapper.find(Form).invoke('handleChange')({ target: { value: '12344' } });
        expect(wrapper.find(Form).prop('value')).toBe('12344');
      });
    
    
      it('should truthy value of prop "isDarkTheme"', () => {
        let wrapper = mount(<App />);
        wrapper.find(Header).invoke('handleToggleTheme')()
        expect(wrapper.state('isDarkTheme')).toBeTruthy();
      })
    
    
    이런 테스트도 통과해야 한다.target 속성이 있는 대상을 전달하고 있는지 알고 싶을 수도 있습니다. 이 대상의 값은 다른value 속성이 있는 대상입니다. 왜냐하면 제 handleChange 함수는 다음과 같기 때문입니다.
       handleChange = ({ target: { value } }) => {
        this.setState({
          listItem: value
        })
      }
    

    is(선택기: EnzymeSelector)


    선택기가 현재 포장과 일치하는지 확인하십시오.
    
      it('should return false when checking with ".is"', () => {
        let wrapper = shallow(<App />);
        expect(wrapper.find(List).find('ul').is('.list')).toBeFalsy();
      });
    
    
      it('should return true when checking with ".is"', () => {
        let wrapper = mount(<App />);
        expect(wrapper.find(List).find('ul').is('.list')).toBeTruthy();
      });
    
    첫 번째 테스트가 실패하고 이로 인해 오류가 발생한 원인
    shallow를 사용할 때의 원소 구조는 다음과 같다.
        <div className="light">
          <Header theme="light" message="Hello World" handleToggleTheme={[Function]} 
            />
          <Form handleChange={[Function]} value="" handleClick={[Function]} />
          <List items={{...}} />
        </div>
    
    그것은 l 원소를 나타내지 않지만, 우리가 mount에서 그것을 사용할 때, 그것은 작동할 수 있다.

    isEmptyRender()


    현재 포장이 null 또는 false 로 되돌아오면true로 되돌아옵니다.
    
      it('should not be falsy because "App" does not return neither null or false', () => {
        let wrapper = shallow(<App />);
        expect(wrapper.isEmptyRender()).toBeFalsy();
      });
    
      it('should return "Nothing" literally', () => {
        class Nothing extends React.Component {
          render() {
            return (
              null
            )
          }
        }
        let wrapper = mount(<Nothing />);
        expect(wrapper.isEmptyRender()).toBeTruthy();
      });
    
    
    이 테스트들은 반드시 통과해야 한다.우리가render 방법에서null로 되돌아왔기 때문에, 두 번째 테스트는 통과되었습니다.

    키()


    현재 포장된 키 값을 되돌려줍니다.
      it('should have a prop of items with a length of 2 and a key value of "japan"', () => {
        let wrapper = mount(<Form />);
        let form = wrapper.find(Form);
        form.invoke('handleChange')({ target: { value: 'okinawa' } });
        form.invoke('handleClick')();
        form.invoke('handleChange')({ target: { value: 'japan' } });
        form.invoke('handleClick')();
    
        expect(wrapper.find(List).prop('items')).toHaveLength(2);
        expect(wrapper.find(List).find('ul').childAt(1).key()).toBe('japan');
      });
    
    
    

    마지막 ()


    현재 선택한 포장에 기반한 마지막 노드를 되돌려줍니다.
    
      it('should return the last child type which is "List"', () => {
        let wrapper = shallow(<App />);
        expect(wrapper.children().last().type()).toBe(List);
      });
    
      it('should return the last child type which is "div"', () => {
        let wrapper = mount(<App />)
        expect(wrapper.children().last().type()).toBe('div');
      });
    
    

    이름 ()


    현재 패키지의 이름 을 반환합니다.
       it('should return a name with a value of "div"', () => {
        let wrapper = shallow(<App />);
        expect(wrapper.name()).toBe('div');
      });
    
      it('should return a name with a value of "App"', () => {
        let wrapper = mount(<App />);
        expect(wrapper.name()).toBe('App');
      });
    
    이해에 문제가 있으면 구조 부분을 다시 참조하십시오.

    필터(선택기: EnzymeSelector)


    그것은 주어진 선택기에 따라 새로운 포장기를 되돌려준다.
      it('should have a prop of "item" with length of 3', () => {
        let wrapper = mount(<App />);
        let form = wrapper.find(Form);
        let values = ["ohio", "usa", "amawa"];
        values.forEach((value) => {
          form.invoke('handleChange')({ target: { value } });
          form.invoke('handleClick')();
        })
    
      expect(wrapper.find(List).find('ul li').filter('.list-item')).toHaveLength(3);
    
      });
    
    });
    

    도구()


    현재 포장된prop 대상 되돌리기
      it('should have a prop "items" with a value of []', () => {
        let wrapper = shallow(<App />);
        expect(wrapper.find(List).props().items).toEqual([]);
      });
    
    
      it('should have a prop "message" with a value of "Hello World"', () => {
        let wrapper = mount(<App />);
    
        expect(wrapper.find(Header).props().message).toBe("Hello World");
      });
    
    

    아이템(키: 문자열)


    현재 패키지의 속성 값을 되돌려줍니다.
      it('should have a prop "items" with a value of []', () => {
        let wrapper = shallow(<App />);
        expect(wrapper.find(List).prop('items')).toEqual([]);
      });
    
      it('should have a prop "message" with a value of "Hello World"', () => {
        let wrapper = mount(<App />);
    
        expect(wrapper.find(Header).prop('message')).toBe("Hello World");
      });
    
    

    setProps(newProps:any)


    루트 노드의 새 아이템 대상을 설정합니다.루트 노드에서만 사용할 수 있습니다.
    
     it('should have an updated prop "message" with a value of "What the fun"', () => {
        let wrapper = mount(<App />);
        wrapper.setProps({ message: 'What the fun' })
        expect(wrapper.find(Header).prop('message')).toBe("What the fun");
      });
    
    

    상태 설정(newState:any, callbackFunc:Function)


    루트 노드의 새 상태 객체를 설정합니다.루트 노드에서만 사용할 수 있습니다.
      it('should have an updated prop "isDarkTheme" with a value of true', () => {
        let wrapper = mount(<App />);
        wrapper.setState({ isDarkTheme: true });
        expect(wrapper.state('isDarkTheme')).toBeTruthy();
      });
    
    

    아날로그 (이벤트: 문자열,...args)


    현재 패키지의 이벤트를 호출합니다.
      it('should have an updated value of "1234"', () => {
        let wrapper = mount(<App />);
        wrapper.find('input').simulate('change', { target: { value: '1234' } });
        expect(wrapper.state('listItem')).toBe('1234');
      });
    
    

    상태 (키: 문자열)


    상태 속성의 값을 되돌려줍니다.
    
      it('should a input with a value of "abc"', () => {
        let wrapper = shallow(<App />);
        wrapper.setState({ listItem: 'abc' });
        expect(wrapper.state('listItem')).toBe('abc');
      });
    
      it('should have an updated "message" prop with a value of "Hi"', () => {
        let wrapper = mount(<App />);
        wrapper.setProps({ message: 'Hi' });
        expect(wrapper.prop('message')).toBe('Hi');
      })
    
    
    

    텍스트 ()


    현재 포장된 텍스트를 되돌려줍니다.
      it('should a text of "Hello World"', () => {
        let wrapper = mount(<App />);
        expect(wrapper.find('h1').text()).toBe('Hello World');
      });
    
    

    유형()


    현재 포장의 유형을 되돌려줍니다.
    
       it('should return the App', () => {
        let wrapper = shallow(<App />);
        expect(wrapper.at(0).type()).toBe('div');
      }); 
    
      it('should return the App', () => {
        let wrapper = mount(<App />);
        expect(wrapper.at(0).type()).toBe(App);
      });
    
    
    이것 좀 봐, 개발자를 위해 너의 표지 사진을 만들어라.

    이 글을 읽어 주셔서 감사합니다.


    좋은 하루 되세요.😃!.

    좋은 웹페이지 즐겨찾기