2016-02-01 29 views
37

Tôi đang sử dụng Mocha, Chai, Karma, Sinon, Webpack cho các bài kiểm tra Đơn vị.Làm thế nào để kiểm tra đơn vị React-Redux kết nối các thành phần?

Tôi đã nhấp vào liên kết này để định cấu hình môi trường thử nghiệm của mình cho Mã phản hồi-Redux.

https://medium.com/@scbarrus/how-to-get-test-coverage-on-react-with-karma-babel-and-webpack-c9273d805063#.7kcckz73r

tôi thành công có thể kiểm tra hành động, giảm thiểu tôi mã javascript, nhưng khi nói đến việc kiểm tra các thành phần của tôi nó luôn ném một số lỗi.

import React from 'react'; 
import TestUtils from 'react/lib/ReactTestUtils'; //I like using the Test Utils, but you can just use the DOM API instead. 
import chai from 'chai'; 
// import sinon from 'sinon'; 
import spies from 'chai-spies'; 

chai.use(spies); 

let should = chai.should() 
    , expect = chai.expect; 

import { PhoneVerification } from '../PhoneVerification'; 

let fakeStore = { 
     'isFetching': false, 
     'usernameSettings': { 
     'errors': {}, 
     'username': 'sahil', 
     'isEditable': false 
     }, 
     'emailSettings': { 
     'email': '[email protected]', 
     'isEmailVerified': false, 
     'isEditable': false 
     }, 
     'passwordSettings': { 
     'errors': {}, 
     'password': 'showsomestarz', 
     'isEditable': false 
     }, 
     'phoneSettings': { 
     'isEditable': false, 
     'errors': {}, 
     'otp': null, 
     'isOTPSent': false, 
     'isOTPReSent': false, 
     'isShowMissedCallNumber': false, 
     'isShowMissedCallVerificationLink': false, 
     'missedCallNumber': null, 
     'timeLeftToVerify': null, 
     '_verifiedNumber': null, 
     'timers': [], 
     'phone': '', 
     'isPhoneVerified': false 
     } 
} 

function setup() { 
    console.log(PhoneVerification); 
    // PhoneVerification.componentDidMount = chai.spy(); 
    let output = TestUtils.renderIntoDocument(<PhoneVerification {...fakeStore}/>); 
    return { 
     output 
    } 
} 

describe('PhoneVerificationComponent',() => { 
    it('should render properly', (done) => { 
     const { output } = setup(); 
     expect(PhoneVerification.prototype.componentDidMount).to.have.been.called; 
     done(); 
    }) 
}); 

Lỗi sau đây đi kèm với mã trên.

FAILED TESTS: 
    PhoneVerificationComponent 
    ✖ should render properly 
     Chrome 48.0.2564 (Mac OS X 10.11.3) 
    Error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. 

Đã cố gắng chuyển từ gián điệp sin sang gián điệp.

Tôi nên kiểm tra các thành phần kết nối phản ứng-Redux của tôi như thế nào (Các thành phần thông minh)?

+0

Bạn đang xuất thành phần của mình như thế nào? Bạn đang sử dụng xuất có tên hoặc chỉ mặc định xuất? 'Import {PhoneVerification} from ' ../ PhoneVerification '; 'là dòng vi phạm của bạn, khi bạn thực hiện việc này, bạn sẽ không nhận được thông báo lỗi tương tự nếu bạn không thực hiện xuất tên được đặt tên –

+0

Tôi đang sử dụng Xuất tên đã đặt tên – Ayushya

+0

Tôi cũng có cài đặt tương tự và nhận được thông báo lỗi tương tự – FujiRoyale

Trả lời

35

Cách tốt hơn để thực hiện việc này là xuất cả thành phần thuần túy của bạn và thành phần được bao bọc trong kết nối. Các tên xuất khẩu sẽ là thành phần, mặc định là thành phần bọc:

