Problems mocking react infinite scroll when testing with jest

190 Views Asked by At

I am having some issues testing a react infinite controller. This is my element file:

import InfiniteScroll from 'react-infinite-scroll-component';
import { List } from 'semantic-ui-react';
import styled from 'styled-components';

const StyledList = styled(List)`
  margin-bottom: 0.25rem;
  flex: 1;
  overflow-y: auto;
  height: calc(100vh - 190px);
  overflow-x: hidden;
  padding-top: 5px;

  &::-webkit-scrollbar {
    width: 5px;
    padding: 0px;
  }
`;

const StyledInfiniteScroll = styled(InfiniteScroll)`
  && {
    padding: 0;
  }
`;

export const Styled = {
  List: StyledList,
  InfiniteScroll: StyledInfiniteScroll,
};

import { ContentArea } from 'Components/shared/ContentArea';
import { FilterBox } from 'Components/shared/FilterBox';
import { InfoMessageBanner } from 'Components/shared/InfoMessageBanner';
import { debounce } from 'lodash';
import { MobXProviderContext, observer } from 'mobx-react';
import * as React from 'react';
import { RootStoreProps } from 'Stores/RootStore.types';
import { DirectoryListItem } from '../DirectoryListItem';
import { Styled } from './index.styles';

export const Directory: React.FC = observer(() => {
  const {
    search: {
      directoryPageNumber,
      getDirectorySearch,
      isDirectoryLoading,
      searchValue,
      selectDirectorySearchById,
      setDirectorySearchValue,
      isTopBarDirectoryLoading,
    },
    ui,
    conversation,
    phoneCall,
    person,
  } = React.useContext<RootStoreProps>(MobXProviderContext);

  const [pageNumber, setPageNumber] = React.useState(0);
  const [maxContacts, setMaxContacts] = React.useState(0);
  const testid = 'directory';

  React.useEffect(() => {
    const loadContacts = async () => {
      const data = await getDirectorySearch('DIRECTORY', '', 20, 1);
      if (data?.data?.hits) setMaxContacts(data?.data?.hits);
      setPageNumber(1);
    };

    loadContacts().catch((err) => console.error(err));
  }, [isTopBarDirectoryLoading]);

  const filter = debounce((q: string) => {
    setDirectorySearchValue(q);
    if (searchValue && directoryPageNumber > 1) setPageNumber(1);

    getDirectorySearch('DIRECTORY', q, 20, pageNumber);
  }, 500);

  const handleLoadMoreContacts = debounce(async () => {
    if (maxContacts === directory.data.results.length) return;

    const nextPageNumber = pageNumber + 1;
    setPageNumber(nextPageNumber);
    await getDirectorySearch(
      'DIRECTORY',
      searchValue,
      20,
      nextPageNumber,
      true
    );
  }, 500);

  const directory = selectDirectorySearchById('DIRECTORY');

  return (
    <ContentArea>
      <FilterBox
        placeholder="Search Directory (min 3 characters)"
        sendInput={filter}
        loading={isDirectoryLoading}
        testid={`${testid}-filterBoxDirectory`}
      />
      <Styled.InfiniteScroll
        dataLength={pageNumber * 20} //This is important field to render the next data
        next={handleLoadMoreContacts}
        hasMore
        loader={<React.Fragment />}
        // below props only if you need pull down functionality
        refreshFunction={handleLoadMoreContacts}
        pullDownToRefresh
        pullDownToRefreshThreshold={2}
        scrollableTarget="directory-list"
      >
        <Styled.List id="directory-list">
          {directory?.data?.results?.map(({ source: { id } }) => (
            <DirectoryListItem
              key={id}
              phoneStore={phoneCall}
              searchItemId={Number(id)}
              uiStore={ui}
              {...{ conversation, person, testid }}
            />
          ))}
          <InfoMessageBanner
            testid={`${testid}-bannerInfoNoResultsFound`}
            show={directory?.query && !directory?.data?.hits}
            content={`No results found for "${directory?.query}"`}
          />
        </Styled.List>
      </Styled.InfiniteScroll>
    </ContentArea>
  );
});

And this is my test file where i am mocking all the components and then where i am testing that the infinite scroll component is created with the correct props.

import { render } from '@testing-library/react';
import type { RenderResult } from '@testing-library/react';
import React from 'react';
import type { DirectoryPanelProps } from './types';

const mockInject = jest.fn(() => (Component) => Component);
jest.mock('mobx-react', () => ({
  ...jest.requireActual('mobx-react'),
  inject: mockInject,
  observer: (Component) => Component,
}));

const mockDirectory = jest.fn(() => <span>Directory</span>);
jest.mock('Components/DirectoryPanel/Directory', () => ({
  Directory: mockDirectory,
}));

const mockRoutes = jest.fn(({ children }) => children);
const mockRoute = jest.fn(({ element }) => element);
jest.mock('react-router-dom', () => ({
  Routes: mockRoutes,
  Route: mockRoute,
}));

const mockGridColumn = jest.fn(({ children }) => children);
jest.mock('./index.styles', () => ({
  Styled: {
    GridColumn: mockGridColumn,
  },
}));

const DEFAULT_PROPS = {
  person: { IsLoggedIn: true },
} as unknown as DirectoryPanelProps;

describe('DirectoryPanel', () => {
  let renderComponent: (props?: Partial<DirectoryPanelProps>) => RenderResult;

  beforeEach(async () => {
    const { DirectoryPanel } = await import('./index');
    renderComponent = (props) =>
      render(<DirectoryPanel {...DEFAULT_PROPS} {...props} />);
  });

  afterEach(jest.clearAllMocks);

  it('does not render when person is not logged in', () => {
    const { container } = renderComponent({
      person: { IsLoggedIn: false },
    } as unknown as DirectoryPanelProps);

    expect(container.firstChild).toBeNull();
  });

  describe.each`
    component       | mockComponent     | expectedResult
    ${'GridColumn'} | ${mockGridColumn} | ${{ children: expect.anything(), id: 'action-panel' }}
    ${'Routes'}     | ${mockRoutes}     | ${{ children: expect.anything() }}
    ${'Route'}      | ${mockRoute}      | ${{ path: '/', element: expect.anything() }}
    ${'Directory'}  | ${mockDirectory}  | ${{}}
  `('$component', ({ mockComponent, expectedResult }) => {
    it('renders with correct props', () => {
      renderComponent();

      expect(mockComponent).toBeCalledTimes(1);
      expect(mockComponent).toBeCalledWith(expectedResult, {});
    });
  });
});

The error i am having is the following:

 ● Directory › InfiniteScroll › renders with correct props

    expect(jest.fn()).toBeCalledWith(...expected)

    - Expected
    + Received

    @@ -1,7 +1,7 @@
      Object {
    -   "children": Anything,
    +   "children": <mockConstructor />,
        "dataLength": 0,
        "hasMore": true,
        "loader": <React.Fragment />,
        "next": [Function mockConstructor],
        "pullDownToRefresh": true,,
      {},

    Number of calls: 1

      105 |
      106 |       expect(mockComponent).toBeCalledTimes(1);
    > 107 |       expect(mockComponent).toBeCalledWith(expectedResult, {});
          |                             ^
      108 |     });
      109 |   });
      110 | });

      at Object.<anonymous> (src/app/components/DirectoryPanel/Directory/index.test.tsx:107:29)

Should't the expect.anything() work here? What am i doing wrong?

0

There are 0 best solutions below