LWC jest mocking ‘@salesforce/apex/refreshApex’ problem

lightning-web-componentslwc-jestmock

I'm trying to get my arms around testing LWC. I'm trying to test a button click that calls some Apex, then calls 'refreshApex' and then throws a success toast.

It seems I'm mocking my own custom Apex call ok. I'm not sure how to mock this 'refreshApex' call I'm using so that it returns a promise. I import it via

import {refreshApex} from "@salesforce/apex";

Here's the lwc:

import {NavigationMixin} from 'lightning/navigation';
import {getFieldValue, getRecord} from "lightning/uiRecordApi";
import {ShowToastEvent} from "lightning/platformShowToastEvent";
import {refreshApex} from "@salesforce/apex";
import {reduceErrors} from 'c/ldsUtils';

import addAdministratorRestCall
    from '@salesforce/apex/ALSLicenceController.addAdministrator';


export default class LicenceAdministratorsOnLicence extends NavigationMixin(LightningElement) {

    @api
    recordId;

    getAdministratorsResult;

    selectedContactId;

    @wire(getRecord, {recordId: '$recordId', fields: [LICENCE_GUID_FIELD]})
    licence;

    @wire(getRecord,
        {recordId: '$selectedContactId', fields: [CONTACT_GUID_FIELD]})
    selectedContact;

    handleAdd() {
        addAdministratorRestCall({
            licenceGuid: this.licenceGuid,
            contactGuid: this.selectedContactGuid
        })
        .then((result) => {
            refreshApex(this.getAdministratorsResult);
        })
        .then((result) => {
            this.throwSucceededToast('Licence Administrator added');
        })
        .catch((errors) => {
            this.throwFailedToast(errors);
        })
        .finally(() => {
            this.closeModal();
        });
    }

    throwSucceededToast(message) {
        this.dispatchEvent(
            new ShowToastEvent({
                title: 'Success',
                message: message,
                variant: 'success'
            })
        );
    }

    throwFailedToast(errors) {
        let errorMsg = String(reduceErrors(errors));
        this.dispatchEvent(
            new ShowToastEvent({
                title: 'Error',
                message: errorMsg,
                variant: 'error',
                mode: 'sticky'
            })
        );

        this.closeModal();
    }

    
    get licenceGuid() {
        return getFieldValue(this.licence.data, LICENCE_GUID_FIELD);
    }

    get selectedContactGuid() {
        return getFieldValue(this.selectedContact.data, CONTACT_GUID_FIELD);
    }

}

here's the test:

import {createElement} from 'lwc';
import {getRecord} from 'lightning/uiRecordApi';
import {ShowToastEventName} from 'lightning/platformShowToastEvent';
import {registerApexTestWireAdapter, registerLdsTestWireAdapter} from '@salesforce/sfdx-lwc-jest';

// how do I mock this?
import {refreshApex} from "@salesforce/apex";

import addAdministratorRestCall from '@salesforce/apex/LicenceController.addAdministrator';

const mockedResponses = require('./data/mockedResponses.json');
const getLicenceAdministratorsAdapter = registerApexTestWireAdapter(getLicenceAdministrators);
const getLicenceAdapter = registerLdsTestWireAdapter(getRecord);
const getContactAdapter = registerLdsTestWireAdapter(getRecord);
const addAdministratorAdapter = registerApexTestWireAdapter(addAdministratorRestCall);

    jest.mock(
        '@salesforce/apex/LicenceController.addAdministrator',
        () => {
            return {
                default: jest.fn(() => Promise.resolve({ data: {} }))
            };
        },
        { virtual: true }
    );


    it('handles contact change', () => {
        const element = createElement('c-licence-administrators-on-licence', {
            is: LicenceAdministratorsOnLicence
        });

        getLicenceAdministratorsAdapter.emit(mockedResponses.testAdministrators);
        getUserPermissionsAdapter.emit(mockedResponses.allowed);
        document.body.appendChild(element);

        const showToastHandler = jest.fn();
        const refreshApexHandler = jest.fn(() => Promise.resolve({ data: {} }));

        element.addEventListener(ShowToastEventName, showToastHandler);
        element.addEventListener(refreshApex, refreshApexHandler);

        getLicenceAdapter.emit(mockedResponses.testLicence);
        getContactAdapter.emit(mockedResponses.testContact);

        return Promise.resolve().then(() => {
            const addAdministratorButton = element.shadowRoot.querySelector("lightning-button[data-id=add-administrator]");
            addAdministratorButton.click();
        }).then(()=> {
            const submitButton = element.shadowRoot.querySelector("lightning-button[data-id=submit-button]");
            submitButton.click();
        }).then(()=> {
            expect(showToastHandler).toBeCalledTimes(1);
        })

    });
});

I appreciate any guidance

Best Answer

You need to mock the refreshApex module just like you mock the apex method modules as well.

import { refreshApex } from "@salesforce/apex";

jest.mock(
    "@salesforce/apex",
    () => {
        return {
            refreshApex: jest.fn(() => Promise.resolve()),
        };
    },
    { virtual: true }
);

...

Then, in your actual tests you can assert it's been called however many times you expect

expect(refreshApex).toHaveBeenCalledTimes(1);

Or, provide a mock response to the refresh call before the test runs

refreshApex.mockResolvedValue(someMockedValueYouCreate);