Comment tester React PropTypes à travers Jest?

j'écris des tests de Jest pour mon code React et j'espère utiliser / tester les vérifications PropType. Je suis tout à fait nouveau dans L'univers Javascript. J'utilise npm pour installer react-0.11.2 et avoir un simple:

var React = require('react/addons');

dans mes tests. Mon test ressemble beaucoup à l'exemple de tutoriel jest/react avec du code comme:

var eventCell = TestUtils.renderIntoDocument(
  <EventCell
    slot={slot}
    weekId={weekId}
    day={day}
    eventTypes={eventTypes}
    />
);

var time = TestUtils.findRenderedDOMComponentWithClass(eventCell, 'time');
expect(time.getDOMNode().textContent).toEqual('19:00 ');

cependant, il semble que les vérifications de type PropType dans le composant EventCell ne sont pas déclenchées. Je comprends que les vérifications ne sont exécutées qu'en mode développement, mais ensuite j'ai aussi pensé que le fait de passer react par npm vous donnait la version de développement. Les vérifications se déclenchent dans mon navigateur lorsque je construis le composant avec watchify.

Qu'est-ce que je rate?

24
demandé sur machineghost 2014-09-30 19:45:33

5 réponses

Le problème sous-jacent est Comment tester console.log ?

la réponse courte est que vous devez remplacer le console.{method} pour la durée du test. L'approche commune est d'utiliser espions . Dans ce cas particulier, vous pouvez utiliser stubs pour empêcher la sortie.

voici un exemple d'implémentation utilisant Sinon.js (Sinon.js fournit des espions autonomes, des talons et des moqueries):

import {
    expect
} from 'chai';
import DateName from './../../src/app/components/DateName';
import createComponent from './create-component';
import sinon from 'sinon';

describe('DateName', () => {
    it('throws an error if date input does not represent 12:00:00 AM UTC', () => {
        let stub;

        stub = sinon.stub(console, 'error');

        createComponent(DateName, {date: 1470009600000});

        expect(stub.calledOnce).to.equal(true);
        expect(stub.calledWithExactly('Warning: Failed propType: Date unix timestamp must represent 00:00:00 (HH:mm:ss) time.')).to.equal(true);

        console.error.restore();
    });
});

dans cet exemple, DataName composante jettera une erreur lors de l'initialisation avec une valeur de timestamp qui ne représente pas une date précise (12:00:00 AM).

j'entaille la méthode console.error (c'est ce que le module Facebook warning utilise en interne pour générer l'erreur). Je m'assure que le talon a été appelé une fois et avec exactement un paramètre représentant l'erreur.

29
répondu Gajus 2017-09-27 13:17:30

Intro

la réponse de @Gajus m'a certainement aidé (donc, merci Gajus ). Cependant, j'ai pensé que je fournirais une réponse qui:

  • utilise un plus up-to-date React (v15.4.1)
  • utilise Jest (qui vient avec React)
  • permet de tester valeurs de prop multiple pour un seul prop
  • est plus générique

résumé

comme L'approche suggérée ici par Gajus et ailleurs par d'autres, l'approche de base que je suggère est aussi de déterminer si oui ou non console.error est utilisé par React en réponse à une valeur d'essai inacceptable . Plus précisément, cette approche implique de faire pour chaque valeur de l'hélice d'essai:

  • mocking and clearing console.error (pour s'assurer que les appels antérieurs à console.error n'interfèrent pas),
  • création du composant à l'aide de la valeur d'essai de l'hélice et
  • "
  • confirmant si oui ou non console.error a été tiré comme prévu.

Le testPropTypes Fonction

le code suivant peut être placé soit dans le test, soit dans un module/fichier distinct importé/requis:

const testPropTypes = (component, propName, arraysOfTestValues, otherProps) => {
    console.error = jest.fn();
    const _test = (testValues, expectError) => {
        for (let propValue of testValues) {
            console.error.mockClear();
            React.createElement(component, {...otherProps, [propName]: propValue});
            expect(console.error).toHaveBeenCalledTimes(expectError ? 1 : 0);
        }
    };
    _test(arraysOfTestValues[0], false);
    _test(arraysOfTestValues[1], true);
};

appelant la fonction

tout essai examinant propTypes can appel testPropTypes utilisant trois ou quatre paramètres :

  • component , le composant modifié par la prop;
  • propName , la chaîne nom de l'hélice à l'essai;
  • arraysOfTestValues , un tableau de tableaux de toutes les valeurs d'essai désirées de l'hélice à essayer:
    • le premier sous-tableau contient toutes les valeurs acceptable props test, tandis que
    • le deuxième sous-tableau contient toutes les valeurs inacceptable prop Test; et
  • facultativement, otherProps , un objet contenant paires de nom/valeur d'hélice pour tout autre accessoire requis de ce composant.

    l'objet otherProps est nécessaire pour s'assurer que React ne fait pas d'appels non pertinents à console.error parce que les autres accessoires requis sont par inadvertance manquant. Il suffit d'inclure une seule valeur acceptable pour tous les accessoires requis, par exemple {requiredPropName1: anyAcceptableValue, requiredPropName2: anyAcceptableValue} .

"1519280920 De La Fonction" Logique

