¿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?
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.
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 aconsole.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 aconsole.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.
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`.');
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"
]
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' );
});
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