diff --git a/src/views/Card/Card.js b/src/views/Card/Card.js index ab4d58f494..ccd2d35721 100644 --- a/src/views/Card/Card.js +++ b/src/views/Card/Card.js @@ -2,9 +2,10 @@ import cx from 'classnames' import React, { PropTypes } from 'react' import { + customPropTypes, + getUnhandledProps, META, SUI, - getUnhandledProps, useKeyOnly, } from '../../lib' import CardContent from './CardContent' @@ -19,8 +20,11 @@ function Card(props) { children, className, color, + description, fluid, + header, href, + meta, onClick, raised, } = props @@ -47,7 +51,7 @@ function Card(props) { href={href} onClick={handleClick} > - {children} + {children || } ) } @@ -73,12 +77,30 @@ Card.propTypes = { /** A Card can be formatted to display different colors. */ color: PropTypes.oneOf(Card._meta.props.color), + /** Shorthand prop for CardDescription. Mutually exclusive with children. */ + description: customPropTypes.every([ + customPropTypes.disallow(['children']), + PropTypes.node, + ]), + /** A Card can be formatted to take up the width of its container. */ fluid: PropTypes.bool, + /** Shorthand prop for CardHeader. Mutually exclusive with children. */ + header: customPropTypes.every([ + customPropTypes.disallow(['children']), + PropTypes.node, + ]), + /** Render as an `a` tag instead of a `div` and adds the href attribute. */ href: PropTypes.string, + /** Shorthand prop for CardMeta. Mutually exclusive with children. */ + meta: customPropTypes.every([ + customPropTypes.disallow(['children']), + PropTypes.node, + ]), + /** Render as an `a` tag instead of a `div` and called with event on Card click. */ onClick: PropTypes.func, diff --git a/src/views/Card/CardGroup.js b/src/views/Card/CardGroup.js index f8c9c54ea0..c7d0d86bd7 100644 --- a/src/views/Card/CardGroup.js +++ b/src/views/Card/CardGroup.js @@ -34,7 +34,7 @@ CardGroup._meta = { name: 'CardGroup', parent: 'Card', props: { - width: SUI.WIDTHS, + itemsPerRow: SUI.WIDTHS, }, type: META.TYPES.VIEW, } @@ -47,7 +47,7 @@ CardGroup.propTypes = { ]), doubling: PropTypes.bool, items: customPropTypes.every([ - customPropTypes.disallow(['description', 'title']), + customPropTypes.disallow(['description', 'header']), PropTypes.arrayOf(PropTypes.shape({ description: PropTypes.node, meta: PropTypes.node, diff --git a/test/specs/views/Card/Card-test.js b/test/specs/views/Card/Card-test.js index 176115b1e6..d624cd649b 100644 --- a/test/specs/views/Card/Card-test.js +++ b/test/specs/views/Card/Card-test.js @@ -1,8 +1,53 @@ +import faker from 'faker' +import React from 'react' + import * as common from 'test/specs/commonTests' +import { sandbox } from 'test/utils' import Card from 'src/views/Card/Card' +import CardContent from 'src/views/Card/CardContent' +import CardDescription from 'src/views/Card/CardDescription' +import CardGroup from 'src/views/Card/CardGroup' +import CardHeader from 'src/views/Card/CardHeader' +import CardMeta from 'src/views/Card/CardMeta' describe('Card', () => { common.isConformant(Card) - common.rendersChildren(Card) common.hasUIClassName(Card) + common.hasSubComponents(Card, [CardContent, CardDescription, CardGroup, CardHeader, CardMeta]) + common.propKeyOnlyToClassName(Card, 'centered') + common.propKeyOnlyToClassName(Card, 'fluid') + common.propKeyOnlyToClassName(Card, 'raised') + common.rendersChildren(Card) + + describe('renders different elements', () => { + it('
by default', () => { + shallow().should.have.tagName('div') + }) + + it(' with `href` prop', () => { + const url = faker.internet.url() + const wrapper = shallow() + + wrapper.should.have.tagName('a') + wrapper.should.have.attr('href', url) + }) + + describe('onClick prop', () => { + it('can be omitted', () => { + const click = () => mount({faker.hacker.phrase()}).simulate('click') + expect(click).to.not.throw() + }) + + it('renders and handles click', () => { + const handleClick = sandbox.spy() + const wrapper = mount() + + wrapper.should.have.tagName('a') + wrapper.simulate('click') + + handleClick.should.have.been.calledOnce() + handleClick.should.have.been.calledWithMatch({}) + }) + }) + }) }) diff --git a/test/specs/views/Card/CardContent-test.js b/test/specs/views/Card/CardContent-test.js new file mode 100644 index 0000000000..940bdcd604 --- /dev/null +++ b/test/specs/views/Card/CardContent-test.js @@ -0,0 +1,41 @@ +import faker from 'faker' +import React from 'react' + +import * as common from 'test/specs/commonTests' +import CardContent from 'src/views/Card/CardContent' +import CardDescription from 'src/views/Card/CardDescription' +import CardHeader from 'src/views/Card/CardHeader' +import CardMeta from 'src/views/Card/CardMeta' + +describe('CardContent', () => { + common.isConformant(CardContent) + common.propKeyOnlyToClassName(CardContent, 'extra') + common.rendersChildren(CardContent) + + describe('description prop', () => { + it('renders description component', () => { + const text = faker.hacker.phrase() + + shallow() + .should.contain() + }) + }) + + describe('header prop', () => { + it('renders header component', () => { + const text = faker.hacker.phrase() + + shallow() + .should.contain() + }) + }) + + describe('meta prop', () => { + it('renders meta component', () => { + const text = faker.hacker.phrase() + + shallow() + .should.contain() + }) + }) +}) diff --git a/test/specs/views/Card/CardDescription-test.js b/test/specs/views/Card/CardDescription-test.js new file mode 100644 index 0000000000..004ac4db9d --- /dev/null +++ b/test/specs/views/Card/CardDescription-test.js @@ -0,0 +1,26 @@ +import faker from 'faker' +import React from 'react' + +import * as common from 'test/specs/commonTests' +import CardDescription from 'src/views/Card/CardDescription' + +describe('CardDescription', () => { + common.isConformant(CardDescription) + common.rendersChildren(CardDescription) + + describe('description prop', () => { + it('renders child text', () => { + const text = faker.hacker.phrase() + + shallow() + .should.contain.text(text) + }) + + it('renders child node', () => { + const child =
+ + shallow() + .should.contain(child) + }) + }) +}) diff --git a/test/specs/views/Card/CardGroup-test.js b/test/specs/views/Card/CardGroup-test.js new file mode 100644 index 0000000000..2918f3ffc1 --- /dev/null +++ b/test/specs/views/Card/CardGroup-test.js @@ -0,0 +1,43 @@ +import faker from 'faker' +import React from 'react' +import * as common from 'test/specs/commonTests' +import Card from 'src/views/Card/Card' +import CardGroup from 'src/views/Card/CardGroup' + +describe('CardGroup', () => { + common.isConformant(CardGroup) + common.hasUIClassName(CardGroup) + common.propKeyOnlyToClassName(CardGroup, 'doubling') + common.propKeyOnlyToClassName(CardGroup, 'stackable') + common.implementsNumberToWordProp(CardGroup, 'itemsPerRow') + + describe('renders children', () => { + const firstText = faker.hacker.phrase() + const secondText = faker.hacker.phrase() + + it('with `children` prop', () => { + const wrapper = mount( + + {firstText} + {secondText} + + ) + .find('Card') + + wrapper.first().should.contain.text(firstText) + wrapper.last().should.contain.text(secondText) + }) + + it('with `items` prop', () => { + const items = [ + { header: firstText }, + { header: secondText }, + ] + + const wrapper = mount().find('Card') + + wrapper.first().find('CardHeader').should.contain.text(firstText) + wrapper.last().find('CardHeader').should.contain.text(secondText) + }) + }) +}) diff --git a/test/specs/views/Card/CardHeader-test.js b/test/specs/views/Card/CardHeader-test.js new file mode 100644 index 0000000000..30ab01ca53 --- /dev/null +++ b/test/specs/views/Card/CardHeader-test.js @@ -0,0 +1,26 @@ +import faker from 'faker' +import React from 'react' + +import * as common from 'test/specs/commonTests' +import CardHeader from 'src/views/Card/CardHeader' + +describe('CardHeader', () => { + common.isConformant(CardHeader) + common.rendersChildren(CardHeader) + + describe('description prop', () => { + it('renders child text', () => { + const text = faker.hacker.phrase() + + shallow() + .should.contain.text(text) + }) + + it('renders child node', () => { + const child =
+ + shallow() + .should.contain(child) + }) + }) +}) diff --git a/test/specs/views/Card/CardMeta-test.js b/test/specs/views/Card/CardMeta-test.js new file mode 100644 index 0000000000..ce675b90a4 --- /dev/null +++ b/test/specs/views/Card/CardMeta-test.js @@ -0,0 +1,26 @@ +import faker from 'faker' +import React from 'react' + +import * as common from 'test/specs/commonTests' +import CardMeta from 'src/views/Card/CardMeta' + +describe('CardMeta', () => { + common.isConformant(CardMeta) + common.rendersChildren(CardMeta) + + describe('description prop', () => { + it('renders child text', () => { + const text = faker.hacker.phrase() + + shallow() + .should.contain.text(text) + }) + + it('renders child node', () => { + const child =
+ + shallow() + .should.contain(child) + }) + }) +})