2

我写了一个 React 组件Button

import PropTypes from 'prop-types'
import Radium from 'radium'
import React from 'react'

import { Icon } from 'components'
import { COLOURS, GLOBAL_STYLES, ICONS, MEASUREMENTS } from 'app-constants'

@Radium
export default class Button extends React.Component {
  static propTypes = {
    children: PropTypes.string,
    dark: PropTypes.bool,
    icon: PropTypes.oneOf(Object.values(ICONS)).isRequired,
    style: PropTypes.object,
  }

  render() {
    const { children, dark, icon, style } = this.props
    let mergedStyles = Object.assign({}, styles.base, style)

    if (!children)
      mergedStyles.icon.left = 0

    if (dark)
      mergedStyles = Object.assign(mergedStyles, styles.dark)

    return (
      <button
        className="btn btn-secondary"
        style={mergedStyles}
        tabIndex={-1}>
        <Icon name={icon} style={mergedStyles.icon} />
        {children &&
          <span style={mergedStyles.text}>{children}</span>
        }
      </button>
    )
  }
}

export const styles = {
  base: {
    backgroundColor: COLOURS.WHITE,
    border: `1px solid ${COLOURS.BORDER_LIGHT}`,
    borderRadius: GLOBAL_STYLES.BORDER_RADIUS,
    cursor: 'pointer',
    padding: GLOBAL_STYLES.BUTTON_PADDING,

    ':focus': {
      outline: 'none',
    },

    ':hover': {
      boxShadow: GLOBAL_STYLES.BOX_SHADOW,
    },

    icon: {
      fontSize: GLOBAL_STYLES.ICON_SIZE_TINY,
      left: '-3px',
      verticalAlign: 'middle',
    },

    text: {
      fontSize: GLOBAL_STYLES.FONT_SIZE_TINY,
      fontWeight: GLOBAL_STYLES.FONT_2_WEIGHT_MEDIUM,
      marginLeft: `${MEASUREMENTS.BUTTON_PADDING.HORIZONTAL}px`,
      verticalAlign: 'middle',
    },
  },

  dark: {
    backgroundColor: COLOURS.PRIMARY_3,
    border: `1px solid ${COLOURS.PRIMARY_2}`,
    color: COLOURS.WHITE,

    ':hover': {
      boxShadow: GLOBAL_STYLES.BOX_SHADOW_DARK,
    },
  },
}

我还Button用 Jest 和 Enzyme 编写了一个测试,它验证它的dark样式是否在其darkprop 设置为时应用true

import { ICONS } from 'app-constants'
import Button, { styles } from 'components/Button'

describe("<Button>", () => {
  let props
  let mountedComponent
  const getComponent = () => {
    if (!mountedComponent)
      mountedComponent = shallow(
        <Button {...props} />
      )
    return mountedComponent
  }

  beforeEach(() => {
    mountedComponent = undefined
    props = {
      children: undefined,
      dark: undefined,
      icon: ICONS.VIBE,
      style: undefined,
    }
  })

  describe("when `dark` is `true`", () => {
    beforeEach(() => {
      props.dark = true
    })

    it("applies the component's `dark` styles", () => {
      const componentStyles = getComponent().props().style
      expect(componentStyles).toEqual(expect.objectContaining(styles.dark))
    })
  })
})

如您所见,我通过检查 的属性styles.dark是否在 renderButton的属性中来做到这一点style。如果是,则表示样式已成功应用。

问题是,styles.darkcomponentStyles匹配:

的输出console.log(styles.dark)

ObjectContaining{  
   ":hover": {  
      "boxShadow": "0px 0px 0px 2px rgba(0,0,0,0.2)"
   },
   "backgroundColor": [Object],
   "border": "1px solid rgb(47, 52, 63)",
   "color": [Object]
}

的输出console.log(componentStyles)

{  
    "backgroundColor": "rgb(31, 34, 40)",
    "border": "1px solid rgb(47, 52, 63)",
    "borderRadius": "4px",
    "color": "rgb(255, 255, 255)",
    "cursor": "pointer",
    "padding": "3px 5px 3px 5px"
}

我注意到这里有几个问题:

  • styles.dark图书馆有几个Color() [Object]s 。color它们没有将它们的rgb()值作为字符串输出,但具有相同的属性componentStyles,因此导致不匹配。
  • componentStyles剥离了 Radium 的交互样式,例如:focus:hover(我假设 Radium 在由 Enzyme 的shallow()函数触发的渲染期间执行此操作)。这会导致与 不匹配styles.dark,而不会剥离这些属性。

结果,我不确定如何测试它。我想不出任何替代解决方案来验证styles.dark已应用。我认为styles.dark在测试期间执行以下操作将是一个解决方案:

  • 递归地使所有Color() [Object]s 进行处理,以便将它们的rgb()值作为字符串输出。
  • 递归删除所有交互式 Radium 样式(如:focus:hover

这样做会导致styles.dark等于 的值componentStyles,从而通过测试。我只是不知道该怎么做。

4

1 回答 1

0

几天后,我以崭新的眼光回到这个问题上并想到了一个解决方案:

describe("<Button>", () => {
  let props
  let mountedComponent
  let defaultComponent
  const getComponent = () => {
    if (!mountedComponent)
      mountedComponent = shallow(
        <Button {...props} />
      )
    return mountedComponent
  }

  beforeEach(() => {
    props = {
      children: undefined,
      dark: undefined,
      icon: ICONS.VIBE,
      style: undefined,
    }
    defaultComponent = getComponent()
    mountedComponent = undefined
  })

  describe("when `dark` is `true`", () => {
    beforeEach(() => {
      props.dark = true
    })

    it("applies the component's `dark` styles", () => {
      const darkStyles = getComponent().props().style
      expect(defaultComponent.props().style).not.toEqual(darkStyles)
    })
  })
})

与其断言渲染组件的styleprop 包含(这是脆弱的),它只是检查当prop 设置为styles.dark时样式是否发生了变化。darktrue

于 2017-11-08T03:40:28.220 回答