Skip to content

Commit

Permalink
Expand refresh view api recipes (#922)
Browse files Browse the repository at this point in the history
Add custom component view refresh recipe
  • Loading branch information
albarivas authored May 6, 2024
1 parent acb619f commit b4e3c2d
Show file tree
Hide file tree
Showing 11 changed files with 294 additions and 4 deletions.
5 changes: 5 additions & 0 deletions force-app/main/default/classes/AccountController.cls
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ public with sharing class AccountController {
return [SELECT Id, Name FROM Account WITH USER_MODE LIMIT 10];
}

@AuraEnabled(cacheable=true)
public static Integer getTotalNumber() {
return [SELECT COUNT() FROM Account WITH USER_MODE];
}

@AuraEnabled(cacheable=true)
public static Account getSingleAccount() {
return [
Expand Down
11 changes: 11 additions & 0 deletions force-app/main/default/classes/TestAccountController.cls
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ public class TestAccountController {
Assert.areEqual(10, accts.size());
}

@isTest
static void getTotalNumber_returnsCount() {
TestAccountController.createAccounts(10);

Test.startTest();
Integer accountNumber = AccountController.getTotalNumber();
Test.stopTest();

Assert.areEqual(10, accountNumber);
}

@isTest
static void getSingleAccount() {
TestAccountController.createAccounts(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@
<type>Region</type>
</flexiPageRegions>
<flexiPageRegions>
<itemInstances>
<componentInstance>
<componentName>viewToRefresh</componentName>
<identifier>c_viewToRefresh</identifier>
</componentInstance>
</itemInstances>
<name>region3</name>
<type>Region</type>
</flexiPageRegions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
</div>

<c-view-source source="lwc/dispatchRefreshEvent" slot="footer">
Refresh data in a view without reloading the page thanks to the
Create an account and refresh data in a view without reloading the
page thanks to the&nbsp;
<a
href="https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.data_refreshview"
target="_blank"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"apiName": "Contact",
"childRelationships": {},
"eTag": "846fdcd21a53214d447e578adbe263c6",
"fields": {
"Email": {
"displayValue": null,
"value": "amy@demo.net"
},
"Name": {
"displayValue": null,
"value": "Amy Taylor"
},
"Phone": {
"displayValue": null,
"value": "4152568563"
},
"Title": {
"displayValue": null,
"value": "VP of Engineering"
},
"Picture__c": {
"displayValue": null,
"value": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/amy_taylor.jpg"
}
},
"id": "0031700000pHcf8AAC",
"lastModifiedById": "00517000002fESIAA2",
"lastModifiedDate": "2019-02-15T10:33:07.000Z",
"recordTypeInfo": null,
"systemModstamp": "2019-02-15T10:33:07.000Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"apiName": "Contact",
"childRelationships": {},
"eTag": "846fdcd21a53214d447e578adbe263c6",
"fields": {
"Email": {
"displayValue": null,
"value": "amy@demo.net"
},
"Name": {
"displayValue": null,
"value": "Amy Taylor"
},
"Phone": {
"displayValue": null,
"value": "4152568563"
},
"Title": {
"displayValue": null,
"value": "VP of Engineering"
}
},
"id": "0031700000pHcf8AAC",
"lastModifiedById": "00517000002fESIAA2",
"lastModifiedDate": "2019-02-15T10:33:07.000Z",
"recordTypeInfo": null,
"systemModstamp": "2019-02-15T10:33:07.000Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { createElement } from 'lwc';
import ViewToRefresh from 'c/viewToRefresh';
import getTotalNumber from '@salesforce/apex/AccountController.getTotalNumber';
import {
registerRefreshHandler,
unregisterRefreshHandler,
RefreshEvent
} from 'lightning/refresh';
import { refreshApex } from '@salesforce/apex';

// Mock Apex wire adapter
jest.mock(
'@salesforce/apex/AccountController.getTotalNumber',
() => {
const {
createApexTestWireAdapter
} = require('@salesforce/sfdx-lwc-jest');
return {
default: createApexTestWireAdapter(jest.fn())
};
},
{ virtual: true }
);

// Mock refreshApex module
jest.mock(
'@salesforce/apex',
() => {
return {
refreshApex: jest.fn(() => Promise.resolve())
};
},
{ virtual: true }
);

describe('c-view-to-refresh', () => {
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 wait until the microtask queue is empty. This is needed for promise
// timing when calling imperative Apex.
async function flushPromises() {
return Promise.resolve();
}

it('registers itself as refresh handler on connected callback', () => {
// Create component
const element = createElement('c-view-to-refresh', {
is: ViewToRefresh
});
document.body.appendChild(element);

// Validate if pubsub got registered after connected to the DOM
expect(registerRefreshHandler).toHaveBeenCalled();
});

it('invokes getTotalNumber onload', async () => {
// Create component
const element = createElement('c-view-to-refresh', {
is: ViewToRefresh
});
document.body.appendChild(element);

// Emit data from @wire
getTotalNumber.emit(10);

// Wait for any asynchronous DOM updates
await flushPromises();

// Check UI
const divEl = element.shadowRoot.querySelector('div.account-number');
expect(divEl.textContent).toBe('Number of accounts: 10');
});

it('invokes refreshApex when RefreshEvent is listened', async () => {
// Create component
const element = createElement('c-view-to-refresh', {
is: ViewToRefresh
});
document.body.appendChild(element);

// Emit data from @wire
getTotalNumber.emit(10);

// Fire a RefreshEvent
element.dispatchEvent(new RefreshEvent());

// Wait for any asynchronous DOM updates
await flushPromises();

// Check refreshApex has been called
expect(refreshApex).toHaveBeenCalled();
});

it('unregisters itself as refresh handler on disconnected callback', () => {
// Create component
const element = createElement('c-view-to-refresh', {
is: ViewToRefresh
});
document.body.appendChild(element);

document.body.removeChild(element);

// Validate if pubsub got registered after connected to the DOM
expect(unregisterRefreshHandler).toHaveBeenCalled();
});

it('is accessible', async () => {
// Create component
const element = createElement('c-view-to-refresh', {
is: ViewToRefresh
});
document.body.appendChild(element);

// Assign mock value for resolved Apex promise
getTotalNumber.mockResolvedValue(10);

// Wait for any asynchronous DOM updates
await flushPromises();

// Check accessibility
await expect(element).toBeAccessible();
});
});
18 changes: 18 additions & 0 deletions force-app/main/default/lwc/viewToRefresh/viewToRefresh.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<template>
<lightning-card title="ViewToRefresh" icon-name="standard:account">
<div class="slds-var-m-around_medium">
<template lwc:if={numOfAccounts.data}>
<div class="account-number">
Number of accounts: {numOfAccounts.data}
</div>
</template>
<template lwc:elseif={numOfAccounts.error}>
<c-error-panel errors={numOfAccounts.error}></c-error-panel>
</template>
</div>

<c-view-source source="lwc/viewToRefresh" slot="footer">
Refresh a custom component when a Refresh View event is listened.
</c-view-source>
</lightning-card>
</template>
29 changes: 29 additions & 0 deletions force-app/main/default/lwc/viewToRefresh/viewToRefresh.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { LightningElement, wire } from 'lwc';
import getTotalNumber from '@salesforce/apex/AccountController.getTotalNumber';
import {
registerRefreshHandler,
unregisterRefreshHandler
} from 'lightning/refresh';
import { refreshApex } from '@salesforce/apex';

export default class ViewToRefresh extends LightningElement {
refreshHandlerID;

@wire(getTotalNumber)
numOfAccounts;

connectedCallback() {
this.refreshHandlerID = registerRefreshHandler(
this,
this.refreshHandler
);
}

disconnectedCallback() {
unregisterRefreshHandler(this.refreshHandlerID);
}

refreshHandler() {
refreshApex(this.numOfAccounts);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>60.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
</targets>
</LightningComponentBundle>
27 changes: 24 additions & 3 deletions force-app/test/jest-mocks/lightning/refresh.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
/**
* Refresh Event base class
*/
export const RefreshEventName = 'lightning__refreshevent';

export const RefreshEventName = 'lightning__refresh';
export class RefreshEvent extends CustomEvent {
constructor() {
super(RefreshEventName, { bubbles: true, composed: true });
super(RefreshEventName, {
composed: true,
cancelable: true,
bubbles: true
});
}
}

let eventHandler;
let elementToRefresh;
export const registerRefreshHandler = jest.fn((element, handler) => {
elementToRefresh = element;
eventHandler = handler;
window.addEventListener(
RefreshEventName,
eventHandler.bind(elementToRefresh)
);
});

export const unregisterRefreshHandler = jest.fn((id) => {
window.removeEventListener(
RefreshEventName,
eventHandler.bind(elementToRefresh)
);
});

0 comments on commit b4e3c2d

Please sign in to comment.