运行测试套件时,React单元测试不会失败

时间:2019-07-20 12:02:10

标签: reactjs jestjs

我为React组件创建了一个单元测试。如果没有提供电子邮件地址,则第一个测试应该通过,并且我们提醒用户没有提供。这作为单独的测试以及整个套件运行都通过。如果提供了电子邮件但没有提供密码,则第二项测试应该通过,并通过一条消息提示用户需要提供密码来提醒用户。

我看到的问题是,如果我告诉密码单元测试来检查警报是否未提供电子邮件。在这种情况下,如果我单独运行测试,它将失败,表示需要按预期提供电子邮件。但是,如果我将它作为套件运行,并且首先运行了电子邮件检查,则密码检查单独运行了,如果不应该提供密码,则密码检查通过,因为提供了电子邮件地址并且警报消息应该没有密码。如果我先使用密码检查来运行测试套件,然后将电子邮件检查与电子邮件检查分开,则密码检查会按我的预期失败。根据测试的执行顺序,我会得到不同的结果。

我已经尝试通过命令行运行选项--env = jsdom --watchAll = false --coverage,使用package.json中的npm配置,并使用webstorm运行配置,但是它们都产生相同的结果结果。

单元测试:

import React from 'react';
import { configure, shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16.3';
import SignInForm from '../components/SignInForm';
//import { mount, shallow, render } from 'enzyme';

configure({ adapter: new Adapter() });

test('Errors when no email is input', () => {
  jest.spyOn(window, 'alert').mockImplementation(() => {});
  const wrapper = shallow(<SignInForm />);
  wrapper.find('input#email_address').simulate('change', {target: { value: '' }});
  wrapper.find('button').simulate('click');
  expect(window.alert).toHaveBeenCalledWith('Email address is required to sign in');
});

test('Errors when no password is input', () => {
  jest.spyOn(window, 'alert').mockImplementation(() => {});
  const wrapper = shallow(<SignInForm />);
  wrapper.find('input#email_address').simulate('change', {target: { value: "Tst@test.com" }});
  wrapper.find('button').simulate('click');
  expect(window.alert).toHaveBeenCalledWith('Email address is required to sign in');

});

登录表单Web组件:

import React, {Component} from 'react';

export default class SignInForm extends Component {
    constructor(props) {
    super(props);
    this.state = {email_address: '', password: ''};
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
}

handleChange(field, event) {
    this.setState({[field]: event.target.value});
}

handleSubmit(event) {
    if (event) {
        event.preventDefault();
    }
    const {email_address, password} = this.state;
    if (email_address === '') {
        alert("Email address is required to sign in");
        return;
    } else if (password === '') {
        alert("Password is required to sign in");
        return;
    }
}

render() {
    return (
        <form id="signInForm">
            <div className="form-group">
                <label htmlFor="email_address">Email address</label>
                <input type="email" className="form-control" name="email_address" id="email_address"
                    aria-describedby="emailHelp" placeholder="Enter email" onChange={this.handleChange.bind(null, 'email_address')} />
            </div>
            <div className="form-group">
                <label htmlFor="password">Password</label>
                <input type="password" className="form-control" id="password" name="password" placeholder="Password" onChange={this.handleChange.bind(null, 'password')} />
            </div>
            <button type="submit" className="btn btn-primary" onClick={this.handleSubmit.bind(this)}>Submit</button>
      </form >
    );
}

}

1 个答案:

答案 0 :(得分:0)

这是因为开玩笑在内部跟踪正在发生的一切。如果它运行一次(从您的第一个测试开始),它将“记住”第二个测试运行的时间。我敢打赌,如果您更改这两个测试的顺序,它们将通过。但这不是真正的解决方案。

运行每个测试之前,您必须先jest.clearAllMocks()。您应该将所有测试划分为一个describe块,并在其中运行beforeEach,以便可以在每次测试之前自动运行jest.clearAllMocks()

describe('unit tests', () => ({
  beforeEach(() => {
    jest.clearAllMocks()
  })
  // test('Errors when no email is input', () => { unit tests here
})