Jest spyOn is not detecting my function call

Viewed 455

I am writing unit tests for a process that creates products on a site based on the contents in the database. I know this process is working but as a best practice, I am adding the unit test below:

  describe('Creations Endpoints', () => {
    it('should create new product in Woo', async () => {
      await cronHelper.getNewProductsAndUploadToWoo();
      expect(getItemSkusWithWebContentSpy).toHaveBeenCalledTimes(1);
      expect(getAllProductsSpy).toHaveBeenCalledTimes(1);
      expect(getItemLocationDetailSpy).toHaveBeenCalledTimes(1);
      expect(getItemMasterSpy).toHaveBeenCalledTimes(1);
      expect(getItemWebContentBySkuSpy).toHaveBeenCalledTimes(1);
      expect(createProductSpy).toHaveBeenCalledTimes(1);
    });
  });

Here are the setups for the Spies:

beforeEach(async () => {
  getItemSkusWithWebContentSpy = jest
    .spyOn(opSuiteFunctions, 'getItemSkusWithWebContent')
    .mockImplementation(() => Promise.resolve(opsuiteData.getItemSkusWithWebContentData));
  getAllProductsSpy = jest.spyOn(wooFunctions, 'getAllProducts').mockImplementation(() => Promise.resolve(wooData.getAllProductsData.data));
  getItemLocationDetailSpy = jest
    .spyOn(opSuiteFunctions, 'getItemLocationDetail')
    .mockImplementation(() => Promise.resolve(opsuiteData.GetItemLocationDetailTransformed));
  getItemMasterSpy = jest.spyOn(opSuiteFunctions, 'getItemMaster').mockImplementation(() => Promise.resolve(opsuiteData.getItemMaster));
  getItemWebContentBySkuSpy = jest
    .spyOn(opSuiteFunctions, 'getItemWebContentBySku')
    .mockImplementation(() => Promise.resolve(opsuiteData.getItemWebContentBySku));
  createProductSpy = jest.spyOn(wooFunctions, 'createProduct').mockImplementation(() => Promise.resolve({ status: 201, headers: 'abc', data: 'tings' }));
  editProductSpy = jest.spyOn(wooFunctions, 'editProduct').mockImplementation(() => Promise.resolve({ status: 201, headers: 'def', data: 'stuff' }));
});

afterEach(() => {
  [getItemSkusWithWebContentSpy, getAllProductsSpy, getItemLocationDetailSpy, getItemMasterSpy, createProductSpy].forEach((mock) => {
    if (mock) mock.mockRestore();
  });
});

These are set up to return data objects to mock the various API calls. When I run the test I see logging output that indicates that all the functions have been called correctly. However, the test results do not reflect this:

  ● Cron Tests › Creations Endpoints › should create new product in Woo

    expect(jest.fn()).toHaveBeenCalledTimes(expected)

    Expected number of calls: 1
    Received number of calls: 0

      64 |       expect(getItemWebContentBySkuSpy).toHaveBeenCalledTimes(1);
    > 65 |       expect(createProductSpy).toHaveBeenCalledTimes(1);
         |                                ^
      66 |     });

      at Object.<anonymous> (tests/cronHelper.test.js:65:32)

As I said, I am logging at various steps and I can see that createProductSpy is called and the test data is returned as defined in the Spy above.

Here is the createProduct section of the actual code that I am trying to test:

      // GetItemLocationDetail
      let getItemLocationDetailPromise = new Promise((resolve, reject) => {
        opSuiteFunctions
          .getItemLocationDetail(sku)
          .then((itemLocationDetail) => {
            resolve(itemLocationDetail);
          })
          .catch((err) => {
            reject(err);
          });
      }).catch((err) => console.error(err));

      // GetItemMaster
      let getItemMasterPromise = new Promise((resolve, reject) => {
        opSuiteFunctions
          .getItemMaster(sku)
          .then((item) => {
            resolve(item);
          })
          .catch((err) => {
            reject(err);
          });
      }).catch((err) => console.error(err));

      // GetItemWebContentBySku
      let getItemWebContentBySku = new Promise((resolve, reject) => {
        opSuiteFunctions
          .getItemWebContentBySku(sku)
          .then((itemWebContentBySku) => {
            resolve(itemWebContentBySku);
          })
          .catch((err) => {
            reject(err);
          });
      });

      const { itemLocationDetail, itemMaster, itemWebContent } = await Promise.all([getItemLocationDetailPromise, getItemMasterPromise, getItemWebContentBySku])
        .then(([itemLocationDetail, itemMaster, itemWebContent]) => {
          return { itemLocationDetail, itemMaster, itemWebContent };
        })
        .catch((err) => {
          throw { message: `Failed to resolve promise: `, details: err };
        });

      // Create the product object
      let product = {
       ...
      };

      // Create the product in WooCommerce
      const createResult = await wooFunctions
        .createProduct(product)
        .then((res) => {
          return res;
        })
        .catch((err) => {
          throw { message: `Failed to create product with sku: ${sku}`, details: err };
        });

      if (createResult.status !== 201) {
        throw { message: `Failed to create product with sku: ${sku}`, details: `createProduct returned with response ${createResult}` };
      }

      console.info(`Successfully created product with sku: ${sku}`);
    });
1 Answers

I solved this by wrapping the expect(createProductSpy).toHaveBeenCalledTimes(1); in a setTimeout.

Related