prop-types-exact
Version:
For use with React PropTypes. Will error on any prop not explicitly specified.
141 lines (113 loc) • 4.04 kB
JSX
import test from 'tape';
import React from 'react';
import ownKeys from 'own-keys';
import exact from '..';
import callValidator from './helpers/callValidator';
function stringSort(a, b) {
if (typeof a !== 'string') {
return 1;
}
if (typeof b !== 'string') {
return -1;
}
return b.localeCompare(a);
}
test('exact', (t) => {
const [specialProperty] = ownKeys(exact({}));
function assertPasses(tt, validator, element, propName, componentName) {
tt.equal(callValidator(validator, element, propName, componentName), null);
}
function assertFails(tt, validator, element, propName, componentName) {
tt.equal(callValidator(validator, element, propName, componentName) instanceof Error, true);
}
t.test('throws when the given propTypes is not an object', (st) => {
st['throws'](() => exact(), TypeError);
st['throws'](() => exact(undefined), TypeError);
st['throws'](() => exact(null), TypeError);
st['throws'](() => exact(''), TypeError);
st['throws'](() => exact(42), TypeError);
st['throws'](() => exact(true), TypeError);
st['throws'](() => exact(false), TypeError);
st['throws'](() => exact(() => {}), TypeError);
st.end();
});
t.test('throws when the given propTypes has the magic property', (st) => {
st['throws'](() => exact({ [specialProperty]: true }), TypeError);
st.end();
});
t.test('returns an object', (st) => {
st.equal(typeof exact({}), 'object');
st.end();
});
t.test('adds one extra key', (st) => {
const propTypes = { a: 1, b: 2, c: 3 };
const result = exact(propTypes);
const resultOwnKeys = ownKeys(result).sort(stringSort);
const propTypesOwnKeys = ownKeys(propTypes).concat(specialProperty).sort(stringSort);
st.deepEqual(resultOwnKeys, propTypesOwnKeys);
st.end();
});
t.test('allows for merging of propTypes that have been processed', (st) => {
st.doesNotThrow(() => exact(exact({})));
st.end();
});
t.test('exact()', (st) => {
const knownProp = 'a';
function setup() {
const Component = class Component extends React.Component {};
// eslint-disable-next-line no-empty-function
Component.propTypes = exact({ [knownProp]() {} });
const validator = Component.propTypes[specialProperty];
return { validator, Component };
}
st.test('adds a function', (s2t) => {
const { validator } = setup();
s2t.equal(typeof validator, 'function');
s2t.end();
});
st.test('passes via normal propTypes when given no props', (s2t) => {
const { Component } = setup();
s2t.doesNotThrow(() => <Component />);
s2t.end();
});
st.test('passes when given no props', (s2t) => {
const { validator } = setup();
assertPasses(s2t, validator, <div />, knownProp, 'Foo div');
s2t.end();
});
st.test('passes via normal propTypes when given only known props', (s2t) => {
const { Component } = setup();
s2t.doesNotThrow(() => <Component {...{ [knownProp]: true }} />);
s2t.end();
});
st.test('passes when given only known props', (s2t) => {
const { validator } = setup();
assertPasses(s2t, validator, <div {...{ [knownProp]: true }} />, knownProp, 'Foo div');
s2t.end();
});
st.test('fails via normal propTypes', (s2t) => {
const { Component } = setup();
s2t['throws'](
() => <Component unknown {...{ [knownProp]: true }} />,
EvalError,
);
s2t.end();
});
st.test('fails when given an unknown prop', (s2t) => {
const { validator } = setup();
// eslint-disable-next-line react/no-unknown-property
assertFails(s2t, validator, <div unknown {...{ [knownProp]: true }} />, knownProp, 'Foo div');
s2t.end();
});
st.test('does not emit a warning when `key` is passed', (s2t) => {
const resultsE = s2t.intercept(console, 'error');
const resultsW = s2t.intercept(console, 'warn');
const { validator } = setup();
assertPasses(s2t, validator, <div key="key" />, 'key', 'Foo div');
s2t.deepEqual(resultsE(), [], 'no console errors');
s2t.deepEqual(resultsW(), [], 'no console warnings');
s2t.end();
});
});
t.end();
});