/* eslint react/no-multi-comp: 0, react/prefer-stateless-function: 0 */ import React from 'react'; import { expect } from 'chai'; import { componentWithName } from '..'; import callValidator from './_callValidator'; function SFC() {} function SFCwithName() {} SFCwithName.displayName = 'SFC with a display name!'; class Component extends React.Component {} class ComponentWithName extends React.Component {} ComponentWithName.displayName = 'Component with a display name!'; class ComponentWithHOCs extends React.Component {} ComponentWithHOCs.displayName = 'withA(withB(withC(Connect(X))))'; const describeIfForwardRefs = React.forwardRef ? describe : describe.skip; describe('componentWithName', () => { it('returns a function', () => { expect(typeof componentWithName('name')).to.equal('function'); }); it('throws when not given a string or a regex', () => { expect(() => componentWithName()).to.throw(TypeError); expect(() => componentWithName(null)).to.throw(TypeError); expect(() => componentWithName(undefined)).to.throw(TypeError); expect(() => componentWithName(true)).to.throw(TypeError); expect(() => componentWithName(false)).to.throw(TypeError); expect(() => componentWithName(42)).to.throw(TypeError); expect(() => componentWithName(NaN)).to.throw(TypeError); expect(() => componentWithName([])).to.throw(TypeError); expect(() => componentWithName({})).to.throw(TypeError); }); it('throws when given unknown options', () => { expect(() => componentWithName('Foo', {})).not.to.throw(); expect(() => componentWithName('Foo', { stripHOCS: 'typo in the last "s"' })).to.throw(TypeError); expect(() => componentWithName('Foo', { stripHOCs: [], extra: true })).to.throw(TypeError); }); it('throws when given names of HOCs to strip that are not strings', () => { const notStrings = [null, undefined, true, false, 42, NaN, [], {}, () => {}]; notStrings.forEach((notString) => { expect(() => componentWithName('Foo', { stripHOCs: [notString] })).to.throw(TypeError); }); }); it('throws when given names of HOCs to strip that have parens', () => { expect(() => componentWithName('Foo', { stripHOCs: ['with()Foo'] })).to.throw(TypeError); }); it('throws when given names of HOCs to strip that are not in camelCase', () => { expect(() => componentWithName('Foo', { stripHOCs: ['with_foo'] })).to.throw(TypeError); }); function assertPasses(validator, element, propName) { expect(callValidator(validator, element, propName)).to.equal(null); } function assertFails(validator, element, propName) { expect(callValidator(validator, element, propName)).to.be.instanceOf(Error); } describe('with a single child of the specified name', () => { it('passes with an SFC', () => assertPasses( componentWithName('SFC'), (
), 'children', )); it('passes with an SFC + displayName', () => assertPasses( componentWithName(SFCwithName.displayName), (
), 'children', )); it('passes with a Component', () => assertPasses( componentWithName('Component'), (
), 'children', )); it('passes with a Component + displayName', () => assertPasses( componentWithName(ComponentWithName.displayName), (
), 'children', )); it('passes with a component with HOCs', () => { assertPasses( componentWithName('X', { stripHOCs: ['withA', 'withB', 'withC', 'Connect'] }), (
), 'children', ); assertPasses( componentWithName('withC(Connect(X))', { stripHOCs: ['withA', 'withB'] }), (
), 'children', ); assertPasses( componentWithName('withB(withC(Connect(X)))', { stripHOCs: ['withA', 'withC'] }), (
), 'children', ); }); }); describe('with multiple children of the specified name', () => { it('passes with an SFC', () => assertPasses( componentWithName('SFC'), (
), 'children', )); it('passes with an SFC + displayName', () => assertPasses( componentWithName(SFCwithName.displayName), (
), 'children', )); it('passes with a Component', () => assertPasses( componentWithName('Component'), (
), 'children', )); it('passes with a Component + displayName', () => assertPasses( componentWithName(ComponentWithName.displayName), (
), 'children', )); it('passes with a component with HOCs', () => { assertPasses( componentWithName('X', { stripHOCs: ['withA', 'withB', 'withC', 'Connect'] }), (
), 'children', ); assertPasses( componentWithName('withC(Connect(X))', { stripHOCs: ['withA', 'withB'] }), (
), 'children', ); assertPasses( componentWithName('withB(withC(Connect(X)))', { stripHOCs: ['withA', 'withC'] }), (
), 'children', ); }); }); describe('with children of the specified names passed as an array', () => { it('passes with an SFC', () => assertPasses( componentWithName('SFC'), (
{[ , , , ]}
), 'children', )); it('passes with an SFC + displayName', () => assertPasses( componentWithName(SFCwithName.displayName), (
{[ , , , ]}
), 'children', )); it('passes with a Component', () => assertPasses( componentWithName('Component'), (
{[ , , , ]}
), 'children', )); it('passes with a Component + displayName', () => assertPasses( componentWithName(ComponentWithName.displayName), (
{[ , , , ]}
), 'children', )); it('passes with a component with HOCs', () => { assertPasses( componentWithName('X', { stripHOCs: ['withA', 'withB', 'withC', 'Connect'] }), (
{[ , , , , ]}
), 'children', ); assertPasses( componentWithName('withC(Connect(X))', { stripHOCs: ['withA', 'withB'] }), (
{[ , , , , ]}
), 'children', ); assertPasses( componentWithName('withB(withC(Connect(X)))', { stripHOCs: ['withA', 'withC'] }), (
{[ , , , , ]}
), 'children', ); }); }); describe('when an unspecified name is provided as a child', () => { it('fails with an SFC', () => assertFails( componentWithName('SFC'), (
No way.
), 'children', )); it('fails with an SFC + displayName', () => assertFails( componentWithName(SFCwithName.displayName), (
No way.
), 'children', )); it('fails with a Component', () => assertFails( componentWithName('Component'), (
No way.
), 'children', )); it('fails with a Component + displayName', () => assertFails( componentWithName(ComponentWithName.displayName), (
No way.
), 'children', )); it('fails with a component with HOCs', () => { assertFails( componentWithName('X', { stripHOCs: ['withA', 'withB', 'withC', 'Connect'] }), (
No way.
), 'children', ); assertFails( componentWithName('withC(Connect(X))', { stripHOCs: ['withA', 'withB'] }), (
No way.
), 'children', ); assertFails( componentWithName('withB(withC(Connect(X)))', { stripHOCs: ['withA', 'withC'] }), (
No way.
), 'children', ); }); }); describe('when a regex value is provided instead of a string', () => { it('passes with an SFC', () => assertPasses( componentWithName(/FC$/), (
), 'children', )); it('passes with an SFC + displayName', () => assertPasses( componentWithName(/display name/), (
), 'children', )); it('passes with a Component', () => assertPasses( componentWithName(/^Comp/), (
), 'children', )); it('passes with a Component + displayName', () => assertPasses( componentWithName(/display name/), (
), 'children', )); it('passes with a component with HOCs', () => { assertPasses( componentWithName(/^X$/, { stripHOCs: ['withA', 'withB', 'withC', 'Connect'] }), (
), 'children', ); assertPasses( componentWithName(/^withC\(Connect\(X\)\)$/, { stripHOCs: ['withA', 'withB'] }), (
), 'children', ); assertPasses( componentWithName(/^withB\(withC\(Connect\(X\)\)\)$/, { stripHOCs: ['withA', 'withC'] }), (
), 'children', ); }); it('fails when SFC name does not match the regex provided', () => assertFails( componentWithName(/foobar/), (
), 'children', )); it('fails when Component name does not match the regex provided', () => assertFails( componentWithName(/foobar/), (
), 'children', )); it('fails with a component with HOCs that does not match the regex', () => { assertFails( componentWithName(/^zX$/, { stripHOCs: ['withA', 'withB', 'withC'] }), (
), 'children', ); assertFails( componentWithName(/^zwithC\(X\)$/, { stripHOCs: ['withA', 'withB'] }), (
), 'children', ); assertFails( componentWithName(/^zwithB\(withC\(X\)\)$/, { stripHOCs: ['withA', 'withC'] }), (
), 'children', ); }); }); it('fails when the provided prop is not a component', () => assertFails( componentWithName('SFC'), (
Blah blah blah.
), 'children', )); it('passes when the prop is null', () => assertPasses( componentWithName('SFC'), (
), 'a', )); it('passes when the prop is absent', () => assertPasses( componentWithName('SFC'), (
), 'a', )); describe('when the prop is required', () => { it('fails when the prop is null', () => assertFails( componentWithName('SFC').isRequired, (
), 'a', )); it('passes when the prop is the right component', () => assertPasses( componentWithName('SFC').isRequired, (
} />), 'a', )); }); describeIfForwardRefs('Forward Refs', () => { it('passes on a forward ref', () => { const Reffy = React.forwardRef(() =>
); Reffy.displayName = 'Reffy Name'; assertPasses( componentWithName('Reffy Name').isRequired, (
} />), 'a', ); }); }); });