0

I have been having a ton of trouble trying to render a react-redux-firebase connected component using react-testing-library. I keep getting hit with a [TypeError: ref.collection is not a function] error that crashes my test as soon as I try to run it.

The component:

@firestoreConnect((props, {getState}) => {
  const {auth} = getState();
  const {clientId} = auth.data;

  return [
    {
      collection: 'clients',
      doc: clientId,
      subcollections: [{collection: 'users'}]
    },
    {
      collection: 'clients',
      doc: clientId,
      subcollections: [{collection: 'scripts'}]
    },
    {
      collection: 'clients',
      doc: clientId,
      subcollections: [{collection: 'teams'}]
    },
    {
      collection: 'clients',
      doc: clientId,
      subcollections: [{collection: 'lists'}],
      where: [
        ['status', '==', 'complete'],
        ['archived', '==', false]
      ]
    }
  ];
})
@connect(({auth, profile, ggFirestore}, {params}) => {
  const {clientRef, displayName, legacyClientId, permissions} = auth.data;
  return {
    users: ggFirestore.getIn(['users']),
    lists: ggFirestore.getIn(['lists']),
    scripts: ggFirestore.getIn(['scripts']),
    teams: ggFirestore.getIn(['teams']),
    profile,
    clientRef,
    displayName,
    legacyClientId,
    permissions,
    params
  };
})
export default class CampaignForm extends Component {
  constructor(props) {
    super(props);
    const campaignTypes = {
      '1to1sms': [
        VisibilityStep,
        TemplatesStep,
        ListsStep,
        OwnerStep,
        NameStep,
        SummaryStep
      ],
      '1to1email': [
        NameStep,
        TemplatesStep,
        ListsStep,
        SendEmailsStep,
        SuccessStep
      ]
    };

    this.state = {
      step: 0,
      contactTypeSteps: campaignTypes[props.params.contactType],
      campaignId: '',
      draftCampaignId: '',
      type: 'organizing',
      isProcessing: false,
      confirmSummary: false,
      contactType: props.params.contactType
    };
  }

...

  render() {
    const {
      step,
      success,
      error,
      contactTypeSteps,
      campaignId,
      draftCampaignId,
      isProcessing,
      confirmSummary,
      contactType
    } = this.state;

    const {params, lists, users, teams, scripts, profile} = this.props;
    const isLastStep =
      contactTypeSteps.length === step + 1 ||
      (contactType === '1to1email' && step === 3);
    const StepComponent = contactTypeSteps[step];
    if (profile && profile.role === 'volunteer') {
      return <PermissionDenied />;
    }
    if (users && lists && scripts && teams) {
      return (
        <div className="top-spacer" date-testid="_campaign-form">
          <SuccessMessage
            message={success}
            handleDismiss={() => {
              this.setState({success: null});
            }}
          />
          <ErrorMessage
            error={error}
            handleDismiss={() => {
              this.setState({error: null});
            }}
          />
          {confirmSummary ? (
            <SuccessStep
              campaignId={campaignId ? campaignId : draftCampaignId}
              campaignType={params.contactType}
              {...this.state}
              {...this.props}
              isOrganizer={profile && profile.role === 'organizer'}
            />
          ) : (
            <StepComponent
              handleNext={
                isLastStep ? ::this.handleFinalSubmit : ::this.handleNextClick
              }
              handlePrev={::this.handleBackClick}
              handleChange={::this.handleChange}
              contactType={params.contactType}
              isLastStep={isLastStep}
              isProcessing={isProcessing}
              {...this.props}
              {...this.state}
              isOrganizer={profile && profile.role === 'organizer'}
            />
          )}
        </div>
      );
    }
    return <Loading />;
  }
}

My test wrapper:

import '@testing-library/jest-dom/extend-expect';
import 'firebase/firestore';

import { render } from '@testing-library/react';
import firebase from 'firebase';
import { createMemoryHistory } from 'history';
import React from 'react';
import { Provider } from 'react-redux';
import { reactReduxFirebase } from 'react-redux-firebase';
import { MemoryRouter } from 'react-router-dom';
import { compose, createStore } from 'redux';
import { reduxFirestore } from 'redux-firestore';

import rootReducer from '../ducks';

jest.mock('../store/fbTestConfig', () => ({
  firebase: {
    firestore: jest.fn(() => ({})),
    initializeApp: jest.fn(() => {})
  }
}));

const mockStore = compose(
  reactReduxFirebase(firebase, {}),
  reduxFirestore(firebase)
)(createStore);

export function renderWithRedux(
  Component,
  {
    initialState,
    store = mockStore(rootReducer, initialState),
    route = '/',
    history = createMemoryHistory({initialEntries: [route]})
  } = {}
) {
  return {
    ...render(
      <Provider store={store}>
        <MemoryRouter initialEntries={[route]}>{Component}</MemoryRouter>
      </Provider>,
      {}
    ),
    store,
    history
  };
}

My test:

import '@testing-library/jest-dom/extend-expect';

import { cleanup } from '@testing-library/react';
import React from 'react';

import CampaignForm from '../../components/Campaigns/CampaignForm';
import { renderWithRedux } from '../renderWithRedux';

beforeEach(cleanup);

test('CampaignForm renders', () => {
  const {debug} = renderWithRedux(<CampaignForm />, {
    route: 'organize/1to1sms'
  });
  debug();
});

I tried console logging the component and it looks like it is wrapped properly by firestoreConnect, but the ref key is always set to null. I have tried looking everywhere for some kind of answer but no luck. Any help would be GREATLY appreciated!

XavierM
  • 9
  • 1

1 Answers1

0

So I finally figured it out! The component was expecting props that I did not seed properly when setting up my test.

In my component I had these lines:

const {auth} = getState();
const {clientId} = auth.data;

Where auth is a piece of my application state. The initial state for this was an empty Map, so when I tried to pull clientId from there and use it to get my collections, it threw an error.

The solution was just using my mock store to dispatch the appropriate action to populate the auth Map. Worked like a charm.

XavierM
  • 9
  • 1