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}`);
});