2017-01-19 2 views
4

Ich habe eine Higher Order Component/Komponent Component erstellt, um sicherzustellen, dass ein Benutzer authentifiziert wird, bevor die Komponente geladen wird. Es ist sehr einfach, aber ich habe Probleme damit, es zu testen. Ich möchte die folgenden Punkte prüfen, die zu den Prüfungen ähnlich sind, habe ich bereits an anderer Stelle:Enzyme testen eine Authentifizierung Higher Order Component (HOC)

  • Renders die Komponente (I normalerweise überprüfen, indem der Suche nach einem Component spezifischen className)
  • Hat richtig props (in meinem Fall authenticated)
  • Renders die verpackte Komponente, wenn authenticated und macht null wenn nicht

die HOC:

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

import { makeSelectAuthenticated } from 'containers/App/selectors'; 

export default function RequireAuth(ComposedComponent) { 
    class AuthenticatedComponent extends React.Component { 
    static contextTypes = { 
     router: React.PropTypes.object, 
    } 

    static propTypes = { 
     authenticated: React.PropTypes.bool, 
    } 

    componentWillMount() { 
     if (!this.props.authenticated) this.context.router.push('/'); 
    } 

    componentWillUpdate(nextProps) { 
     if (!nextProps.authenticated) this.context.router.push('/'); 
    } 

    render() { 
     return (
     <div className="authenticated"> 
      { this.props.authenticated ? <ComposedComponent {...this.props} /> : null } 
     </div> 
    ); 
    } 
    } 

    const mapStateToProps = createStructuredSelector({ 
    authenticated: makeSelectAuthenticated(), 
    }); 

    return connect(mapStateToProps)(AuthenticatedComponent); 
} 

Ich verwende enzyme und jest für meine Tests, aber habe keine Möglichkeit gefunden, die HOC während meiner Tests erfolgreich zu rendern.

Irgendwelche Ideen?

Lösung dank unten beantworten:

import React from 'react'; 
import { shallow, mount } from 'enzyme'; 
import { Provider } from 'react-redux'; 

import { AuthenticatedComponent } from '../index'; 

describe('AuthenticatedComponent',() => { 
    let MockComponent; 

    beforeEach(() => { 
    MockComponent =() => <div />; 
    MockComponent.displayName = 'MockComponent'; 
    }); 

    it('renders its children when authenticated',() => { 
    const wrapper = shallow(
     <AuthenticatedComponent 
     composedComponent={MockComponent} 
     authenticated={true} 
     />, 
     { context: { router: { push: jest.fn() } } } 
    ); 

    expect(wrapper.find('MockComponent').length).toEqual(1); 
    }); 

    it('renders null when not authenticated',() => { 
    const wrapper = shallow(
     <AuthenticatedComponent 
     composedComponent={MockComponent} 
     authenticated={false} 
     />, 
     { context: { router: { push: jest.fn() } } } 
    ); 

    expect(wrapper.find('MockComponent').length).toEqual(0); 
    }); 
}); 

Antwort

5

Der „tricky“ Teil hier ist, dass Ihr HOC eine angeschlossene Komponente zurückgibt, die härter Tests macht, weil man zwei Schichten flach machen haben (die angeschlossene Komponente und die tatsächliche Komponente) und Sie müssen den redux Speicher verspotten.

Stattdessen können Sie die AuthenticatedComponent im Voraus definieren und als benannten Export exportieren. Als Sie es unabhängig von connect testen können, wie Sie jede andere Komponente testen:

export class AuthenticatedComponent extends React.Component { 
    static contextTypes = { 
    router: React.PropTypes.object, 
    } 

    static propTypes = { 
    authenticated: React.PropTypes.bool, 
    composedComponent: React.PropTypes.any.isRequired, 
    } 

    componentWillMount() { 
    if (!this.props.authenticated) this.context.router.push('/'); 
    } 

    componentWillUpdate(nextProps) { 
    if (!nextProps.authenticated) this.context.router.push('/'); 
    } 

    render() { 
    const ComposedComponent = this.props.composedComponent; 
    return (
     <div className="authenticated"> 
     { this.props.authenticated ? <ComposedComponent {...this.props} /> : null } 
     </div> 
    ); 
    } 
} 

export default function RequireAuth(ComposedComponent) { 
    const mapStateToProps =() => { 
    const selectIsAuthenticated = makeSelectAuthenticated(); 
    return (state) => ({ 
     authenticated: selectIsAuthenticated(state), 
     composedComponent: ComposedComponent, 
    }); 
    }; 

    return connect(mapStateToProps)(AuthenticatedComponent); 
} 

Beispiel Test:

import React from 'react'; 
import { shallow, mount } from 'enzyme'; 
import { Provider } from 'react-redux'; 
import configureStore from 'redux-mock-store'; 
import RequireAuth, { AuthenticatedComponent } from '../'; 

const Component =() => <div />; 
Component.displayName = 'CustomComponent'; 

const mockStore = configureStore([]); 

describe.only('HOC',() => { 
    const RequireAuthComponent = RequireAuth(Component); 
    const context = { router: { push: jest.fn() } }; 
    const wrapper = mount(
    <Provider store={mockStore({})}> 
     <RequireAuthComponent /> 
    </Provider>, 
    { 
     context, 
     childContextTypes: { router: React.PropTypes.object.isRequired }, 
    } 
); 
    it('should return a component',() => { 
    expect(wrapper.find('Connect(AuthenticatedComponent)')).toHaveLength(1); 
    }); 
    it('should pass correct props',() => { 
    expect(wrapper.find('AuthenticatedComponent').props()).toEqual(
     expect.objectContaining({ 
     authenticated: false, 
     composedComponent: Component, 
     }) 
    ); 
    }); 
}); 

describe('rendering',() => { 
    describe('is authenticated',() => { 
    const wrapper = shallow(
     <AuthenticatedComponent 
     composedComponent={Component} 
     authenticated 
     />, 
     { context: { router: { push: jest.fn() } } } 
    ); 
    it('should render the passed component',() => { 
     expect(wrapper.find('CustomComponent')).toHaveLength(1); 
    }); 
    }); 
    describe('is not authenticated',() => { 
    const wrapper = shallow(
     <AuthenticatedComponent 
     composedComponent={Component} 
     authenticated={false} 
     />, 
     { context: { router: { push: jest.fn() } } } 
    ); 
    it('should not render the passed component',() => { 
     expect(wrapper.find('CustomComponent')).toHaveLength(0); 
    }); 
    }); 
}); 
+0

Danke für die Erklärung ist es Ihnen möglich, ein Beispiel zu geben, wie man nur machen die Komponente im Test? Ich habe viele verschiedene Methoden mit 'shallow' und' mount' ausprobiert, aber es scheint nicht zu funktionieren, dass alles zum Testen richtig gerendert wird. – germainelol

+0

Auch ein bisschen verwirrt durch die 'composedComponent' -Variable, die Sie an' mapStateToProps' übergeben. Das wird immer noch normal funktionieren? – germainelol

+0

Ein Beispiel hinzugefügt, wie Sie die 'AuthenticatedComponent' testen können. Ich stimme der Verwendung von mapStateToProps zu, um die 'composedComponent' zu übergeben, sieht ein bisschen komisch aus. Da die 'AuthenticatedComponent' nun außerhalb der HOC definiert ist, können wir sie nur über Props übergeben. Ich dachte, wir können einfach 'mapStateToProps' oder das verwenden. – PhilippSpo

Verwandte Themen