2017-08-11 1 views
2

J'ai un composant React avec un dialogue modal (construit en utilisant reactstrap, mais d'autres ont signalé des problèmes similaires avec react-bootstrap et d'autres types de composants modaux). Enzyme ne trouve aucun des composants à l'intérieur du modal, même s'ils sont très bien dans l'application. exemple minimal:Le contenu des boîtes de dialogue modales React n'est pas disponible pour les tests enzymatiques utilisant mount()

import React from 'react' 
import { Modal } from 'reactstrap' 

export default class MyModal extends React.Component { 

    render() { 
     return (
      <div className="outside"> Some elements outside of the dialog </div> 
      <Modal isOpen={this.props.modalOpen}> 
       <div className="inside"> Content of dialog </div> 
      </Modal> 
     ); 
    } 
} 

Je voudrais tester le contenu (dans ce cas, en utilisant jest) comme celui-ci

import React from 'react' 
import MyModal from './MyModal' 
import { mount } from 'enzyme' 

it('renders correctly',() => { 
    const wrapper = mount(<MyModal modalOpen/>); 

    expect(wrapper).toMatchSnapshot(); 

    // Passes 
    expect(wrapper.find('.outside')).toHaveLength(1); 

    // Fails, 0 length 
    expect(wrapper.find('.inside')).toHaveLength(1); 
}); 

Le test détecte le contenu en dehors du Modal correctement, mais ne trouve rien à l'intérieur . En regardant l'instantané montre que, en effet, rien à l'intérieur du <Modal> n'est rendu. Cependant, cela fonctionne si je remplace mount par shallow. Le problème avec cela est que j'ai besoin mount pour tester les méthodes de cycle de vie comme componentDidMount.

Pourquoi le mount ne restitue-t-il pas le contenu du modal? Je pensais que le point entier était qu'il rendait l'arbre entier des éléments enfants.

Répondre

6

Le problème est qu'un dialogue modal est (dans la plupart des implémentations) un composant portal. Cela signifie qu'il crée des éléments DOM qui sont attachés directement à la racine du document, plutôt que d'être des enfants du composant React parent.

La méthode find du ReactWrapper créé par mount regarde à travers les DOM en commençant par l'élément créé par le composant de haut niveau, donc il ne peut pas trouver le contenu du modal. Mais shallow de l'enzyme ne se fixe pas à un DOM, et construit à la place son propre arbre de composants qui contient le contenu modal.

Pour tester un composant de portail, vous devez d'abord rechercher les éléments DOM qui ont été attachés au corps du document. Ensuite, vous pouvez créer une nouvelle ReactWrapper autour d'eux afin que toutes les fonctions enzymatiques habituelles de travail:

import React from 'react' 
import MyModal from './MyModal' 
import { mount, ReactWrapper } from 'enzyme' 

it('renders correctly',() => { 
    const wrapper = mount(<MyModal modalOpen/>); 

    expect(wrapper).toMatchSnapshot(); 

    // Passes 
    expect(wrapper.find('.outside')).toHaveLength(1); 

    // Construct new wrapper rooted at modal content 
    inside_els = document.getElementsByClassName("inside")[0] 
    inside_wrapper = new ReactWrapper(inside_els, true) 

    // Passes 
    expect(inside_wrapper.find('.inside')).toHaveLength(1); 
}); 

Actuellement, c'est un open bug en enzyme.

Mise à jour: Il semble que Enzyme laisse également le modal attaché au DOM après la fin du test, de sorte que vous pouvez vous retrouver avec plusieurs boîtes de dialogue ouvertes dans un test ultérieur. Si c'est un problème, vous pouvez effacer le DOM après chaque test comme ceci:

afterEach(() => { 
    var node = global.document.body; 
    while (node.firstChild) { 
    node.removeChild(node.firstChild); 
    } 
});