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 aconsole.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 aconsole.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.