-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Restructure to an unopionated structure
- Loading branch information
1 parent
db9abfd
commit dfa40f9
Showing
4 changed files
with
37 additions
and
229 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,25 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import classNames from 'classnames'; | ||
import { KuiTab } from './tab'; | ||
|
||
export const KuiTabs = ({ | ||
children, | ||
selectedTabIndex, | ||
onSelectedTabChanged, | ||
className, | ||
...rest | ||
}) => { | ||
const classes = classNames('kuiTabs', className); | ||
const tabs = children.map((child, index)=>( | ||
<KuiTab | ||
key={index} | ||
onClick={() => onSelectedTabChanged(index)} | ||
isSelected={index === selectedTabIndex} | ||
> | ||
{child} | ||
</KuiTab> | ||
)); | ||
|
||
return ( | ||
<div | ||
className={classes} | ||
{...rest} | ||
> | ||
{tabs} | ||
{children} | ||
</div> | ||
); | ||
}; | ||
|
||
const selectedTabIndexCheck = (props, propName, componentName) => { | ||
const childrenLength = props.children ? props.children.length : 0; | ||
const selectedTabIndex = props.selectedTabIndex; | ||
|
||
// An undefined selected tab is OK in all situations. | ||
if (selectedTabIndex === undefined) { | ||
return; | ||
} | ||
|
||
if (!Number.isInteger(selectedTabIndex)) { | ||
throw new Error(`${componentName}'s selectedTabIndex must be an integer.`); | ||
} | ||
|
||
if (childrenLength === 0) { | ||
throw new Error(`${componentName}'s selectedTabIndex must be undefined if there is no tab to select.`); | ||
} | ||
|
||
if ((selectedTabIndex < 0) || (selectedTabIndex > (childrenLength - 1))) { | ||
throw new Error(`${componentName}'s selectedTabIndex(${selectedTabIndex}) must be within the range defined by the number of tabs.`); | ||
} | ||
}; | ||
|
||
/** | ||
* children: Each element of this array will be wrapped into KuiTab | ||
* onSelectedTabChanged: Arguments: tabIndex | ||
*/ | ||
KuiTabs.propTypes = { | ||
children: PropTypes.node, | ||
selectedTabIndex: selectedTabIndexCheck, | ||
onSelectedTabChanged: PropTypes.func.isRequired, | ||
className: PropTypes.string, | ||
className: PropTypes.string | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,165 +1,17 @@ | ||
import React from 'react'; | ||
import { render, shallow } from 'enzyme'; | ||
import { render } from 'enzyme'; | ||
import { requiredProps } from '../../test/required_props'; | ||
import sinon from 'sinon'; | ||
|
||
import { | ||
KuiTabs, | ||
} from './tabs'; | ||
|
||
import { | ||
KuiTab, | ||
} from './tab'; | ||
|
||
describe('KuiTabs', () => { | ||
const tabs = [ | ||
'Cobalt', | ||
'Dextrose', | ||
'Helium-3', | ||
'Monosodium Glutamate', | ||
]; | ||
|
||
describe('throws an error', () => { | ||
let consoleStub; | ||
|
||
beforeEach(() => { | ||
consoleStub = sinon.stub(console, 'error'); | ||
}); | ||
|
||
afterEach(() => { | ||
console.error.restore(); | ||
}); | ||
|
||
test(`when selectedTabIndex is defined but there's no child`, () => { | ||
const component = ( // eslint-disable-line no-unused-vars | ||
<KuiTabs | ||
selectedTabIndex={1} | ||
onSelectedTabChanged={()=>{}} | ||
/> | ||
); | ||
|
||
expect(consoleStub.calledOnce).toBe(true); | ||
expect(consoleStub.getCall(0).args[0]).toContain( | ||
`selectedTabIndex must be undefined if there is no tab to select.` | ||
); | ||
}); | ||
|
||
test(`when selectedTabIndex is not an integer`, () => { | ||
const component = ( // eslint-disable-line no-unused-vars | ||
<KuiTabs | ||
selectedTabIndex={-0.1} | ||
onSelectedTabChanged={()=>{}} | ||
> | ||
{tabs} | ||
</KuiTabs> | ||
); | ||
|
||
expect(consoleStub.calledOnce).toBe(true); | ||
expect(consoleStub.getCall(0).args[0]).toContain( | ||
`selectedTabIndex must be an integer.` | ||
); | ||
}); | ||
|
||
test(`when selectedTabIndex is negative`, () => { | ||
const component = ( // eslint-disable-line no-unused-vars | ||
<KuiTabs | ||
selectedTabIndex={-1} | ||
onSelectedTabChanged={()=>{}} | ||
> | ||
{tabs} | ||
</KuiTabs> | ||
); | ||
|
||
expect(consoleStub.calledOnce).toBe(true); | ||
expect(consoleStub.getCall(0).args[0]).toContain( | ||
`selectedTabIndex(-1) must be within the range defined by the number of tabs.` | ||
); | ||
}); | ||
|
||
test(`when selectedTabIndex is greater than the upper limit defined by the number of tabs`, () => { | ||
const component = ( // eslint-disable-line no-unused-vars | ||
<KuiTabs | ||
selectedTabIndex={tabs.length} | ||
onSelectedTabChanged={()=>{}} | ||
> | ||
{tabs} | ||
</KuiTabs> | ||
); | ||
|
||
expect(consoleStub.calledOnce).toBe(true); | ||
expect(consoleStub.getCall(0).args[0]).toContain( | ||
`selectedTabIndex(4) must be within the range defined by the number of tabs.` | ||
); | ||
}); | ||
}); | ||
|
||
describe(`doesn't throw an error`, () => { | ||
let consoleStub; | ||
|
||
beforeEach(() => { | ||
consoleStub = sinon.stub(console, 'error'); | ||
}); | ||
|
||
afterEach(() => { | ||
console.error.restore(); | ||
}); | ||
|
||
test(`when selectedTabIndex is undefined and there's no child`, () => { | ||
const component = ( // eslint-disable-line no-unused-vars | ||
<KuiTabs | ||
onSelectedTabChanged={()=>{}} | ||
/> | ||
); | ||
|
||
expect(consoleStub.calledOnce).toBe(false); | ||
}); | ||
|
||
test(`when selectedTabIndex is within the range defined by the number of tabs`, () => { | ||
const component = ( // eslint-disable-line no-unused-vars | ||
<KuiTabs | ||
selectedTabIndex={tabs.length - 1} | ||
onSelectedTabChanged={()=>{}} | ||
> | ||
{tabs} | ||
</KuiTabs> | ||
); | ||
|
||
expect(consoleStub.calledOnce).toBe(false); | ||
}); | ||
}); | ||
|
||
test('renders', () => { | ||
const component = ( | ||
<KuiTabs | ||
selectedTabIndex={0} | ||
onSelectedTabChanged={()=>{}} | ||
{ ...requiredProps } | ||
> | ||
{tabs} | ||
</KuiTabs> | ||
<KuiTabs { ...requiredProps } /> | ||
); | ||
|
||
expect(render(component)).toMatchSnapshot(); | ||
}); | ||
|
||
describe('Props', () => { | ||
describe('onSelectedTabChanged', () => { | ||
test('is called when the button is clicked', () => { | ||
const onSelectedTabChangedHandler = sinon.spy(); | ||
|
||
const component = shallow( | ||
<KuiTabs | ||
selectedTabIndex={0} | ||
onSelectedTabChanged={onSelectedTabChangedHandler} | ||
> | ||
{tabs} | ||
</KuiTabs> | ||
); | ||
|
||
component.find(KuiTab).at(1).simulate('click'); | ||
sinon.assert.calledOnce(onSelectedTabChangedHandler); | ||
sinon.assert.calledWith(onSelectedTabChangedHandler,1); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters