Jest快照测试

时间:2016-09-12 14:58:20

标签: jestjs

我对我的一个组件使用了jest快照测试,生成的快照文件很大(199Kb和4310行)。当快照测试失败时,所有快照文件都会打印到控制台(渲染时间为3-4秒),它给了我“你做错了”的感觉。

所以我的问题是:我是否正确使用快照测试?

组件代码:

import _ = require('lodash');
import React = require('react');
import {TranslatedMessage} from 'translator';

import {UserProfile} from './user-profile';
import {ICustomerProfile} from '../customer/customer-profile';

interface IUserProfile {
    firstName: string;
    lastName: string;
    id: string;
    customer: ICustomerProfile;
    job: string;
    email: string;
    contacts: string;
    phoneNumber: string;
}

interface IUserProfileProps {
    contact: IUserProfile;
}

interface IUserProfileState {}

export class UserProfile extends React.Component<IUserProfileProps, IUserProfileState> {
    constructor(props: IUserProfileProps) {
        super(props);
    }

    public render(): JSX.Element {
        return (
            <div className="ext-admin-user-infos-details">
                <div className="ext-admin-user-infos-details-content">
                    <div className="row">
                        <div className="col-md-12">
                            <h3>{this.props.contact.firstName } {this.props.contact.lastName}</h3>
                            <p className="ext-subtitle">
                                <span className="ext-minor">{this.props.contact.id}</span>
                            </p>
                        </div>
                    </div>
                    <div className="row">
                        <div className="col-md-8">
                            <div className="ext-admin-user-infos-card">
                                <h6>
                                    <TranslatedMessage messageKey="common.labels.customer" />
                                </h6>
                                <ul>
                                    <li>{this.props.contact.customer.name}</li>
                                </ul>
                            </div>
                            <div className="ext-admin-user-infos-card">
                                <h6>
                                    <TranslatedMessage messageKey="admin.contact.infos.job" />
                                </h6>
                                <ul>
                                    <li>{this.props.contact.job}</li>
                                </ul>
                            </div>
                            <div className="ext-admin-user-infos-card">
                                <h6>
                                    <TranslatedMessage messageKey="admin.contact.infos.email" />
                                </h6>
                                <ul>
                                    <li>{this.props.contact.email}</li>
                                </ul>
                            </div>
                        </div>
                        <div className="col-md-4">
                            <div className="ext-admin-user-infos-card">
                                <h6>
                                    <TranslatedMessage messageKey="common.labels.followed" />
                                </h6>
                                <ol>
                                    {this.renderContacts(this.props.contact.contacts)}
                                </ol>
                            </div>
                            <div className="ext-admin-user-infos-card">
                                <h6>
                                    <TranslatedMessage messageKey="common.labels.phone" />
                                </h6>
                                <ul>
                                    <li>{this.props.contact.phoneNumber}</li>
                                </ul>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }

    protected renderContacts(contacts: IUserProfile[]): JSX.Element[] {
        let contacts= [];
        if (sales) {
            _.map(sales, function(contact: IUserProfile): void {
                salesContact.push(
                    <li>
                        { contact.firstName}
                        { contact.lastName}
                    </li>
                );
            });
        }

        return contacts;
    }
}

和测试文件

jest.mock('TranslatedMessage');

import React = require('react');
import {render} from 'enzyme';

import {user} from '../../../tests/tools';

import {UserProfile} from '../../../app/components/user-profile/user-profile';

describe('UserProfile', () => {
    it('should match the snapshot', () => {
        const tree = render(<UserProfile user={user} />);

        expect(tree).toMatchSnapshot();
    });
});

3 个答案:

答案 0 :(得分:1)

相信那种感觉。

您正确使用快照测试,但您已经达到了需要将大型组件分解为更小组件的程度。将它们分开将允许您模拟子组件,这将减少您的快照大小(每个快照,而不是聚合)并使您的差异更容易查看和修复。

例如,而不是:

export class UserProfile extends Component {
  public render() {
    return (
      <div className="ext-admin-user-infos-details">
        <div className="ext-admin-user-infos-details-content">
          <div className="row">
            <div className="col-md-12">
              <h3>{this.props.contact.firstName } {this.props.contact.lastName}</h3>
              <p className="ext-subtitle">
                <span className="ext-minor">{this.props.contact.id}</span>
              </p>
            </div>
          </div>
          // ...
        </div>
      </div>
    )
  }
}

你这样做:

export class UserProfile extends Component {
  public render() {
    return (
      <div className="ext-admin-user-infos-details">
        <div className="ext-admin-user-infos-details-content">
          <div className="row">
            <div className="col-md-12">
              <UserProfileName
                first={this.props.contact.firstName}
                last={this.props.contact.firstName}
                contactId={this.props.contact.id}
              />
            </div>
          </div>
          // ...
        </div>
      </div>
    )
  }
}

export class UserProfileName extends Component {
  public render() {
    return (
      <div>
        <h3>{this.props.contact.first} {this.props.contact.last}</h3>
        <p className="ext-subtitle">
          <span className="ext-minor">{this.props.contact.contactId}</span>
        </p>
      </div>
    );
  }
}

请注意,我已将用户名称的逻辑移至另一个组件。这是更新的测试,模拟子组件:

jest.mock('TranslatedMessage');
jest.mock('UserProfileName'); // Mock this and other children

import React = require('react');
import {render} from 'enzyme';

import {user} from '../../../tests/tools';

import {UserProfile} from '../../../app/components/user-profile/user-profile';

describe('UserProfile', () => {
  it('should match the snapshot', () => {
    const tree = render(<UserProfile user={user} />);

    expect(tree).toMatchSnapshot();
  });
});

此快照将比一个组件中的快照小得多。当然,您也可以对子组件进行测试:

import React = require('react');
import {render} from 'enzyme';

import {UserProfileName} from '../../../app/components/user-profile/user-profile-name';

describe('UserProfileName', () => {
  it('should match the snapshot with all props', () => {
    const tree = render(<UserProfile first="Test" last="Testerson" contactId="test-id" />);

    expect(tree).toMatchSnapshot();
  });

  it('should render without a first name', () => {
    const tree = render(<UserProfile last="Testerson" contactId="test-id" />);

    expect(tree).toMatchSnapshot();
  });

  it('should render without a last name', () => {
    const tree = render(<UserProfile first="Test" contactId="test-id" />);

    expect(tree).toMatchSnapshot();
  });
});

请注意,在这些测试中,我在最后添加了两个案例。当你像这样打破组件时,它更容易理解和测试子组件的特定用例!

最后,这种方法的另一个好处是,现在您有一个可重用的组件,它知道如何呈现用户名!您可以对此进行概括,并在需要时将其填入。

答案 1 :(得分:0)

您正在进行正确的测试,但是您应该将您的组件分成多个较小的组件,因为它目前太大了。 在使用enzyme时,您might not want always to use render for testing,因为它使输出变得如此之大。例如,在快照测试纯组件时,您应该使用shallow

我们正在使用react-test-rendered for snapshot testing,它比酶更轻量。

答案 2 :(得分:-1)

如果您使用的是<!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script src="Dating.js"></script> </head> <body> <div id="startDate">Start Date:</div> <div id="seconds">Seconds:</div> <div id="interval">Interval:</div> <div id="finalDate">Final Date:</div> <div id="finalSeconds">Final Seconds:</div> <div id="timeBetween">Seconds Between:</div> <div id="reply">Reply:</div> <div id="validated"></div> </body> </html>,则应该使用浅渲染。

enzyme

您也可以使用import { shallow } from 'enzyme'; const component = shallow(<UserProfile user={user} />); expect(component.text()).toMatchSnapshot();

react-test-renderer