Closed AllanOricil closed 4 years ago
Hi @AllanOricil , in the example you mentioned does not seems that is registering the test wire adapter: const getRecordWireAdapter = registerLdsTestWireAdapter(getRecord);
You can look a complete example in: https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.unit_testing_using_wire_utility
If that does not solves your case, can you share it with us?
Ok, disregard his example. The guy forgot to register the wire adapter. Our code, it is completly fine. We have everything that is needed and it does not work.
The flushPromises
method is only relevant when using a Promise. The wire
adapter is not a promise, so that won't fit your case.
It would be good to see your markup and code (anonymized if needed), otherwise it's a shot in the dark.
<template>
<template if:true={i18n}>
<lightning-input type="toggle" label={i18n.SPECIFIC_PRODUCTS} name="input4" message-toggle-active="On" message-toggle-inactive="Off" onchange={handleChange} checked={toggleOids} disabled={disableToggle}></lightning-input>
<lightning-tabset>
<lightning-tab label={i18n.TOP_RESOLUTIONS_TRUE}>
<template if:false={isDataAvailable}>
<template if:false={topResolutionDocuments}>
<lightning-tile>
<div class="slds-p-top_large medium-height">
<lightning-spinner size="small" variant="brand"></lightning-spinner>
</div>
</lightning-tile>
</template>
<template if:true={topResolutionDocuments}>
<lightning-tile>
<div class="slds-grid slds-grid_vertical">
<template for:each={topResolutionDocuments} for:item="doc">
<div key={doc.kmdocid} class="slds-col slds-p-bottom_small slds-size_12-of-12">
<div>{doc.kmdoctypedetails} - <lightning-formatted-date-time value={doc.t_date} year="numeric" month="short" day="2-digit"></lightning-formatted-date-time></div>
<lightning-formatted-url value={doc.kmurl} label={doc.title} target="_blank" ></lightning-formatted-url>
</div>
</template>
</div>
<template if:true={viewMoreDocs}>
<lightning-formatted-url value={topResolutionsViewAllUrl} label={i18n.VIEW_MORE}></lightning-formatted-url>
</template>
</lightning-tile>
</template>
</template>
</lightning-tab>
<lightning-tab label={i18n.SECURITY_BULLETINS_TITLE}>
<template if:false={isDataAvailable}>
<template if:false={securityBullletins}>
<lightning-tile>
<div class="slds-p-top_large medium-height">
<lightning-spinner size="small" variant="brand"></lightning-spinner>
</div>
</lightning-tile>
</template>
<template if:true={securityBullletins}>
<lightning-tile>
<div class="slds-grid slds-grid_vertical">
<template for:each={securityBullletins} for:item="doc">
<div key={doc.kmdocid} class="slds-col slds-p-bottom_small slds-size_12-of-12">
<div>{doc.kmdoctypedetails} - <lightning-formatted-date-time value={doc.t_date} year="numeric" month="short" day="2-digit"></lightning-formatted-date-time></div>
<lightning-formatted-url value={doc.kmurl} label={doc.title} target="_blank" ></lightning-formatted-url>
</div>
</template>
</div>
<template if:true={viewMoreSecB}>
<lightning-formatted-url value={securityBulletinViewAllUrl} label={i18n.VIEW_MORE} ></lightning-formatted-url>
</template>
</lightning-tile>
</template>
</template>
</lightning-tab>
</lightning-tabset>
<template if:true={isDataAvailable}>
<div class="slds-grid slds-grid_align-left">
<div class="slds-col slds-grid medium-height">
<div class="slds-col slds-size_1-of_12 slds-m-right_xx-small">
<lightning-icon icon-name="utility:warning" class="warning-icon" size="small"></lightning-icon>
</div>
<div class="slds-col slds-size_11-of_12">
<p id="gsd-label-url-paragraph">
<template if:true={richTextMsg}>
<lightning-formatted-rich-text value={infoMsg}></lightning-formatted-rich-text>
</template>
<template if:false={richTextMsg}>
{infoMsg}<lightning-button variant="base" label="Turn off 'Specific to My Products'" title="Turn off 'Specific to My Products'" onclick={turnOffToggle} class="slds-m-left_x-small"></lightning-button>{infoMsg1}
</template>
</p>
</div>
</div>
</div>
</template>
</template>
</template>
import { LightningElement, track, wire, api } from 'lwc';
import { loadScript, loadStyle } from 'lightning/platformResourceLoader';
import getTopResolutions from '@salesforce/apex/GSDCEPTopResolutionsController.getTopResolutions';
import getSecurityBulletins from '@salesforce/apex/GSDCEPTopResolutionsController.getSecurityBulletins';
import getGSDCEPProperties from '@salesforce/apex/GSDCEPTopResolutionsController.getGSDCEPProperties';
import TOP_RESOLUTIONS_TRUE from '@salesforce/label/c.TopResolutionstrue';
import VIEW_MORE from '@salesforce/label/c.viewMore';
import SECURITY_BULLETINS_TITLE from '@salesforce/label/c.securityBulletinTitle';
import SPECIFIC_PRODUCTS from '@salesforce/label/c.specificProducts';
import NO_PRODUCTS_LINKED from '@salesforce/label/c.noProductsLinked';
import ERROR_NO_PRODUCTS from '@salesforce/label/c.errorNoProducts';
import gsdCepTopResolutionsCss from '@salesforce/resourceUrl/gsdCepTopResolutions';
import gsdCepProductOids from '@salesforce/resourceUrl/gsdCepProductOids';
export default class GsdCepTopResolutions extends LightningElement {
@track
topResolutionDocuments;
@track
securityBullletins;
@track
viewMoreDocs = false;
@track
viewMoreSecB = false;
@api
productOids = null;
@track
toggleOids = false;
@track
disableToggle = true;
@track
toggleOidsLabel;
@track
infoMsg = null;
@track
infoMsg1 = null;
@track
richTextMsg = true;
@track
topResolutionsViewAllUrl = "/connect/s/search?toggle=OFF#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctopissue=[TopResolutionstrue]";;
@track
securityBulletinViewAllUrl = "/connect/s/search?toggle=OFF#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctypedetails=[cv5500009]";;
@track
portalHomeUrl;
i18n = {
TOP_RESOLUTIONS_TRUE,
VIEW_MORE,
SECURITY_BULLETINS_TITLE,
SPECIFIC_PRODUCTS,
NO_PRODUCTS_LINKED,
ERROR_NO_PRODUCTS
};
connectedCallback() {
Promise.all([
loadScript(this, gsdCepProductOids),
loadStyle(this, gsdCepTopResolutionsCss)
])
.then(() => {
console.log("script loaded ");
window.apiWrapper.EntitlementApi.callApis('lwc', () => {
console.log("no products: ", 'OFF');
this.productOids = null;
//this.toggleOids = false;
this.disableToggle = false;
this.toggleOidsLabel = 'OFF';
this.topResolutionsViewAllUrl = "/connect/s/search?toggle=OFF#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctopissue=[TopResolutionstrue]";
this.securityBulletinViewAllUrl = "/connect/s/search?toggle=OFF#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctypedetails=[cv5500009]";
}, (result) => {
console.log("product oids: ", result);
this.productOids = result;
//this.toggleOids = true;
this.disableToggle = false;
this.toggleOidsLabel = 'ON';
this.topResolutionsViewAllUrl = "/connect/s/search?toggle=ON#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctopissue=[TopResolutionstrue]";
this.securityBulletinViewAllUrl = "/connect/s/search?toggle=ON#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctypedetails=[cv5500009]";
}, (error) => {
console.log("error with multiple oids ", error);
this.productOids = null;
//this.toggleOids = false;
this.disableToggle = false;
this.toggleOidsLabel = "ERROR";
}) ;
})
.catch(error => {
console.log("error in loading scripts ", error);
})
}
@wire(getTopResolutions, { productOids: '$productOids', toggleOids: '$toggleOids' })
wireTopResolutions({error, data}) {
if(data != undefined && data.length > 0){
if(data.length > 3) {
this.topResolutionDocuments = data.slice(0,3);
this.viewMoreDocs = true;
} else {
this.topResolutionDocuments = data;
this.viewMoreDocs = false;
}
}else {
console.log("top resolutions error: ", error);
this.viewMoreDocs = false;
}
}
@wire(getSecurityBulletins, { productOids: '$productOids', toggleOids: '$toggleOids' })
wireSecurityBulletins({error, data}) {
if(data != undefined && data.length > 0){
if(data.length > 3) {
this.securityBullletins = data.slice(0,3);
this.viewMoreSecB = true;
} else {
this.securityBullletins = data;
this.viewMoreSecB = false;
}
}else {
console.log("security bulletins error: ", error);
this.viewMoreSecB = false;
}
}
@wire(getGSDCEPProperties)
fetchPortalHomeUrl({error, data}){
if(data){
this.portalHomeUrl = data[0].portalHomeUrl__c;
console.log('PORTAL URL: ' + this.portalHomeUrl);
}else if(error){
console.log("could not get the portalHomeUrl__c value: ", error);
}
}
handleChange(event) {
this.toggleOids = event.target.checked;
if (event.target.checked) {
if (this.infoMsg === null && this.productOids === null) {
if (this.toggleOidsLabel === 'ERROR') {
let msg = this.i18n.ERROR_NO_PRODUCTS.split("{BUTTON}");
this.infoMsg = msg[0];
this.infoMsg1 = msg[1];
this.richTextMsg = false;
} else {
this.infoMsg = this.i18n.NO_PRODUCTS_LINKED.replace("{URL}", this.portalHomeUrl);
this.infoMsg = this.i18n.NO_PRODUCTS_LINKED.replace("{URL}", "https://portal-ext-itg-h4.itcs.hpe.com/portal/site/hpsc/aae/home");
this.richTextMsg = true;
}
} else {
this.topResolutionsViewAllUrl = "/connect/s/search?toggle=ON#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctopissue=[TopResolutionstrue]";
this.securityBulletinViewAllUrl = "/connect/s/search?toggle=ON#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctypedetails=[cv5500009]";
}
} else {
this.infoMsg = null;
this.topResolutionsViewAllUrl = "/connect/s/search?toggle=OFF#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctopissue=[TopResolutionstrue]";
this.securityBulletinViewAllUrl = "/connect/s/search?toggle=OFF#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctypedetails=[cv5500009]";
}
}
turnOffToggle() {
this.toggleOids = false;
this.infoMsg = null;
this.infoMsg1 = null;
this.topResolutionsViewAllUrl = "/connect/s/search?toggle=OFF#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctopissue=[TopResolutionstrue]";
this.securityBulletinViewAllUrl = "/connect/s/search?toggle=OFF#t=Documents&sort=%40hpescuniversaldate%20descending&layout=table&f:@kmdoctypedetails=[cv5500009]";
}
get isDataAvailable() {
return this.infoMsg != null;
}
}
import { createElement } from 'lwc';
import { registerApexTestWireAdapter } from '@salesforce/lwc-jest';
import GsdCepTopResolutions from 'c/gsdCepTopResolutions';
import getTopResolutions from '@salesforce/apex/GSDCEPTopResolutionsController.getTopResolutions';
import getSecurityBulletins from '@salesforce/apex/GSDCEPTopResolutionsController.getSecurityBulletins';
import TopResolutionstrue from '@salesforce/label/c.TopResolutionstrue';
import viewMore from '@salesforce/label/c.viewMore';
import securityBulletinTitle from '@salesforce/label/c.securityBulletinTitle';
import specificProducts from '@salesforce/label/c.specificProducts';
// Realistic data with a list of top resolutions
const mockTopResolutionstList = require('./data/topResolutionsList.json');
// Realistic data with a list of security bulletins - 2 items only
const mockSecurityBulletinsList = require('./data/securityBulletinsList.json');
// An empty list of records to verify the component does something reasonable
// when there is no data to display
const mockTopResolutionsListNoRecords = require('./data/topResolutionsListNoData.json');
const apiResponse = require('./data/apiResponse.json');
// Register as Apex wire adapter. Some tests verify that provisioned values trigger desired behavior.
const topResolutionsListAdapter = registerApexTestWireAdapter(getTopResolutions);
const securityBulletinsListAdapter = registerApexTestWireAdapter(getSecurityBulletins);
jest.mock('@salesforce/label/c.TopResolutionstrue', () => {
return { default: "Top Resolutions" };
}, { virtual : true });
jest.mock('@salesforce/label/c.viewMore', () => {
return { default: "View All" };
}, { virtual : true });
jest.mock('@salesforce/label/c.securityBulletinTitle', () => {
return { default: "Security Bulletins" };
}, { virtual : true });
jest.mock('@salesforce/label/c.specificProducts', () => {
return { default: "Specific to My Products" };
}, { virtual : true });
jest.mock('EntitlementApi.callEntitlementApi', () => {
let apiResponseTmp = require('./data/apiResponse.json');
return Promise.resolve({ ok: true, json: () => Promise.resolve(apiResponseTmp.multipleProducts), jsonResponse: apiResponseTmp.multipleProducts })
}, { virtual : true });
jest.mock(
'lightning/platformResourceLoader',
() => {
return {
loadScript() {
return new Promise((resolve, reject) => {
require('../../../staticresources/gsdCepProductOids');
resolve();
});
},
loadStyle() {
return new Promise((resolve, reject) => {
global.elementResizeDetectorMaker = "success";//require('../../../staticresources/elementResizeDetector');
resolve();
});
}
};
},
{ virtual: true }
);
describe('c-topResolutions-component', () => {
afterEach(() => {
// The jsdom instance is shared across test cases in a
// single file so reset the DOM
while (document.body.firstChild) {
document.body.removeChild(document.body.firstChild);
}
// Prevent data saved on mocks from leaking between tests
jest.clearAllMocks();
});
// Helper function to mock a resolved fetch call.
function mockFetch(data1, data2) {
return jest
.fn()
.mockImplementationOnce(() =>
Promise.resolve({ ok: true, json: () => Promise.resolve(data1), jsonResponse: data1 })
)
.mockImplementationOnce(() =>
Promise.resolve({ ok: true, json: () => Promise.resolve(data2), jsonResponse: data2 })
);
}
// Helper function to wait until the microtask queue is empty.
// This is needed for promise timing.
function flushPromises() {
// eslint-disable-next-line no-undef
return new Promise(resolve => setImmediate(resolve));
}
it('Test Wire Method to get TopResolutions', () => {
fetch = global.fetch = mockFetch(apiResponse.multipleProducts, apiResponse.multipleOids);
const WIRE_PARAMETER = { productOids: '465619,465674,465616', toggleOids: false};
const element = createElement('c-topResolutions-component', {
is: GsdCepTopResolutions,
});
document.body.appendChild(element);
// Emit data from @wire
topResolutionsListAdapter.emit(mockTopResolutionstList);
securityBulletinsListAdapter.emit(mockSecurityBulletinsList);
return flushPromises().then(() => {
// THIS IS ALSO FAILING
/*expect(topResolutionsListAdapter.getLastConfig()).toEqual(
WIRE_PARAMETER
);*/
// Query lightning-tab field element
const tabFields = element.shadowRoot.querySelectorAll('lightning-tab');
// Top Resolutions and Security Bulletins
expect(tabFields.length).toBe(2);
expect(tabFields[0].label).toEqual("Top Resolutions");
expect(tabFields[1].label).toEqual("Security Bulletins");
const lightningTile = tabFields[0].childNodes[0];
const topResolutionsGrid = lightningTile.childNodes[0];
const spinner = topResolutionsGrid.querySelector('lightning-spinner');
//IT FAILS HERE
expect(spinner).toBeNull();
}
} );
});
});
JEST OUTPUT FOR THIS TEST
I put a "expect(spinner).toBeNull()" to make the test fail on purpose. The test on line 134 is passing if I remove the line 132. In summary, the spinner is rendered even after I emit mock data for the wire that fills the "topResolutionDocuments" property
Awesome how much is going on in your component. Love it!
I've a bit limited time, but I'm wondering a) what the error message for the failing getLastConfig
is and b) if it passes if you move away from your flushPromises
approach and just check in a standard Promise.resolve()
.
Also what sfdx-lwc-jest
version are you using?
My component is a mess. I know. That is why I used that guy's code as an example hahaha We are gonna fix that later using the best practices you suggest in the recipes.
a)
b) Same result!
I isntalled sfdx-lwc-jest yesterday using this page https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.unit_testing_using_jest_installation
The only difference is that I am using "scripts": { "test:unit": "lwc-jest", "test:unit:watch": "lwc-jest --watch" },
and not "scripts": { "test:unit": "sfdx-lwc-jest", "test:unit:watch": "sfdx-lwc-jest --watch" }
Hi guys. Somehow after issuing the following commands the error changed saying that I was missing one wire Adapter.
After I added the missing wire adapter I was able to continue my tests.
Description
I have a similar problem like the one described in this post. In my case, I have a wired method which fills a track property that is used in a if:true/if:false. After emiting the mock data, the component renders the if:false={property} even when the property has a value.
Steps to Reproduce
Use this guy example. Mine is similar. https://salesforce.stackexchange.com/questions/280315/lightning-web-component-unit-testing-with-get-record-and-conditional-rendering/283233#283233