From ed3474489eca3c327c79e100e6159a1f6f8f9b76 Mon Sep 17 00:00:00 2001 From: Philippe Ozil Date: Tue, 8 Aug 2023 17:00:03 +0200 Subject: [PATCH] feat: migrated from promises to async/await (#836) * feat: migrated from promises to async/await * fix: clean test CSS selectors * fix: removed duplicate lightning mocks --- .../__tests__/apexImperativeMethod.test.js | 2 + .../apexImperativeMethod.js | 18 +++-- ...xImperativeMethodWithComplexParams.test.js | 28 +++----- .../apexImperativeMethodWithComplexParams.js | 18 +++-- .../apexImperativeMethodWithParams.test.js | 2 + .../apexImperativeMethodWithParams.js | 18 +++-- .../apexWireMethodWithComplexParams.test.js | 30 ++++----- .../compositionContactSearch.test.js | 2 + .../compositionContactSearch.js | 18 +++-- .../__tests__/dispatchRefreshEvent.test.js | 8 +-- .../__tests__/editRecordScreenAction.test.js | 54 ++++++++------- .../editRecordScreenAction.js | 42 ++++++------ .../__tests__/ldsCreateRecord.test.js | 9 +-- .../lwc/ldsCreateRecord/ldsCreateRecord.html | 1 + .../lwc/ldsCreateRecord/ldsCreateRecord.js | 41 ++++++------ .../lwc/ldsDeleteRecord/ldsDeleteRecord.js | 42 ++++++------ .../ldsGenerateRecordInputForCreate.js | 39 ++++++----- .../ldsNotifyRecordUpdateAvailable.test.js | 67 +++++++------------ .../ldsNotifyRecordUpdateAvailable.js | 51 +++++++------- .../default/lwc/libsChartjs/libsChartjs.js | 21 +++--- force-app/main/default/lwc/libsD3/libsD3.js | 33 +++++---- .../__tests__/miscGetUserId.test.js | 2 +- .../miscNotificationModules.js | 8 +-- .../__tests__/wireGetPicklistValues.test.js | 27 ++++---- force-app/test/jest-mocks/lightning/alert.js | 13 ---- .../test/jest-mocks/lightning/confirm.js | 13 ---- force-app/test/jest-mocks/lightning/prompt.js | 14 ---- jest.config.js | 6 -- 28 files changed, 269 insertions(+), 358 deletions(-) delete mode 100644 force-app/test/jest-mocks/lightning/alert.js delete mode 100644 force-app/test/jest-mocks/lightning/confirm.js delete mode 100644 force-app/test/jest-mocks/lightning/prompt.js diff --git a/force-app/main/default/lwc/apexImperativeMethod/__tests__/apexImperativeMethod.test.js b/force-app/main/default/lwc/apexImperativeMethod/__tests__/apexImperativeMethod.test.js index 108cbcafc..dc36cc3de 100644 --- a/force-app/main/default/lwc/apexImperativeMethod/__tests__/apexImperativeMethod.test.js +++ b/force-app/main/default/lwc/apexImperativeMethod/__tests__/apexImperativeMethod.test.js @@ -75,6 +75,7 @@ describe('c-apex-imperative-method', () => { // Wait for any asynchronous DOM updates await flushPromises(); + await flushPromises(); const detailEls = element.shadowRoot.querySelectorAll('p:not([class])'); expect(detailEls.length).toBe(APEX_CONTACTS_SUCCESS.length); @@ -98,6 +99,7 @@ describe('c-apex-imperative-method', () => { // Wait for any asynchronous DOM updates await flushPromises(); + await flushPromises(); const errorPanelEl = element.shadowRoot.querySelector('c-error-panel'); expect(errorPanelEl).not.toBeNull(); diff --git a/force-app/main/default/lwc/apexImperativeMethod/apexImperativeMethod.js b/force-app/main/default/lwc/apexImperativeMethod/apexImperativeMethod.js index c74d07bf8..077112fc9 100644 --- a/force-app/main/default/lwc/apexImperativeMethod/apexImperativeMethod.js +++ b/force-app/main/default/lwc/apexImperativeMethod/apexImperativeMethod.js @@ -5,15 +5,13 @@ export default class ApexImperativeMethod extends LightningElement { contacts; error; - handleLoad() { - getContactList() - .then((result) => { - this.contacts = result; - this.error = undefined; - }) - .catch((error) => { - this.error = error; - this.contacts = undefined; - }); + async handleLoad() { + try { + this.contacts = await getContactList(); + this.error = undefined; + } catch (error) { + this.contacts = undefined; + this.error = error; + } } } diff --git a/force-app/main/default/lwc/apexImperativeMethodWithComplexParams/__tests__/apexImperativeMethodWithComplexParams.test.js b/force-app/main/default/lwc/apexImperativeMethodWithComplexParams/__tests__/apexImperativeMethodWithComplexParams.test.js index eb4a2b842..f99678826 100644 --- a/force-app/main/default/lwc/apexImperativeMethodWithComplexParams/__tests__/apexImperativeMethodWithComplexParams.test.js +++ b/force-app/main/default/lwc/apexImperativeMethodWithComplexParams/__tests__/apexImperativeMethodWithComplexParams.test.js @@ -66,23 +66,18 @@ describe('c-apex-imperative-method-with-complex-params', () => { document.body.appendChild(element); // Select input field for simulating string user input - const inputStringEl = element.shadowRoot.querySelector( - 'lightning-input[class="string-input"]' - ); + const inputStringEl = element.shadowRoot.querySelector('.string-input'); inputStringEl.value = APEX_PARAMETER.someString; inputStringEl.dispatchEvent(new CustomEvent('change')); // Select input field for simulating number user input - const inputNumberEl = element.shadowRoot.querySelector( - 'lightning-input[class="number-input"]' - ); + const inputNumberEl = element.shadowRoot.querySelector('.number-input'); inputNumberEl.value = APEX_PARAMETER.someInteger; inputNumberEl.dispatchEvent(new CustomEvent('change')); // Select input field for simulating list item user input - const inputListItemEl = element.shadowRoot.querySelector( - 'lightning-input[class="list-item-input"]' - ); + const inputListItemEl = + element.shadowRoot.querySelector('.list-item-input'); inputListItemEl.value = APEX_PARAMETER.someList.length; inputListItemEl.dispatchEvent(new CustomEvent('change')); @@ -114,23 +109,18 @@ describe('c-apex-imperative-method-with-complex-params', () => { document.body.appendChild(element); // Select input field for simulating string user input - const inputStringEl = element.shadowRoot.querySelector( - 'lightning-input[class="string-input"]' - ); + const inputStringEl = element.shadowRoot.querySelector('.string-input'); inputStringEl.value = APEX_PARAMETER.someString; inputStringEl.dispatchEvent(new CustomEvent('change')); // Select input field for simulating number user input - const inputNumberEl = element.shadowRoot.querySelector( - 'lightning-input[class="number-input"]' - ); + const inputNumberEl = element.shadowRoot.querySelector('.number-input'); inputNumberEl.value = APEX_PARAMETER.someInteger; inputNumberEl.dispatchEvent(new CustomEvent('change')); // Select input field for simulating list item user input - const inputListItemEl = element.shadowRoot.querySelector( - 'lightning-input[class="list-item-input"]' - ); + const inputListItemEl = + element.shadowRoot.querySelector('.list-item-input'); inputListItemEl.value = APEX_PARAMETER.someList.length; inputListItemEl.dispatchEvent(new CustomEvent('change')); @@ -140,6 +130,7 @@ describe('c-apex-imperative-method-with-complex-params', () => { // Wait for any asynchronous DOM updates await flushPromises(); + await flushPromises(); // Select p for validating conditionally changed text content const detailEl = element.shadowRoot.querySelector('p'); @@ -162,6 +153,7 @@ describe('c-apex-imperative-method-with-complex-params', () => { // Wait for any asynchronous DOM updates await flushPromises(); + await flushPromises(); const errorPanelEl = element.shadowRoot.querySelector('c-error-panel'); expect(errorPanelEl).not.toBeNull(); diff --git a/force-app/main/default/lwc/apexImperativeMethodWithComplexParams/apexImperativeMethodWithComplexParams.js b/force-app/main/default/lwc/apexImperativeMethodWithComplexParams/apexImperativeMethodWithComplexParams.js index 8334c5756..6836c99f8 100644 --- a/force-app/main/default/lwc/apexImperativeMethodWithComplexParams/apexImperativeMethodWithComplexParams.js +++ b/force-app/main/default/lwc/apexImperativeMethodWithComplexParams/apexImperativeMethodWithComplexParams.js @@ -21,7 +21,7 @@ export default class ApexImperativeMethodWithComplexParams extends LightningElem this.listItemValue = event.target.value; } - handleButtonClick() { + async handleButtonClick() { // Creating the object that represents the shape // of the Apex wrapper class. let parameterObject = { @@ -36,14 +36,12 @@ export default class ApexImperativeMethodWithComplexParams extends LightningElem // Calling the imperative Apex method with the JSON // object as parameter. - checkApexTypes({ wrapper: parameterObject }) - .then((result) => { - this.message = result; - this.error = undefined; - }) - .catch((error) => { - this.message = undefined; - this.error = error; - }); + try { + this.message = await checkApexTypes({ wrapper: parameterObject }); + this.error = undefined; + } catch (error) { + this.message = undefined; + this.error = error; + } } } diff --git a/force-app/main/default/lwc/apexImperativeMethodWithParams/__tests__/apexImperativeMethodWithParams.test.js b/force-app/main/default/lwc/apexImperativeMethodWithParams/__tests__/apexImperativeMethodWithParams.test.js index 800c5abae..a7e4f5703 100644 --- a/force-app/main/default/lwc/apexImperativeMethodWithParams/__tests__/apexImperativeMethodWithParams.test.js +++ b/force-app/main/default/lwc/apexImperativeMethodWithParams/__tests__/apexImperativeMethodWithParams.test.js @@ -102,6 +102,7 @@ describe('c-apex-imperative-method-with-params', () => { // Wait for any asynchronous DOM updates await flushPromises(); + await flushPromises(); // Select div for validating conditionally changed text content const detailEls = element.shadowRoot.querySelectorAll('p'); @@ -125,6 +126,7 @@ describe('c-apex-imperative-method-with-params', () => { // Wait for any asynchronous DOM updates await flushPromises(); + await flushPromises(); const errorPanelEl = element.shadowRoot.querySelector('c-error-panel'); expect(errorPanelEl).not.toBeNull(); diff --git a/force-app/main/default/lwc/apexImperativeMethodWithParams/apexImperativeMethodWithParams.js b/force-app/main/default/lwc/apexImperativeMethodWithParams/apexImperativeMethodWithParams.js index 55a17daa9..ee585a8cb 100644 --- a/force-app/main/default/lwc/apexImperativeMethodWithParams/apexImperativeMethodWithParams.js +++ b/force-app/main/default/lwc/apexImperativeMethodWithParams/apexImperativeMethodWithParams.js @@ -10,15 +10,13 @@ export default class ApexImperativeMethodWithParams extends LightningElement { this.searchKey = event.target.value; } - handleSearch() { - findContacts({ searchKey: this.searchKey }) - .then((result) => { - this.contacts = result; - this.error = undefined; - }) - .catch((error) => { - this.error = error; - this.contacts = undefined; - }); + async handleSearch() { + try { + this.contacts = await findContacts({ searchKey: this.searchKey }); + this.error = undefined; + } catch (error) { + this.error = error; + this.contacts = undefined; + } } } diff --git a/force-app/main/default/lwc/apexWireMethodWithComplexParams/__tests__/apexWireMethodWithComplexParams.test.js b/force-app/main/default/lwc/apexWireMethodWithComplexParams/__tests__/apexWireMethodWithComplexParams.test.js index ae0493094..b6b7bcd99 100644 --- a/force-app/main/default/lwc/apexWireMethodWithComplexParams/__tests__/apexWireMethodWithComplexParams.test.js +++ b/force-app/main/default/lwc/apexWireMethodWithComplexParams/__tests__/apexWireMethodWithComplexParams.test.js @@ -87,23 +87,20 @@ describe('c-apex-wire-method-with-complex-params', () => { document.body.appendChild(element); // Select input field for simulating string user input - const inputStringEl = element.shadowRoot.querySelector( - 'lightning-input[class="string-input"]' - ); + const inputStringEl = + element.shadowRoot.querySelector('.string-input'); inputStringEl.value = WIRE_INPUT.someString; inputStringEl.dispatchEvent(new CustomEvent('change')); // Select input field for simulating number user input - const inputNumberEl = element.shadowRoot.querySelector( - 'lightning-input[class="number-input"]' - ); + const inputNumberEl = + element.shadowRoot.querySelector('.number-input'); inputNumberEl.value = WIRE_INPUT.someInteger; inputNumberEl.dispatchEvent(new CustomEvent('change')); // Select input field for simulating list item user input - const inputListItemEl = element.shadowRoot.querySelector( - 'lightning-input[class="list-item-input"]' - ); + const inputListItemEl = + element.shadowRoot.querySelector('.list-item-input'); inputListItemEl.value = WIRE_INPUT.someList.length; inputListItemEl.dispatchEvent(new CustomEvent('change')); @@ -127,23 +124,20 @@ describe('c-apex-wire-method-with-complex-params', () => { document.body.appendChild(element); // Select input field for simulating string user input - const inputStringEl = element.shadowRoot.querySelector( - 'lightning-input[class="string-input"]' - ); + const inputStringEl = + element.shadowRoot.querySelector('.string-input'); inputStringEl.value = WIRE_INPUT.someString; inputStringEl.dispatchEvent(new CustomEvent('change')); // Select input field for simulating number user input - const inputNumberEl = element.shadowRoot.querySelector( - 'lightning-input[class="number-input"]' - ); + const inputNumberEl = + element.shadowRoot.querySelector('.number-input'); inputNumberEl.value = WIRE_INPUT.someInteger; inputNumberEl.dispatchEvent(new CustomEvent('change')); // Select input field for simulating list item user input - const inputListItemEl = element.shadowRoot.querySelector( - 'lightning-input[class="list-item-input"]' - ); + const inputListItemEl = + element.shadowRoot.querySelector('.list-item-input'); inputListItemEl.value = WIRE_INPUT.someList.length; inputListItemEl.dispatchEvent(new CustomEvent('change')); diff --git a/force-app/main/default/lwc/compositionContactSearch/__tests__/compositionContactSearch.test.js b/force-app/main/default/lwc/compositionContactSearch/__tests__/compositionContactSearch.test.js index f6f28db1b..7f4aa7765 100644 --- a/force-app/main/default/lwc/compositionContactSearch/__tests__/compositionContactSearch.test.js +++ b/force-app/main/default/lwc/compositionContactSearch/__tests__/compositionContactSearch.test.js @@ -101,6 +101,7 @@ describe('c-composition-contact-search', () => { // Wait for any asynchronous DOM updates. await flushPromises(); + await flushPromises(); const contactTileEl = element.shadowRoot.querySelector('c-contact-tile'); @@ -133,6 +134,7 @@ describe('c-composition-contact-search', () => { // for the Promise chain to complete before ending the test and fail // the test if the promise ends in the rejected state. await flushPromises(); + await flushPromises(); const errorPanelEl = element.shadowRoot.querySelector('c-error-panel'); expect(errorPanelEl).not.toBeNull(); diff --git a/force-app/main/default/lwc/compositionContactSearch/compositionContactSearch.js b/force-app/main/default/lwc/compositionContactSearch/compositionContactSearch.js index 819458ee0..daeb160da 100644 --- a/force-app/main/default/lwc/compositionContactSearch/compositionContactSearch.js +++ b/force-app/main/default/lwc/compositionContactSearch/compositionContactSearch.js @@ -14,16 +14,14 @@ export default class CompositionContactSearch extends LightningElement { window.clearTimeout(this.delayTimeout); const searchKey = event.target.value; // eslint-disable-next-line @lwc/lwc/no-async-operation - this.delayTimeout = setTimeout(() => { - findContacts({ searchKey }) - .then((result) => { - this.contacts = result; - this.error = undefined; - }) - .catch((error) => { - this.error = error; - this.contacts = undefined; - }); + this.delayTimeout = setTimeout(async () => { + try { + this.contacts = await findContacts({ searchKey }); + this.error = undefined; + } catch (error) { + this.error = error; + this.contacts = undefined; + } }, DELAY); } } diff --git a/force-app/main/default/lwc/dispatchRefreshEvent/__tests__/dispatchRefreshEvent.test.js b/force-app/main/default/lwc/dispatchRefreshEvent/__tests__/dispatchRefreshEvent.test.js index f281001a0..c616f5b7e 100644 --- a/force-app/main/default/lwc/dispatchRefreshEvent/__tests__/dispatchRefreshEvent.test.js +++ b/force-app/main/default/lwc/dispatchRefreshEvent/__tests__/dispatchRefreshEvent.test.js @@ -38,12 +38,8 @@ describe('c-dispatch-refresh-event', () => { // Wait for any asynchronous DOM updates. await flushPromises(); - // Validate dispatch refresh event on success - // Return a promise to wait for any asynchronous DOM updates. - return Promise.resolve().then(() => { - //Validate RefreshEvent is fired - expect(refreshHandler).toHaveBeenCalledTimes(1); - }); + //Validate RefreshEvent is fired + expect(refreshHandler).toHaveBeenCalledTimes(1); }); it('is accessible', async () => { diff --git a/force-app/main/default/lwc/editRecordScreenAction/__tests__/editRecordScreenAction.test.js b/force-app/main/default/lwc/editRecordScreenAction/__tests__/editRecordScreenAction.test.js index 5be673f15..3eb73b12f 100644 --- a/force-app/main/default/lwc/editRecordScreenAction/__tests__/editRecordScreenAction.test.js +++ b/force-app/main/default/lwc/editRecordScreenAction/__tests__/editRecordScreenAction.test.js @@ -18,6 +18,12 @@ describe('c-editRecordScreenAction', () => { } }); + // Helper function to wait until the microtask queue is empty. This is needed for promise + // timing when calling imperative Apex. + async function flushPromises() { + return Promise.resolve(); + } + it('Test populates name from getRecord wire', async () => { // Create initial element const element = createElement('c-editRecordScreenAction', { @@ -33,11 +39,12 @@ describe('c-editRecordScreenAction', () => { // Emit data from @wire await getRecord.emit(mockGetRecord); - // Return a promise to wait for any asynchronous DOM updates. - return Promise.resolve().then(() => { - expect(firstNameEl.value).toBe('User'); - expect(lastNameEl.value).toBe('User'); - }); + // Wait for any asynchronous DOM updates. + await flushPromises(); + + // Check values + expect(firstNameEl.value).toBe('User'); + expect(lastNameEl.value).toBe('User'); }); it('Test update record from updateRecord wire on save', async () => { @@ -57,26 +64,23 @@ describe('c-editRecordScreenAction', () => { const inputEl = element.shadowRoot.querySelectorAll('lightning-button'); inputEl[1].click(); - // Return a promise to wait for any asynchronous DOM updates. - return Promise.resolve() - .then(() => { - const expectedFields = { - fields: { - Id: RECORD_ID, - FirstName: mockGetRecord.fields.FirstName.value, - LastName: mockGetRecord.fields.FirstName.value - } - }; - expect(updateRecord).toHaveBeenCalledTimes(1); - expect(updateRecord).toHaveBeenCalledWith(expectedFields); - }) - .then(() => { - // Check if toast event has been fired - expect(handler).toHaveBeenCalled(); - expect(handler.mock.calls[0][0].detail.message).toBe( - TOAST_MESSAGE - ); - }); + // Wait for any asynchronous DOM updates. + await flushPromises(); + + // Check for record update + const expectedFields = { + fields: { + Id: RECORD_ID, + FirstName: mockGetRecord.fields.FirstName.value, + LastName: mockGetRecord.fields.FirstName.value + } + }; + expect(updateRecord).toHaveBeenCalledTimes(1); + expect(updateRecord).toHaveBeenCalledWith(expectedFields); + + // Check if toast event has been fired + expect(handler).toHaveBeenCalled(); + expect(handler.mock.calls[0][0].detail.message).toBe(TOAST_MESSAGE); }); it('Test close screen on Cancel', async () => { diff --git a/force-app/main/default/lwc/editRecordScreenAction/editRecordScreenAction.js b/force-app/main/default/lwc/editRecordScreenAction/editRecordScreenAction.js index 29addf0a4..b083184bb 100644 --- a/force-app/main/default/lwc/editRecordScreenAction/editRecordScreenAction.js +++ b/force-app/main/default/lwc/editRecordScreenAction/editRecordScreenAction.js @@ -28,7 +28,7 @@ export default class EditRecordScreenAction extends LightningElement { : null; } - handleSave() { + async handleSave() { const fields = {}; fields[ID_FIELD.fieldApiName] = this.recordId; fields[FIRSTNAME_FIELD.fieldApiName] = this.template.querySelector( @@ -39,27 +39,25 @@ export default class EditRecordScreenAction extends LightningElement { ).value; const recordInput = { fields }; - updateRecord(recordInput) - .then(() => { - this.dispatchEvent( - new ShowToastEvent({ - title: 'Success', - message: 'Contact updated', - variant: 'success' - }) - ); - - this.dispatchEvent(new CloseActionScreenEvent()); - }) - .catch((error) => { - this.dispatchEvent( - new ShowToastEvent({ - title: 'Error updating record, try again...', - message: error.body.message, - variant: 'error' - }) - ); - }); + try { + await updateRecord(recordInput); + this.dispatchEvent( + new ShowToastEvent({ + title: 'Success', + message: 'Contact updated', + variant: 'success' + }) + ); + this.dispatchEvent(new CloseActionScreenEvent()); + } catch (error) { + this.dispatchEvent( + new ShowToastEvent({ + title: 'Error updating record, try again...', + message: error.body.message, + variant: 'error' + }) + ); + } } handleCancel() { diff --git a/force-app/main/default/lwc/ldsCreateRecord/__tests__/ldsCreateRecord.test.js b/force-app/main/default/lwc/ldsCreateRecord/__tests__/ldsCreateRecord.test.js index b56511a46..ea829b9f8 100644 --- a/force-app/main/default/lwc/ldsCreateRecord/__tests__/ldsCreateRecord.test.js +++ b/force-app/main/default/lwc/ldsCreateRecord/__tests__/ldsCreateRecord.test.js @@ -36,7 +36,7 @@ describe('c-lds-create-record', () => { // Select input field for simulating user input const inputEl = element.shadowRoot.querySelector( - 'lightning-input[class="slds-var-m-bottom_x-small"]' + 'lightning-input[data-id="name"]' ); inputEl.value = USER_INPUT; inputEl.dispatchEvent(new CustomEvent('change')); @@ -67,7 +67,7 @@ describe('c-lds-create-record', () => { // Select input field for simulating user input const inputEl = element.shadowRoot.querySelector( - 'lightning-input[class="slds-var-m-bottom_x-small"]' + 'lightning-input[data-id="name"]' ); inputEl.value = USER_INPUT; inputEl.dispatchEvent(new CustomEvent('change')); @@ -78,6 +78,7 @@ describe('c-lds-create-record', () => { // Wait for any asynchronous DOM updates. await flushPromises(); + await flushPromises(); // Select element for validation const displayEl = element.shadowRoot.querySelector( @@ -105,7 +106,7 @@ describe('c-lds-create-record', () => { // Select input field for simulating user input const inputEl = element.shadowRoot.querySelector( - 'lightning-input[class="slds-var-m-bottom_x-small"]' + 'lightning-input[data-id="name"]' ); inputEl.value = USER_INPUT; inputEl.dispatchEvent(new CustomEvent('change')); @@ -141,7 +142,7 @@ describe('c-lds-create-record', () => { // Select input field for simulating user input const inputEl = element.shadowRoot.querySelector( - 'lightning-input[class="slds-var-m-bottom_x-small"]' + 'lightning-input[data-id="name"]' ); inputEl.value = USER_INPUT; inputEl.dispatchEvent(new CustomEvent('change')); diff --git a/force-app/main/default/lwc/ldsCreateRecord/ldsCreateRecord.html b/force-app/main/default/lwc/ldsCreateRecord/ldsCreateRecord.html index 81a4fdd4f..31265eed4 100644 --- a/force-app/main/default/lwc/ldsCreateRecord/ldsCreateRecord.html +++ b/force-app/main/default/lwc/ldsCreateRecord/ldsCreateRecord.html @@ -9,6 +9,7 @@ > diff --git a/force-app/main/default/lwc/ldsCreateRecord/ldsCreateRecord.js b/force-app/main/default/lwc/ldsCreateRecord/ldsCreateRecord.js index 99103e1e0..4d8cc9414 100644 --- a/force-app/main/default/lwc/ldsCreateRecord/ldsCreateRecord.js +++ b/force-app/main/default/lwc/ldsCreateRecord/ldsCreateRecord.js @@ -15,29 +15,28 @@ export default class LdsCreateRecord extends LightningElement { this.name = event.target.value; } - createAccount() { + async createAccount() { const fields = {}; fields[NAME_FIELD.fieldApiName] = this.name; const recordInput = { apiName: ACCOUNT_OBJECT.objectApiName, fields }; - createRecord(recordInput) - .then((account) => { - this.accountId = account.id; - this.dispatchEvent( - new ShowToastEvent({ - title: 'Success', - message: 'Account created', - variant: 'success' - }) - ); - }) - .catch((error) => { - this.dispatchEvent( - new ShowToastEvent({ - title: 'Error creating record', - message: reduceErrors(error).join(', '), - variant: 'error' - }) - ); - }); + try { + const account = await createRecord(recordInput); + this.accountId = account.id; + this.dispatchEvent( + new ShowToastEvent({ + title: 'Success', + message: 'Account created', + variant: 'success' + }) + ); + } catch (error) { + this.dispatchEvent( + new ShowToastEvent({ + title: 'Error creating record', + message: reduceErrors(error).join(', '), + variant: 'error' + }) + ); + } } } diff --git a/force-app/main/default/lwc/ldsDeleteRecord/ldsDeleteRecord.js b/force-app/main/default/lwc/ldsDeleteRecord/ldsDeleteRecord.js index bd48b5d67..57d3a9df7 100644 --- a/force-app/main/default/lwc/ldsDeleteRecord/ldsDeleteRecord.js +++ b/force-app/main/default/lwc/ldsDeleteRecord/ldsDeleteRecord.js @@ -24,27 +24,27 @@ export default class LdsDeleteRecord extends LightningElement { } } - deleteAccount(event) { + async deleteAccount(event) { const recordId = event.target.dataset.recordid; - deleteRecord(recordId) - .then(() => { - this.dispatchEvent( - new ShowToastEvent({ - title: 'Success', - message: 'Account deleted', - variant: 'success' - }) - ); - return refreshApex(this.wiredAccountsResult); - }) - .catch((error) => { - this.dispatchEvent( - new ShowToastEvent({ - title: 'Error deleting record', - message: reduceErrors(error).join(', '), - variant: 'error' - }) - ); - }); + + try { + await deleteRecord(recordId); + this.dispatchEvent( + new ShowToastEvent({ + title: 'Success', + message: 'Account deleted', + variant: 'success' + }) + ); + await refreshApex(this.wiredAccountsResult); + } catch (error) { + this.dispatchEvent( + new ShowToastEvent({ + title: 'Error deleting record', + message: reduceErrors(error).join(', '), + variant: 'error' + }) + ); + } } } diff --git a/force-app/main/default/lwc/ldsGenerateRecordInputForCreate/ldsGenerateRecordInputForCreate.js b/force-app/main/default/lwc/ldsGenerateRecordInputForCreate/ldsGenerateRecordInputForCreate.js index 7d3a173e1..a9138d9a1 100644 --- a/force-app/main/default/lwc/ldsGenerateRecordInputForCreate/ldsGenerateRecordInputForCreate.js +++ b/force-app/main/default/lwc/ldsGenerateRecordInputForCreate/ldsGenerateRecordInputForCreate.js @@ -41,25 +41,24 @@ export default class LdsGenerateRecordInputForCreate extends LightningElement { event.target.value; } - createAccount() { - createRecord(this.recordInput) - .then((account) => { - this.dispatchEvent( - new ShowToastEvent({ - title: 'Success', - message: 'Account created, with id: ' + account.id, - variant: 'success' - }) - ); - }) - .catch((error) => { - this.dispatchEvent( - new ShowToastEvent({ - title: 'Error creating record', - message: reduceErrors(error).join(', '), - variant: 'error' - }) - ); - }); + async createAccount() { + try { + const account = await createRecord(this.recordInput); + this.dispatchEvent( + new ShowToastEvent({ + title: 'Success', + message: 'Account created, with id: ' + account.id, + variant: 'success' + }) + ); + } catch (error) { + this.dispatchEvent( + new ShowToastEvent({ + title: 'Error creating record', + message: reduceErrors(error).join(', '), + variant: 'error' + }) + ); + } } } diff --git a/force-app/main/default/lwc/ldsNotifyRecordUpdateAvailable/__tests__/ldsNotifyRecordUpdateAvailable.test.js b/force-app/main/default/lwc/ldsNotifyRecordUpdateAvailable/__tests__/ldsNotifyRecordUpdateAvailable.test.js index 1c1d8fff7..1ab63c0e1 100644 --- a/force-app/main/default/lwc/ldsNotifyRecordUpdateAvailable/__tests__/ldsNotifyRecordUpdateAvailable.test.js +++ b/force-app/main/default/lwc/ldsNotifyRecordUpdateAvailable/__tests__/ldsNotifyRecordUpdateAvailable.test.js @@ -47,20 +47,17 @@ describe('c-lds-notify-record-update-available', () => { is: LdsNotifyRecordUpdateAvailable }); document.body.appendChild(element); - const firstNameEl = element.shadowRoot.querySelector( - 'lightning-input[class="first-name"]' - ); - const lastNameEl = element.shadowRoot.querySelector( - 'lightning-input[class="last-name"]' - ); + const firstNameEl = element.shadowRoot.querySelector('.first-name'); + const lastNameEl = element.shadowRoot.querySelector('.last-name'); // Emit data from @wire await getRecord.emit(mockGetRecord); - // Return a promise to wait for any asynchronous DOM updates. - return Promise.resolve().then(() => { - expect(firstNameEl.value).toBe('Amy'); - expect(lastNameEl.value).toBe('Taylor'); - }); + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Check input values + expect(firstNameEl.value).toBe('Amy'); + expect(lastNameEl.value).toBe('Taylor'); }); it('should update contact and call notifyRecordUpdateAvailable', async () => { @@ -82,12 +79,8 @@ describe('c-lds-notify-record-update-available', () => { await flushPromises(); //Assign values to be updated in the input elements - const firstNameEl = element.shadowRoot.querySelector( - 'lightning-input[class="first-name"]' - ); - const lastNameEl = element.shadowRoot.querySelector( - 'lightning-input[class="last-name"]' - ); + const firstNameEl = element.shadowRoot.querySelector('.first-name'); + const lastNameEl = element.shadowRoot.querySelector('.last-name'); firstNameEl.value = 'John'; lastNameEl.value = 'Doe'; @@ -98,25 +91,18 @@ describe('c-lds-notify-record-update-available', () => { // Wait for any asynchronous DOM updates await flushPromises(); - // Return a promise to wait for any asynchronous DOM updates. - return Promise.resolve() - .then(() => { - //Validate updateContact has been called - expect(updateContact).toHaveBeenCalledTimes(1); - //Validate updateContact is called with correct parameters - expect(updateContact.mock.calls[0]).toEqual([ - { firstName: 'John', lastName: 'Doe' } - ]); - //Validate notifyRecordUpdateAvailable is called - expect(notifyRecordUpdateAvailable).toHaveBeenCalledTimes(1); - }) - .then(() => { - //Validate success toast handler is called - expect(toastHandler).toHaveBeenCalledTimes(1); - expect(toastHandler.mock.calls[0][0].detail.variant).toBe( - 'success' - ); - }); + //Validate updateContact has been called + expect(updateContact).toHaveBeenCalledTimes(1); + //Validate updateContact is called with correct parameters + expect(updateContact.mock.calls[0]).toEqual([ + { firstName: 'John', lastName: 'Doe' } + ]); + //Validate notifyRecordUpdateAvailable is called + expect(notifyRecordUpdateAvailable).toHaveBeenCalledTimes(1); + + //Validate success toast handler is called + expect(toastHandler).toHaveBeenCalledTimes(1); + expect(toastHandler.mock.calls[0][0].detail.variant).toBe('success'); }); it('displays an error toast on update record error', async () => { @@ -147,12 +133,9 @@ describe('c-lds-notify-record-update-available', () => { // Wait for any asynchronous DOM updates await flushPromises(); - // Return a promise to wait for any asynchronous DOM updates. - return Promise.resolve().then(() => { - //Validate error toast handler is called - expect(toastHandler).toHaveBeenCalledTimes(1); - expect(toastHandler.mock.calls[0][0].detail.variant).toBe('error'); - }); + //Validate error toast handler is called + expect(toastHandler).toHaveBeenCalledTimes(1); + expect(toastHandler.mock.calls[0][0].detail.variant).toBe('error'); }); it('is accessible when data is returned', async () => { diff --git a/force-app/main/default/lwc/ldsNotifyRecordUpdateAvailable/ldsNotifyRecordUpdateAvailable.js b/force-app/main/default/lwc/ldsNotifyRecordUpdateAvailable/ldsNotifyRecordUpdateAvailable.js index 819a0a855..b07691640 100644 --- a/force-app/main/default/lwc/ldsNotifyRecordUpdateAvailable/ldsNotifyRecordUpdateAvailable.js +++ b/force-app/main/default/lwc/ldsNotifyRecordUpdateAvailable/ldsNotifyRecordUpdateAvailable.js @@ -26,32 +26,31 @@ export default class LdsNotifyRecordUpdateAvailable extends LightningElement { return getFieldValue(this.contact.data, LASTNAME_FIELD); } - handleContactUpdate() { - //Here we are using an imperative apex call for a simple update only to show the usage of notifyRecordUpdateAvailable - //It is preferred to use updateRecord from the UI API for a simple update. - updateContact({ - recordId: this.recordId, - firstName: this.refs.firstName.value, - lastName: this.refs.lastName.value - }) - .then(() => { - this.dispatchEvent( - new ShowToastEvent({ - title: 'Success', - message: 'Contact updated', - variant: 'success' - }) - ); - notifyRecordUpdateAvailable([{ recordId: this.recordId }]); - }) - .catch((error) => { - this.dispatchEvent( - new ShowToastEvent({ - title: 'Error updating record', - message: error.body.message, - variant: 'error' - }) - ); + async handleContactUpdate() { + try { + //Here we are using an imperative apex call for a simple update only to show the usage of notifyRecordUpdateAvailable + //It is preferred to use updateRecord from the UI API for a simple update. + await updateContact({ + recordId: this.recordId, + firstName: this.refs.firstName.value, + lastName: this.refs.lastName.value }); + this.dispatchEvent( + new ShowToastEvent({ + title: 'Success', + message: 'Contact updated', + variant: 'success' + }) + ); + notifyRecordUpdateAvailable([{ recordId: this.recordId }]); + } catch (error) { + this.dispatchEvent( + new ShowToastEvent({ + title: 'Error updating record', + message: error.body.message, + variant: 'error' + }) + ); + } } } diff --git a/force-app/main/default/lwc/libsChartjs/libsChartjs.js b/force-app/main/default/lwc/libsChartjs/libsChartjs.js index 39b862863..34979100d 100644 --- a/force-app/main/default/lwc/libsChartjs/libsChartjs.js +++ b/force-app/main/default/lwc/libsChartjs/libsChartjs.js @@ -59,21 +59,20 @@ export default class LibsChartjs extends LightningElement { } }; - renderedCallback() { + async renderedCallback() { if (this.chartjsInitialized) { return; } this.chartjsInitialized = true; - loadScript(this, chartjs) - .then(() => { - const canvas = document.createElement('canvas'); - this.template.querySelector('div.chart').appendChild(canvas); - const ctx = canvas.getContext('2d'); - this.chart = new window.Chart(ctx, this.config); - }) - .catch((error) => { - this.error = error; - }); + try { + await loadScript(this, chartjs); + const canvas = document.createElement('canvas'); + this.template.querySelector('div.chart').appendChild(canvas); + const ctx = canvas.getContext('2d'); + this.chart = new window.Chart(ctx, this.config); + } catch (error) { + this.error = error; + } } } diff --git a/force-app/main/default/lwc/libsD3/libsD3.js b/force-app/main/default/lwc/libsD3/libsD3.js index 018adfd41..72c6383f4 100644 --- a/force-app/main/default/lwc/libsD3/libsD3.js +++ b/force-app/main/default/lwc/libsD3/libsD3.js @@ -22,28 +22,27 @@ export default class LibsD3 extends LightningElement { d3Initialized = false; - renderedCallback() { + async renderedCallback() { if (this.d3Initialized) { return; } this.d3Initialized = true; - Promise.all([ - loadScript(this, D3 + '/d3.v5.min.js'), - loadStyle(this, D3 + '/style.css') - ]) - .then(() => { - this.initializeD3(); - }) - .catch((error) => { - this.dispatchEvent( - new ShowToastEvent({ - title: 'Error loading D3', - message: error.message, - variant: 'error' - }) - ); - }); + try { + await Promise.all([ + loadScript(this, D3 + '/d3.v5.min.js'), + loadStyle(this, D3 + '/style.css') + ]); + this.initializeD3(); + } catch (error) { + this.dispatchEvent( + new ShowToastEvent({ + title: 'Error loading D3', + message: error.message, + variant: 'error' + }) + ); + } } initializeD3() { diff --git a/force-app/main/default/lwc/miscGetUserId/__tests__/miscGetUserId.test.js b/force-app/main/default/lwc/miscGetUserId/__tests__/miscGetUserId.test.js index 44371abf3..2c4c74b1b 100644 --- a/force-app/main/default/lwc/miscGetUserId/__tests__/miscGetUserId.test.js +++ b/force-app/main/default/lwc/miscGetUserId/__tests__/miscGetUserId.test.js @@ -21,7 +21,7 @@ describe('c-misc-get-user-id', () => { // Query div element that displays user id. const divEl = element.shadowRoot.querySelector( - 'div[class="slds-var-m-around_medium"]' + 'div.slds-var-m-around_medium' ); expect(divEl).not.toBeNull(); expect(divEl.textContent).toBe('User Id:' + USER_ID); diff --git a/force-app/main/default/lwc/miscNotificationModules/miscNotificationModules.js b/force-app/main/default/lwc/miscNotificationModules/miscNotificationModules.js index c5b095e90..52e96cd9a 100644 --- a/force-app/main/default/lwc/miscNotificationModules/miscNotificationModules.js +++ b/force-app/main/default/lwc/miscNotificationModules/miscNotificationModules.js @@ -29,15 +29,13 @@ export default class MiscNotificationModules extends LightningElement { } } - handlePromptClick() { - LightningPrompt.open({ + async handlePromptClick() { + // Returned value is input text if OK clicked or null if cancel was clicked + this.promptValue = await LightningPrompt.open({ message: 'Please enter a value', label: 'Please Respond', defaultValue: 'initial value', theme: 'shade' - }).then((result) => { - //result is input text if OK clicked and null if cancel was clicked - this.promptValue = result; }); } } diff --git a/force-app/main/default/lwc/wireGetPicklistValues/__tests__/wireGetPicklistValues.test.js b/force-app/main/default/lwc/wireGetPicklistValues/__tests__/wireGetPicklistValues.test.js index 6e4b77a78..908d56a94 100644 --- a/force-app/main/default/lwc/wireGetPicklistValues/__tests__/wireGetPicklistValues.test.js +++ b/force-app/main/default/lwc/wireGetPicklistValues/__tests__/wireGetPicklistValues.test.js @@ -20,7 +20,7 @@ describe('c-wire-get-picklist-values', () => { } describe('getPicklistValues @wire data', () => { - it('renders seven lightning-input fields of type checkbox', () => { + it('renders seven lightning-input fields of type checkbox', async () => { // Create element const element = createElement('c-wire-get-picklist-values', { is: WireGetPicklistValues @@ -30,20 +30,17 @@ describe('c-wire-get-picklist-values', () => { // Emit data from @wire getPicklistValues.emit(mockGetPicklistValues); - // Return a promise to wait for any asynchronous DOM updates. Jest - // will automatically wait for the Promise chain to complete before - // ending the test and fail the test if the promise rejects. - return Promise.resolve().then(() => { - // Select elements for validation - const checkboxEls = - element.shadowRoot.querySelectorAll('lightning-input'); - expect(checkboxEls.length).toBe( - mockGetPicklistValues.values.length - ); - - checkboxEls.forEach((checkboxEl) => { - expect(checkboxEl.type).toBe('checkbox'); - }); + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Ensures that inputs are checkboxes + const checkboxEls = + element.shadowRoot.querySelectorAll('lightning-input'); + expect(checkboxEls.length).toBe( + mockGetPicklistValues.values.length + ); + checkboxEls.forEach((checkboxEl) => { + expect(checkboxEl.type).toBe('checkbox'); }); }); }); diff --git a/force-app/test/jest-mocks/lightning/alert.js b/force-app/test/jest-mocks/lightning/alert.js deleted file mode 100644 index dfaa5c64e..000000000 --- a/force-app/test/jest-mocks/lightning/alert.js +++ /dev/null @@ -1,13 +0,0 @@ -import { LightningElement, api } from 'lwc'; - -export default class Alert extends LightningElement { - static open() { - throw new Error( - 'The LightningAlert documentation contains examples for mocking .open in Jest' - ); - } - @api label; - @api message; - @api theme; - @api variant; -} diff --git a/force-app/test/jest-mocks/lightning/confirm.js b/force-app/test/jest-mocks/lightning/confirm.js deleted file mode 100644 index 4d6b63bd7..000000000 --- a/force-app/test/jest-mocks/lightning/confirm.js +++ /dev/null @@ -1,13 +0,0 @@ -import { LightningElement, api } from 'lwc'; - -export default class Confirm extends LightningElement { - static open() { - throw new Error( - 'The LightningConfirm documentation contains examples for mocking .open in Jest' - ); - } - @api label; - @api message; - @api theme; - @api variant; -} diff --git a/force-app/test/jest-mocks/lightning/prompt.js b/force-app/test/jest-mocks/lightning/prompt.js deleted file mode 100644 index 53b707b5c..000000000 --- a/force-app/test/jest-mocks/lightning/prompt.js +++ /dev/null @@ -1,14 +0,0 @@ -import { LightningElement, api } from 'lwc'; - -export default class Prompt extends LightningElement { - static open() { - throw new Error( - 'The LightningPrompt documentation contains examples for mocking .open in Jest' - ); - } - @api defaultValue; - @api label; - @api message; - @api theme; - @api variant; -} diff --git a/jest.config.js b/jest.config.js index 028f217c1..87902fac1 100644 --- a/jest.config.js +++ b/jest.config.js @@ -21,12 +21,6 @@ module.exports = { '/force-app/test/jest-mocks/lightning/messageService', '^lightning/actions$': '/force-app/test/jest-mocks/lightning/actions', - '^lightning/alert$': - '/force-app/test/jest-mocks/lightning/alert', - '^lightning/confirm$': - '/force-app/test/jest-mocks/lightning/confirm', - '^lightning/prompt$': - '/force-app/test/jest-mocks/lightning/prompt', '^lightning/modal*': '/force-app/test/jest-mocks/lightning/modal', '^lightning/refresh$':