web-dev-qa-db-fra.com

Jest La fonction fictive attendue a été appelée, mais pas

J'ai examiné diverses suggestions pour résoudre le test d'une propriété de classe sans succès et je me demandais si quelqu'un pourrait peut-être éclaircir un peu plus mon erreur, voici les tests que j'ai essayés avec l'erreur attendue. la fonction a été appelée, mais elle ne l’a pas été.

Search.jsx

import React, { Component } from 'react'
import { func } from 'prop-types'
import Input from './Input'
import Button from './Button'

class SearchForm extends Component {
  static propTypes = {
    toggleAlert: func.isRequired
  }

  constructor() {
    super()

    this.state = {
      searchTerm: ''
    }

    this.handleSubmit = this.handleSubmit.bind(this)
  }

  handleSubmit = () => {
    const { searchTerm } = this.state
    const { toggleAlert } = this.props

    if (searchTerm === 'mocky') {
      toggleAlert({
        alertType: 'success',
        alertMessage: 'Success!!!'
      })

      this.setState({
        searchTerm: ''
      })
    } else {
      toggleAlert({
        alertType: 'error',
        alertMessage: 'Error!!!'
      })
    }
  }

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

  render() {
    const { searchTerm } = this.state
    const btnDisabled = (searchTerm.length === 0) === true

    return (
      <div className="well search-form soft Push--bottom">
        <ul className="form-fields list-inline">
          <li className="flush">
            <Input
              id="search"
              name="search"
              type="text"
              placeholder="Enter a search term..."
              className="text-input"
              value={searchTerm}
              onChange={this.handleChange}
            />
            <div className="feedback Push-half--right" />
          </li>
          <li className="Push-half--left">
            <Button className="btn btn--positive" disabled={btnDisabled} onClick={this.handleSubmit}>
              Search
            </Button>
          </li>
        </ul>
      </div>
    )
  }
}

export default SearchForm

Première option:

it('should call handleSubmit function on submit', () => {
    const wrapper = shallow(<Search toggleAlert={jest.fn()} />)
    const spy = jest.spyOn(wrapper.instance(), 'handleSubmit')
    wrapper.instance().forceUpdate()
    wrapper.find('.btn').simulate('click')
    expect(spy).toHaveBeenCalled()
    spy.mockClear()
  })

Deuxième option:

it('should call handleSubmit function on submit', () => {
    const wrapper = shallow(<Search toggleAlert={jest.fn()} />)
    wrapper.instance().handleSubmit = jest.fn()
    wrapper.update()
    wrapper.find('.btn').simulate('click')
    expect(wrapper.instance().handleSubmit).toHaveBeenCalled()
  })

J'obtiens qu'avec une propriété de classe, la fonction est une instance de la classe nécessitant la mise à jour du composant pour pouvoir enregistrer la fonction. Il semble toutefois que la fonction handleSubmit du composant soit appelée à la place du simulacre?

Echanger le descripteur en remplaçant une fonction de classe en tant que méthode me permet d'accéder au prototype de classe qui passe le test lorsque vous espionnez Search.prototype, mais j'aimerais vraiment obtenir une solution à l'approche des propriétés de classe. 

Toutes les suggestions et recommandations seraient reconnaissantes!

3
styler

Je suppose que votre test unitaire doit être suffisamment robuste pour détecter la variable error, si des modifications indésirables du code surviennent.

S'il vous plaît inclure des assertions strictes dans vos tests.

Pour les déclarations conditionnelles, veuillez couvrir également les branches. Par exemple, dans le cas d'instructions if et else, vous devrez écrire des tests two.

Pour les actions de l'utilisateur, vous devez essayer de simuler les actions plutôt que d'appeler la fonction manuellement.

S'il vous plaît voir l'exemple ci-dessous,

import React from 'react';
import { shallow } from 'enzyme';
import { SearchForm } from 'components/Search';


