diff --git a/packages/top-app-bar/FixedAdjust.js b/packages/top-app-bar/FixedAdjust.tsx similarity index 70% rename from packages/top-app-bar/FixedAdjust.js rename to packages/top-app-bar/FixedAdjust.tsx index a65472e65..723b73600 100644 --- a/packages/top-app-bar/FixedAdjust.js +++ b/packages/top-app-bar/FixedAdjust.tsx @@ -20,21 +20,28 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; +import * as React from 'react'; +import * as classnames from 'classnames'; -const FixedAdjust = (props) => { - const { - tag: Tag, - children, - className, - dense, - prominent, - short, - ...otherProps - } = props; +export interface TopAppbarFixedAdjustProps { + tag?: string; + className?: string; + dense?: boolean; + prominent?: boolean; + short?: boolean; +}; +const FixedAdjust: React.FunctionComponent = ({ + /* eslint-disable react/prop-types */ + tag: Tag = 'main', + children, + className = '', + dense = false, + prominent = false, + short = false, + /* eslint-enable react/prop-types */ + ...otherProps +}) => { const base = 'mdc-top-app-bar'; const suffix = '-fixed-adjust'; const classes = classnames(className, { @@ -46,25 +53,12 @@ const FixedAdjust = (props) => { }); return ( - {children} + // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/26635 + // @ts-ignore + + {children} + ); }; -FixedAdjust.propTypes = { - tag: PropTypes.string, - children: PropTypes.node.isRequired, - className: PropTypes.string, - dense: PropTypes.bool, - prominent: PropTypes.bool, - short: PropTypes.bool, -}; - -FixedAdjust.defaultProps = { - tag: 'main', - className: '', - dense: false, - prominent: false, - short: false, -}; - export default FixedAdjust; diff --git a/packages/top-app-bar/index.js b/packages/top-app-bar/index.tsx similarity index 61% rename from packages/top-app-bar/index.js rename to packages/top-app-bar/index.tsx index 33b4df69f..65ee4b845 100644 --- a/packages/top-app-bar/index.js +++ b/packages/top-app-bar/index.tsx @@ -20,27 +20,67 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; -import TopAppBarFixedAdjust from './FixedAdjust'; +import * as React from 'react'; +import * as classnames from 'classnames'; +import TopAppBarFixedAdjust, {TopAppbarFixedAdjustProps} from './FixedAdjust'; import { MDCFixedTopAppBarFoundation, MDCTopAppBarFoundation, MDCShortTopAppBarFoundation, +// no mdc .d.ts file +// @ts-ignore } from '@material/top-app-bar/dist/mdc.topAppBar'; -export default class TopAppBar extends React.Component { - foundation_ = null; +export type MDCTopAppBarFoundationTypes + = MDCFixedTopAppBarFoundation | MDCTopAppBarFoundation | MDCShortTopAppBarFoundation; + +export interface TopAppBarProps { + actionItems?: React.ReactElement[]; + className: string; + dense: boolean; + fixed: boolean; + navigationIcon?: React.ReactElement; + prominent: boolean; + short: boolean; + shortCollapsed: boolean; + style: React.CSSProperties; + title: React.ReactNode; +} + +interface TopAppBarState { + classList: Set; + style: React.CSSProperties; +} - state = { +type Props = TopAppBarProps & React.HTMLProps; +export type VariantType = 'dense' | 'fixed' | 'prominent' | 'short' | 'shortCollapsed'; +// function isElement(element: any): element is React.ReactElement { +// return typeof element !== 'string' || +// typeof element !== 'number' || +// typeof element !== 'boolean'; +// } +export default class TopAppBar extends React.Component< + Props, + TopAppBarState + > { + topAppBarElement: React.RefObject = React.createRef(); + foundation?: MDCTopAppBarFoundationTypes; + + state: TopAppBarState = { classList: new Set(), + style: {}, }; - constructor(props) { - super(props); - this.topAppBarElement = React.createRef(); - } + static defaultProps: Partial = { + className: '', + dense: false, + fixed: false, + prominent: false, + short: false, + shortCollapsed: false, + style: {}, + title: '', + }; get classes() { const {classList} = this.state; @@ -52,7 +92,6 @@ export default class TopAppBar extends React.Component { short, shortCollapsed, } = this.props; - return classnames('mdc-top-app-bar', Array.from(classList), className, { 'mdc-top-app-bar--fixed': fixed, 'mdc-top-app-bar--short': shortCollapsed || short, @@ -62,80 +101,64 @@ export default class TopAppBar extends React.Component { }); } + componentDidMount() { this.initializeFoundation(); } componentWillUnmount() { - this.foundation_.destroy(); + this.foundation.destroy(); } - componentDidUpdate(prevProps) { - const foundationChanged = ['short', 'shortCollapsed', 'fixed'] - .some((variant) => this.props[variant] !== prevProps[variant] ); - + componentDidUpdate(prevProps: Props) { + const foundationChanged = ['short', 'shortCollapsed', 'fixed'].some( + (variant: string) => this.props[variant as VariantType] !== prevProps[variant as VariantType] + ); if (foundationChanged) { this.initializeFoundation(); } } - - initializeFoundation = () => { + private initializeFoundation = () => { const {short, shortCollapsed, fixed} = this.props; - if (this.foundation_) { - this.foundation_.destroy(); + if (this.foundation) { + this.foundation.destroy(); } - if (short || shortCollapsed) { - this.foundation_ = new MDCShortTopAppBarFoundation(this.adapter); + this.foundation = new MDCShortTopAppBarFoundation(this.adapter); } else if (fixed) { - this.foundation_ = new MDCFixedTopAppBarFoundation(this.adapter); + this.foundation = new MDCFixedTopAppBarFoundation(this.adapter); } else { - this.foundation_ = new MDCTopAppBarFoundation(this.adapter); + this.foundation = new MDCTopAppBarFoundation(this.adapter); } + this.foundation.init(); + }; - this.foundation_.init(); - } - - - addClassesToElement(classes, element) { + addClassesToElement(classes: string, element: React.ReactElement) { const updatedProps = { className: classnames(classes, element.props.className), }; return React.cloneElement(element, updatedProps); } - enableRippleOnElement(element) { - // If `element` is a Native React Element, throw error to enforce - // ripple - if (typeof element.type === 'string') { - const errorText = 'Material Design requires all Top App Bar Icons to ' + - 'have ripple. Please use @material/react-ripple HOC with your icons.'; - throw new Error(errorText); - } - - return React.cloneElement(element, {hasRipple: true}); - } - getMergedStyles = () => { const {style} = this.state; return Object.assign({}, style, this.props.style); - } + }; get adapter() { const {actionItems} = this.props; - return { - addClass: (className) => + addClass: (className: string) => this.setState({classList: this.state.classList.add(className)}), - removeClass: (className) => { + removeClass: (className: string) => { const {classList} = this.state; classList.delete(className); this.setState({classList}); }, - hasClass: (className) => this.classes.split(' ').includes(className), - setStyle: (varName, value) => { - const updatedStyle = Object.assign({}, this.state.style); + hasClass: (className: string) => this.classes.split(' ').includes(className), + setStyle: (varName: keyof React.CSSProperties, value: string) => { + const updatedStyle = Object.assign({}, this.state.style) as React.CSSProperties; updatedStyle[varName] = value; this.setState({style: updatedStyle}); }, @@ -143,17 +166,18 @@ export default class TopAppBar extends React.Component { if (this.topAppBarElement && this.topAppBarElement.current) { return this.topAppBarElement.current.clientHeight; } + return 0; }, - registerScrollHandler: (handler) => + registerScrollHandler: (handler: EventListener) => window.addEventListener('scroll', handler), - deregisterScrollHandler: (handler) => + deregisterScrollHandler: (handler: EventListener) => window.removeEventListener('scroll', handler), getViewportScrollY: () => window.pageYOffset, getTotalActionItems: () => !!(actionItems && actionItems.length), }; } - get otherProps() { + render() { const { /* eslint-disable no-unused-vars */ actionItems, @@ -169,16 +193,13 @@ export default class TopAppBar extends React.Component { ...otherProps } = this.props; - return otherProps; - } - - render() { return (
+ ref={this.topAppBarElement} + >
{this.renderTitleAndNavigationSection()} {this.renderActionItems()} @@ -191,26 +212,23 @@ export default class TopAppBar extends React.Component { const {title} = this.props; const classes = 'mdc-top-app-bar__section mdc-top-app-bar__section--align-start'; - return (
{this.renderNavigationIcon()} - - {title} - + {title}
); } renderNavigationIcon() { const {navigationIcon} = this.props; - if (!navigationIcon) { return; } - - const elementWithClasses = this.addClassesToElement('mdc-top-app-bar__navigation-icon', navigationIcon); - return this.enableRippleOnElement(elementWithClasses); + return this.addClassesToElement( + 'mdc-top-app-bar__navigation-icon', + navigationIcon + ); } renderActionItems() { @@ -218,50 +236,21 @@ export default class TopAppBar extends React.Component { if (!actionItems) { return; } - return (
- {/* to set key on the element, the element needs to be cloned */} {actionItems.map((item, key) => { const elementWithClasses = this.addClassesToElement( - 'mdc-top-app-bar__action-item', item); - const elementWithRipple = this.enableRippleOnElement(elementWithClasses); - return React.cloneElement(elementWithRipple, {key}); + 'mdc-top-app-bar__action-item', + item + ); + return React.cloneElement(elementWithClasses, {key}); })}
); } } -TopAppBar.propTypes = { - actionItems: PropTypes.arrayOf(PropTypes.element), - className: PropTypes.string, - dense: PropTypes.bool, - fixed: PropTypes.bool, - navigationIcon: PropTypes.element, - prominent: PropTypes.bool, - short: PropTypes.bool, - shortCollapsed: PropTypes.bool, - style: PropTypes.object, - title: PropTypes.oneOfType([ - PropTypes.string, PropTypes.element, - ]), -}; - -TopAppBar.defaultProps = { - actionItems: null, - className: '', - dense: false, - fixed: false, - navigationIcon: null, - prominent: false, - short: false, - shortCollapsed: false, - style: {}, - title: '', -}; - -export {TopAppBarFixedAdjust}; +export {TopAppBarFixedAdjust, TopAppbarFixedAdjustProps}; diff --git a/test/screenshot/drawer/DrawerAboveTopAppBar.tsx b/test/screenshot/drawer/DrawerAboveTopAppBar.tsx index eaa882e54..8a465a5d4 100644 --- a/test/screenshot/drawer/DrawerAboveTopAppBar.tsx +++ b/test/screenshot/drawer/DrawerAboveTopAppBar.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import '../../../packages/drawer/index.scss'; import './index.scss'; -// @ts-ignore import TopAppBar from '../../../packages/top-app-bar/index'; import Drawer, { DrawerAppContent, @@ -12,7 +11,7 @@ import Drawer, { } from '../../../packages/drawer/index'; // @ts-ignore import List from './List.js'; -import MaterialIcon from '../../../packages/material-icon/index'; +import {MaterialIconProps} from '../../../packages/material-icon/index'; // eslint-disable-line no-unused-vars interface DrawerScreenshotTestProps { onClose: () => void; @@ -21,7 +20,7 @@ interface DrawerScreenshotTestProps { modal: boolean; dismissible: boolean; renderLoremIpsum: (section: number) => JSX.Element; - renderNavigationIcon: () => MaterialIcon | void; + renderNavigationIcon: () => React.ReactElement | undefined; }; const DrawerScreenshotTest: React.FunctionComponent = ({ diff --git a/test/screenshot/drawer/DrawerBelowTopAppBar.tsx b/test/screenshot/drawer/DrawerBelowTopAppBar.tsx index 14728e938..1331eb25c 100644 --- a/test/screenshot/drawer/DrawerBelowTopAppBar.tsx +++ b/test/screenshot/drawer/DrawerBelowTopAppBar.tsx @@ -3,7 +3,6 @@ import '../../../packages/drawer/index.scss'; import './index.scss'; import TopAppBar, { TopAppBarFixedAdjust, -// @ts-ignore } from '../../../packages/top-app-bar/index'; import Drawer, { DrawerAppContent, @@ -14,7 +13,7 @@ import Drawer, { } from '../../../packages/drawer/index'; // @ts-ignore import List from './List.js'; -import MaterialIcon from '../../../packages/material-icon/index'; +import {MaterialIconProps} from '../../../packages/material-icon/index'; // eslint-disable-line no-unused-vars interface DrawerScreenshotTestProps { onClose: () => void; @@ -23,7 +22,7 @@ interface DrawerScreenshotTestProps { modal: boolean; dismissible: boolean; renderLoremIpsum: (section: number) => JSX.Element; - renderNavigationIcon: () => MaterialIcon | void; + renderNavigationIcon: () => React.ReactElement | undefined; }; const DrawerScreenshotTest: React.FunctionComponent = ({ diff --git a/test/screenshot/drawer/DrawerTest.tsx b/test/screenshot/drawer/DrawerTest.tsx index 1ab77fb69..ef5ac70c0 100644 --- a/test/screenshot/drawer/DrawerTest.tsx +++ b/test/screenshot/drawer/DrawerTest.tsx @@ -5,7 +5,7 @@ import MaterialIcon from '../../../packages/material-icon/index'; import DrawerAboveTopAppBar from './DrawerAboveTopAppBar'; import DrawerBelowTopAppBar from './DrawerBelowTopAppBar'; -const noop = () => {}; +const noop = () => undefined; interface DrawerScreenshotTestProps { open?: boolean; diff --git a/test/screenshot/index.tsx b/test/screenshot/index.tsx index 48af6dd72..bc5fb28db 100644 --- a/test/screenshot/index.tsx +++ b/test/screenshot/index.tsx @@ -2,8 +2,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import {HashRouter, Route} from 'react-router-dom'; import App from './App'; -// @ts-ignore -import topAppBarVariants from './top-app-bar/variants.js'; +import topAppBarVariants from './top-app-bar/variants'; import drawerVariants from './drawer/variants'; import textFieldVariants from './text-field/variants'; import {COMPONENTS} from './constants'; diff --git a/test/screenshot/screenshot-test-urls.tsx b/test/screenshot/screenshot-test-urls.tsx index 8b6eb36cd..2be636ac4 100644 --- a/test/screenshot/screenshot-test-urls.tsx +++ b/test/screenshot/screenshot-test-urls.tsx @@ -1,5 +1,4 @@ -// @ts-ignore -import topAppBarVariants from './top-app-bar/variants.js'; +import topAppBarVariants from './top-app-bar/variants'; import drawerVariants from './drawer/variants'; import textFieldVariants from './text-field/variants'; const urls = [ diff --git a/test/screenshot/top-app-bar/dense.js b/test/screenshot/top-app-bar/dense.tsx similarity index 59% rename from test/screenshot/top-app-bar/dense.js rename to test/screenshot/top-app-bar/dense.tsx index 22be80ce5..9d7421335 100644 --- a/test/screenshot/top-app-bar/dense.js +++ b/test/screenshot/top-app-bar/dense.tsx @@ -1,22 +1,23 @@ -import React from 'react'; +import * as React from 'react'; import TopAppBar from '../../../packages/top-app-bar'; - import MaterialIcon from '../../../packages/material-icon'; import MainTopAppBarContent from './mainContent'; -const TopAppBarDenseScreenshotTest = () => { +const TopAppBarDenseScreenshotTest: React.FunctionComponent = () => { return (
console.log('dense click')} - />} + navigationIcon={ + console.log('dense click')} + /> + } actionItems={[]} /> - +
); }; diff --git a/test/screenshot/top-app-bar/fixed.js b/test/screenshot/top-app-bar/fixed.tsx similarity index 59% rename from test/screenshot/top-app-bar/fixed.js rename to test/screenshot/top-app-bar/fixed.tsx index 11705d5fc..daec6d033 100644 --- a/test/screenshot/top-app-bar/fixed.js +++ b/test/screenshot/top-app-bar/fixed.tsx @@ -1,21 +1,23 @@ -import React from 'react'; +import * as React from 'react'; import TopAppBar from '../../../packages/top-app-bar'; import MaterialIcon from '../../../packages/material-icon'; import MainTopAppBarContent from './mainContent'; -const TopAppBarFixedScreenshotTest = () => { +const TopAppBarFixedScreenshotTest: React.FunctionComponent = () => { return (
console.log('fixed click')} - />} + navigationIcon={ + console.log('fixed click')} + /> + } actionItems={[]} /> - +
); }; diff --git a/test/screenshot/top-app-bar/index.js b/test/screenshot/top-app-bar/index.tsx similarity index 83% rename from test/screenshot/top-app-bar/index.js rename to test/screenshot/top-app-bar/index.tsx index f7f2d580a..a06948f71 100644 --- a/test/screenshot/top-app-bar/index.js +++ b/test/screenshot/top-app-bar/index.tsx @@ -1,12 +1,11 @@ -import React from 'react'; +import * as React from 'react'; import {Link} from 'react-router-dom'; import topAppBarVariants from './variants'; - import '../../../packages/top-app-bar/index.scss'; import '../../../packages/material-icon/index.scss'; import './index.scss'; -const TopAppBarHomePage = () => { +const TopAppBarHomePage: React.FunctionComponent = () => { return (
{topAppBarVariants.map((variant, index) => ( diff --git a/test/screenshot/top-app-bar/mainContent.js b/test/screenshot/top-app-bar/mainContent.js deleted file mode 100644 index b671762c6..000000000 --- a/test/screenshot/top-app-bar/mainContent.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import {TopAppBarFixedAdjust} from '../../../packages/top-app-bar'; - -const MainTopAppBarContent = (props) => { - return ( - -

- {'Look at me I\'m a header'} -

- Lorem ipsum dolor sit amet, consectetur adipiscing elit, - sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris - nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in - reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa - qui officia deserunt mollit anim id est laborum. -
- ); -}; - -export default MainTopAppBarContent; diff --git a/test/screenshot/top-app-bar/mainContent.tsx b/test/screenshot/top-app-bar/mainContent.tsx new file mode 100644 index 000000000..47bec24e2 --- /dev/null +++ b/test/screenshot/top-app-bar/mainContent.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; +import { + TopAppBarFixedAdjust, + TopAppbarFixedAdjustProps, // eslint-disable-line no-unused-vars +} from '../../../packages/top-app-bar'; + +const MainTopAppBarContent: React.FunctionComponent = (props) => { + return ( + +

{'Look at me I\'m a header'}

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim + veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea + commodo consequat. Duis aute irure dolor in reprehenderit in voluptate + velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat + cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum. +
+ ); +}; + +export default MainTopAppBarContent; diff --git a/test/screenshot/top-app-bar/prominent.js b/test/screenshot/top-app-bar/prominent.tsx similarity index 58% rename from test/screenshot/top-app-bar/prominent.js rename to test/screenshot/top-app-bar/prominent.tsx index 9a609402c..88b791ece 100644 --- a/test/screenshot/top-app-bar/prominent.js +++ b/test/screenshot/top-app-bar/prominent.tsx @@ -1,22 +1,23 @@ -import React from 'react'; +import * as React from 'react'; import TopAppBar from '../../../packages/top-app-bar'; - import MaterialIcon from '../../../packages/material-icon'; import MainTopAppBarContent from './mainContent'; -const TopAppBarProminentScreenshotTest = () => { +const TopAppBarProminentScreenshotTest: React.FunctionComponent = () => { return (
console.log('prominent click')} - />} + navigationIcon={ + console.log('prominent click')} + /> + } actionItems={[]} /> - +
); }; diff --git a/test/screenshot/top-app-bar/prominentDense.js b/test/screenshot/top-app-bar/prominentDense.tsx similarity index 58% rename from test/screenshot/top-app-bar/prominentDense.js rename to test/screenshot/top-app-bar/prominentDense.tsx index db7089fb8..1c4f9afdb 100644 --- a/test/screenshot/top-app-bar/prominentDense.js +++ b/test/screenshot/top-app-bar/prominentDense.tsx @@ -1,23 +1,24 @@ -import React from 'react'; +import * as React from 'react'; import TopAppBar from '../../../packages/top-app-bar'; - import MaterialIcon from '../../../packages/material-icon'; import MainTopAppBarContent from './mainContent'; -const TopAppBarProminentDenseScreenshotTest = () => { +const TopAppBarProminentDenseScreenshotTest: React.FunctionComponent = () => { return (
console.log('prominent dense click')} - />} + navigationIcon={ + console.log('prominent dense click')} + /> + } actionItems={[]} /> - +
); }; diff --git a/test/screenshot/top-app-bar/prominentToShortCollapsed.js b/test/screenshot/top-app-bar/prominentToShortCollapsed.tsx similarity index 66% rename from test/screenshot/top-app-bar/prominentToShortCollapsed.js rename to test/screenshot/top-app-bar/prominentToShortCollapsed.tsx index a59f25bb2..ba247a497 100644 --- a/test/screenshot/top-app-bar/prominentToShortCollapsed.js +++ b/test/screenshot/top-app-bar/prominentToShortCollapsed.tsx @@ -1,9 +1,16 @@ -import React from 'react'; +import * as React from 'react'; import TopAppBar from '../../../packages/top-app-bar'; import MaterialIcon from '../../../packages/material-icon'; import MainTopAppBarContent from './mainContent'; -class TopAppBarProminentToShortCollapsedScreenshotTest extends React.Component { +interface TopAppBarProminentToShortCollapsedScreenshotTestState { + isPhone: boolean; +} + +class TopAppBarProminentToShortCollapsedScreenshotTest extends React.Component< + {}, + TopAppBarProminentToShortCollapsedScreenshotTestState + > { state = { isPhone: window.innerWidth < 599, }; @@ -12,7 +19,7 @@ class TopAppBarProminentToShortCollapsedScreenshotTest extends React.Component { window.addEventListener('resize', this.updateTopAppBarVariant); } - shouldComponentUpdate(_, nextState) { + shouldComponentUpdate(_: {}, nextState: TopAppBarProminentToShortCollapsedScreenshotTestState) { return nextState.isPhone !== this.state.isPhone; } @@ -23,7 +30,7 @@ class TopAppBarProminentToShortCollapsedScreenshotTest extends React.Component { updateTopAppBarVariant = () => { const isPhone = window.innerWidth < 599; this.setState({isPhone}); - } + }; render() { if (this.state.isPhone) { @@ -31,10 +38,9 @@ class TopAppBarProminentToShortCollapsedScreenshotTest extends React.Component {
console.log('click')} - />} + navigationIcon={ + console.log('click')} /> + } />
@@ -46,10 +52,9 @@ class TopAppBarProminentToShortCollapsedScreenshotTest extends React.Component { console.log('click')} - />} + navigationIcon={ + console.log('click')} /> + } />
diff --git a/test/screenshot/top-app-bar/short.js b/test/screenshot/top-app-bar/short.tsx similarity index 59% rename from test/screenshot/top-app-bar/short.js rename to test/screenshot/top-app-bar/short.tsx index 3a66f08cb..b932eb9fb 100644 --- a/test/screenshot/top-app-bar/short.js +++ b/test/screenshot/top-app-bar/short.tsx @@ -1,21 +1,23 @@ -import React from 'react'; +import * as React from 'react'; import TopAppBar from '../../../packages/top-app-bar'; import MaterialIcon from '../../../packages/material-icon'; import MainTopAppBarContent from './mainContent'; -const TopAppBarShortScreenshotTest = () => { +const TopAppBarShortScreenshotTest: React.FunctionComponent = () => { return (
console.log('short click')} - />} + navigationIcon={ + console.log('short click')} + /> + } actionItems={[]} /> - +
); }; diff --git a/test/screenshot/top-app-bar/shortCollapsed.js b/test/screenshot/top-app-bar/shortCollapsed.tsx similarity index 50% rename from test/screenshot/top-app-bar/shortCollapsed.js rename to test/screenshot/top-app-bar/shortCollapsed.tsx index 682265ca8..2ba375ea0 100644 --- a/test/screenshot/top-app-bar/shortCollapsed.js +++ b/test/screenshot/top-app-bar/shortCollapsed.tsx @@ -1,19 +1,21 @@ -import React from 'react'; +import * as React from 'react'; import TopAppBar from '../../../packages/top-app-bar'; import MaterialIcon from '../../../packages/material-icon'; import MainTopAppBarContent from './mainContent'; -const TopAppBarShortCollapsedScreenshotTest = () => { +const TopAppBarShortCollapsedScreenshotTest: React.FunctionComponent = () => { return (
console.log('shortCollapsed click')} - />} + navigationIcon={ + console.log('shortCollapsed click')} + /> + } /> - +
); }; diff --git a/test/screenshot/top-app-bar/standard.js b/test/screenshot/top-app-bar/standard.tsx similarity index 58% rename from test/screenshot/top-app-bar/standard.js rename to test/screenshot/top-app-bar/standard.tsx index ddc027517..5054a0db4 100644 --- a/test/screenshot/top-app-bar/standard.js +++ b/test/screenshot/top-app-bar/standard.tsx @@ -1,20 +1,22 @@ -import React from 'react'; +import * as React from 'react'; import TopAppBar from '../../../packages/top-app-bar'; import MaterialIcon from '../../../packages/material-icon'; import MainTopAppBarContent from './mainContent'; -const TopAppBarStandardScreenshotTest = () => { +const TopAppBarStandardScreenshotTest: React.FunctionComponent = () => { return (
console.log('standard click')} - />} + navigationIcon={ + console.log('standard click')} + /> + } actionItems={[]} /> - +
); }; diff --git a/test/screenshot/top-app-bar/standardNoActionItems.js b/test/screenshot/top-app-bar/standardNoActionItems.tsx similarity index 57% rename from test/screenshot/top-app-bar/standardNoActionItems.js rename to test/screenshot/top-app-bar/standardNoActionItems.tsx index b3d99e220..4392e3514 100644 --- a/test/screenshot/top-app-bar/standardNoActionItems.js +++ b/test/screenshot/top-app-bar/standardNoActionItems.tsx @@ -1,19 +1,18 @@ -import React from 'react'; +import * as React from 'react'; import TopAppBar from '../../../packages/top-app-bar'; import MaterialIcon from '../../../packages/material-icon'; import MainTopAppBarContent from './mainContent'; -const TopAppBarStandardNoActionItemsScreenshotTest = () => { +const TopAppBarStandardNoActionItemsScreenshotTest: React.FunctionComponent = () => { return (
console.log('click')} - />} + navigationIcon={ + console.log('click')} /> + } /> - +
); }; diff --git a/test/screenshot/top-app-bar/standardWithNavigationIconElement.js b/test/screenshot/top-app-bar/standardWithNavigationIconElement.js deleted file mode 100644 index 86d908803..000000000 --- a/test/screenshot/top-app-bar/standardWithNavigationIconElement.js +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; -import TopAppBar from '../../../packages/top-app-bar'; -import MaterialIcon from '../../../packages/material-icon'; -import {withRipple} from '../../../packages/ripple'; -import MainTopAppBarContent from './mainContent'; - -const NavigationIcon = ({ - hasRipple, initRipple, unbounded, ...otherProps // eslint-disable-line react/prop-types -}) => ( - console.log('navigation icon click')} - ref={initRipple} - {...otherProps}> - - - - - -); - -const NavigationIconWithRipple = withRipple(NavigationIcon); - -const TopAppBarStandardWithNavigationIconElementScreenshotTest = () => { - return ( -
- } - actionItems={[]} - /> - -
- ); -}; - -export default TopAppBarStandardWithNavigationIconElementScreenshotTest; diff --git a/test/screenshot/top-app-bar/standardWithNavigationIconElement.tsx b/test/screenshot/top-app-bar/standardWithNavigationIconElement.tsx new file mode 100644 index 000000000..70d91e5b5 --- /dev/null +++ b/test/screenshot/top-app-bar/standardWithNavigationIconElement.tsx @@ -0,0 +1,63 @@ +import * as React from 'react'; +import TopAppBar from '../../../packages/top-app-bar'; +import MaterialIcon from '../../../packages/material-icon'; +import {withRipple, InjectedProps} from '../../../packages/ripple'; +import MainTopAppBarContent from './mainContent'; + +interface RippleProps extends InjectedProps { + hasRipple?: boolean; +} + +// TODO: Replace RippleProps with real tsx ripple props. Fix with #528 +// @ts-ignore +const NavigationIcon: React.FunctionComponent = ({ + /* eslint-disable react/prop-types */ + hasRipple, + initRipple, + unbounded, + /* eslint-enable react/prop-types */ + ...otherProps +}) => ( + console.log('navigation icon click')} + ref={initRipple} + {...otherProps} + > + + + + + +); + +const NavigationIconWithRipple = withRipple(NavigationIcon); + +const TopAppBarStandardWithNavigationIconElementScreenshotTest: React.FunctionComponent = () => { + return ( +
+ } + actionItems={[]} + /> + +
+ ); +}; + +export default TopAppBarStandardWithNavigationIconElementScreenshotTest; diff --git a/test/screenshot/top-app-bar/variants.js b/test/screenshot/top-app-bar/variants.tsx similarity index 100% rename from test/screenshot/top-app-bar/variants.js rename to test/screenshot/top-app-bar/variants.tsx diff --git a/test/unit/top-app-bar/FixedAdjust.test.js b/test/unit/top-app-bar/FixedAdjust.test.tsx similarity index 53% rename from test/unit/top-app-bar/FixedAdjust.test.js rename to test/unit/top-app-bar/FixedAdjust.test.tsx index 12b5cc49e..212a235ad 100644 --- a/test/unit/top-app-bar/FixedAdjust.test.js +++ b/test/unit/top-app-bar/FixedAdjust.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import * as React from 'react'; import {assert} from 'chai'; import {shallow} from 'enzyme'; import {TopAppBarFixedAdjust} from '../../../packages/top-app-bar/index'; @@ -6,50 +6,60 @@ import {TopAppBarFixedAdjust} from '../../../packages/top-app-bar/index'; suite('TopAppBarFixedAdjust'); test('classNames adds classes', () => { - const wrapper = shallow( - hello - ); + const wrapper = shallow( + + hello + + ); assert.isTrue(wrapper.hasClass('test-class-name')); assert.isTrue(wrapper.hasClass('mdc-top-app-bar--fixed-adjust')); }); test('renders children', () => { - const wrapper = shallow( - HI - ); + const wrapper = shallow( + + HI + + ); assert.equal(wrapper.find('.child-element').length, 1); }); test('renders as a different tag name when passed props.tag', () => { - const wrapper = shallow(hello); + const wrapper = shallow( + hello + ); assert.equal(wrapper.find('main').length, 0); assert.equal(wrapper.type(), 'div'); }); test('has correct dense class', () => { - const wrapper = shallow( - hello - ); + const wrapper = shallow( + hello + ); assert.isTrue(wrapper.hasClass('mdc-top-app-bar--dense-fixed-adjust')); }); test('has correct dense prominent class', () => { - const wrapper = shallow( - hello - ); - assert.isTrue(wrapper.hasClass('mdc-top-app-bar--dense-prominent-fixed-adjust')); + const wrapper = shallow( + + hello + + ); + assert.isTrue( + wrapper.hasClass('mdc-top-app-bar--dense-prominent-fixed-adjust') + ); }); test('has correct prominent class', () => { - const wrapper = shallow( - hello - ); + const wrapper = shallow( + hello + ); assert.isTrue(wrapper.hasClass('mdc-top-app-bar--prominent-fixed-adjust')); }); test('has correct short class', () => { - const wrapper = shallow( - hello - ); + const wrapper = shallow( + hello + ); assert.isTrue(wrapper.hasClass('mdc-top-app-bar--short-fixed-adjust')); }); diff --git a/test/unit/top-app-bar/index.test.js b/test/unit/top-app-bar/index.test.js deleted file mode 100644 index 37d48d09b..000000000 --- a/test/unit/top-app-bar/index.test.js +++ /dev/null @@ -1,339 +0,0 @@ -import React from 'react'; -import {assert} from 'chai'; -import {mount, shallow} from 'enzyme'; -import td from 'testdouble'; -import TopAppBar from '../../../packages/top-app-bar/index'; -import {withRipple} from '../../../packages/ripple/index'; - -suite('TopAppBar'); - -const NavigationIcon = ({ - initRipple, hasRipple, unbounded, className, ...otherProps // eslint-disable-line react/prop-types -}) => ( -
-); -const RippledNavigationIcon = withRipple(NavigationIcon); - -const ActionItem = ({ - initRipple, hasRipple, unbounded, className, ...otherProps // eslint-disable-line react/prop-types -}) => ( - -); -const RippledActionItem = withRipple(ActionItem); - -test('classNames adds classes', () => { - const wrapper = shallow(); - assert.isTrue(wrapper.hasClass('test-class-name')); - assert.isTrue(wrapper.hasClass('mdc-top-app-bar')); -}); - -test('has correct standard class', () => { - const wrapper = shallow(); - assert.isTrue(wrapper.hasClass('mdc-top-app-bar')); -}); - -test('has correct shortCollapsed class', () => { - const wrapper = shallow(); - assert.isTrue(wrapper.hasClass('mdc-top-app-bar--short')); - assert.isTrue(wrapper.hasClass('mdc-top-app-bar--short-collapsed')); -}); - -test('has correct short class', () => { - const wrapper = shallow(); - assert.isTrue(wrapper.hasClass('mdc-top-app-bar--short')); - assert.isFalse(wrapper.hasClass('mdc-top-app-bar--short-collapsed')); -}); - -test('has correct prominent class', () => { - const wrapper = shallow(); - assert.isTrue(wrapper.hasClass('mdc-top-app-bar--prominent')); -}); - -test('has correct fixed class', () => { - const wrapper = shallow(); - assert.isTrue(wrapper.hasClass('mdc-top-app-bar--fixed')); -}); - -test('has correct dense class', () => { - const wrapper = shallow(); - assert.isTrue(wrapper.hasClass('mdc-top-app-bar--dense')); -}); - -test('has correct prominent dense class', () => { - const wrapper = shallow(); - assert.isTrue(wrapper.hasClass('mdc-top-app-bar--dense')); - assert.isTrue(wrapper.hasClass('mdc-top-app-bar--prominent')); -}); - -test('navigationIcon is rendered with navigation icon class', () => { - const wrapper = mount( - } /> - ); - assert.isTrue(wrapper.find('.test-top-app-bar-nav-icon').hasClass('mdc-top-app-bar__navigation-icon')); -}); - -test('navigationIcon have hasRipple prop', () => { - const wrapper = mount( - } /> - ); - assert.isTrue(wrapper.find('.mdc-top-app-bar__navigation-icon').first().props().hasRipple); -}); - -test('navigationIcon is rendered as custom component that accepts a className prop', () => { - const wrapper = mount( - } /> - ); - const navigationIcon = wrapper.find(RippledNavigationIcon); - assert.isTrue(navigationIcon.hasClass('mdc-top-app-bar__navigation-icon')); -}); - -test('actionItems are rendered with action item class', () => { - const wrapper = mount( - ]} /> - ); - assert.isTrue(wrapper.find('.test-action-icon-1').hasClass('mdc-top-app-bar__action-item')); -}); - -test('actionItems have hasRipple prop', () => { - const wrapper = mount( - ]} /> - ); - assert.isTrue(wrapper.find('.mdc-top-app-bar__action-item').first().props().hasRipple); -}); - -test('actionItems are rendered as a custom component that accepts a className prop', () => { - const wrapper = mount( - ]} /> - ); - const actionItem = wrapper.find(RippledActionItem); - assert.isTrue(actionItem.hasClass('mdc-top-app-bar__action-item')); -}); - -test('top app bar style should be set by state', () => { - const wrapper = mount(); - wrapper.setState({style: {color: 'blue'}}); - assert.equal(wrapper.getDOMNode().style.color, 'blue'); -}); - -test('#adapter.addClass adds a class to state', () => { - const wrapper = shallow(); - wrapper.instance().adapter.addClass('test-class-1'); - assert.isTrue(wrapper.state().classList.has('test-class-1')); -}); - -test('#adapter.removeClass removes classes from list', () => { - const wrapper = shallow(); - wrapper.instance().adapter.addClass('test-class-1'); - assert.isTrue(wrapper.state().classList.has('test-class-1')); - wrapper.instance().adapter.removeClass('test-class-1'); - assert.isFalse(wrapper.state().classList.has('test-class-1')); -}); - -test('#adapter.hasClass returns true for an added className', () => { - const wrapper = shallow(); - wrapper.instance().adapter.addClass('test-class-1'); - assert.isTrue(wrapper.instance().adapter.hasClass('test-class-1')); -}); - -test('#adapter.registerScrollHandler triggers handler on window scroll', () => { - const wrapper = shallow(); - const testHandler = td.func(); - wrapper.instance().adapter.registerScrollHandler(testHandler); - const event = new Event('scroll'); - window.dispatchEvent(event); - td.verify(testHandler(event), {times: 1}); -}); - -test('#adapter.deregisterScrollHandler does not trigger handler ' + - 'after registering scroll handler', () => { - const wrapper = shallow(); - const testHandler = td.func(); - wrapper.instance().adapter.registerScrollHandler(testHandler); - const event = new Event('scroll'); - wrapper.instance().adapter.deregisterScrollHandler(testHandler); - window.dispatchEvent(event); - td.verify(testHandler(event), {times: 0}); -}); - -test('#adapter.getTotalActionItems returns true with one actionItem ' + - 'passed', () => { - const wrapper = shallow( - ]}/> - ); - assert.isTrue(wrapper.instance().adapter.getTotalActionItems()); -}); - -test('#adapter.getTotalActionItems returns false with no actionItem ' + - 'passed', () => { - const wrapper = shallow(); - assert.isFalse(wrapper.instance().adapter.getTotalActionItems()); -}); - -test('#adapter.setStyle should update state', () => { - const wrapper = shallow(); - wrapper.instance().adapter.setStyle('display', 'block'); - assert.equal(wrapper.state().style.display, 'block'); -}); - -test('#adapter.getTopAppBarHeight should return clientHeight', () => { - const div = document.createElement('div'); - // needs to be attached to real DOM to get width - // https://github.com/airbnb/enzyme/issues/1525 - document.body.append(div); - const options = {attachTo: div}; - const wrapper = mount(, options); - const topAppBarHeight = wrapper.instance().adapter.getTopAppBarHeight(); - // 18 is the rendered height in pixels. It won't have the actual - // top app bar height since the css is not applied. 18 is the height - // of the title element. - assert.equal(topAppBarHeight, 18); - div.remove(); -}); - -test('#enableRippleOnElement throws error if a native element', () => { - const wrapper = mount(); - assert.throws( - () => wrapper.instance().enableRippleOnElement({type: 'test'}), - Error, - 'Material Design requires all Top App Bar Icons to have ripple. ' - + 'Please use @material/react-ripple HOC with your icons.' - ); -}); - -test('when changes from short to fixed the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({fixed: true, short: false}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from short to fixed the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({fixed: true, short: false}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from short to standard the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({short: false}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from short to prominent the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({short: false, prominent: true}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from short to shortCollpased the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({shortCollapsed: true}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from fixed to prominent the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({fixed: false, prominent: true}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from fixed to short the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({fixed: false, short: true}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from fixed to shortCollpased the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({fixed: false, shortCollapsed: true}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from fixed to standard the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({fixed: false}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from standard to fixed the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({fixed: true}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from standard to short the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({short: true}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from standard to shortCollapsed the foundation changes', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({shortCollapsed: true}); - assert.notEqual(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('when changes from standard to prominent the foundation does not ' + - 'change', () => { - const wrapper = shallow(); - const originalFoundation = wrapper.instance().foundation_; - wrapper.setProps({prominent: true}); - assert.equal(wrapper.instance().foundation_, originalFoundation); - assert.exists(wrapper.instance().foundation_); -}); - -test('#componentWillUnmount destroys foundation', () => { - const wrapper = shallow(); - const foundation = wrapper.instance().foundation_; - foundation.destroy = td.func(); - wrapper.unmount(); - td.verify(foundation.destroy()); -}); - -test('have remaining props', () => { - const wrapper = shallow(); - const props = wrapper.props(); - assert.isTrue( - props.id === 'identifier' && - props.dataKey === 'secret' && - wrapper.hasClass('classes') - ); -}); diff --git a/test/unit/top-app-bar/index.test.tsx b/test/unit/top-app-bar/index.test.tsx new file mode 100644 index 000000000..4725a1e35 --- /dev/null +++ b/test/unit/top-app-bar/index.test.tsx @@ -0,0 +1,349 @@ +import * as React from 'react'; +import {assert} from 'chai'; +import {mount, shallow} from 'enzyme'; +import * as td from 'testdouble'; +import TopAppBar from '../../../packages/top-app-bar/index'; +import {withRipple, InjectedProps} from '../../../packages/ripple/index'; +import {coerceForTesting} from '../helpers/types'; + +suite('TopAppBar'); + +interface RippleProps extends InjectedProps { + hasRipple?: boolean; + className: string; +} + +type DivRippleProps = RippleProps & React.HTMLProps; +type ActionItemRippleProps = RippleProps & React.HTMLProps; + +// TODO: Replace with real tsx ripple props. Fix with #528 +// @ts-ignore +const NavigationIcon: React.FunctionComponent = ({ + /* eslint-disable react/prop-types */ + initRipple, + hasRipple, + unbounded, + className, + /* eslint-enable react/prop-types */ + ...otherProps +}) => ( +
+); + +const RippledNavigationIcon = withRipple, HTMLDivElement>(NavigationIcon); + +const ActionItem: React.FunctionComponent = ({ + /* eslint-disable react/prop-types */ + initRipple, + hasRipple, + unbounded, + className, + ref, + /* eslint-enable react/prop-types */ + ...otherProps +}) => ( + +); + +const RippledActionItem = withRipple, HTMLAnchorElement>(ActionItem); + +test('classNames adds classes', () => { + const wrapper = shallow(); + assert.isTrue(wrapper.hasClass('test-class-name')); + assert.isTrue(wrapper.hasClass('mdc-top-app-bar')); +}); + +test('has correct standard class', () => { + const wrapper = shallow(); + assert.isTrue(wrapper.hasClass('mdc-top-app-bar')); +}); + +test('has correct shortCollapsed class', () => { + const wrapper = shallow(); + assert.isTrue(wrapper.hasClass('mdc-top-app-bar--short')); + assert.isTrue(wrapper.hasClass('mdc-top-app-bar--short-collapsed')); +}); + +test('has correct short class', () => { + const wrapper = shallow(); + assert.isTrue(wrapper.hasClass('mdc-top-app-bar--short')); + assert.isFalse(wrapper.hasClass('mdc-top-app-bar--short-collapsed')); +}); + +test('has correct prominent class', () => { + const wrapper = shallow(); + assert.isTrue(wrapper.hasClass('mdc-top-app-bar--prominent')); +}); + +test('has correct fixed class', () => { + const wrapper = shallow(); + assert.isTrue(wrapper.hasClass('mdc-top-app-bar--fixed')); +}); + +test('has correct dense class', () => { + const wrapper = shallow(); + assert.isTrue(wrapper.hasClass('mdc-top-app-bar--dense')); +}); + +test('has correct prominent dense class', () => { + const wrapper = shallow(); + assert.isTrue(wrapper.hasClass('mdc-top-app-bar--dense')); + assert.isTrue(wrapper.hasClass('mdc-top-app-bar--prominent')); +}); + +test('navigationIcon is rendered with navigation icon class', () => { + const wrapper = mount( + } /> + ); + assert.isTrue( + wrapper + .find('.test-top-app-bar-nav-icon') + .hasClass('mdc-top-app-bar__navigation-icon') + ); +}); + +test('navigationIcon is rendered as custom component that accepts a className prop', () => { + const wrapper = mount( + } /> + ); + const navigationIcon = wrapper.find(RippledNavigationIcon); + assert.isTrue(navigationIcon.hasClass('mdc-top-app-bar__navigation-icon')); +}); + +test('actionItems are rendered with action item class', () => { + const wrapper = mount( + ]} /> + ); + assert.isTrue( + wrapper.find('.test-action-icon-1').hasClass('mdc-top-app-bar__action-item') + ); +}); + +test('actionItems are rendered as a custom component that accepts a className prop', () => { + const wrapper = mount( + ]} /> + ); + const actionItem = wrapper.find(RippledActionItem); + assert.isTrue(actionItem.hasClass('mdc-top-app-bar__action-item')); +}); + +test('top app bar style should be set by state', () => { + const wrapper = mount(); + wrapper.setState({style: {color: 'blue'}}); + assert.equal(coerceForTesting(wrapper.getDOMNode()).style.color, 'blue'); +}); + +test('#adapter.addClass adds a class to state', () => { + const wrapper = shallow(); + wrapper.instance().adapter.addClass('test-class-1'); + assert.isTrue(wrapper.state().classList.has('test-class-1')); +}); + +test('#adapter.removeClass removes classes from list', () => { + const wrapper = shallow(); + wrapper.instance().adapter.addClass('test-class-1'); + assert.isTrue(wrapper.state().classList.has('test-class-1')); + wrapper.instance().adapter.removeClass('test-class-1'); + assert.isFalse(wrapper.state().classList.has('test-class-1')); +}); + +test('#adapter.hasClass returns true for an added className', () => { + const wrapper = shallow(); + wrapper.instance().adapter.addClass('test-class-1'); + assert.isTrue(wrapper.instance().adapter.hasClass('test-class-1')); +}); + +test('#adapter.registerScrollHandler triggers handler on window scroll', () => { + const wrapper = shallow(); + const testHandler = coerceForTesting(td.func()); + wrapper.instance().adapter.registerScrollHandler(testHandler); + const event = new Event('scroll'); + window.dispatchEvent(event); + td.verify(testHandler(event), {times: 1}); +}); +test( + '#adapter.deregisterScrollHandler does not trigger handler ' + + 'after registering scroll handler', + () => { + const wrapper = shallow(); + const testHandler = coerceForTesting(td.func()); + wrapper.instance().adapter.registerScrollHandler(testHandler); + const event = new Event('scroll'); + wrapper.instance().adapter.deregisterScrollHandler(testHandler); + window.dispatchEvent(event); + td.verify(testHandler(event), {times: 0}); + } +); +test( + '#adapter.getTotalActionItems returns true with one actionItem ' + 'passed', + () => { + const wrapper = shallow( + ]} /> + ); + assert.isTrue(wrapper.instance().adapter.getTotalActionItems()); + } +); +test( + '#adapter.getTotalActionItems returns false with no actionItem ' + 'passed', + () => { + const wrapper = shallow(); + assert.isFalse(wrapper.instance().adapter.getTotalActionItems()); + } +); + +test('#adapter.setStyle should update state', () => { + const wrapper = shallow(); + wrapper.instance().adapter.setStyle('display', 'block'); + assert.equal(wrapper.state().style.display, 'block'); +}); + +test('#adapter.getTopAppBarHeight should return clientHeight', () => { + const div = document.createElement('div'); + // needs to be attached to real DOM to get width + // https://github.com/airbnb/enzyme/issues/1525 + document.body.append(div); + const options = {attachTo: div}; + const wrapper = mount(, options); + const topAppBarHeight = wrapper.instance().adapter.getTopAppBarHeight(); + // 18 is the rendered height in pixels. It won't have the actual + // top app bar height since the css is not applied. 18 is the height + // of the title element. + assert.equal(topAppBarHeight, 18); + div.remove(); +}); + +test('when changes from short to fixed the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({fixed: true, short: false}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test('when changes from short to fixed the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({fixed: true, short: false}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test('when changes from short to standard the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({short: false}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test('when changes from short to prominent the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({short: false, prominent: true}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test('when changes from short to shortCollpased the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({shortCollapsed: true}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test('when changes from fixed to prominent the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({fixed: false, prominent: true}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test('when changes from fixed to short the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({fixed: false, short: true}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test('when changes from fixed to shortCollpased the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({fixed: false, shortCollapsed: true}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test('when changes from fixed to standard the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({fixed: false}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test('when changes from standard to fixed the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({fixed: true}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test('when changes from standard to short the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({short: true}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test('when changes from standard to shortCollapsed the foundation changes', () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({shortCollapsed: true}); + assert.notEqual(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); +}); + +test( + 'when changes from standard to prominent the foundation does not ' + 'change', + () => { + const wrapper = shallow(); + const originalFoundation = wrapper.instance().foundation; + wrapper.setProps({prominent: true}); + assert.equal(wrapper.instance().foundation, originalFoundation); + assert.exists(wrapper.instance().foundation); + } +); + +test('#componentWillUnmount destroys foundation', () => { + const wrapper = shallow(); + const foundation = wrapper.instance().foundation; + foundation.destroy = td.func(); + wrapper.unmount(); + td.verify(foundation.destroy()); +}); + +test('have remaining props', () => { + const wrapper = shallow( + + ); + const props = wrapper.props(); + assert.isTrue( + props.id === 'identifier' && + props.data === 'secret' && + wrapper.hasClass('classes') + ); +});