Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,72 @@
import { createElement } from 'lwc';
import ScheduledMaintenanceComponent from 'c/scheduledMaintenanceComponent';
import getActiveScheduledMaintenances from '@salesforce/apex/ScheduledMaintenanceService.getActiveScheduledMaintenances';
import getAppIdByDeveloperName from '@salesforce/apex/ScheduledMaintenanceService.getAppIdByDeveloperName';
import getUserLocaleInfo from '@salesforce/apex/ScheduledMaintenanceService.getUserLocaleInfo';

jest.mock(
'@salesforce/apex/ScheduledMaintenanceService.getActiveScheduledMaintenances',
() => ({ default: jest.fn() }),
{ virtual: true }
);
jest.mock(
'@salesforce/apex/ScheduledMaintenanceService.getAppIdByDeveloperName',
() => ({ default: jest.fn() }),
{ virtual: true }
);
jest.mock(
'@salesforce/apex/ScheduledMaintenanceService.getUserLocaleInfo',
() => ({ default: jest.fn() }),
{ virtual: true }
);

// Flush all pending promise microtasks
async function flushPromises() {
for (let i = 0; i < 10; i++) {
// eslint-disable-next-line no-await-in-loop
await Promise.resolve();
}
}

function isoOffset(ms) {
return new Date(Date.now() + ms).toISOString();
}

const HOUR = 60 * 60 * 1000;

function baseRecord(overrides = {}) {
return {
Id: 'rec001',
Start_Date_Time__c: isoOffset(-HOUR),
End_Date_Time__c: isoOffset(HOUR),
Dismissible__c: true,
Applicable_Apps__c: 'TestApp',
Alert_Frequency__c: 'Every Visit',
Subject__c: 'Test Maintenance',
Description__c: 'Test description',
Alert_Buffer__c: 0,
...overrides
};
}

// Find a lightning-button stub element by its label property
function findButtonByLabel(root, label) {
return Array.from(root.querySelectorAll('lightning-button')).find(el => el.label === label) || null;
}

describe('c-scheduled-maintenance-component', () => {
beforeEach(() => {
// Provide safe default mocks so tests that don't care about Apex don't throw
getActiveScheduledMaintenances.mockResolvedValue([]);
getAppIdByDeveloperName.mockResolvedValue(null);
getUserLocaleInfo.mockResolvedValue({ timeZone: 'UTC', locale: 'en-US' });
});

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);
}
jest.clearAllMocks();
});

it('TODO: test case generated by CLI command, please fill in test logic', () => {
Expand All @@ -22,4 +82,47 @@ describe('c-scheduled-maintenance-component', () => {
// const div = element.shadowRoot.querySelector('div');
expect(1).toBe(1);
});

// --- Footer button rendering driven by showNavigateButton / isDismissible ---

describe('footer button rendering', () => {
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.useRealTimers();
});

async function mountWith(records) {
getActiveScheduledMaintenances.mockResolvedValue(records);
const element = createElement('c-scheduled-maintenance-component', {
is: ScheduledMaintenanceComponent
});
document.body.appendChild(element);
await flushPromises();
return element;
}

it('shows Dismiss button and hides Navigate button when active maintenance is dismissible', async () => {
const el = await mountWith([baseRecord({ Dismissible__c: true })]);

expect(findButtonByLabel(el.shadowRoot, 'Dismiss')).not.toBeNull();
expect(findButtonByLabel(el.shadowRoot, 'Navigate to Welcome App')).toBeNull();
});

it('shows Navigate button and hides Dismiss button for a non-system app-lock (isDismissible=false, isFullLock=false)', async () => {
const el = await mountWith([baseRecord({ Dismissible__c: false, Applicable_Apps__c: 'App1' })]);

expect(findButtonByLabel(el.shadowRoot, 'Navigate to Welcome App')).not.toBeNull();
expect(findButtonByLabel(el.shadowRoot, 'Dismiss')).toBeNull();
});

it('hides both buttons during a full system lock (isDismissible=false, isFullLock=true)', async () => {
const el = await mountWith([baseRecord({ Dismissible__c: false, Applicable_Apps__c: 'System' })]);

expect(findButtonByLabel(el.shadowRoot, 'Navigate to Welcome App')).toBeNull();
expect(findButtonByLabel(el.shadowRoot, 'Dismiss')).toBeNull();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@
<div class="slds-modal__container">
<header class="slds-modal__header">
<template if:true={isDismissible}>
<template if:false={isFullLock}>
<button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse" title="Close" onclick={dismissAllRecords}>
<lightning-icon icon-name="utility:close" alternative-text="close" size="small"></lightning-icon>
<span class="slds-assistive-text">Close</span>
</button>
</template>
<button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse" title="Close" onclick={dismissAllRecords}>
<lightning-icon icon-name="utility:close" alternative-text="close" size="small"></lightning-icon>
<span class="slds-assistive-text">Close</span>
</button>
</template>
<h2 class="slds-text-heading_large">{title}</h2>
<template if:false={isDismissible}>
Expand Down Expand Up @@ -108,15 +106,11 @@ <h2 class="slds-text-heading_small slds-var-m-bottom_small"><strong>{maint.Subje
</template>
</div>
<footer class="slds-modal__footer">
<template if:false={isDismissible}>
<template if:false={isFullLock}>
<lightning-button variant="neutral" label="Navigate to Welcome App" title="Navigate to Welcome App" onclick={navigateToApp}></lightning-button>
</template>
<template if:true={showNavigateButton}>
<lightning-button variant="neutral" label="Navigate to Welcome App" title="Navigate to Welcome App" onclick={navigateToApp}></lightning-button>
</template>
<template if:true={isDismissible}>
<template if:false={isFullLock}>
<lightning-button variant="neutral" label="Dismiss" title="Dismiss" onclick={dismissAllRecords}></lightning-button>
</template>
<lightning-button variant="neutral" label="Dismiss" title="Dismiss" onclick={dismissAllRecords}></lightning-button>
</template>
</footer>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ export default class ScheduledMaintenanceComponent extends NavigationMixin(Light
fetchAndSetupNextInterval();
}

// True when the modal can be closed/dismissed (no active non-dismissible maintenance).
// isDismissible already implies !isFullLock, so the two flags are always consistent.
get showNavigateButton() {
return !this.isDismissible && !this.isFullLock;
}

// Updates the dismissible status based on system admin rights or maintenance conditions.
updateDismissibleStatus() {
const now = new Date();
Expand Down
Loading