import { expect } from 'chai'; import { number, string } from 'prop-types'; import React from 'react'; import { childrenSequenceOf } from '..'; import callValidator from './_callValidator'; describe('childrenSequenceOf', () => { it('is a function', () => { expect(typeof childrenSequenceOf).to.equal('function'); }); function assertPasses(validator, element, propName) { const error = callValidator(validator, element, propName, '"childrenSequenceOf" passing test'); expect(error).to.equal(null); } function assertFails(validator, element, propName) { const error = callValidator(validator, element, propName, '"childrenSequenceOf" failing test'); expect(error).to.be.instanceOf(Error); } it('throws if not given at least one specifier', () => { expect(() => childrenSequenceOf()).to.throw(RangeError); expect(() => childrenSequenceOf(undefined)).to.throw(TypeError); expect(() => childrenSequenceOf(null)).to.throw(TypeError); expect(() => childrenSequenceOf([])).to.throw(TypeError); expect(() => childrenSequenceOf('')).to.throw(TypeError); expect(() => childrenSequenceOf(42)).to.throw(TypeError); expect(() => childrenSequenceOf(NaN)).to.throw(TypeError); }); it('throws if given an invalid validator', () => { expect(() => childrenSequenceOf({ validator: null })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator: undefined })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator: false })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator: [] })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator: {} })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator: '' })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator: 3 })).to.throw(TypeError); }); it('throws given a non-positive-integer min or max', () => { const validator = number; expect(() => childrenSequenceOf({ validator, min: -1 })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, max: -1 })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, min: -1.4 })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, max: -1.4 })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, min: NaN })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, max: NaN })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, min: Infinity })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, max: Infinity })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, min: -Infinity })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, max: -Infinity })).to.throw(TypeError); }); it('throws given inverted "min"/"max"', () => { const validator = number; expect(() => childrenSequenceOf({ validator, min: 2, max: 1 })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, max: 1, min: 2 })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, min: 2, max: 0 })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, max: 0, min: 2 })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, min: 1, max: 0 })).to.throw(TypeError); expect(() => childrenSequenceOf({ validator, max: 0, min: 1 })).to.throw(TypeError); // "min" defaults to 1 expect(() => childrenSequenceOf({ validator, max: 0 })).to.throw(TypeError); }); it('returns a function', () => { expect(typeof childrenSequenceOf({ validator: number })).to.equal('function'); }); it('fails on a non-children prop', () => { const validator = childrenSequenceOf({ validator: number }); assertFails(validator, (
), 'cousins'); assertFails(validator.isRequired, (
), 'cousins'); }); it('passes with null/undefined when optional', () => { const validator = childrenSequenceOf({ validator: number }); assertPasses(validator, (
), 'children'); assertPasses(validator, (
{null}
), 'children'); assertPasses(validator, (
{undefined}
), 'children'); }); it('fails with null/undefined when required', () => { const validator = childrenSequenceOf({ validator: number }).isRequired; assertFails(validator, (
), 'children'); assertFails(validator, (
{null}
), 'children'); assertFails(validator, (
{undefined}
), 'children'); }); it('works with specifiers without "max"/"min"', () => { const validator = childrenSequenceOf({ validator: number }); assertPasses(validator, (
{1}
), 'children'); assertPasses(validator.isRequired, (
{1}
), 'children'); assertPasses(validator, (
{NaN}
), 'children'); assertFails(validator.isRequired, (
{NaN}
), 'children'); assertPasses(validator, (
{-0}
), 'children'); assertPasses(validator.isRequired, (
{-0}
), 'children'); assertPasses(validator, (
{Infinity}
), 'children'); assertPasses(validator.isRequired, (
{Infinity}
), 'children'); assertFails(validator, (
{1} {2} {null} {() => {}}
), 'children'); assertFails(validator, (
1
), 'children'); assertFails( validator,
1 {2}
, 'children', ); }); it('works with specifiers only providing "min"', () => { const optional = childrenSequenceOf({ validator: number, min: 0 }); const twoPlus = childrenSequenceOf({ validator: number, min: 2 }); assertPasses(optional, (
), 'children'); assertFails(optional.isRequired, (
), 'children'); assertPasses(twoPlus, (
), 'children'); assertFails(twoPlus.isRequired, (
), 'children'); assertFails(twoPlus, (
{1}
), 'children'); assertPasses( twoPlus,
{1} {2}
, 'children', ); assertPasses( twoPlus,
{1} {2} {3}
, 'children', ); assertFails(twoPlus, (
1
), 'children'); assertFails( twoPlus,
1 {2}
, 'children', ); assertFails( twoPlus,
{1} 2 {3}
, 'children', ); }); it('works with specifiers only providing "max"', () => { const optional = childrenSequenceOf({ validator: number, max: 1 }); const twoOrLess = childrenSequenceOf({ validator: number, max: 2 }); assertPasses(optional, (
), 'children'); assertFails(optional.isRequired, (
), 'children'); assertPasses(twoOrLess, (
), 'children'); assertFails(twoOrLess.isRequired, (
), 'children'); assertPasses(twoOrLess, (
{1}
), 'children'); assertPasses( twoOrLess,
{1} {2}
, 'children', ); assertFails( twoOrLess,
{1} {2} {3}
, 'children', ); assertFails(twoOrLess, (
1
), 'children'); assertFails( twoOrLess,
1 {2}
, 'children', ); assertFails( twoOrLess,
{1} 2 {3}
, 'children', ); }); it('works with specifiers with both "min" and "max"', () => { const twoOrThree = childrenSequenceOf({ validator: number, min: 2, max: 3 }); const oneOrTwo = childrenSequenceOf({ validator: number, max: 2, min: 1 }); assertFails(twoOrThree, (
{1}
), 'children'); assertPasses( twoOrThree,
{1} {2}
, 'children', ); assertPasses( twoOrThree,
{1} {2} {3}
, 'children', ); assertFails( twoOrThree,
{1} {2} {3} {4}
, 'children', ); assertFails(oneOrTwo.isRequired, (
), 'children'); assertPasses(oneOrTwo, (
{1}
), 'children'); assertPasses( oneOrTwo,
{1} {2}
, 'children', ); assertFails( oneOrTwo,
{1} {2} {3}
, 'children', ); }); it('works with an optional unmet, and a required met, specifier', () => { const validator = childrenSequenceOf( { validator: string, min: 0 }, { validator: number }, ); assertPasses( validator,
a {1}
, 'children', ); assertPasses(validator, (
{1}
), 'children'); assertFails(validator, (
a
), 'children'); assertFails( validator, /* eslint react/jsx-curly-brace-presence: 0 */
a {'b'}
, 'children', ); assertFails( validator,
{1} {2}
, 'children', ); }); });