Skip to content

Commit

Permalink
Restructure to an unopionated structure
Browse files Browse the repository at this point in the history
  • Loading branch information
PopradiArpad committed Jun 28, 2017
1 parent db9abfd commit dfa40f9
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 229 deletions.
23 changes: 1 addition & 22 deletions ui_framework/components/tabs/__snapshots__/tabs.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,5 @@ exports[`KuiTabs renders 1`] = `
aria-label="aria-label"
class="kuiTabs testClass1 testClass2"
data-test-subj="test subject string"
>
<button
class="kuiTab kuiTab-isSelected"
>
Cobalt
</button>
<button
class="kuiTab"
>
Dextrose
</button>
<button
class="kuiTab"
>
Helium-3
</button>
<button
class="kuiTab"
>
Monosodium Glutamate
</button>
</div>
/>
`;
44 changes: 2 additions & 42 deletions ui_framework/components/tabs/tabs.js
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
};
152 changes: 2 additions & 150 deletions ui_framework/components/tabs/tabs.test.js
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);
});
});
});
});
47 changes: 32 additions & 15 deletions ui_framework/doc_site/src/views/tabs/tabs.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,55 @@
import React from 'react';

import {
KuiTabs
KuiTabs,
KuiTab,
} from '../../../../components';

class KuiTabsExample extends React.Component {
constructor(props) {
super(props);

this.tabs = [
'Cobalt',
'Dextrose',
'Helium-3',
'Monosodium Glutamate',
];
this.tabs = [{
id: 'cobalt',
name: 'Cobalt',
}, {
id: 'dextrose',
name: 'Dextrose',
}, {
id: 'helium_3',
name: 'Helium-3',
}, {
id: 'monosodium_glutammate',
name: 'Monosodium Glutamate',
}];

this.state = {
selectedTabIndex: 0,
selectedTabId: 'cobalt',
};
}

onSelectedTabChanged = (index) => {
onSelectedTabChanged = id => {
this.setState({
selectedTabIndex: index,
selectedTabId: id,
});
}

renderTabs() {
return this.tabs.map((tab,index) => (
<KuiTab
onClick={() => this.onSelectedTabChanged(tab.id)}
isSelected={tab.id === this.state.selectedTabId}
key={index}
>
{tab.name}
</KuiTab>
));
}

render() {
return (
<KuiTabs
selectedTabIndex={this.state.selectedTabIndex}
onSelectedTabChanged={this.onSelectedTabChanged}
>
{this.tabs}
<KuiTabs>
{this.renderTabs()}
</KuiTabs>
);
}
Expand Down

0 comments on commit dfa40f9

Please sign in to comment.