I've been writing lwcs since they came out, but never wrote unit tests for them. Just getting my feet wet here :)

I have an lwc with three datatables. The first one has row actions that process the row and then removes if from the first datatable rows (data array) and adds it to one of the others.

The code is working - I see it when I manually test on the page, and I also put console.log lines in the lwc js controller to debug the number of rows before and after.

However, when I test it, the numbers don't match.

LWC js file:

        console.log('before remove ili row, the invoiceLineItem length: ', this.invoiceLineItems.length);
        this.invoiceLineItems.forEach(inv => {console.log('the ili id: ', inv.Id, ' matches iliRow.Id: ', iliRow.Id, ': ', (inv.Id !== iliRow.Id))});
        this.invoiceLineItems = this.invoiceLineItems.filter(invLI => invLI.Id !== iliRow.Id);
        console.log('after remove ili row, the ili length: ', this.invoiceLineItems.length);

Test js:

const detailEls = element.shadowRoot.querySelectorAll('lightning-datatable');
const billedDataTable = detailEls[0];
const originalBilledRows = billedDataTable.data.length; //outputs 22


billedDataTable.dispatchEvent(confirmRowActionEvent);      // this calls the method in the controller, the logs are printed in the terminal
return Promise.resolve().then(() => {
       const detailEls2 = element.shadowRoot.querySelectorAll('lightning-datatable');
       const billedRows2 = detailEls2[0].data.length;
        //assert that there is one less billed
        expect(billedRows2).toBe(originalBilledRows - 1);    


Expected: 21
Received: 22

How can I force the test to recognize the new data rows?

  • what do your console logs say? Have you added more info to them to verify the data provided in the test is the issue? What is being included in that confirmRowAction - put another way, are you providing the necessary details that a real row action would provide in manual testing? Commented Jul 14, 2022 at 19:53
  • 1
    Yes - the console logs show that the filter worked and that the row is being removed from the first datatable. console.log before remove ili row, the invoiceLineItem length: 22 and after remove ili row, the ili length: 21
    – hgolov
    Commented Jul 14, 2022 at 19:55
  • What if you try adding async to not run immediately after the promise is resolved? ex. return Promise.resolve().then(async () => {.... Similarly, you can try using the async function used in the lwc-recipes repo which will accomplish the same thing Commented Jul 15, 2022 at 13:24
  • Thank you! That worked. It seems the Trailhead examples are outdated. I was using that format. If you make the comment an answer, I'll be able to mark it as correct. @KrisGoncalves
    – hgolov
    Commented Jul 17, 2022 at 9:04

1 Answer 1


lwc-recipes has a helper function it uses to

wait until the microtask queue is empty. This is needed for promise timing when calling imperative Apex.

async function flushPromises() {
    return Promise.resolve();

//in their actual test
await flushPromises();

Writing it out in a similar manner to what you're attempting the above becomes

return Promise.resolve().then(async () => {
    //query & do assertions on dom

You'll notice it's similar to what you're attempting expect for the addition of the async function.

Why can this be helpful?

As the code comment says - promise timing is important when LWC makes its own DOM changes, can call imperative apex, etc. My previous answer regarding the event loop is relevant to this.

Not sure of all your specifics and what happens when table 1 re-renders - but, the above ensures your test is querying selectors after all the relevant microtasks have occurred (tracked changes to your array property, dom re-render).

You must log in to answer this question.

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