Как проверить HOC с помощью фермента, чай

У меня есть функция HOC, которая получает компонент React и возвращает этот компонент реакции с двумя новыми свойствами метода (handleBack и moveitOnTop), например:

import React, { Component } from "react";
import classNames from "classnames";

 export default WrappedComponent => {
  return class extends Component {
      constructor(props) {
          super(props);
            this.moveitOnTop = this.moveitOnTop.bind(this);
            this.handleBack = this.handleBack.bind(this);

        this.state = {
            isSearchActive: false
        };
    }
    moveitOnTop(flag) {
        this.setState({ isSearchActive: flag });
        window.scrollTo(0, -100);
    }

    handleBack() {
        this.setState({ isSearchActive: false });
        if (document.body.classList.contains("lock-position")) {
            document.body.classList.remove("lock-position");
        }
    }

    render() {
        const props = {
            ...this.props,
            isSearchActive: this.state.isSearchActive,
            moveitOnTop: this.moveitOnTop,
            goBack: this.handleBack
        };

        const classes = classNames({ "c-ftsOnTop": this.state.isSearchActive });
        return (
            <div className = {classes}>
                <WrappedComponent {...props} />
            </div>
        );
    }
  };
 };

Компонент:

 //import fireAnalytics
import { fireAnalytics } from "@modules/js-utils/lib";
class MyComponent extender Component{
  constructor(){
     super(props);
     this.handleClick = this.handleClick.bind(this);
  }

   handleClick(e) {
     // calling analytics function by passing vals
    fireAnalytics({
        event: "GAEvent",
        category: "",
        action: `Clicked on the ${e.target.id} input`,
        label: "Click"
    });

     // I CALL THE HOC PROPERTY
     this.props.moveitOnTop(true);

     // I CALL THE HOC PROPERTY
     this.props.handleBack();
   }

  render(){
     return(
        <div className = "emailBlock">
          <input type = "text" onClick = {handleClick} />
          <Button className = "submit">Submit</Button>
        </div>
     )
  }
}

// export HOC component
export default hoc(MyComponent);

// export just MyComponent
export {MyComponent};

Я хочу протестировать HOC:

  1. Мне нужно проверить, что класс .c-ftsOnTop существует
  2. Мне нужно проверить onClick функцию, которая вызывает this.props.handleBack и `this.props.moveitOnTop'
  3. Мне нужно проверить, существует ли className emailBlock.

Тест, который я пробовал, но терпит неудачу:

 import { mount, shallow } from 'enzyme';
 import sinon from 'sinon';
 import React from 'react';
 import { expect } from 'chai';
 import hoc from '....';
 import {MyComponent} from '...';
 import MyComponent from '....';

 it('renders component', () => {

const props = {}
const HocComponent = hoc(MyComponent);
const wrapper = mount(
  <HocComponent {...props} />
);

console.info('wrapper:', wrapper);
expect(wrapper.find('.c-ftsOnTop')).to.have.lengthOf(1);
expect(wrapper.hasClass('c-fts-input-container')).toEqual(true);
 })

Ошибка

AssertionError: expected {} to have a length of 1 but got 0

console.info: wrapper: ReactWrapper {}

Может ли кто-нибудь помочь мне в том, как сделать HOC?

Зачем добавлять класс? Свойство состояния, которое переключает его по умолчанию, имеет значение false, верно? Вы смотрели на методы отладки или html, чтобы увидеть, что отображается?

jonrsharpe 04.04.2019 23:47

Можете ли вы использовать макеты для ваших компонентов ввода и вывода?

CyclopeanCity 04.04.2019 23:48

Я думаю, что такое тестирование (деталей реализации) не следует поощрять, и вместо этого вы должны проверить, что волнует пользователя вашего компонента, например, наличие элемента при передаче правильных реквизитов и т. д. Я предлагаю вам взять посмотрите на react-testing-library от Kent C Dodds и ознакомьтесь с примерами для тестирования HOC, это намного проще и эффективнее или даже лучше.

Luciano Semerini 05.04.2019 00:11
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
3
3
1 620
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот рабочий тест:

import { mount } from 'enzyme';
import React from 'react';
import WrappedMyComponent from './MyComponent';

it('renders component', () => {
  const props = {}
  const moveitOnTopSpy = jest.spyOn(WrappedMyComponent.prototype, 'moveitOnTop');
  const handleBackSpy = jest.spyOn(WrappedMyComponent.prototype, 'handleBack');
  const wrapper = mount(
    <WrappedMyComponent {...props} />
  );

  // 1. I need to check that class .c-ftsOnTop exists
  wrapper.setState({ isSearchActive: true });  // <= set isSearchActive to true so .c-ftsOnTop is added
  expect(wrapper.find('.c-ftsOnTop')).toHaveLength(1);  // Success!

  // 2. I need to check onClick function that calls this.props.handleBack & `this.props.moveitOnTop'
  window.scrollTo = jest.fn();  // mock window.scrollTo
  wrapper.find('input').props().onClick();
  expect(moveitOnTopSpy).toHaveBeenCalled();  // Success!
  expect(window.scrollTo).toHaveBeenCalledWith(0, -100);  // Success!
  expect(handleBackSpy).toHaveBeenCalled();  // Success!

  // 3. I need to check if className emailBlock exists
  expect(wrapper.find('.emailBlock')).toHaveLength(1);  // Success!
})

Подробности

.c-ftsOnTop добавляется только тогда, когда isSearchActive является true, поэтому просто установите состояние компонента, чтобы добавить класс.

Если вы создадите своих шпионов на методах прототипа для moveitOnTop и handleBack, то когда hoc создаст свои методы экземпляра, привязав их к this в конструкторе, методы экземпляра будут привязаны к вашим шпионам.

window.scrollTo регистрирует ошибку на консоли по умолчанию в jsdom, поэтому вы можете смоделировать ее, чтобы избежать этого сообщения об ошибке и убедиться, что она была вызвана с ожидаемыми аргументами.


Обратите внимание, что приведенный выше тест требует исправления следующих опечаток в MyComponent:

  • extender должно быть extends
  • constructor должен принять props аргумент
  • onClick должен быть привязан к this.handleClick, а не просто handleClick
  • handleClick следует называть this.props.goBack() вместо this.props.handleBack()

(Я предполагаю, что MyComponent был просто собран как пример фактического компонента)

да спасибо. Я забыл упомянуть, что внутри handleClick есть и другие вещи, например, вызов другой функции перед вызовом moveitOnTop, например fireAnalytics(a,b,c,d) . Так что я могу издеваться над этой функцией, как const fireAnalytics = jest.fn();. ?

Theo Itzaris 05.04.2019 10:52

Является ли fireAnalytics функцией, которая импортируется в ваш компонент? Если это так, то да, вы можете смоделировать его из своего тестового файла. @ТеоИцарис

Brian Adams 06.04.2019 10:01

На самом деле это модуль, и я использую функцию. Я обновил код, я вызываю fireAnalytics в handleClick. Если я просто издеваюсь над ним в тесте, я думаю, этого недостаточно, мне также нужно как-то внедрить его в компонент?

Theo Itzaris 06.04.2019 12:12

Другие вопросы по теме