¿Cómo probar PropTypes de React a través de la broma?


Estoy escribiendo pruebas de Jest para mi código de React y espero hacer uso de/test las comprobaciones PropType. Soy bastante nuevo en el universo Javascript. Estoy usando npm para instalar react-0.11.2 y tengo un simple:

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

En mis pruebas. Mi prueba es bastante similar al ejemplo del tutorial jest / react con código como:

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 ');

Sin embargo, parece que las comprobaciones PropType en el componente EventCell no se están activando. Entiendo que las comprobaciones solo se ejecutan en modo de desarrollo, pero luego también pensé que obtener react a través de npm le dio la versión de desarrollo. Las comprobaciones se activan en mi navegador cuando compilo el componente con watchify.

¿Qué me estoy perdiendo?

Author: machineghost, 2014-09-30

5 answers

El problema subyacente es ¿Cómo probar console.log?

La respuesta corta es que debe reemplazar el console.{method} durante la duración de la prueba. El enfoque común es usar espías . En este caso particular, es posible que desee utilizar stubs para evitar la salida.

Aquí hay un ejemplo de implementación usando Sinon.js (Sinon.js proporciona espías independientes, talones y burlas):

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();
    });
});

En este ejemplo, el componente DataName lanzará un error cuando inicializado con un valor de marca de tiempo que no representa una fecha precisa (12:00:00 AM).

Estoy stubbing el método console.error (Esto es lo que Facebook warning módulo está utilizando internamente para generar el error). Me aseguro de que el stub ha sido llamado una vez y con exactamente un parámetro que representa el error.

 29
Author: Gajus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-27 13:17:30

Intro

La respuesta de @Gajus definitivamente me ayudó (así que, gracias Gajus). Sin embargo, pensé que iba a dar una respuesta que:

  • Utiliza un React más actualizado (v15.4.1)
  • Usa Jest (que viene con React)
  • Permite probar múltiples valores de prop para un solo prop
  • Es más genérico

Resumen

Como el enfoque sugerido aquí por Gajus y en otros lugares por otros, el enfoque básico que estoy sugiriendo es también para determinar si console.error es utilizado o no por React en respuesta a un valor de prop de prueba inaceptable. Específicamente, este enfoque implica hacer lo siguiente para cada valor de prop de prueba:

  • burla y limpieza console.error (para asegurar que las llamadas anteriores a console.error no interfieran),
  • creando el componente usando el valor de prop de prueba bajo consideración, y
  • confirmando si console.error fue disparado como se esperaba.

La Función testPropTypes

El siguiente código se puede colocar dentro de la prueba o como un módulo/archivo importado/requerido por separado:

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);
};

Llamando a la función

Cualquier prueba de examen propTypes puede llamar testPropTypes con tres o cuatro parámetros:

  • component, el componente React que es modificado por el prop;
  • propName, la cadena nombre de la prop bajo prueba;
  • arraysOfTestValues, una matriz de matrices de todos los valores de prueba deseados del prop a probar:
    • el primer sub-array contiene todos los aceptables valores de prop de prueba, mientras que
    • el segundo sub-array contiene todos los inaceptables valores de prop de prueba; y
  • Opcionalmente, otherProps, un objeto que contiene pares nombre/valor de prop para cualquier otro props requeridos de este componente.

    El objeto otherProps es necesario para asegurar que React no haga llamadas irrelevantes a console.error porque otros accesorios requeridos faltan inadvertidamente. Simplemente incluya un único valor aceptable para cualquier accesorio requerido, por ejemplo, {requiredPropName1: anyAcceptableValue, requiredPropName2: anyAcceptableValue}.

Función lógica

La función hace lo siguiente:

  • Se establece una burla de console.error que es lo que React usa para reportar apoyos de incorrectos tipo.

  • For each sub-array of test prop values provided it loops through each test prop value in each sub-array to test for prop type:

    • El primero de los dos subarrays debe ser una lista de valores de prop de prueba aceptables.
    • El segundo debe ser de valores inaceptables de prop de prueba.
  • Dentro del bucle para cada valor de prop de prueba individual, el console.error mock es el primero cleared para que se pueda suponer que cualquier mensaje de error detectado procede de esta prueba.

  • Luego se crea una instancia del componente utilizando el valor de prop de prueba, así como cualquier otro prop necesario que no se esté probando actualmente.

  • Finalmente, se realiza una comprobación para ver si se ha activado una advertencia, lo que debería suceder si su prueba intentó crear un componente utilizando un componente inapropiado o faltante apuntalar.

Pruebas para Accesorios Opcionales versus Requeridos

Tenga en cuenta que asignar null (o undefined) a un valor de prop es, desde la perspectiva de React, esencialmente lo mismo que no proporcionar ningún valor para ese prop. Por definición, esto es aceptable para un apoyo opcional, pero inaceptable para uno requerido. Por lo tanto, colocando null en la matriz de valores aceptables o inaceptables, prueba si esa prop es opcional o requerida respectivamente.

Código de ejemplo

MyComponent.js (solo el 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.prueba.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);
    });
});

Limitación de Este Enfoque (IMPORTANTE)

Actualmente hay algunas limitaciones significativas sobre cómo puede usar este enfoque que, si se sobrepasa, podría ser la fuente de algunos errores de prueba difíciles de rastrear. Las razones y las implicaciones de estas limitaciones se explican en esta otra pregunta/respuesta. En resumen, para tipos de prop simples, como para myProp1, puede probar tantos valores de prop de prueba inaceptables que no seannull como desee siempre que sean de diferentes tipos de datos. Para algunos tipos de prop complejos, como para myProp2, solo se puede probar un único inaceptable no-null valor de prop de cualquier tipo. Vea esa otra pregunta / respuesta para una discusión más profunda.

 6
Author: Andrew Willems,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:26

Burlarse console.error no es adecuado para su uso en pruebas unitarias! @AndrewWillems vinculado a otra pregunta SO en un comentario anterior que describe los problemas con este enfoque.

Echa un vistazo a este problema en facebook/prop-types para discutir sobre la capacidad de esa biblioteca para lanzar errores PropType en lugar de registrar (en el momento de escribir, no es compatible).

He publicado una biblioteca auxiliar para proporcionar ese comportamiento mientras tanto, check-prop-types. Puedes usarlo así:

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
Author: Phil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-06 20:17:10

Un nuevo paquete jest-prop-type-error es fácil de agregar y falla en PropType errores:

Instalar a través de:

yarn add -D jest-prop-type-error

Luego agrega lo siguiente a tus package.json's {[4] } en la sección jest:

"setupFiles": [
  "jest-prop-type-error"
]
 2
Author: YPCrumble,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-08 16:22:01

Dado que ReactJS solo enviará advertencias a la consola, pero en realidad no arrojará un error, pruebo los valores de prop de esta manera:

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

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

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

});
 1
Author: Guy Laor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-11 21:02:41