Bằng cách này bạn có thể nhập bình thường trong ứng dụng của bạn, nhưng khi nói đến kiểm tra bạn có thể nhập tên xuất khẩu bằng cách sử dụng import { Sample } from 'component'.

+0

Cảm ơn một tấn, nó hoạt động! – Ayushya

+0

Bạn có thể chấp nhận bài đăng của tôi làm câu trả lời không? –

+0

giải pháp tuyệt vời. cảm ơn! –

1

Thử tạo 2 tệp, một tệp có chính thành phần, không biết về bất kỳ cửa hàng nào hoặc bất kỳ thứ gì (PhoneVerification-component.js). Rồi một giây (PhoneVerification.js), mà bạn sẽ sử dụng trong ứng dụng của bạn và đó chỉ trả về thành phần đầu tiên đăng ký để lưu trữ thông qua connect chức năng, một cái gì đó giống như

import PhoneVerificationComponent from './PhoneVerification-component.js' 
import {connect} from 'react-redux' 
... 
export default connect(mapStateToProps, mapDispatchToProps)(PhoneVerificationComponent) 

Sau đó, bạn có thể kiểm tra "câm" của bạn thành phần bằng cách yêu cầu PhoneVerification-component.js trong thử nghiệm của bạn và cung cấp nó với đạo cụ giả lập cần thiết. Không có điểm thử nghiệm nào đã được kiểm tra (kết nối trang trí, mapStateToProps, mapDispatchToProps, v.v.)

+0

Cảm ơn giải pháp – Ayushya

+0

Hey @ george.cz, bạn mô tả 'mapStateToProps' là" đã được thử nghiệm ". thử nghiệm 'mapStateToProps' và' mapDispatchToProps'? Bạn có xuất chúng từ vùng chứa và tạo kiểm tra cho các chức năng đã xuất? – stone

+1