describe('Search Component', () => {
  let wrapper;
  const toggleAlert = jest.fn();
  const handleChange = jest.fn();
  const successAlert = {
    alertType: 'success',
    alertMessage: 'Success!!!'
  }
  const errorAlert = {
    alertType: 'error',
    alertMessage: 'Error!!!'
  }
  beforeEach(() => {
    wrapper = shallow(<SearchForm toggleAlert={toggleAlert} />);
  });
  it('"handleSubmit" to have been called with "mocky"', () => {
    expect(toggleAlert).not.toHaveBeenCalled();
    expect(handleChange).not.toHaveBeenCalled();
    wrapper.find('Input').simulate('change', { target: { value: 'mocky' } });
    expect(handleChange).toHaveBeenCalledTimes(1);
    expect(wrapper.state().searchTerm).toBe('mocky');
    wrapper.find('Button').simulate('click');
    expect(toggleAlert).toHaveBeenCalledTimes(1);
    expect(toggleAlert).toHaveBeenCalledWith(successAlert);
    expect(wrapper.state().searchTerm).toBe('');
  });

  it('"handleSubmit" to have been called with "other than mocky"', () => {
    expect(toggleAlert).not.toHaveBeenCalled();
    expect(handleChange).not.toHaveBeenCalled();
    wrapper.find('Input').simulate('change', { target: { value: 'Hello' } });
    expect(handleChange).toHaveBeenCalledTimes(1);
    expect(wrapper.state().searchTerm).toBe('Hello');
    wrapper.find('Button').simulate('click');
    expect(toggleAlert).toHaveBeenCalledTimes(1);
    expect(toggleAlert).toHaveBeenCalledWith(errorAlert);
    expect(wrapper.state().searchTerm).toBe('Hello');
  });
});

3
Kuldeep Bhimte

J'ai donc réussi à créer une solution de travail en mettant tout d'abord à jour l'instance du wrapper, puis en mettant à jour le wrapper. Test fonctionne maintenant.

Test de travail ressemble à:

it('should call handleSubmit function on submit', () => {
    const wrapper = shallow(<Search toggleAlert={jest.fn()} />)
    wrapper.instance().handleSubmit = jest.fn()
    wrapper.instance().forceUpdate()
    wrapper.update()
    wrapper.find('.btn').simulate('click')
    expect(wrapper.instance().handleSubmit).toHaveBeenCalled()
  })
1
styler

Essayez quelque chose comme ça 

it('should call handleSubmit function on submit', () => {
        const toggleAlert = jest.fn();
        const wrapper = shallow(<Search toggleAlert={toggleAlert} />)
        wrapper.setState({ searchText: 'mocky' });
        wrapper.find('Button').at(0).simulate('click');
        expect(toggleAlert).toHaveBeenLastCalledWith({
                   alertType: 'success',
                   alertMessage: 'Success!!!'
              });
      })

****Mettre à jour

 constructor(props) {
    super(props) //you have to add props to access it this.props

    this.state = {
      searchTerm: ''
    }

    this.handleSubmit = this.handleSubmit.bind(this)
  }

Vous ne devriez pas avoir besoin d'écrire des tests unitaires pour ce scénario. Vous devriez pouvoir avoir confiance que le cadre déclenchera les bons gestionnaires que vous avez fournis. Un test plus utile serait un test qui se moque du prop toggleAlert et teste la méthode d'instance handleSubmit. C’est là que réside la majorité de la logique personnalisée et, par conséquent, où nous sommes le plus susceptibles de trouver des erreurs. Le test des instantanés devrait convenir à tout ce qui fait partie de la sortie de la fonction de rendu.

Une suite de tests judicieuse pour ce composant ressemblerait à quelque chose comme ce qui suit:

describe('handleSubmit', () => {
  let wrapper;
  let spy;

  describe('when searchTerm is "mocky"', () => {
    beforeEach(() => {
      spy = jest.fn();
      wrapper = shallow(<SearchForm toggleAlert={spy} />);
      wrapper.setState({ searchTerm: 'mocky' });
    });

    it('will fire spy with expected arguments', () => {
      // verify that spy has not been fired prior to test
      expect(spy).not.toBeCalled();

      wrapper.instance().handleSubmit();

      expect(spy).toBeCalled();
      expect(spy).toBeCalledWith({
        alertType: 'success',
        alertMessage: 'Success!!!'
      });
    });

    it('will set searchTerm to ""', () => {
      expect(wrapper.state('searchTerm')).toBe('mocky');
      wrapper.instance().handleSubmit();
      expect(wrapper.state('searchTerm')).toBe('');
    });
  });

  describe('when searchTerm is "something else"', () => {
    beforeEach(() => {
      spy = jest.fn();
      wrapper = shallow(<SearchForm toggleAlert={spy} />);
      wrapper.setState({ searchTerm: 'something else' });
    });

    it('will fire spy with expected arguments', () => {
      // verify that spy has not been fired prior to test
      expect(spy).not.toBeCalled();

      wrapper.instance().handleSubmit();

      expect(spy).toBeCalled();
      expect(spy).toBeCalledWith({
        alertType: 'error',
        alertMessage: 'Error!!!'
      });
    });
  });
});
0
trevorgk