Enzyme: Enzyme don't provide support for multiple layer in component?

Created on 10 Sep 2019  ·  3Comments  ·  Source: enzymejs/enzyme

Hello guys, after of all, thanks for the great job!

I have a little problem when i need testing functions after add lib for translate. I reproduce code and console.log for clear the idea.

Code working:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';

class AddAccesses extends Component {
  state = { isAccessEnabled: false }

  toggleInputAccess = () => {
    const { isAccessEnabled } = this.state;

    this.setState({
      isAccessEnabled: !isAccessEnabled
    });
  }

  render() {
    const { isAccessEnabled } = this.state;
    const { t } = this.props;

    return (
      <div>
        <Box
          data-testid="BoxAccess"
          bg={isAccessEnabled}
          onClick={this.toggleInputAccess}
        >
          {t('add_accesses_button_search_role_guide_off')}
        </Box>
        <Tooltip span text={t('add_accesses_tooltip_role_guide_off')} />
      </div>
    );
  }
}

AddAccesses.propTypes = {
  t: PropTypes.func.isRequired,
};

const mapStateToProps = state => ({
  systems: state.systems,
  accesses: state.accesses,
});

export default connect(
  mapStateToProps, { fetchIdentities },
)(AddAccesses);

Test working:

  beforeEach(() => {
    store = mockStore(initialState);
    wrapper = shallow(
      <AddAccessesCaseEnzyme store={store} />,
    ).childAt(0).dive();
    instance = wrapper.instance();
  });

  it('should find BoxAccess, BoxIdentity, BoxCriticalComponent, BoxAccessKit', () => {
    console.log(wrapper.debug());
    expect(wrapper.find('[data-testid="BoxAccess"]')).toHaveLength(1);
  });

Console:

 <Box data-testid="BoxAccess" bg={isAccessEnabled} onClick={this.toggleInputAccess}>{t('add_accesses_button_search_role_guide_off')}</Box>
          |                                                                                                 ^
      192 |             <Tooltip span text={t('add_accesses_tooltip_role_guide_off')} />

So far, so good. But when i add another layer for translate in component stop work the test.

Code working with import { withNamespaces } from 'react-i18next';:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { withNamespaces } from 'react-i18next';

class AddAccesses extends Component {
  state = { isAccessEnabled: false }

  toggleInputAccess = () => {
    const { isAccessEnabled } = this.state;

    this.setState({
      isAccessEnabled: !isAccessEnabled
    });
  }

  render() {
    const { isAccessEnabled } = this.state;
    const { t } = this.props;

    return (
      <div>
        <Box
          data-testid="BoxAccess"
          bg={isAccessEnabled}
          onClick={this.toggleInputAccess}
        >
          {t('add_accesses_button_search_role_guide_off')}
        </Box>
        <Tooltip span text={t('add_accesses_tooltip_role_guide_off')} />
      </div>
    );
  }
}

AddAccesses.propTypes = {
  t: PropTypes.func.isRequired,
};

const mapStateToProps = state => ({
  systems: state.systems,
  accesses: state.accesses,
});

export default withNamespaces()(connect(
  mapStateToProps, { fetchIdentities },
)(AddAccesses));

Test with shallow() don't work:

  beforeEach(() => {
    store = mockStore(initialState);
    wrapper = shallow(
      <Provider store={store}>
        <I18nextProvider i18n={i18n}>
          <BrowserRouter>
            <Switch>
              <AddAccessesCaseEnzyme />
            </Switch>
          </BrowserRouter>
        </I18nextProvider>
      </Provider>,
    ).childAt(0).dive();
    instance = wrapper.instance();
  });

  it('should user does not selected benefited', () => {
    history.push('/benefited');

    expect(window.location.href).toBe('http://localhost/benefited');
  });

  it('should find BoxAccess, BoxIdentity, BoxCriticalComponent, BoxAccessKit', () => {
    expect(wrapper.find('[data-testid="BoxAccess"]')).toHaveLength(3);
  });

  it('toggleInputIdentities and enableInputIdentities function should update state as expected', () => {
    console.log(wrapper.debug());
    instance.toggleInputAccess();
  });

