如何验证Jest和Enzyme中的React道具?

时间:2018-05-16 07:27:01

标签: javascript reactjs unit-testing jestjs enzyme

所以我试图了解React中的测试,我有这个:Button.jsButton.test.js

这个问题与下面的代码一起评论:

// Button.js
import React from 'react';
import { string, bool, func } from 'prop-types';
import { StyledButton } from './styled'

const Button = ({
  size,
  text,
}) => (
  <StyledButton
    size={size}
    // the test will alway fail with result:
    // Expected value to be: "Join us"
    // Received: undefined
    // Unless I add add this line below
    text={text}
  >
    {text} // but the text props is here. That is my current practice of passing the props to the children, am I missing anything?
  </StyledButton>
);

Button.propTypes = {
  size: string,
  text: string,
};

Button.defaultProps = {
  size: '',
  text: '',
};

export default Button;

// Button.test.js
import React from 'react';
import { shallow } from 'enzyme';

import Button from '../../components/Button/Button';

describe('Component: Button', () => {
  const minProps = {
    text: '',
    size: '',
  };  

  it('renders a button in size of "small" with text in it', () => {
    const wrapper = shallow(
      <Button {...minProps} size="small" text="Join us" />
    );

    expect(wrapper.prop('size')).toBe('small');
    expect(wrapper.prop('text')).toBe('Join us');
  });
});


// StyledButton
import Button from 'antd/lib/button';

const StyledButton = styled(Button)`
  &.ant-btn {
    padding: 0 24px;

    ${({ size }) => {
      if (size === 'small') {
        return css`
          font-size: 14px;
          line-height: 32px;
        `;
      }
      return null;
    }};
`;

export { StyledButton };

有没有人知道为什么测试不会通过,除非我将道具传递给StyledButton

2 个答案:

答案 0 :(得分:5)

在声明道具之前,您需要在 1 0 0 0 1 0 0 0 1 组件中找到StyledButton

Button

答案 1 :(得分:0)

我意识到这篇文章有点陈旧,但是有一种更好的方法来测试预期的道具类型及其值。

这就是我所拥有的,它工作正常:

Accordion.js

import React from "react";
import PropTypes from "prop-types";
import { Icon } from "../Icon";
import styled from "styled-components";

const AccordionContainer = styled.div`
  display: flex;
  flex-direction: column;
  flex: 1;
  justify-content: ${props => props.justifyContent};
  background-color: ${props => props.theme.color[props.color]};
  ${props => props.theme.fontSize(14)};
`;

const ChildrenContainer = styled.div`
  display: flex;
  flex-direction: column;
`;

const LabelWrapper = styled.div`
  padding: 10px;
`;

/**
 * Accordion is nearly a Higher Order Component (HOC) in the fact that it encapsulates an Icon and when that
 * Icon is clicked an onClick callback provided should toggle the closed state.
 */
export class Accordion extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      closed: props.closed
    };
  }

  render() {
    let {
      props: {
        children,
        hasIcon,
        iconColor,
        iconFlexDirection,
        iconExpand,
        iconName,
        iconSize,
        label,
        color,
        justifyContent
      },
      state: { closed }
    } = this;

    return (
      <AccordionContainer color={color} justifyContent={justifyContent}>
        <div onClick={() => this.setState({ closed: !closed })}>
          {hasIcon ? (
            <>
              <LabelWrapper>
                <Icon
                  fontSize={iconSize}
                  name={iconName}
                  color={iconColor}
                  flexDirection={iconFlexDirection}
                  expand={iconExpand}
                />
              </LabelWrapper>
              {!closed && <ChildrenContainer>{children}</ChildrenContainer>}
            </>
          ) : (
            <>
              <LabelWrapper>
                <div>{label}</div>
              </LabelWrapper>
              {!closed && <ChildrenContainer>{children}</ChildrenContainer>}
            </>
          )}
        </div>
      </AccordionContainer>
    );
  }
}

Accordion.propTypes = {
  color: PropTypes.string,
  closed: PropTypes.bool,
  justifyContent: PropTypes.string,
  hasIcon: PropTypes.bool,
  iconName: PropTypes.string,
  iconColor: PropTypes.string,
  iconExpand: PropTypes.bool,
  iconSize: PropTypes.number,
  label: PropTypes.string
};

Accordion.defaultProps = {
  closed: true,
  hasIcon: false,
  iconExpand: false,
  justifyContent: "flex-start"
};

Accordion.spec.js

import React from "react";
import { shallow, mount, render } from "enzyme";
import styled, { ThemeProvider } from "styled-components";
import theme from "../../styles/theme";
import { Accordion } from "./Accordion";
import sinon from "sinon";

describe("Accordion", () => {

  const AccordionJSX = (
    <ThemeProvider theme={theme}>
      <Accordion
        iconName="home"
        iconColor="#777"
        iconSize={14}
        hasIcon={true}
      >
        HELLO ACCORDION
      </Accordion>
    </ThemeProvider>
  );

  it("Should render without throwing an error", () => {
    expect(shallow(
      AccordionJSX
    )).not.toBeNull();
  });

  const AccordionComponent = mount(AccordionJSX);

  it("Should have a styled-components theme", () => {
    expect(AccordionComponent.props().theme).not.toBeNull();
  });

  it('check props passed in', () => {
    console.log(AccordionComponent.props().children);
    expect(AccordionComponent.props().children.props).toEqual({
      iconName: 'home',
      iconColor: '#777',
      iconSize: 14,
      hasIcon: true,
      children: 'HELLO ACCORDION',
      closed: true,
      iconExpand: false,
      justifyContent: 'flex-start'
    });
  });

  it('check state after opened', () => {
    expect(AccordionComponent.props().theme).not.toBeNull();
  })


});