From ec62d04e3fa4ea3ac0ea0fee792355e6346185af Mon Sep 17 00:00:00 2001 From: sam-m-m Date: Thu, 10 Dec 2020 13:57:08 -0800 Subject: [PATCH] chore #175 - Add IconButton tests --- src/__snapshots__/storybook.test.ts.snap | 93 ++++++++++++------- .../IconButton/IconButton.stories.tsx | 23 +++++ src/components/IconButton/IconButton.test.tsx | 53 +++++++++++ src/components/IconButton/index.tsx | 17 ++-- src/components/IconButton/utils.ts | 21 ++++- 5 files changed, 163 insertions(+), 44 deletions(-) create mode 100644 src/components/IconButton/IconButton.stories.tsx create mode 100644 src/components/IconButton/IconButton.test.tsx diff --git a/src/__snapshots__/storybook.test.ts.snap b/src/__snapshots__/storybook.test.ts.snap index 2c6d284a..55cc3d0b 100644 --- a/src/__snapshots__/storybook.test.ts.snap +++ b/src/__snapshots__/storybook.test.ts.snap @@ -229,12 +229,41 @@ exports[`Storyshots Icon Predefined 1`] = ` `; +exports[`Storyshots IconButton Default 1`] = ` +
+ + + +
+`; + exports[`Storyshots Input Default 1`] = `
  @@ -311,7 +340,7 @@ exports[`Storyshots Input Placeholder 1`] = ` className="light storyWrapper-0-1-2" >
 
 
  @@ -792,10 +821,10 @@ exports[`Storyshots Select Default 1`] = ` className="light storyWrapper-0-1-2" >
