2016-06-13 159 views
21

我有一個組件SampleComponent,它安裝了另一個「連接組件」(即container)。當我嘗試通過mount ING測試SampleComponent(因爲我需要的componentDidMount),我得到的錯誤:使用React&Redux內部酶進行測試的嵌套組件

Invariant Violation: Could not find "store" in either the context or props of "Connect(ContainerComponent)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(ContainerComponent)".

什麼是測試這個的最佳方式?

回答

4

我基本上沒在我的redux存儲(和Provider)帶來,並把它包在一個工具組件,如下所示:

export const CustomProvider = ({ children }) => { 
    return (
    <Provider store={store}> 
     {children} 
    </Provider> 
); 
}; 

然後,我mountSampleComponent和運行測試反對:

it('contains <ChildComponent/> Component',() => { 
    const wrapper = mount(
    <CustomProvider> 
     <SampleComponent {...defaultProps} /> 
    </CustomProvider> 
); 
    expect(wrapper.find(ChildComponent)).to.have.length(1); 
}); 
+0

我看到你正在使用mount,如果我嘗試用''shallo''替換''mount''出現錯誤。你也遇到過嗎? – Mehrdad

+2

雖然此答案在某些情況下有效,但在需要測試組件的生命週期時不起作用。例如,調用'wrapper.setProps()'不會觸發'SampleComponent'上的'componentWillReceiveProps()'。 –

25

酶的安裝需要可選參數。兩所必需的,你需要的是

options.context: (Object [optional]): Context to be passed into the component

options.childContextTypes: (Object [optional]): Merged contextTypes for all children of the wrapper 您將登上SampleComponent與選擇對象,像這樣:

const store = { 
    subscribe:() => {}, 
    dispatch:() => {}, 
    getState:() => ({ ... whatever state you need to pass in ... }) 
} 
const options = { 
    context: { store }, 
    childContextTypes: { store: React.PropTypes.object.isRequired } 
} 

const _wrapper = mount(<SampleComponent {...defaultProps} />, options) 

現在你SampleComponent將通過您所提供到上下文。

+2

這是完美的!儘管接受的答案在大多數情況下都適用,但缺點是您無法使用安裝API來發揮最大能力。例如,使用「提供者」包裝組件的接受答案不允許使用'wrapper.state()'api。該解決方案將爲您提供包裝的全套方法。 – neurosnap

+0

由於上述原因(即,您的掛載包裝實際上不是您正在嘗試測試的組件),這比接受的答案更好,也因爲您可以使用模擬商店而不是實際商店,所有這些都減少了。 – GTF

+2

此可選參數不在文檔中,您是如何找到它的?在代碼中? –

1

您可以使用名稱出口來解決這個問題:

你應該有:

class SampleComponent extends React.Component{ 
... 
    render(){ 
     <div></div> 
    } 
} 

export default connect(mapStateToProps, mapDispatchToProps)(SampleComponent) 

您可以在課前添加一個出口:

export class SampleComponent extends React.Component{ 

,並沒有導入該組件REDO商店:

import { SampleComponent } from 'your-path/SampleComponent'; 

使用此解決方案,您無需將商店導入到測試文件中。

1

選項1)您可以在測試中使用React-Redux的Provider組件包裝容器組件。因此,採用這種方法,您實際上會引用商店,將其傳遞給提供商,並在測試中組成您的組件。這種方法的優點是您可以爲測試創建一個自定義商店。如果要測試組件的與Redux相關的部分,此方法非常有用。 選項2)也許你不在乎測試Redux相關的部分。如果您只想測試組件的渲染和本地狀態相關行爲,則可以簡單地爲組件的未連接純文本版本添加命名導出。並且只是爲了澄清何時將「導出」關鍵字添加到您的課程中,基本上您會說現在該課程可以通過兩種方式導入,不管是花括號還是不導入。例如:

export class MyComponent extends React.Component{ render(){ ... }} 

... 

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent) 

以後你的測試文件:

import MyComponent from 'your-path/MyComponent'; // it needs a store because you use "default export" with connect 
import {MyComponent} from 'your-path/MyComponent'; // don't need store because you use "export" on top of your class. 

我希望可以幫助那裏的人。