Как протестировать PropTypes через Jest?
Я пишу тесты Jest для моего кода React и надеюсь использовать/проверить проверки PropType. Я совершенно новичок в юниверсе Javascript. Я использую npm для установки react-0.11.2
и имею простой:
var React = require('react/addons');
В моих тестах. Мой тест очень похож на пример шутки/реакции с кодом, например:
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 ');
Однако кажется, что проверки PropType в компоненте EventCell
не запускаются. Я понимаю, что проверки выполняются только в режиме разработки, но потом я также подумал, что получение react
через npm дает вам версию для разработки. Триггер проверки в моем браузере, когда я создаю компонент с функцией watchify.
Что мне не хватает?
Ответы
Ответ 1
Основная проблема Как протестировать console.log
?
Короткий ответ заключается в том, что вы должны заменить console.{method}
на время теста. Общий подход заключается в использовании spies. В этом конкретном случае вы можете использовать stubs, чтобы предотвратить выход.
Вот пример реализации с использованием Sinon.js (Sinon.js предоставляет автономные шпионы, заглушки и макеты):
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();
});
});
В этом примере компонент DataName
будет вызывать ошибку при инициализации с отметкой времени, которая не соответствует точной дате (12:00:00 AM).
Я завершаю метод console.error
(это то, что модуль Facebook warning
использует внутренне для генерации ошибки). Я гарантирую, что заглушка была вызвана один раз и точно одним параметром, представляющим ошибку.
Ответ 2
Введение
Ответ от @Gajus определенно помог мне (так, спасибо Gajus). Тем не менее, я думал, что дам ответ:
- Использует более обновленный (v15.4.1)
- Использует Jest (который поставляется с React)
- Позволяет тестировать несколько значений поддержки для одиночной прокрутки
- более общий
Резюме
Как и подход, предложенный здесь Гаюсом и другими людьми другими, основной подход, который я предлагаю, также должен определить, используется ли console.error
Реакт в ответ на недопустимое значение прокрутки теста. В частности, этот подход включает в себя выполнение следующего для каждого значения теста:
- mocking и clearing
console.error
(для обеспечения того, чтобы предыдущие вызовы console.error
не мешали),
- создание компонента с использованием значения тестового значения и
- , подтверждающий, был ли запущен
console.error
, как ожидалось.
Функция testPropTypes
Следующий код может быть размещен либо внутри теста, либо как отдельный импортированный/требуемый модуль/файл:
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);
};
Вызов функции
Любое тестирование propTypes
может вызвать testPropTypes
, используя три или четыре параметра :
-
component
, React компонент, который модифицируется prop;
-
propName
, строка имя тестируемого;
-
arraysOfTestValues
, массив массивов всех требуемых тестовых значений тестируемого проспекта:
- первая подматрица содержит все значения приемлемые, а
- вторая подматрица содержит все неприемлемые значения test prop; и
-
необязательно otherProps
, объект, содержащий пары prop name/value для любых других необходимых реквизитов этого компонента.
Объект otherProps
необходим для обеспечения того, чтобы React не делал нерелевантные вызовы console.error
, потому что другие требуемые реквизиты непреднамеренно отсутствуют. Просто включите одно приемлемое значение для любых необходимых реквизитов, например. {requiredPropName1: anyAcceptableValue, requiredPropName2: anyAcceptableValue}
.
Функциональная логика
Функция выполняет следующие действия:
-
Он устанавливает макет console.error
, что и используется Реагтом для сообщения реквизитов неправильного типа.
-
Для каждого вспомогательного массива значений prop prop при условии, что он проходит через каждое тестовое значение поддержки в каждой подгруппе для проверки типа prop:
- Первый из двух подматриц должен быть списком допустимых значений прогона.
- Второй должен состоять из неприемлемых значений значений прокрутки.
-
Внутри цикла для каждого отдельного значения прокрутки теста макет console.error
сначала очищается, так что любые обнаруженные сообщения об ошибках могут считаться полученными из этого теста.
-
Затем создается экземпляр компонента с использованием значения тестового значения, а также любых других необходимых необходимых реквизитов, которые в настоящее время не тестируются.
-
Наконец, делается проверка на , было ли предупреждение вызвано, что должно произойти, если ваш тест попытался создать компонент с использованием несоответствующей или отсутствующей прокрутки.
Тестирование для необязательных и требуемых реквизитов
Обратите внимание, что присвоение null
(или undefined
) значению prop является, с точки зрения реактивов, по существу тем же самым, что и не дает никакого значения для этой опоры. По определению это приемлемо для опционной опоры, но неприемлемо для требуемого. Таким образом, , поместив null
в массив допустимых или неприемлемых значений, вы проверяете, является ли эта поддержка необязательной или требуется соответственно.
Пример кода
MyComponent.js(только 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);
});
});
Ограничение этого подхода (ВАЖНО)
В настоящее время существуют некоторые существенные ограничения в отношении того, как вы можете использовать этот подход, который, если бы он перешагнул, мог бы стать источником некоторых труднопробных тестовых ошибок. Причины и последствия этих ограничений объясняются в этом другом SO-вопросе/ответе., Таким образом, для простых типов прокрутки, например, для myProp1
, вы можете протестировать как можно больше недопустимых значений null
test prop, поскольку они представляют собой все разные типы данных. Для некоторых сложных типов prop, например, для myProp2
, вы можете проверить только одно неприемлемое значение non null
prop любого типа. См. Этот другой вопрос/ответ для более углубленного обсуждения.
Ответ 3
Mocking console.error
не подходит для использования в модульных тестах! @AndrewWillems, связанный с другим вопросом SO в комментарии выше, который описывает проблемы с этим подходом.
Откажитесь от эту проблему в facebook/prop-types для обсуждения возможности для этой библиотеки бросать вместо регистрации ошибок propType (at время написания, оно не поддерживается).
Я опубликовал вспомогательную библиотеку, чтобы обеспечить это поведение в среднем времени check-prop-types. Вы можете использовать его следующим образом:
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
Так как ReactJS будет отправлять предупреждения только на консоль, но на самом деле не выдает ошибку, я проверяю значения prop таким образом:
var myTestElement = TestUtils.renderIntoDocument(
<MyTestElement height={100} /> );
it("check MyTestElement props", function() {
expect( typeof myTestElement.props.height ).toEqual ( 'number' );
});