@skypecakes Tôi tin rằng anh ấy có nghĩa là ['connect' chính nó] (https://github.com/reactjs/react-redux/blob/master/test/components/connect.spec.js). – falsarella

10

Bạn có thể kiểm tra thành phần được kết nối của mình và tôi nghĩ bạn nên làm như vậy. Bạn có thể muốn kiểm tra thành phần chưa được kết nối trước, nhưng tôi khuyên bạn sẽ không có phạm vi kiểm tra hoàn chỉnh mà không cần kiểm tra thành phần được kết nối.

Dưới đây là phần trích dẫn chưa được kiểm chứng về những gì tôi làm với Redux và Enzyme. Ý tưởng trung tâm là sử dụng Nhà cung cấp để kết nối trạng thái trong thử nghiệm với thành phần được kết nối trong thử nghiệm.

import { Provider } from 'react-redux'; 
import configureMockStore from 'redux-mock-store'; 
import SongForm from '../SongForm'; // import the CONNECTED component 

// Use the same middlewares you use with Redux's applyMiddleware 
const mockStore = configureMockStore([ /* middlewares */ ]); 
// Setup the entire state, not just the part Redux passes to the connected component. 
const mockStoreInitialized = mockStore({ 
    songs: { 
     songsList: { 
      songs: { 
       songTags: { /* ... */ } 
      } 
     } 
    } 
}); 

const nullFcn1 =() => null; 
const nullFcn2 =() => null; 
const nullFcn3 =() => null; 

const wrapper = mount(// enzyme 
     <Provider store={store}> 
      <SongForm 
      screen="add" 
      disabled={false} 
      handleFormSubmit={nullFcn1} 
      handleModifySong={nullFcn2} 
      handleDeleteSong={nullFcn3} 
      /> 
     </Provider> 
    ); 

const formPropsFromReduxForm = wrapper.find(SongForm).props(); // enzyme 
expect(
     formPropsFromReduxForm 
    ).to.be.deep.equal({ 
     screen: 'add', 
     songTags: initialSongTags, 
     disabled: false, 
     handleFormSubmit: nullFcn1, 
     handleModifySong: nullFcn2, 
     handleDeleteSong: nullFcn3, 
     }); 

===== ../SongForm.js 

import React from 'react'; 
import { connect } from 'react-redux'; 

const SongForm = (/* object */ props) /* ReactNode */ => { 
    /* ... */ 
    return (
     <form onSubmit={handleSubmit(handleFormSubmit)}> 
      .... 
     </form> 

}; 

const mapStateToProps = (/* object */ state) /* object */ => ({ 
    songTags: state.songs.songTags 
}); 
const mapDispatchToProps =() /* object..function */ => ({ /* ... */ }); 

export default connect(mapStateToProps, mapDispatchToProps)(SongForm) 

Bạn có thể muốn tạo một cửa hàng có Redux thuần túy. redux-mock-store chỉ là một phiên bản trọng lượng nhẹ của nó có nghĩa là để thử nghiệm.

Bạn có thể muốn sử dụng phản ứng-addons-test-utils thay vì Enzyme của airbnb.

Tôi sử dụng enzym chai của airbnb để có tùy chọn mong đợi phản ứng. Nó không cần thiết trong ví dụ này.

+0

Xin lỗi @Tarjei Huse, nhưng tôi đã khôi phục bản chỉnh sửa của bạn. là những gì Redux cung cấp để móc vào React. Bản chỉnh sửa của bạn được mã hóa cứng như thế nào hiện tại. Tuy nhiên, tôi không muốn mã của mình bị lộ nên từng thay đổi việc triển khai mã. – JohnSz

0

Vấn đề với câu trả lời được chấp nhận là chúng tôi đang xuất một thứ gì đó không cần thiết chỉ để có thể kiểm tra nó. Và xuất khẩu một lớp học chỉ để kiểm tra nó không phải là một ý tưởng tốt trong quan điểm của tôi.

Dưới đây là một giải pháp gọn gàng mà không cần phải xuất khẩu bất cứ điều gì nhưng các thành phần kết nối:

Nếu bạn đang sử dụng jest, bạn có thể thử connect phương pháp để trở về ba điều:

  1. mapStateToProps
  2. mapDispatchToProps
  3. ReactComponent

Làm như vậy là khá đơn giản. Có 2 cách: Mock nội tuyến hoặc mocks toàn cầu.

1. Sử dụng inline giả

Thêm đoạn mã sau đây trước khi mô tả chức năng của kiểm tra.

jest.mock('react-redux',() => { 
 
    return { 
 
    connect: (mapStateToProps, mapDispatchToProps) => (reactComponent) => ({ 
 
     mapStateToProps, 
 
     mapDispatchToProps, 
 
     ReactComponent 
 
    }), 
 
    Provider: ({ children }) => children 
 
    } 
 
})

2. Sử dụng tập tin giả

  1. Tạo một file __mocks__/react-redux.js trong thư mục gốc (nơi package.json nằm)
  2. Thêm đoạn mã sau trong tập tin.

module.exports = { 
 
    connect: (mapStateToProps, mapDispatchToProps) => (reactComponent) => ({ 
 
    mapStateToProps, 
 
    mapDispatchToProps, 
 
    ReactComponent, 
 
    }), 
 
    Provider: ({children}) => children 
 
};

Sau khi chế giễu, bạn sẽ có thể truy cập tất cả các bên trên ba sử dụng Container.mapStateToProps, Container.mapDispatchToPropsContainer.ReactComponent.

container có thể được nhập khẩu bằng cách đơn giản làm

import Container from '<path>/<fileName>.container.js'

Hy vọng nó giúp.

Lưu ý rằng nếu bạn sử dụng tệp giả. Tệp được giả lập sẽ được sử dụng trên toàn cầu cho tất cả các trường hợp thử nghiệm (trừ khi bạn thực hiện jest.unmock('react-redux')) trước khi kiểm tra.

Các vấn đề liên quan