2016-06-13 14 views
21

Ho un componente SampleComponent che monta un altro "componente connesso" (ad esempio container). Quando provo a testare SampleComponent da mount ING (da quando ho bisogno del componentDidMount), ottengo l'errore:Componenti nidificati che eseguono test con Enzyme all'interno di 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)".

Qual è il modo migliore di prove?

risposta

4

Quello che in sostanza fatto è stato portare in mia redux negozio (e Provider) e lo avvolse in un componente di utilità come segue:

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

allora, mount i test SampleComponent ed eseguire contro di essa:

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

Vedo che stai usando mount, se provo a sostituire '' mount'' con '' shallo'', ricevo un errore. hai incontrato anche questo? – Mehrdad

+2

Sebbene questa risposta funzioni in alcuni casi, non funziona quando è necessario testare il ciclo di vita del componente. Ad esempio, chiamando 'wrapper.setProps()' non attiverà 'componentWillReceiveProps()' su 'SampleComponent'. –

25

Il supporto dell'enzima accetta i parametri facoltativi. I due che sono necessari per quello che serve sono

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

options.childContextTypes: (Object [optional]): Merged contextTypes for all children of the wrapper Si potrebbe montare SampleComponent con una delle opzioni oggetto in questo modo:

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) 

Ora il vostro SampleComponent passerà contesto che hai fornito fino a il .

+2

Questo è perfetto! Mentre la risposta accettata funziona la maggior parte del tempo, il lato negativo è che si perde la capacità di utilizzare la montatura api alla sua massima capacità. Ad esempio, l'utilizzo della risposta accettata per il wrapping del componente in un 'Provider' non consente di usare l'API' wrapper.state() '. Questa soluzione ti fornirà l'intera gamma di metodi per il tuo wrapper. – neurosnap

+0

Questa è una risposta migliore rispetto alla risposta accettata, per i motivi sopra indicati (ovvero il wrapper montato non è in realtà il componente che si sta tentando di testare), e anche perché è possibile utilizzare un negozio simulato al posto del proprio negozio, lasciando tutto di nuovo fuori dall'equazione. – GTF

+2

questo argomento facoltativo non è in documenti, come lo hai trovato? nel codice? –

1

È possibile utilizzare il nome di esportazione per risolvere questo problema:

si dovrebbe avere:

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

export default connect(mapStateToProps, mapDispatchToProps)(SampleComponent) 

È possibile aggiungere un'esportazione prima classe:

export class SampleComponent extends React.Component{ 

e importare questa componente senza negozio redux:

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

Con questa soluzione non è necessario importare il negozio nei file di test.

1

Opzione 1) È possibile avvolgere il componente contenitore con il componente Provider di React-Redux nel test. Pertanto, con questo approccio, si fa effettivamente riferimento al negozio, lo si passa al provider e si compone il componente in prova all'interno. Il vantaggio di questo approccio è che puoi effettivamente creare un negozio personalizzato per il test. Questo approccio è utile se si desidera testare le porzioni correlate al Redux del componente. Opzione 2) Forse non ti interessa testare i pezzi relativi a Redux. Se sei semplicemente interessato a testare il rendering del componente e i comportamenti relativi allo stato locale, puoi semplicemente aggiungere un'esportazione nominata per la versione normale non connessa del tuo componente. E giusto per chiarire quando aggiungi la parola chiave "export" alla tua classe in pratica stai dicendo che ora la classe potrebbe essere importata in 2 modi con parentesi graffe {} oppure no. Esempio:

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

... 

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent) 

in seguito sul file di test:

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. 

spero aiuta qualcuno là fuori.

Problemi correlati