0

I have this component

    import React, { useEffect } from 'react';
import './App.css';

import { connect } from 'react-redux';
import { CircularProgress } from '@material-ui/core';
import { loadPhones } from './redux/actions/actions.js';
import TablePhones from './Table.js';

const mapStateToProps = (state) => state;

function mapDispatchToProps(dispatch) {
  return {
    loadPhones: () => {
      dispatch(loadPhones());
    },
  };
}

export function App(props) {
  useEffect(() => {
    props.loadPhones();
  }, []);

  if (props.phones.data) {
    return (
      <div className="App">
        <div className="introductoryNav">Phones</div>
        <TablePhones phones={props.phones.data} />
      </div>
    );
  }
  return (
    <div className="gridLoadingContainer">
      <CircularProgress color="secondary" iconStyle="width: 1000, height:1000" />
      <p className="loadingText1">Loading...</p>
    </div>
  );
}

export default connect(mapStateToProps, mapDispatchToProps)(App);

For whom ive written

import React from 'react';
import { render } from '@testing-library/react';
import { Provider } from "react-redux";
import App from './App';
import { shallow, mount } from "enzyme";
import configureMockStore from "redux-mock-store";

const mockStore = configureMockStore();
const store = mockStore({});

describe('App comp testing', () => {
 

  it("should render without throwing an error", () => {
    const app = mount(
      <Provider store={store}>
        <App />
      </Provider>
    ).dive()
    expect(app.find('.introductoryNav').text()).toContain("Phones");
  });

})

But that test keeps failing

ypeError: Cannot read property 'data' of undefined

I also tried importing App as {App} instead and using shallow testing, but no luck. It gives the same erros, so im left without access to the context, and I cant keep doing my tests

How can I solve this?

skyboyer
  • 22,209
  • 7
  • 57
  • 64
mouchin777
  • 1,428
  • 1
  • 31
  • 59
  • Why *wouldn't* it fail? Think it through: your store is empty, so there is no props.phones. – jonrsharpe Jul 29 '20 at 22:45
  • @jonrsharpe yea i suppose thats it, but how am I supposed to test it then? do i write some mock data in the store? – mouchin777 Jul 29 '20 at 22:45
  • Well possibly you've found a bug, but if the real store has an initial value you need to provide that in the test too. There's nothing magic here, you have to arrange the test conditions to match what you actually expect in real life. – jonrsharpe Jul 29 '20 at 22:46
  • @jonrsharpe Theres no bug, redux fetches the data and displays it. So I dont really understand what im supposed to do then. – mouchin777 Jul 29 '20 at 22:49
  • Simply pass your `phones = { data: 'mock' }` prop manually in your test... – k-wasilewski Jul 30 '20 at 17:12

1 Answers1

1

You could use the non-default export of your component here and shallow render test if you pass your component the props and don't try to mock the store (if I recall correctly).

I was thinking something like this might work, tesing the "pure" non-store connected version of the component. This seems to be a popular answer for this question as this was asked (in a different way) before here:

import React from 'react';
import { App } from './App';
import { shallow } from "enzyme";

// useful function that is reusable for desturcturing the returned
// wrapper and object of props inside of beforeAll etc...
const setupFunc = overrideProps => {

  const props = {
    phones: {
      ...phones, // replace with a mock example of a render of props.phones
      data: {
        ...phoneData // replace with a mock example of a render of props.phones.data
      },
    },
    loadPhones: jest.fn()
  };

  const wrapper = shallow(<App {...props} />);

  return {
    wrapper,
    props
  };
};

// this is just the way I personally write my inital describe, I find it the easiest way
// to describe the component being rendered. (alot of the things below will be opinios on test improvements as well).
describe('<App />', () => {

  describe('When the component has intially rendered' () => {

    beforeAll(() => {
      const { props } = setupFunc();
    });


    it ('should call loadPhones after the component has initially rendered, () => {
      expect(props.loadPhones).toHaveBeenCalled();
    });
  });

  describe('When it renders WITH props present', () => {
  // we should use describes to section our tests as per how the code is written
  // 1. when it renders with the props present in the component
  // 2. when it renders without the props

    beforeAll(() => {
      const { wrapper, props } = setupFunc();
    });

    // "render without throwing an error" sounds quite broad or more like
    // how you would "describe" how it rendered before testing something
    // inside of the render. We want to have our "it" represent what we're
    // actually testing; that introductoryNave has rendered with text.

    it("should render an introductoryNav with text", () => {
      // toContain is a bit broad, toBe would be more specific
      expect(wrapper.find('.introductoryNav').text()).toBe("Phones");
    });

   it("should render a TablePhones component with data from props", () => {
      // iirc toEqual should work here, you might need toStrictEqual though. 
      expect(wrapper.find('TablePhones').prop('phones')).toEqual(props.phones);
    });
  });

  describe('When it renders WITHOUT props present', () => {

    it("should render with some loading components", () => {
     
      expect(wrapper.find('.gridLoadingContainer').exists()).toBeTruthy();
      expect(wrapper.find('CircularProgress').exists()).toBeTruthy();
      expect(wrapper.find('.loadingText1').exists()).toBeTruthy();
    });
  });
});
kJs0
  • 138
  • 1
  • 9