2017-04-27 31 views
2

我試圖測試我的組件,每次我的測試失敗,我都無法弄清楚問題出在哪裏。反應,酶:無法讀取未定義的屬性「歷史記錄」

Login.test.js:

import { Meteor } from 'meteor/meteor'; 
import React from 'react'; 
import expect from 'expect'; 
import { mount } from 'enzyme'; 

import { Login } from './Login'; 

if (Meteor.isClient) { 
    describe("Login", function() { 
     it("should show error messages", function() { 
      const error = "This is not working"; 
      const wrapper = mount(<Login loginWithPassword={() => {}}/>); 

      wrapper.setState({ error: error }); 

      expect(wrapper.find("p").text()).toBe(error); 

      wrapper.setState({ error: "" }); 
      expect(wrapper.find("p").length).toBe(0); 
     }); 

     it("should called loginWithPassword with the form data", function() { 
      const email = "[email protected]"; 
      const password = "password1234"; 
      const spy = expect.createSpy(); 
      const wrapper = mount(<Login loginWithPassword={spy}/>); 

      wrapper.ref("email").node.value = email; 
      wrapper.ref("password").node.value = password; 
      wrapper.find("form").simulate("submit"); 

      expect(spy.calls[0].arguments[0]).toEqual({email: email}); 
      expect(spy.calls[0].arguments[1]).toEqual(password); 
     }); 

     it("should set loginWithPassword callback errors", function() { 

     }); 
    }) 
} 

Login.js:

import React from "react"; 
import { Link, Redirect } from "react-router-dom"; 
import { Meteor } from "meteor/meteor"; 
import { createContainer } from 'meteor/react-meteor-data'; 

export class Login extends React.Component { 
    constructor(props) { 
    super(props); 

    this.onSubmit = this.onSubmit.bind(this); 

    this.state = { 
     error: "" 
    }; 
    } 
    onSubmit(e) { 
    e.preventDefault(); 
    let email = this.refs.email.value.trim(); 
    let password = this.refs.password.value.trim(); 

    this.props.loginWithPassword({ email }, password, err => { 
     if (err) { 
     this.setState({ error: "Unable to login. Check your credentials." }); 
     } else { 
     this.setState({ error: "" }); 
     } 
    }); 
    } 
    render() { 
    return (
     <div className="boxed-view"> 
     <div className="boxed-view__box"> 
      <h1>Login</h1> 

      {this.state.error 
      ? <p className="boxed-view__box__error">{this.state.error}</p> 
      : undefined} 

      <form 
      onSubmit={this.onSubmit} 
      noValidate 
      className="boxed-view__form" 
      > 
      <input type="email" ref="email" name="email" placeholder="Email" /> 
      <input 
       type="password" 
       ref="password" 
       name="password" 
       placeholder="Password" 
      /> 
      <button className="button">Login</button> 
      </form> 
      <Link to="/signup">Not registered yet?</Link> 
     </div> 
     </div> 
    ); 
    } 
} 

Login.PropTypes = { 
    loginWithPassword: React.PropTypes.func.isRequired 
}; 

export default createContainer(() => { 
    return { 
    loginWithPassword: Meteor.loginWithPassword 
    } 
}, Login); 

摩卡客戶端和服務器測試:

Screenshot Chrome Mocha tests

謝謝你幫我出去!

回答

3

這是一個恥辱,沒有人回答這個問題呢。

希望你已經意識到這個問題是React路由器的組件渲染超出了路由器組件的結果。

您需要將組件包裝到組件中以解決此問題,然後在您的包裝器變量將發生更改時進行相應的更改,並且組件將不再是根組件,這將改變對包裝器變量的操作方式。

2

你必須與你的代碼一對夫婦的問題,請使用以下&讓我知道如果你還有任何問題

原代碼

[問題

import { Meteor } from 'meteor/meteor'; import React from 'react'; import expect from 'expect'; import { configure } from 'enzyme'; import { mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-15'; configure({ adapter: new Adapter() }); import { Login } from './Login'; //notice we are importing the "raw" named-export Login not the containerized default one. if (Meteor.isClient) { describe('Login',() => { it('Should show error messages',() => { const error = 'This is not working'; const wrapper = mount(<Login loginWithPassword={() => { }} />); wrapper.setState({ error: error }); expect(wrapper.find('p').text()).toBe(error); wrapper.setState({error: ''}); expect(wrapper.find('p').length).toBe(0); }); it('should call loginWithPassword with the form data',() => { const email = '[email protected]'; const password = 'password123'; const spy = expect.createSpy(); const wrapper = mount (<Login loginWithPassword={spy}/>); //notice the change, node ==> instance() due to deprecation of use of private properties by enzyme. wrapper.find('input[name="email"]').instance().value = email; wrapper.find('input[name="password"]').instance().value = password; wrapper.find('form').simulate('submit'); expect(spy.calls[0].arguments[0]).toEqual({email:email}); expect(spy.calls[0].arguments[1]).toBe(password); //above we used toBe (instead of toEqual) because second argument is a variable not object }); }); } 

摘要1]使用node引用DOM對象,如下面的代碼片段所示,已被酶廢棄 wrapper.ref("email").node.value = email;

此外,React不贊成使用字符串參考。您應該使用回調來避免控制檯警告。

因此,正確的方法是使用instance()find()按以下代碼段 wrapper.find('input[name="email"]').instance().value = email;

[2]聲明在原始代碼中定義的電子郵件作爲對象和密碼作爲變量(下面片斷) this.props.loginWithPassword({ email }, password, err => {

因此,我們應該從expect挑選合適的斷言的方法來處理每一種情況下爲每下面片斷

expect(spy.calls[0].arguments[0]).toEqual({email:email}); 
expect(spy.calls[0].arguments[1]).toBe(password); 
+0

歡迎來到Stack Oveflow!可以很好地解釋你做出了哪些改變,使其更易於理解。 –

+0

謝謝@FranciscodelaPeña,我已經通過代碼中的註釋突出顯示了所有更改。將在一分鐘內將它們分成評論。 – helcode

+0

我修改了我的答案以反映原始代碼中的問題。享受... – helcode

相關問題