diff --git a/react/src/components/__tests__/IonRouterOutlet.tsx b/react/src/components/__tests__/IonRouterOutlet.spec.tsx similarity index 100% rename from react/src/components/__tests__/IonRouterOutlet.tsx rename to react/src/components/__tests__/IonRouterOutlet.spec.tsx diff --git a/react/src/components/__tests__/IonTabs.spec.tsx b/react/src/components/__tests__/IonTabs.spec.tsx new file mode 100644 index 00000000000..4ef1b3f07a2 --- /dev/null +++ b/react/src/components/__tests__/IonTabs.spec.tsx @@ -0,0 +1,102 @@ +import React, { ReactElement } from 'react'; +import { Router } from 'react-router-dom'; +import { createMemoryHistory } from 'history' +import { IonTabs, IonTab, IonTabBar, IonTabButton, IonLabel, IonIcon} from '../index'; +import { render, cleanup } from 'react-testing-library'; + +afterEach(cleanup) + +function renderWithRouter( + ui: ReactElement, + { + route = '/', + history = createMemoryHistory({ initialEntries: [route] }), + } = {} +) { + return { + ...render({ui}), + history + } +} + +describe('IonTabs', () => { + test('should render happy path', () => { + const { container } = renderWithRouter( + + Schedule Content + Speakers Content + Map Content + About Content + + + + Schedule + + + + Speakers + + + + Map + + + + About + + + + + ); + + expect(container.children[0].children.length).toEqual(2); + expect(container.children[0].children[0].tagName).toEqual('DIV'); + expect(container.children[0].children[0].className).toEqual('tabs-inner'); + + expect(container.children[0].children[1].tagName).toEqual('ION-TAB-BAR'); + expect(container.children[0].children[1].children.length).toEqual(4); + expect(Array.from(container.children[0].children[1].children).map(c => c.tagName)).toEqual(['ION-TAB-BUTTON', 'ION-TAB-BUTTON', 'ION-TAB-BUTTON', 'ION-TAB-BUTTON']); + }); + + test('should allow for conditional children', () => { + const { container } = renderWithRouter( + + {false && + Schedule Content + } + Speakers Content + Map Content + About Content + + + {false && + + Schedule + + + } + + Speakers + + + + Map + + + + About + + + + + ); + + expect(container.children[0].children.length).toEqual(2); + expect(container.children[0].children[0].tagName).toEqual('DIV'); + expect(container.children[0].children[0].className).toEqual('tabs-inner'); + + expect(container.children[0].children[1].tagName).toEqual('ION-TAB-BAR'); + expect(container.children[0].children[1].children.length).toEqual(3); + expect(Array.from(container.children[0].children[1].children).map(c => c.tagName)).toEqual(['ION-TAB-BUTTON', 'ION-TAB-BUTTON', 'ION-TAB-BUTTON']); + }); +}); diff --git a/react/src/components/__tests__/createComponent.tsx b/react/src/components/__tests__/createComponent.spec.tsx similarity index 97% rename from react/src/components/__tests__/createComponent.tsx rename to react/src/components/__tests__/createComponent.spec.tsx index 9b803830744..2d5de2719b5 100644 --- a/react/src/components/__tests__/createComponent.tsx +++ b/react/src/components/__tests__/createComponent.spec.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Components } from '@ionic/core' +import { Components } from '@ionic/core'; import { createReactComponent } from '../createComponent'; import { render, fireEvent, cleanup } from 'react-testing-library'; diff --git a/react/src/components/__tests__/createControllerComponent.tsx b/react/src/components/__tests__/createControllerComponent.spec.tsx similarity index 100% rename from react/src/components/__tests__/createControllerComponent.tsx rename to react/src/components/__tests__/createControllerComponent.spec.tsx diff --git a/react/src/components/__tests__/createOverlayComponent.tsx b/react/src/components/__tests__/createOverlayComponent.spec.tsx similarity index 100% rename from react/src/components/__tests__/createOverlayComponent.tsx rename to react/src/components/__tests__/createOverlayComponent.spec.tsx diff --git a/react/src/components/__tests__/utils.ts b/react/src/components/__tests__/utils.spec.ts similarity index 100% rename from react/src/components/__tests__/utils.ts rename to react/src/components/__tests__/utils.spec.ts diff --git a/react/src/components/navigation/IonTabBar.tsx b/react/src/components/navigation/IonTabBar.tsx index cff103305c3..07608273e4e 100644 --- a/react/src/components/navigation/IonTabBar.tsx +++ b/react/src/components/navigation/IonTabBar.tsx @@ -25,7 +25,7 @@ class IonTabBar extends Component { const tabActiveUrls: { [key: string]: Tab } = {}; React.Children.forEach(this.props.children, (child) => { - if (typeof child === 'object' && child.type === IonTabButton) { + if (child != null && typeof child === 'object' && child.props && child.type === IonTabButton) { tabActiveUrls[child.props.tab] = { originalHref: child.props.href, currentHref: child.props.href @@ -72,12 +72,15 @@ class IonTabBar extends Component { } renderChild = (activeTab: string) => (child: React.ReactElement void }>) => { - const href = (child.props.tab === activeTab) ? this.props.location.pathname : (this.state.tabs[child.props.tab].currentHref); + if (child != null && typeof child === 'object' && child.props && child.type === IonTabButton) { + const href = (child.props.tab === activeTab) ? this.props.location.pathname : (this.state.tabs[child.props.tab].currentHref); - return React.cloneElement(child, { - href, - onIonTabButtonClick: this.onTabButtonClick - }) + return React.cloneElement(child, { + href, + onIonTabButtonClick: this.onTabButtonClick + }); + } + return null; } render() { diff --git a/react/src/components/navigation/IonTabs.tsx b/react/src/components/navigation/IonTabs.tsx index 812adc05ae8..ba24cf9277a 100644 --- a/react/src/components/navigation/IonTabs.tsx +++ b/react/src/components/navigation/IonTabs.tsx @@ -32,10 +32,13 @@ export default class IonTabs extends Component { let tabBar: React.ReactElement<{ slot: 'bottom' | 'top' }>; React.Children.forEach(this.props.children, child => { - if (typeof child === 'object' && child.type === IonRouterOutlet) { + if (child == null || typeof child !== 'object' || !child.hasOwnProperty('type')) { + return; + } + if (child.type === IonRouterOutlet) { outlet = child; } - if (typeof child === 'object' && child.type === IonTabBar) { + if (child.type === IonTabBar) { tabBar = child; } });