la fonction fait ce qui suit:

  • "It crée une maquette de console.error qui est ce que React utilise pour signaler des accessoires de type incorrect.

  • pour chaque sous-tableau des valeurs d'essai des hélices à condition qu'il boucle à travers chaque valeur d'essai des hélices dans chaque sous-tableau pour tester le type d'hélice:

    • le premier des deux sous-tableaux doit être une liste de valeurs acceptables des propr es d'essai .
    • la seconde doit être de valeurs inacceptables des propr es d'essai .
  • à l'intérieur de la boucle pour chaque valeur de l'hélice d'essai, la simulation console.error est d'abord autorisée de sorte que tout message d'erreur détecté peut être supposé provenir de cet essai.

  • une instance du composant est alors créée en utilisant la valeur d'essai ainsi que tout autre accessoire nécessaire qui n'est pas actuellement testé.

  • enfin, une vérification est faite à voir si un avertissement a été déclenché , ce qui devrait se produire si votre test a essayé de créer un composant en utilisant un accessoire inapproprié ou manquant.

test des accessoires optionnels par rapport aux accessoires requis

noter que l'affectation de null (ou undefined ) à une valeur prop est, du point de vue de React, essentiellement la même chose que de ne pas fournir de valeur pour cet accessoire. Par définition, cela est acceptable pour une option prop, mais inacceptable pour un requis. Ainsi, en plaçant null dans le tableau des valeurs acceptables ou inacceptables que vous testez si cette hélice est optionnelle ou requise respectivement .

Exemple De Code

MyComponent.js (juste le propTypes ):

MyComponent.propTypes = {
    myProp1: React.PropTypes.number,      // optional number
    myProp2: React.PropTypes.oneOfType([  // required number or array of numbers
        React.PropTypes.number,
        React.PropTypes.arrayOf(React.PropTypes.number)
    ]).isRequired

MyComponent.test.js:

describe('MyComponent', () => {

    it('should accept an optional number for myProp1', () => {
        const testValues = [
            [0, null],   // acceptable values; note: null is acceptable
            ['', []] // unacceptable values
        ];
        testPropTypes(MyComponent, 'myProp1', testValues, {myProp2: 123});
    });

    it('should require a number or an array of numbers for myProp2', () => {
        const testValues = [
            [0, [0]], // acceptable values
            ['', null] // unacceptable values; note: null is unacceptable
        ];
        testPropTypes(MyComponent, 'myProp2', testValues);
    });
});

Limitation de cette approche (IMPORTANT)

il y a actuellement des limites importantes sur la façon dont vous pouvez utiliser cette approche qui, si elle est trop poussée, pourrait être la source de quelques bogues de test difficiles à tracer. Les raisons et les implications de ces limitations sont expliquées dans cette autre Donc question / réponse . En résumé, pour les types de props simples, comme pour myProp1 , vous pouvez tester autant de non - null valeurs de Props de test inacceptables que vous voulez tant qu'ils sont tous de différents types de données . Pour certains types d'accessoires complexes, comme pour myProp2 , vous pouvez seulement tester un simple Non -" inacceptable null prop value de tout type . Voir cette autre question / réponse pour en savoir plus une discussion en profondeur.

6
répondu Andrew Willems 2017-05-23 12:09:26

Moqueur console.error n'est pas approprié pour une utilisation dans les tests unitaires! @Andrewwwillems lié à une autre question dans un commentaire ci-dessus qui décrit les problèmes avec cette approche.

Check out ce numéro sur facebook / prop-types pour discuter de la possibilité pour cette bibliothèque de lancer au lieu de journaliser les erreurs propType (au moment de l'écriture, il n'est pas supporté).

, j'ai publié un bibliothèque d'assistance à fournir que le comportement dans le temps de le dire, check-prop-types . Vous pouvez l'utiliser comme ceci:

import PropTypes from 'prop-types';
import checkPropTypes from 'check-prop-types';

const HelloComponent = ({ name }) => (
  <h1>Hi, {name}</h1>
);

HelloComponent.propTypes = {
  name: PropTypes.string.isRequired,
};

let result = checkPropTypes(HelloComponent.propTypes, { name: 'Julia' }, 'prop', HelloComponent.name);
assert(`result` === null);

result = checkPropTypes(HelloComponent.propTypes, { name: 123 }, 'prop', HelloComponent.name);
assert(`result` === 'Failed prop type: Invalid prop `name` of type `number` supplied to `HelloComponent`, expected `string`.');
4
répondu Phil 2017-07-06 20:17:10

Un nouveau package jest-prop-type de l'erreur est simple d'ajouter et échoue sur PropType erreurs:

Installer via:

yarn add -D jest-prop-type-error

puis ajouter ce qui suit à votre package.json 's setupFiles dans la jest section:

"setupFiles": [
  "jest-prop-type-error"
]
2
répondu YPCrumble 2018-08-08 16:22:01

étant donné que ReactJS n'envoie que des avertissements à la console mais ne lance pas d'erreur, je teste les valeurs prop de cette façon:

var myTestElement = TestUtils.renderIntoDocument(
<MyTestElement height={100} /> );

it("check MyTestElement props", function() {

   expect( typeof myTestElement.props.height ).toEqual ( 'number' );

});
1
répondu Guy Laor 2015-06-11 21:02:41