Console:

 FAIL  app/javascript/src/spec/javascript/packs/components/organisms/add_accesses_case_enzyme.spec.js
  Testing AddAccesses component
    ✓ should user does not selected benefited (144ms)
    ✕ should find BoxAccess (10ms)
    ✕ toggleInputAccess function should update state as expected (13ms)

  ● Testing AddAccesses component › should find BoxAccess

    expect(received).toHaveLength(expected)

    Expected length: 3
    Received length: 0
    Received object: {}

      100 |
      101 |   it('should find BoxAccess', () => {
    > 102 |     expect(wrapper.find('[data-testid="BoxAccess"]')).toHaveLength(3);
          |                                                       ^
      103 |   });
      104 |
      105 |   it('toggleInputAccess function should update state as expected', () => {

      at Object.toHaveLength (app/javascript/src/spec/javascript/packs/components/organisms/add_accesses_case_enzyme.spec.js:102:55)

  ● Testing AddAccesses component › toggleInputAccess function should update state as expected

    TypeError: instance.toggleInputAccess is not a function

      105 |   it('toggleInputAccess function should update state as expected', () => {
      106 |     console.log(wrapper.debug());
    > 107 |     instance.toggleInputAccess();
          |              ^
      108 |     expect(instance.state.isAccessEnabled).toBe(true);
      109 |   });
      110 |

      at Object.toggleInputAccess (app/javascript/src/spec/javascript/packs/components/organisms/add_accesses_case_enzyme.spec.js:107:14)

  console.log app/javascript/src/spec/javascript/packs/components/organisms/add_accesses_case_enzyme.spec.js:106
    <ContextProvider value={{...}}>
      <BrowserRouter>
        <Switch>
          <LoadNamespace(Connect(AddAccesses)) />
        </Switch>
      </BrowserRouter>
    </ContextProvider>

Test with mount() don't work:

  beforeEach(() => {
    store = mockStore(initialState);
    wrapper = mount(
      <Provider store={store}>
        <I18nextProvider i18n={i18n}>
          <BrowserRouter>
            <Switch>
              <AddAccessesCaseEnzyme />
            </Switch>
          </BrowserRouter>
        </I18nextProvider>
      </Provider>,
    );
    instance = wrapper.instance();
  });

  it('should user does not selected benefited', () => {
    history.push('/benefited');

    expect(window.location.href).toBe('http://localhost/benefited');
  });

  it('should find BoxAccess', () => {
    expect(wrapper.find('[data-testid="BoxAccess"]')).toHaveLength(3);
  });

  it('toggleInputAccess function should update state as expected', () => {
    console.log(wrapper.debug());
    instance.toggleInputAccess();
    expect(instance.state.isAccessEnabled).toBe(true);
  });

Console:

  <Provider store={{...}}>
      <I18nextProvider i18n={{...}}>
        <BrowserRouter>
          <Router history={{...}}>
            <Switch>
              <LoadNamespace(Connect(AddAccesses)) location={{...}} computedMatch={{...}}>
                <WithMergedOptions i18n={{...}} defaultNS={[undefined]} reportNS={[undefined]} lng="pt" t={[Function: bound t]} location={{...}} computedMatch={{...}}>
                  <LoadNamespace i18n={{...}} t={[Function: bound t]} lng="pt" i18nOptions={{...}} defaultNS={[undefined]} reportNS={[undefined]} location={{...}} computedMatch={{...}}>
                    <WithMergedOptions(NamespacesConsumerComponent) ns={[undefined]} i18n={{...}} t={[Function: bound t]} lng="pt" i18nOptions={{...}} defaultNS={[undefined]} reportNS={[undefined]} location={{...}} computedMatch={{...}}>
                      <WithMergedOptions i18n={{...}} defaultNS={[undefined]} reportNS={[undefined]} lng="pt" t={[Function: bound t]} ns={[undefined]} i18nOptions={{...}} location={{...}} computedMatch={{...}}>
                        <NamespacesConsumerComponent i18n={{...}} t={[Function: bound t]} lng="pt" i18nOptions={{...}} defaultNS={[undefined]} reportNS={[undefined]} ns={[undefined]} location={{...}} computedMatch={{...}}>
                          <Connect(AddAccesses) tReady={true} i18n={{...}} t={[Function: fixedT]} lng="pt" i18nOptions={{...}} defaultNS={[undefined]} reportNS={[undefined]} location={{...}}
computedMatch={{...}}>
                            <AddAccesses tReady={true} i18n={{...}} t={[Function: fixedT]} lng="pt" i18nOptions={{...}} defaultNS={[undefined]} reportNS={[undefined]} location={{...}} computedMatch={{...}} systems={{...}} accesses={{...}} selectedBenefited={{...}} fetchIdentities={[Function]} fetchCriticalComponents={[Function]} fetchSystems={[Function]} setSelectedAccesses={[Function]} updateSelectedAccesses={[Function]}>
                              <div>
                                <styled.div borderBottom={true} alignItems={true}>
                                  <StyledComponent borderBottom={true} alignItems={true} forwardedComponent={{...}} forwardedRef={{...}}>
                                    <div className="sc-dxgOiQ KKGvM">
                                      <Link to="/helpdesk">
                                        <a onClick={[Function: onClick]} href="/helpdesk">
                                          <styled.img src="test-file-stub">
                                            <StyledComponent src="test-file-stub" forwardedComponent={{...}} forwardedRef={{...}}>
                                              <img src="test-file-stub" className="sc-ckVGcZ dvqRth" />
                                            </StyledComponent>
                                          </styled.img>
                                        </a>
                                      </Link>
                                    </div>
                                  </StyledComponent>
                                </styled.div>
                                <styled.div spaceAround={true}>
                                  <StyledComponent spaceAround={true} forwardedComponent={{...}} forwardedRef={{...}}>
                                    <div className="sc-dxgOiQ gfxngO">
                                      <styled.div flexEnd={true}>
                                        <StyledComponent flexEnd={true} forwardedComponent={{...}} forwardedRef={{...}}>
                                          <div className="sc-dxgOiQ kgTxfX">
                                            <styled.button data-testid="BoxAccess" bg={{...}} onClick={[Function]}>
                                              <StyledComponent data-testid="BoxAccess" bg={{...}} onClick={[Function]} forwardedComponent={{...}} forwardedRef={{...}}>
                                                <button data-testid="BoxAccess" onClick={[Function]} className="sc-chPdSV gDtCiS">
                                                  Eu sei o nome ou parte do nome do perfil
                                                </button>

In short, when i add lib i18next-react the test gets lost, and i don't get access for execute the function

 <button data-testid="BoxAccess" onClick={[Function]} className="sc-chPdSV gDtCiS">
                                                  Eu sei o nome ou parte do nome do perfil
                                                </button>
question

Most helpful comment

@drd-2rcl Instead of wrapping the component with your provider, use the wrappingComponent option, like this:

function WrapWithProviders({ children }) {
  return (
    <Provider store={store}>
      <I18nextProvider i18n={i18n}>
        <BrowserRouter>
          <Switch>
            {children}
          </Switch>
        </BrowserRouter>
      </I18nextProvider>
    </Provider>
  );
}
const wrapper = shallow(<AddAccessesCaseEnzyme />, {
  wrappingComponent: WrapWithProviders,
});

All 3 comments

@ljharb Hello, help us please.

@drd-2rcl Instead of wrapping the component with your provider, use the wrappingComponent option, like this:

function WrapWithProviders({ children }) {
  return (
    <Provider store={store}>
      <I18nextProvider i18n={i18n}>
        <BrowserRouter>
          <Switch>
            {children}
          </Switch>
        </BrowserRouter>
      </I18nextProvider>
    </Provider>
  );
}
const wrapper = shallow(<AddAccessesCaseEnzyme />, {
  wrappingComponent: WrapWithProviders,
});

@ljharb did this answer you provide change?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ivanbtrujillo picture ivanbtrujillo  ·  3Comments

nelsonchen90 picture nelsonchen90  ·  3Comments

benadamstyles picture benadamstyles  ·  3Comments

amcmillan01 picture amcmillan01  ·  3Comments

heikkimu picture heikkimu  ·  3Comments