Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue with RadioGroup children #263

Merged
merged 3 commits into from
May 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/components/RadioButtonLabeled/RadioButtonLabeled.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,22 @@ describeWithDOM;
describe('RadioButtonLabeled', () => {
common(RadioButtonLabeled);

describe('render', () => {
it('should allow multiple Label children', () => {
const wrapper = shallow(
<RadioButtonLabeled>
<RadioButtonLabeled.Label>
<span>one</span>
<span>two</span>
</RadioButtonLabeled.Label>
</RadioButtonLabeled>
);

assert.equal(wrapper.find(RadioButtonLabeled.Label).children().at(0).text(), 'one', 'wrong or missing first Label child');
assert.equal(wrapper.find(RadioButtonLabeled.Label).children().at(1).text(), 'two', 'wrong or missing second Label child');
});
});

describe('props', () => {
describe('isDisabled', () => {
it('passes the value through to its `RadioButton` instance.', () => {
Expand Down
23 changes: 11 additions & 12 deletions src/components/RadioGroup/RadioGroup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import reducers from './RadioGroup.reducers';

const cx = lucidClassNames.bind('&-RadioGroup');


const {
func,
node,
Expand Down Expand Up @@ -114,24 +113,24 @@ const RadioGroup = createClass({
// equal to true, then the index of the last one should override the
// value of the `selectedIndex` prop.
const actualSelectedIndex = selectedIndexFromChildren !== -1
? selectedIndexFromChildren
: selectedIndex;
? selectedIndexFromChildren
: selectedIndex;

return (
<span
{...passThroughs}
className={cx('&', className)}
{...passThroughs}
className={cx('&', className)}
>
{_.map(radioButtonChildProps, (radioButtonChildProp, index) => {
return (
<RadioButtonLabeled
{...radioButtonChildProp}
isSelected={actualSelectedIndex === index}
key={index}
callbackId={index}
name={name}
onSelect={this.handleSelected}
Label={_.get(_.first(findTypes(radioButtonChildProp, RadioGroup.Label)), 'props.children', null)}
{...radioButtonChildProp}
isSelected={actualSelectedIndex === index}
key={index}
callbackId={index}
name={name}
onSelect={this.handleSelected}
Label={_.get(_.first(findTypes(radioButtonChildProp, RadioGroup.Label)), 'props', null)}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the actual fix. Most everything else was just whitespace changes, and tests.

/>
);
})}
Expand Down
198 changes: 110 additions & 88 deletions src/components/RadioGroup/RadioGroup.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,134 +18,156 @@ describe('RadioGroup', () => {
describe('props', () => {
describe('name', () => {
it('sets the `name` attribute of the child radio buttons.', () => {
const name = getRandom();
const wrapper = shallow(
<RadioGroup name={name}>
const name = getRandom();
const wrapper = shallow(
<RadioGroup name={name}>
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
</RadioGroup>
);

_.forEach(wrapper.find(RadioButtonLabeled).nodes, (node) => {
assert.equal(node.props.name, name);
});
});

it('defaults to a string that is passed along to the children.', () => {
const wrapper = mount(
<RadioGroup>
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
</RadioGroup>
);
const name = wrapper.first().prop('name');

_.forEach(wrapper.find(RadioButtonLabeled).nodes, (node) => {
assert.equal(node.props.name, name);
_.forEach(wrapper.find(RadioButtonLabeled).nodes, (node) => {
assert.equal(node.props.name, name);
});
});
});

it('defaults to a string that is passed along to the children.', () => {
const wrapper = mount(
<RadioGroup>
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
</RadioGroup>
);
const name = wrapper.first().prop('name');
describe('onSelect', () => {
it('defaults to the Lodash `noop` method.', () => {
const wrapper = shallow(<RadioGroup />);

_.forEach(wrapper.find(RadioButtonLabeled).nodes, (node) => {
assert.equal(node.props.name, name);
assert.equal(wrapper.prop('onSelect'), _.noop);
});
});
});

describe('onSelect', () => {
it('defaults to the Lodash `noop` method.', () => {
const wrapper = shallow(<RadioGroup />);
describe('selectedIndex', () => {
it('sets the `isSelected` prop of the child radio button at the matching index to true...', () => {
const wrapper= shallow(
<RadioGroup selectedIndex={2}>
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
</RadioGroup>
);
const childNodes = wrapper.find(RadioButtonLabeled).nodes;

assert.equal(wrapper.prop('onSelect'), _.noop);
});
});
assert.equal(childNodes[0].props.isSelected, false);
assert.equal(childNodes[1].props.isSelected, false);
assert.equal(childNodes[2].props.isSelected, true);
});

describe('selectedIndex', () => {
it('sets the `isSelected` prop of the child radio button at the matching index to true...', () => {
const wrapper= shallow(
<RadioGroup selectedIndex={2}>
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
</RadioGroup>
);
const childNodes = wrapper.find(RadioButtonLabeled).nodes;
it('...except when a child component already has an explicitly defined `isSelected` prop which takes precedence.', () => {
const wrapper = shallow(
<RadioGroup selectedIndex={2}>
<RadioGroup.RadioButton isSelected={true} />
<RadioGroup.RadioButton isSelected={true} />
<RadioGroup.RadioButton />
</RadioGroup>
);
const childNodes = wrapper.find(RadioButtonLabeled).nodes;

assert.equal(childNodes[0].props.isSelected, false);
assert.equal(childNodes[1].props.isSelected, false);
assert.equal(childNodes[2].props.isSelected, true);
});
assert.equal(childNodes[0].props.isSelected, false);
assert.equal(childNodes[1].props.isSelected, true);
assert.equal(childNodes[2].props.isSelected, false);
});

it('...except when a child component already has an explicitly defined `isSelected` prop which takes precedence.', () => {
const wrapper = shallow(
<RadioGroup selectedIndex={2}>
<RadioGroup.RadioButton isSelected={true} />
<RadioGroup.RadioButton isSelected={true} />
<RadioGroup.RadioButton />
</RadioGroup>
);
const childNodes = wrapper.find(RadioButtonLabeled).nodes;
it('defaults to 0.', () => {
const wrapper = shallow(
<RadioGroup>
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
</RadioGroup>
);
const childNodes = wrapper.find(RadioButtonLabeled).nodes;

assert.equal(childNodes[0].props.isSelected, false);
assert.equal(childNodes[1].props.isSelected, true);
assert.equal(childNodes[2].props.isSelected, false);
assert.equal(childNodes[0].props.isSelected, true);
assert.equal(childNodes[1].props.isSelected, false);
assert.equal(childNodes[2].props.isSelected, false);
});
});

it('defaults to 0.', () => {
const wrapper = shallow(
<RadioGroup>
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
</RadioGroup>
);
const childNodes = wrapper.find(RadioButtonLabeled).nodes;
describe('pass throughs', () => {
it('passes through all props not defined in `propTypes` to the root element.', () => {
const wrapper = shallow(
<RadioGroup foo={1} bar={2} baz={3} qux={4} quux={5}>
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
</RadioGroup>
);
const rootProps = _.keys(wrapper.first().props());

assert.equal(childNodes[0].props.isSelected, true);
assert.equal(childNodes[1].props.isSelected, false);
assert.equal(childNodes[2].props.isSelected, false);
// It should pass `foo`, `bar`, `baz`, `qux`, and `quux` through
// to the root element.
_.forEach(['foo', 'bar', 'baz', 'qux', 'quux'], (prop) => {
assert(_.includes(rootProps, prop));
});
});
});
});

describe('pass throughs', () => {
it('passes through all props not defined in `propTypes` to the root element.', () => {
describe('RadioGroup.Label', () => {
it('passes its children through as the `Label` prop for the corresponding `RadioButtonLabeled`.', () => {
const wrapper = shallow(
<RadioGroup foo={1} bar={2} baz={3} qux={4} quux={5}>
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
<RadioGroup.RadioButton />
<RadioGroup>
<RadioGroup.RadioButton>
<RadioGroup.Label>foo</RadioGroup.Label>
</RadioGroup.RadioButton>
<RadioGroup.RadioButton>
<RadioGroup.Label>bar</RadioGroup.Label>
</RadioGroup.RadioButton>
<RadioGroup.RadioButton>
<RadioGroup.Label>
<span>baz</span>
<span>qux</span>
</RadioGroup.Label>
</RadioGroup.RadioButton>
</RadioGroup>
);
const rootProps = _.keys(wrapper.first().props());
const labels = wrapper.find(RadioGroup.Label);

// It should pass `foo`, `bar`, `baz`, `qux`, and `quux` through
// to the root element.
_.forEach(['foo', 'bar', 'baz', 'qux', 'quux'], (prop) => {
assert(_.includes(rootProps, prop));
});
assert.equal(labels.at(0).children().text(), 'foo');
assert.equal(labels.at(1).children().text(), 'bar');
assert.equal(labels.at(2).children().at(0).text(), 'baz');
assert.equal(labels.at(2).children().at(1).text(), 'qux');
});
});
});

describe('RadioGroup.Label', () => {
it('passes its children through as the `Label` prop for the corresponding `RadioButtonLabeled`.', () => {
const wrapper = shallow(
describeWithDOM('RadioGroup', () => {
it.only('should handle multiple children', () => {
const wrapper = mount(
<RadioGroup>
<RadioGroup.RadioButton>
<RadioGroup.Label>foo</RadioGroup.Label>
</RadioGroup.RadioButton>
<RadioGroup.RadioButton>
<RadioGroup.Label>bar</RadioGroup.Label>
<RadioGroup.Label>
<span id='foo'>foo</span>
<span id='bar'>bar</span>
</RadioGroup.Label>
</RadioGroup.RadioButton>
<RadioGroup.RadioButton></RadioGroup.RadioButton>
</RadioGroup>
);
const childNodes = wrapper.find(RadioButtonLabeled).nodes;

assert.equal(childNodes[0].props.Label, 'foo');
assert.equal(childNodes[1].props.Label, 'bar');
assert(_.isNil(childNodes[2].props.Label));
});
assert.equal(wrapper.find('#foo').text(), 'foo');
assert.equal(wrapper.find('#bar').text(), 'bar');
});
});

describeWithDOM('RadioGroup', () => {
describe('user selects one of the radio button children', () => {
it('calls the function passed in as the `onSelect` prop...', () => {
const onSelect = sinon.spy();
Expand Down