'Jest - how to mock function in initialised class instance

I have the following module:

import { MetadataStore } from 'metadata-store';
import { AttributeMap } from 'aws-sdk/clients/dynamodb';

const dataStore = new MetadataStore();

export async function getContentData(
  dataIds: string[]
): Promise<AttributeMap[]> {
  try {
    return dataStore.getBatch(dataIds);
  } catch (error) {
    logger.error('getContentData error', error);
    throw error;
  }
}

I'm trying to mock the call to getBatch, but I get an error that dataStore is mock constructor and does not a getBatch defined.

This is my test file:

import { mocked } from 'ts-jest/utils';
import * as dataStoreSdk from 'metadata-store';
import { getContentData } from '../metaDataSdk';

jest.mock('metadata-store', () => {
  return {
    MetadataStore: jest.fn()
  };
});

let getBatchMocked: jest.Mock;

describe('getContentData tests', () => {
  beforeEach(() => {
    getBatchMocked = jest.fn();

    mocked(dataStoreSdk.MetadataStore).mockImplementation(() => {
      return { getBatch: getBatchMocked } as unknown as dataStoreSdk.MetadataStore;
    });
  });

  it('Should return successful response', async () => {
    // eslint-disable-next-line @typescript-eslint/camelcase
    getBatchMocked.mockResolvedValue({ is_deleted: true });

    const response = await getContentData(['id_1']);
    expect(response).toEqual(1);

    expect(getBatchMocked.mock.calls.length).toEqual(1);
    expect(getBatchMocked).toHaveBeenCalledWith(1);
  });
});

another attempt which results in a different error:

import { mocked } from 'ts-jest/utils';
import * as dataStoreSdk from 'metadata-store';
import { getContentData } from '../metaDataSdk';

let getBatchMocked: jest.Mock = jest.fn();

jest.mock('metadata-store', () => {
  return {
    MetadataStore: {
      getBatch: getBatchMocked
    }
  };
});

describe('getContentData tests', () => {
  beforeEach(() => {
    getBatchMocked = jest.fn();

    mocked(dataStoreSdk.MetadataStore).mockImplementation(() => {
      return { getBatch: getBatchMocked } as unknown as dataStoreSdk.MetadataStore;
    });
  });

  it('Should return successful response', async () => {
    // eslint-disable-next-line @typescript-eslint/camelcase
    getBatchMocked.mockResolvedValue({ is_deleted: true });

    const response = await getContentData(['id_1']);
    expect(response).toEqual(1);

    expect(getBatchMocked.mock.calls.length).toEqual(1);
    expect(getBatchMocked).toHaveBeenCalledWith(1);
  });
});

ReferenceError: Cannot access 'getBatchMocked' before initialization

Please advise how can I mock this module?



Solution 1:[1]

Typically to test this, you need to use dependency injection to send the data store into the class instead of creating a new instance. That way, you can mock the service, and have the return set there. The constructor would take the instance if using a class, or pass the object to your function.

export async function getContentData(dataStore: MetadataStore, dataIds: string[]): Promise<AttributeMap[]> {}

Then the test would have something like:

 it('Should return successful response', async () => {
     getBatchMocked.mockResolvedValue({ is_deleted: true });
     const response = await getContentData(getBatchedMock, ['id_1']);
     ...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Steven Scott