web-dev-qa-db-fra.com

Test des modifications de React état du composant et espionnage des méthodes d'instance à l'aide d'une enzyme

Je travaille sur un composant wrapper pour charger en douceur les images dans React. J'utilise une enzyme avec du moka, du chai et sinon pour tester unitaire mon composant. Dans le test ici, j'essaie de tester que:

  1. l'état du composant est mis à jour lorsque l'image est chargée

  2. la méthode d'occurrence onLoad sur le composant a été appelée

 const wrapper = shallow (); 
 
 const onLoad = wrapper.find ('img'). props (). onLoad; 
 const onLoadSpy = sinon. espion (onLoad); wrapper.update (); 
 const status = wrapper.state (). status; 
 expect (onLoadSpy) .to.have.been.called; 
 expect (status). to.equal ('LOADED'); 

Je trouve que ni la mise à jour de l'état n'est reflétée par l'enzyme ni le nombre d'appels de l'espion onLoad n'est mis à jour. Voici le code correspondant pour le test:

export default class Image extends Component {
  constructor(props) {
    super(props);
    if (props.src != null && typeof props.src === 'string') {
      this.state = {
        status: LOADING,
      };
    } else {
      this.state = {
        status: PENDING,
      };
    }
    this.onLoad = this.onLoad.bind(this);
  }

  onLoad() {
    this.setState({
      status: LOADED,
    });
  }

  render() {
    //lots of code above the part we care about
    const defaultImageStyle = style({
      opacity: 0,
      transisition: 'opacity 150ms ease',
    });

    const loadedImageStyle = style({
      opacity: 1,
    });

    let imageStyle = defaultImageStyle;

    if (this.state.status === LOADED) {
      imageStyle = merge(defaultImageStyle, loadedImageStyle);
    } else {
      imageStyle = defaultImageStyle;
    }


    let image;
    if (alt != null) {
      image = (<img
        className={imageStyle}
        src={src}
        width={width}
        height={height}
        alt={alt}
        onLoad={this.onLoad}
      />);
    } else {
      image = (<img
        className={imageStyle}
        src={src}
        width={width}
        height={height}
        role="presentation"
        onLoad={this.onLoad}
      />);
    }

    let statusIndicator = null;
    if (this.state.status === LOADING) {
      statusIndicator = (<div className={loadingStyle}></div>);
    }

    return (<div className={wrapperStyle}>
      {statusIndicator}
      {image}
    </div>);

    }}

Pour jeter un œil au code complet pour un meilleur contexte:

14
vamsiampolu

On peut tester cela sans compter sur sinon. En s'attendant à ce que les écouteurs d'événements onLoad et onFire soient appelés, les tests vérifient si img déclenche les événements load et error.

Au lieu de cela, les événements de simulateimg à l'aide de enzyme et vérifiez que la transition d'état appropriée se produit:

it('has a state of LOADED if a good src prop is supplied', () => {
  const wrapper = shallow(<Image 
    src="anyString.jpg"
    width={300}
    height={300}
  />);

  const img = wrapper.find('img');
  img.simulate('load');
  const status = wrapper.state().status;
  expect(status).to.equal('LOADED');
});

Cela élimine également la nécessité de mount le composant. Les tests mis à jour peuvent être trouvés ici .

16
vamsiampolu

Le principal problème que je vois avec cette approche est que l'État est une chose interne, et non quelque chose qui devrait être connu en dehors du composant. Vous divulguez maintenant des informations d'état ("état" dans ce cas) dans les tests.

Cela signifie que vous ne faites pas de "test de boîte noire", qui est le type de test le plus précieux. Vous divulguez les détails d'implémentation du composant. En d'autres termes, "l'encapsulation" doit être très pris en compte.

Il existe peut-être de meilleures façons de tester cela. Vous pouvez par exemple exporter également un composant de présentation, qui prend les parties de l'état dont vous avez besoin pour tester comme accessoires. Ou recherchez un élément qui serait rendu lorsque le statut est "CHARGÉ" avec la méthode enzyme find .

0
darmis