Lorem @@ -989,10 +1018,10 @@ exports[`Storyshots Select Icon 1`] = ` className="light storyWrapper-0-1-2" >
  @@ -1210,27 +1239,27 @@ exports[`Storyshots Skeleton Count 1`] = ` className="light storyWrapper-0-1-2" >           @@ -1242,7 +1271,7 @@ exports[`Storyshots Skeleton Default 1`] = ` className="light storyWrapper-0-1-2" >   diff --git a/src/components/IconButton/IconButton.stories.tsx b/src/components/IconButton/IconButton.stories.tsx new file mode 100644 index 00000000..c54ee3b1 --- /dev/null +++ b/src/components/IconButton/IconButton.stories.tsx @@ -0,0 +1,23 @@ +import { action } from '@storybook/addon-actions' +import React from 'react' +import { IconButton, IconButtonProps, IconSizes } from './index' +import { Meta, Story } from '@storybook/react/types-6-0' + +export default { + argTypes: { + icon: { control: { disable: true } }, + onClick: { defaultValue: action('onClick') }, + size: { + control: { + options: [IconSizes.xs, IconSizes.sm, IconSizes.lg], + type: 'select' + } + } + }, + component: IconButton, + title: 'IconButton' +} as Meta + +const Template: Story = args => + +export const Default = Template.bind({}) diff --git a/src/components/IconButton/IconButton.test.tsx b/src/components/IconButton/IconButton.test.tsx new file mode 100644 index 00000000..c3b132c9 --- /dev/null +++ b/src/components/IconButton/IconButton.test.tsx @@ -0,0 +1,53 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import React from 'react' +import { IconButton, IconSizes } from './index' +import { mount, ReactWrapper } from 'enzyme' + +let wrapper: ReactWrapper +let mockOnClick: jest.Mock + +beforeEach(() => { + mockOnClick = jest.fn() + wrapper = mount() +}) + +afterEach(() => { + wrapper.unmount() +}) + +describe('IconButton', () => { + it('renders', () => { + const iconBtn = wrapper.find(IconButton) + + expect(iconBtn).toHaveLength(1) + }) + + it('passes onClick props to FontAwesomeIcon if one is provided', () => { + wrapper = mount() + + expect(wrapper.find(FontAwesomeIcon).props().onClick).toBeTruthy() + }) + + it('runs onClick function when IconButton is clicked', () => { + wrapper = mount() + + const fontAwesomeIcon = wrapper.find(FontAwesomeIcon) + + fontAwesomeIcon.simulate('click') + expect(mockOnClick).toHaveBeenCalledTimes(1) + }) + + it('inherits fontSize if size prop is not provided', () => { + const styles = window.getComputedStyle(wrapper.find('svg').getDOMNode()) + + expect(styles.fontSize).toBe('inherit') + }) + + it('renders IconButton with fontSize equal to size if size prop is provided', () => { + wrapper = mount() + + const styles = window.getComputedStyle(wrapper.find('svg').getDOMNode()) + + expect(styles.fontSize).toBe(`${IconSizes.xs}px`) + }) +}) diff --git a/src/components/IconButton/index.tsx b/src/components/IconButton/index.tsx index b6496329..225c73f9 100644 --- a/src/components/IconButton/index.tsx +++ b/src/components/IconButton/index.tsx @@ -1,11 +1,14 @@ import cn from 'classnames' import { createUseStyles } from 'react-jss' import { faTimes } from '@fortawesome/free-solid-svg-icons' -import { generateThemedIconBtnStyles } from './utils' import { FontAwesomeIcon, FontAwesomeIconProps } from '@fortawesome/react-fontawesome' +import { + generateThemedHasBorderStyles, + generateThemedIconBtnStyles +} from './utils' import React, { FC, SyntheticEvent } from 'react' import { styleguide, ThemeType } from 'components/assets/styles' @@ -15,7 +18,7 @@ const { light, dark } = ThemeType const useStyles = createUseStyles({ hasBorder: { ...flexCenter, - border: '1px solid', + ...generateThemedHasBorderStyles(light), borderRadius, height: spacing.xl, width: spacing.xl @@ -32,6 +35,7 @@ const useStyles = createUseStyles({ // eslint-disable-next-line sort-keys '@global': { [`.${dark}`]: { + '& $hasBorder': generateThemedHasBorderStyles(dark), '& $iconButton': generateThemedIconBtnStyles(dark) } } @@ -43,7 +47,7 @@ export enum IconSizes { 'lg' = font.h2.fontSize } -interface Props { +export interface IconButtonProps { classes?: string[] hasBorder?: boolean icon?: FontAwesomeIconProps['icon'] @@ -51,14 +55,13 @@ interface Props { size?: number } -/* NOTE: This will be moved to web-components eventually */ -export const IconButton: FC = ({ +export const IconButton: FC = ({ classes = [], hasBorder = false, icon = faTimes, onClick, size -}: Props) => { +}: IconButtonProps) => { const componentClasses = useStyles({ size }) const iconBtnClasses = cn( @@ -69,7 +72,7 @@ export const IconButton: FC = ({ classes ) - const optionalProps: Pick = {} + const optionalProps: Pick = {} if (onClick) { optionalProps.onClick = onClick diff --git a/src/components/IconButton/utils.ts b/src/components/IconButton/utils.ts index b11b8239..46d23a52 100644 --- a/src/components/IconButton/utils.ts +++ b/src/components/IconButton/utils.ts @@ -17,18 +17,29 @@ const iconBtnPalette = { export const generateThemedIconBtnStyles = (themeType: ThemeType) => { const { - base: { borderColor, color }, + base: { color }, hover } = themedStyles[themeType] - const { hoverBorderColor } = iconBtnPalette[themeType] - return { '&:hover': { - borderColor: hoverBorderColor, color: hover.color }, - borderColor, color } } + +export const generateThemedHasBorderStyles = (themeType: ThemeType) => { + const { + base: { borderColor } + } = themedStyles[themeType] + + const { hoverBorderColor } = iconBtnPalette[themeType] + + return { + '&:hover': { + border: `1px solid ${hoverBorderColor}` + }, + border: `1px solid ${borderColor}` + } +}