sfdx-lwc-jest
sfdx-lwc-jest copied to clipboard
Issue when test connectedCallback method on LWC component that use more that one module mock
Description
connectedCallback method does not complete calls to mock modules before tests start.
Steps to Reproduce
customComponent.js
import {api, LightningElement} from "lwc";
import getResult01 from "@salesforce/apex/Controller01.getResult01";
import getResult02 from "@salesforce/apex/Controller02.getResult02";
export default class CustomComponent extends LightningElement {
value01;
value02;
@api
getValue01() {
return this.value01;
}
@api
getValue02() {
return this.value02;
}
async connectedCallback() {
await this.initialization();
}
@api
async customMethod() {
await this.initialization();
}
async initialization() {
console.log("starting callback");
const result01 = await getResult01();
console.log("result 01 is", result01);
this.value01 = result01.field0101;
const result02 = await getResult02();
console.log("result 02 is", result02);
this.value02 = result02.field0201;
console.log("ending callback");
}
}
customComponent.test.js
import {createElement} from 'lwc';
import getResult01 from "@salesforce/apex/Controller01.getResult01";
import getResult02 from "@salesforce/apex/Controller02.getResult02";
import CustomComponent from "../customComponent";
jest.mock(
"@salesforce/apex/Controller01.getResult01",
() => {
return {default: jest.fn()};
},
{virtual: true}
);
jest.mock(
"@salesforce/apex/Controller02.getResult02",
() => {
return {default: jest.fn()};
},
{virtual: true}
);
async function flushPromises() {
return Promise.resolve();
}
const createComponent = async (attributes) => {
const element = createElement("custom-component", {
is: CustomComponent
});
Object.assign(element, attributes);
document.body.appendChild(element);
await flushPromises();
return element;
};
describe("custom component test", () => {
afterEach(() => {
while (document.body.firstChild) {
document.body.removeChild(document.body.firstChild);
}
jest.clearAllMocks();
});
it("connectedCallback", async () => {
getResult01.mockResolvedValue({
field0101: "a",
field0102: "b"
});
getResult02.mockResolvedValue({
field0201: "c",
field0202: "d"
});
const element = await createComponent();
window.console.log("value 01", element.getValue01());
window.console.log("value 02", element.getValue02());
});
it("customMethod", async () => {
getResult01.mockResolvedValue({
field0101: "a",
field0102: "b"
});
getResult02.mockResolvedValue({
field0201: "c",
field0202: "d"
});
const element = await createComponent();
await element.customMethod();
window.console.log("value 01", element.getValue01());
window.console.log("value 02", element.getValue02());
});
});
Expected Results
First tests work as expected. Please note that the second test is for check the correct code flow.
Actual Results
First test fails. The first value (the result to call getResult01) is correct, but the second value (the result to call getResult02) is undefined.
Version
- @salesforce/sfdx-lwc-jest: 1.1.0
- Node: 18.12.0
Possible Solution
No solution found.
Additional context/Screenshots
- Run the test one by time
- To run the second test comment the connectedCallback method (to avoid confusions)
I copy/pasted the code and ran the test and both pass for me:
PASS force-app/main/default/lwc/customComponent/__tests__/customComponent.test.js
custom component test
√ connectedCallback (143 ms)
√ customMethod (15 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3.918 s
Ran all test suites matching /force-app\\main\\default\\lwc\\customComponent\\/i.
Using:
- sfdx-lwc-jest: 1.4.1
- Node: 18.9.0
- Windows 10
Can you consolidate the Apex into a single call? It seems strange to make two calls to Apex in a connectedCallback instead of a single call that would return the data both calls would make, since each call is a separate trip to the server and it would be more efficient to bundle the needed data in a single call.
For example, if you have:
@AuraEnabled
public static Map<String, String> getResult01() {
return new Map<String, String>{
'field0101' => 'a',
'field0102' => 'b'
};
}
@AuraEnabled
public static Map<String, String> getResult02() {
return new Map<String, String>{
'field0201' => 'c',
'field0202' => 'd'
};
}
Then you could do something like:
public static Map<String, String> getResult01() {
return new Map<String, String>{
'field0101' => 'a',
'field0102' => 'b'
};
}
public static Map<String, String> getResult02() {
return new Map<String, String>{
'field0201' => 'c',
'field0202' => 'd'
};
}
@AuraEnabled
public static Map<String, Map<String, String>> getResults() {
return new Map<String, Map<String, String>>{
'result01' => getResult01(),
'result02' => getResult02()
};
}
And in the initialization:
async initialization() {
const results = await getResults();
this.value01 = results.result01.field0101;
this.value02 = results.result02.field0201;
}
@vdyn Could you provide a GitHub repo with the necessary code and steps to reproduce the issue?