5

When I read the sample code in lwc-recipes, it gives me a feeling that in side Promise().resolve().then() in jest method, the subscription of the published message should be received. However, our code looks something like below:

In lwc js:

  connectedCallback() {
    this.subscription = subscribe(
      this.messageContext,
      UpdateAccountsAndGoals,
      (message) => {
      //it seems to me this part is not executed during test
      }

In jest test:

const messageContextWireAdapter = registerTestWireAdapter(MessageContext);
  it("test update accounts and goals secenario", () => {
    getBalances.mockResolvedValue(APEX_FACCOUNTS_SUCCESS);

    const element = createElement('c-account-balances', {
        is: accountBalances
    });
    document.body.appendChild(element);

    const payload = {
      update: true
    };
    publish(messageContextWireAdapter, UpdateAccountsAndGoals, payload);

    return Promise.resolve().then(() => {
        const balanceEle = element.shadowRoot.querySelector('article');
        expect(balanceEle).not.toBeNull();
    });
  });

It seems to me that even if I executed the shadowRoot and query Selector part inside Promise.resolve().then() the subscription is still not done yet.

Is there a method similar to test.stopTest() to force that happen?

---------Edit---------

I wrote a small proof of concept lwc js file and test file to demonstrate the issue according to the request.

So here is the complete lwc js file:

import { LightningElement, wire } from 'lwc';
import { publish, subscribe, MessageContext } from "lightning/messageService";
import UpdateAccountsGoalsTimed from "@salesforce/messageChannel/FinancialAccountGoalsTimedUpdate__c";

export default class SamplePubSub extends LightningElement {
    @wire(MessageContext)
  messageContext;
  subscription = null;
  triggerUpdate;

    connectedCallback() {
      this.subscription = subscribe(
        this.messageContext,
        UpdateAccountsGoalsTimed,
        (message) => {
          if (message.update) {
            this.triggerUpdate = true;
            this.update();
          }
        }
      );
    }

  update() {
    console.log('test');
  }
}

And the complete jest test file:

import samplePubSub from "c/samplePubSub";
import { createElement } from "lwc";
import { publish, subscribe, MessageContext } from "lightning/messageService";
import {
    registerLdsTestWireAdapter,
    registerTestWireAdapter
} from '@salesforce/sfdx-lwc-jest';
import UpdateAccountsGoalsTimed from "@salesforce/messageChannel/FinancialAccountGoalsTimedUpdate__c";

const messageContextWireAdapter = registerTestWireAdapter(MessageContext);

describe("c-samplePubSub", () => {
  //clean the dom and mocks in between test runs
  afterEach(() => {
    while (document.body.firstChild) {
      document.body.removeChild(document.body.firstChild);
    }
    jest.clearAllMocks();
  });

  it("test pub sub", () => {
    const element = createElement('c-samplePubSub', {
        is: samplePubSub
    });
    document.body.appendChild(element);
    
    const payload = {
      update: true
    };
    publish(messageContextWireAdapter, UpdateAccountsGoalsTimed, payload);

    return Promise.resolve().then(() => {
      expect(subscribe).toHaveBeenCalled();
    });
  });
});

When I run the coverage on this test, it shows that Line 16-25 is not covered which means the resolve part is not executed.

6
  • Can you add a full code where I can repro the test execution? The resolve should have happened Jan 6, 2021 at 14:15
  • Hi @MohithShrivastava sorry I can't post the whole set of code. I posted another example of code which is pretty end to end and the comment explains what is not covered in that scenario. Do you mind to take a look?
    – Lance Shi
    Jan 7, 2021 at 2:49
  • it should be MRP code so I can at least replicate! Could be simple example! I will try with what you have in the question! Jan 7, 2021 at 3:32
  • 1
    @MohithShrivastava I have written a small proof of concept code in the edit area which includes the whole js and jest file, which can demonstrate my issue
    – Lance Shi
    Jan 7, 2021 at 4:18
  • Excellent 👌 will take a peak once I have a chance! Jan 7, 2021 at 4:19

1 Answer 1

6

The callback function in your code is not getting called because the standard stubs for lightning messaging service that ship with the sfdx-lwc-jest for the project do not implement it.

Since the project is open source you can easily take a peek at the stub implementation here. Notice clearly how the subscribe function is stubbed

export const subscribe = jest.fn();

What we want to do is write our own stub so that we can pass in the callback. Something like below

// LMS stub implementation that lets you test a single message handler on a 
single channel
var _messageChannel = null;
var _messageHandler = null;

export const subscribe = jest.fn(
(messageContext, messageChannel, messageHandler) => {
    _messageChannel = messageChannel;
    _messageHandler = messageHandler;
 }
);

Create your own custom stub implementation using the moduleNameMapper config of jest

Steps

  1. Create folders in the force-app with the following paths /tests/jest-mocks/lightning(You create tests, jest-mocks, and lightning folders in the same hierarchy as I have listed in the path)

  2. Create a file named messageService.js within the lightning folder in step one with the code file here.

  3. Create a jest.config.js in your project root with the below configuration

    const { jestConfig } = require('@salesforce/sfdx-lwc-jest/config');
    module.exports = {
     ...jestConfig,
     moduleNameMapper: {
     '^lightning/messageService$':
         '<rootDir>/force-app/tests/jest-mocks/lightning/messageService'
       }
    };
    

Rerun the test with the new config and you should see those uncovered lines covered.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .