diff --git a/src/Accordion/Accordion.spec.tsx b/src/Accordion/Accordion.spec.tsx index 00e95467..25c39c0a 100644 --- a/src/Accordion/Accordion.spec.tsx +++ b/src/Accordion/Accordion.spec.tsx @@ -62,13 +62,13 @@ describe('Accordion', () => { ).toEqual(1); }); - it('collapses an expanded item when its title is clicked', () => { - const wrapper = mountAccordion(); - - const fooTitle = wrapper.find(FooTitle); - - fooTitle.simulate('click'); // open - fooTitle.simulate('click'); // close + it('pre expanded accordion', () => { + const wrapper = mount( + + Fake Child + Fake Child + , + ); const instance = wrapper.find(Provider).instance() as Provider; @@ -76,7 +76,46 @@ describe('Accordion', () => { instance.state.items.filter( (item: Item) => item.expanded === true, ).length, - ).toEqual(0); + ).toEqual(1); + }); + + it('works with multiple pre expanded accordion. Extra expands are just ignored.', () => { + const hideBodyClassName = 'HIDE'; + const wrapper = mount( + + + Fake Child + + + Fake Child + + , + ); + + const instance = wrapper.find(Provider).instance() as Provider; + + expect( + instance.state.items.filter((item: Item) => item.expanded) + .length, + ).toEqual(1); + expect( + wrapper.findWhere((item: ReactWrapper) => + item.hasClass(hideBodyClassName), + ).length, + ).toEqual(1); + }); + + it('respects arbitrary user-defined props', () => { + const wrapper = mount(); + const div = wrapper.find('div').getDOMNode(); + + expect(div.getAttribute('lang')).toEqual('en'); }); }); @@ -128,10 +167,11 @@ describe('Accordion', () => { ).toEqual(2); }); - it('collapses an expanded item when its title is clicked', () => { + it('collapses an expanded item when its title is clicked and there is more than one item expanded', () => { const wrapper = mountMultipleExpanded(); wrapper.find(FooTitle).simulate('click'); // open + wrapper.find(BarTitle).simulate('click'); // open wrapper.find(FooTitle).simulate('click'); // close const instance = wrapper.find(Provider).instance() as Provider; @@ -140,7 +180,7 @@ describe('Accordion', () => { instance.state.items.filter( (item: Item) => item.expanded === true, ).length, - ).toEqual(0); + ).toEqual(1); }); }); @@ -167,11 +207,11 @@ describe('Accordion', () => { ).toEqual(0); }); - it('pre expanded accordion', () => { + it('pre expanded accordion when allowMultipleExpanded is true', () => { const wrapper = mount( - + + Fake Child Fake Child - Fake Child , ); @@ -180,60 +220,66 @@ describe('Accordion', () => { expect( instance.state.items.filter((item: Item) => item.expanded === true) .length, - ).toEqual(1); + ).toEqual(2); }); +}); - it('works with multiple pre expanded accordion. Extra expands are just ignored.', () => { - const hideBodyClassName = 'HIDE'; - const wrapper = mount( - - - Fake Child - - - Fake Child +describe('', () => { + const [FooTitle] = [ + (): JSX.Element => Foo, + ]; + + function mountAccordion(): ReactWrapper { + return mount( + + + , ); + } + + it("doesn't collapse an expanded item when it's the only item expanded", () => { + const wrapper = mountAccordion(); + + wrapper.find(FooTitle).simulate('click'); // open + wrapper.find(FooTitle).simulate('click'); // close const instance = wrapper.find(Provider).instance() as Provider; expect( - instance.state.items.filter((item: Item) => item.expanded).length, - ).toEqual(1); - expect( - wrapper.findWhere((item: ReactWrapper) => - item.hasClass(hideBodyClassName), - ).length, + instance.state.items.filter((item: Item) => item.expanded === true) + .length, ).toEqual(1); }); +}); - it('pre expanded accordion when allowMultipleExpanded is true', () => { - const wrapper = mount( - - Fake Child - Fake Child +describe('', () => { + const [FooTitle] = [ + (): JSX.Element => Foo, + ]; + + function mountZeroExpanded(): ReactWrapper { + return mount( + + + + , ); + } - const instance = wrapper.find(Provider).instance() as Provider; + it("collapses an expanded item when its title is clicked and it's the only item open", () => { + const wrapper = mountZeroExpanded(); - expect( - instance.state.items.filter((item: Item) => item.expanded === true) - .length, - ).toEqual(2); - }); + wrapper.find(FooTitle).simulate('click'); // open + wrapper.find(FooTitle).simulate('click'); // close - it('respects arbitrary user-defined props', () => { - const wrapper = mount(); - const div = wrapper.find('div').getDOMNode(); + const provider = wrapper.find(Provider).instance() as Provider; - expect(div.getAttribute('lang')).toEqual('en'); + expect( + provider.state.items.filter((item: Item) => item.expanded === true) + .length, + ).toEqual(0); }); }); diff --git a/src/AccordionContainer/AccordionContainer.tsx b/src/AccordionContainer/AccordionContainer.tsx index cdfa40ff..ac6cd418 100644 --- a/src/AccordionContainer/AccordionContainer.tsx +++ b/src/AccordionContainer/AccordionContainer.tsx @@ -102,22 +102,9 @@ export class Provider extends React.Component { }; removeItem = (key: UUID): void => { - this.setState((state: ProviderState) => { - let items: Item[]; - - if ( - !this.props.allowZeroExpanded && - state.items.filter((item: Item) => item.expanded).length < 2 - ) { - items = state.items; - } else { - items = state.items.filter((item: Item) => item.uuid !== key); - } - - return { - items, - }; - }); + this.setState((state: ProviderState) => ({ + items: state.items.filter((item: Item) => item.uuid !== key), + })); }; setExpanded = (key: UUID, expanded: boolean): void => { @@ -125,10 +112,22 @@ export class Provider extends React.Component { (state: ProviderState) => ({ items: state.items.map((item: Item) => { if (item.uuid === key) { - return { - ...item, - expanded, - }; + if ( + !expanded && + !this.props.allowZeroExpanded && + state.items.filter((item_: Item) => item_.expanded) + .length < 2 + ) { + // If this is an accordion that doesn't allow all items to be closed and the current item is the only one open, don't allow it to close. + return { + ...item, + }; + } else { + return { + ...item, + expanded, + }; + } } if (!this.props.allowMultipleExpanded && expanded) { // If this is an accordion that doesn't allow multiple expansions, we might need to collapse the other expanded item. diff --git a/src/AccordionItem/AccordionItem.spec.tsx b/src/AccordionItem/AccordionItem.spec.tsx index 8f113d1e..81d0576f 100644 --- a/src/AccordionItem/AccordionItem.spec.tsx +++ b/src/AccordionItem/AccordionItem.spec.tsx @@ -216,9 +216,9 @@ describe('AccordionItem', () => { ).toEqual(1); }); - it('can dynamically unset expanded prop', () => { + it('can dynamically unset expanded prop when there is only one item expanded and allowZeroExpanded is set to true', () => { const Wrapper = ({ expanded }: { expanded: boolean }): JSX.Element => ( - +
Fake title
@@ -240,6 +240,35 @@ describe('AccordionItem', () => { ).toEqual(0); }); + it('can dynamically unset expanded prop when there is more than one item expanded', () => { + const Wrapper = ({ expanded }: { expanded: boolean }): JSX.Element => ( + + + +
Fake title
+
+
+ + +
Fake title
+
+
+
+ ); + + const wrapper = mount(); + const instance = wrapper + .find(AccordionProvider) + .instance() as AccordionProvider; + + wrapper.setProps({ expanded: undefined }); + + expect( + instance.state.items.filter((item: Item) => item.expanded === true) + .length, + ).toEqual(1); + }); + it('dynamically changing arbitrary props does not affect expanded state', () => { const Wrapper = ({ className }: { className: string }): JSX.Element => ( @@ -309,35 +338,6 @@ describe('AccordionItem', () => { expect(instance.state.items.length).toEqual(0); }); - it("doesn't unregister itself on unmount in an accordion that doesn't allow zero items to be expanded", () => { - const Wrapper = ({ - showChild, - }: { - showChild: boolean; - }): JSX.Element => ( - - {showChild && ( - - -
Fake title
-
-
- )} -
- ); - - const wrapper = mount(); - const instance = wrapper - .find(AccordionProvider) - .instance() as AccordionProvider; - - expect(instance.state.items.length).toEqual(1); - - wrapper.setProps({ showChild: false }); - - expect(instance.state.items.length).toEqual(1); - }); - it('respects arbitrary user-defined props', () => { const wrapper = mount(