react proptypes props example reactjs jestjs reactjs-testutils react-proptypes

reactjs - proptypes - set props react



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

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

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

En mis pruebas. Mi prueba se parece bastante al ejemplo de tutorial de 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 de PropType en el componente EventCell no se están EventCell . Entiendo que las comprobaciones solo se ejecutan en el modo de desarrollo, pero también pensé que react 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?


¡Mocking console.error no es adecuado para usar 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 obtener información sobre la capacidad de esa biblioteca para lanzar en lugar de registrar los errores propType (en el momento de la escritura, no se admite).

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


Dado que ReactJS solo enviará advertencias a la consola, pero en realidad no generará 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'' ); });


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

La respuesta corta es que debe reemplazar la console.{method} durante la prueba. El enfoque común es utilizar spies . En este caso particular, es posible que desee utilizar stubs para evitar la salida.

Aquí hay una implementación de ejemplo que utiliza Sinon.js (Sinon.js proporciona espías, colillas y simulacros independientes):

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 generará un error cuando se inicialice con un valor de marca de tiempo que no representa una fecha precisa (12:00:00 AM).

Estoy aplastando el método console.error (esto es lo warning módulo de warning Facebook está utilizando internamente para generar el error). Me aseguro de que el código auxiliar haya sido llamado una vez y con exactamente un parámetro que representa el error.


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

Instalar a través de:

yarn add -D jest-prop-type-error

Luego, agregue lo siguiente a los setupFiles de setupFiles su package.json en la sección jest :

"setupFiles": [ "jest-prop-type-error" ]


Introducción

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

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

Resumen

Al igual que el enfoque sugerido aquí por Gajus y en otros lugares, el enfoque básico que estoy sugiriendo es también determinar si React utiliza o no console.error 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:

  • burlándose y despejando console.error (para garantizar que las llamadas anteriores a console.error no interfieran),
  • crear el componente utilizando el valor de prop de prueba en consideración, y
  • confirmando si o no 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 que examine los propTypes puede llamar a testPropTypes usando tres o cuatro parámetros :

  • component , el componente React que es modificado por el prop;
  • propName , el nombre de la cadena del prop bajo prueba;
  • arraysOfTestValues , un conjunto de matrices de todos los valores de prueba deseados del prop. a probar:
    • la primera sub-matriz contiene todos los valores de prop de prueba aceptables , mientras que
    • la segunda sub-matriz contiene todos los valores de prop de prueba inaceptables ; y
  • opcionalmente, otherProps , un objeto que contiene pares de nombre / valor de prop para cualquier otra utilería requerida de este componente.

    El objeto otherProps es necesario para garantizar que React no realice llamadas irrelevantes a console.error porque faltan inadvertidamente otros accesorios necesarios. Simplemente incluya un solo valor aceptable para cualquier {requiredPropName1: anyAcceptableValue, requiredPropName2: anyAcceptableValue} , por ejemplo, {requiredPropName1: anyAcceptableValue, requiredPropName2: anyAcceptableValue} .

Lógica de función

La función hace lo siguiente:

  • Establece un simulacro de console.error que es lo que React utiliza para informar de accesorios de tipo incorrecto.

  • Para cada sub-matriz de valores de prop de prueba, siempre que pase por cada valor de prop de prueba en cada sub-matriz para probar el tipo de prop:

    • El primero de los dos subarreglos debe ser una lista de valores de prop de prueba aceptables .
    • El segundo debe ser de valores de apoyo de prueba inaceptables .
  • Dentro del bucle para cada valor de prop de prueba individual, la simulación de console.error se borra primero, por lo que se puede suponer que los mensajes de error detectados provienen de esta prueba.

  • Luego se crea una instancia del componente utilizando el valor de prop de prueba, así como cualquier otra utilería necesaria 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 accesorio inapropiado o faltante.

Prueba de 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 prop opcional pero inaceptable para uno requerido. Por lo tanto, al colocar null en la matriz de valores aceptables o inaceptables, se comprueba si esa propuesta es opcional o requerida respectivamente .

Código de ejemplo

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

Limitación de este enfoque (IMPORTANTE)

Actualmente hay algunas limitaciones importantes sobre cómo puede utilizar 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 de SO . En resumen, para tipos de accesorios simples, como para myProp1 , puede probar tantos valores de apoyo de prueba no null inaceptables como desee , siempre que sean todos de diferentes tipos de datos . Para algunos tipos de accesorios complejos, como para myProp2 , solo puede probar un único valor de valor no null no aceptable de cualquier tipo . Ver esa otra pregunta / respuesta para una discusión más profunda.