1

I have a LWC with a wired function hooked up to the getFiles method in an Apex class, like this:

myLwc.html

<template>
    <template if:true={showSpinner}>
        <lightning-spinner
            alternative-text="Loading"
            size="medium"
        ></lightning-spinner>
    </template>
    ...
</template>

myLwc.js

import { LightningElement, api, track, wire } from "lwc";
import getFiles from "@salesforce/apex/MyApexController.getFiles";

export default class MyLwc extends LightningElement {
    @track files;
    showSpinner = true;

    @wire(getFiles, { recordId: "$recordId" })
    loadFiles({ data, error }) {
        if (data) {
            this.files = data;
        } else if (error) {
            // ...
        }
        console.log("setting showSpinner to false");
        this.showSpinner = false;
    }
}

I want to write a test that asserts that the spinner appears in the DOM until the wired function gets its return value or errors. I'm trying to do it like this:

myLwc.test.js

import { createElement } from "lwc";
import { registerApexTestWireAdapter } from "@salesforce/sfdx-lwc-jest";
import myLwc from "c/myLwc";
import { getRecord } from "lightning/uiRecordApi";

// Set up wired data mocking
const mockGetFiles = require("./data/getFiles.json");
const getFilesWireAdapter = registerApexTestWireAdapter(getFiles);

// eslint-disable-next-line no-undef
const flushPromises = () => new Promise(setImmediate);

describe("crmOppFiles tests", () => {
    afterEach(() => {
        while (document.body.firstChild) {
            document.body.removeChild(document.body.firstChild);
        }
    });

    it("shows the spinner until files are loaded", async () => {
        console.log("starting test");
        const element = createElement("c-my-lwc", { is: myLwc });
        element.recordId = "OPP001";

        // Add the component to the DOM
        document.body.appendChild(element);
        console.log("after appendChild");

        // The spinner should be present initially
        const spinner = element.shadowRoot.querySelector("lightning-spinner");
        expect(spinner).toBeTruthy(); // IT FAILS HERE

        // Simulate the getRecord wire service returning data
        getFilesWireAdapter.emit(mockGetFiles);

        // Wait for all async processes to complete
        await flushPromises();

        // Now that all initial data retrieval is complete, the spinner should
        // be hidden
        expect(spinner).toBeFalsy();
    });
});

My console output shows up in the following order...

starting test
setting showSpinner to false
after appendChild

... which tells me the LWC framework doesn't actually wait until you call getRecordWireAdapter.emit() to execute the wired function.

That being the case, is there any way to test for conditions that are present before the wire service returns a response (like spinners, etc)?

0

On closer inspection, I found out that the @wire-decorated function gets called immediately when the component loads, before there is an actual response. data and error are both undefined in that call. So my assumption that the function only got called based on a true data/error response was misplaced.

Rewriting my LWC like this, now the test passes:

@wire(getFiles, { recordId: "$recordId" })
loadFiles({ data, error }) {
    if (data) {
        this.files = data;
    } else if (error) {
        // ...
    }
    if (data || error) {
        this.showSpinner = false;
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.