Files
advanced-camera-card/tests/components-lib/notification/notification-popup-controller.browser.test.ts
T

168 lines
4.8 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import type { Notification } from '../../../src/config/schema/actions/types';
import { createLogAction } from '../../../src/utils/action';
import {
clickElement,
deepQuery,
getFocusedElement,
pressKey,
pressTab,
} from '../../browser/dom';
import { MountedCardFactory, type MountedCard } from '../../browser/mounted-card';
import {
CARD_INITIALIZED_MESSAGE,
createGenericCameraHASS,
createInitializedAutomation,
createStillImageCardConfig,
} from '../../browser/test-utils';
const TRIGGER_ENTITY = 'input_boolean.notify';
const BODY_TEXT = 'This camera does not support two-way audio.';
const CONTROL_TAPPED_MESSAGE = /control tapped/;
const NOTIFICATION: Notification = {
heading: { text: 'Two-way audio unavailable' },
body: { text: BODY_TEXT },
};
const mount = async (
notification: Notification = NOTIFICATION,
): Promise<MountedCard> => {
const hass = createGenericCameraHASS({ entities: { [TRIGGER_ENTITY]: 'off' } });
return await MountedCardFactory.createFromSource(
createStillImageCardConfig({
automations: [
createInitializedAutomation(),
{
triggers: [{ trigger: 'state', entity: TRIGGER_ENTITY, to: 'on' }],
actions: [
{
action: 'fire-dom-event',
advanced_camera_card_action: 'notification',
notification,
},
],
},
],
}),
hass,
);
};
const showNotification = async (card: MountedCard): Promise<HTMLElement> => {
card.setEntityState(TRIGGER_ENTITY, 'on');
return await card.waitForSelector<HTMLElement>('.notification');
};
describe('NotificationPopupController', () => {
it('should keep the notification open when its own text is pressed', async () => {
const card = await mount();
await card.console.waitForMessage(CARD_INITIALIZED_MESSAGE);
const elsewhere = document.createElement('button');
document.body.appendChild(elsewhere);
elsewhere.focus();
const notification = await showNotification(card);
const body = deepQuery<HTMLElement>(card.card, '.detail.body span');
expect(body?.textContent).toBe(BODY_TEXT);
if (!body) {
return;
}
await clickElement(body);
expect(notification.classList.contains('exiting')).toBe(false);
});
it('should dismiss the notification when the page outside it is pressed', async () => {
const card = await mount();
await card.console.waitForMessage(CARD_INITIALIZED_MESSAGE);
const outside = document.createElement('button');
outside.textContent = 'outside';
document.body.appendChild(outside);
const notification = await showNotification(card);
expect(notification.classList.contains('exiting')).toBe(false);
await clickElement(outside);
expect(notification.classList.contains('exiting')).toBe(true);
});
it('should take focus when notification is opened', async () => {
const card = await mount();
await card.console.waitForMessage(CARD_INITIALIZED_MESSAGE);
const elsewhere = document.createElement('button');
document.body.appendChild(elsewhere);
elsewhere.focus();
const notification = await showNotification(card);
expect(getFocusedElement()).toBe(notification);
});
it('should move focus to its close control on Tab', async () => {
const card = await mount();
await card.console.waitForMessage(CARD_INITIALIZED_MESSAGE);
await showNotification(card);
const close = deepQuery<HTMLElement>(card.card, 'button.close');
expect(close).toBeTruthy();
await pressTab();
expect(getFocusedElement()).toBe(close);
});
it('should return focus to where it was once dismissed', async () => {
const card = await mount();
await card.console.waitForMessage(CARD_INITIALIZED_MESSAGE);
const elsewhere = document.createElement('button');
document.body.appendChild(elsewhere);
elsewhere.focus();
await showNotification(card);
expect(getFocusedElement()).not.toBe(elsewhere);
await pressKey('Escape');
await card.waitForRender(
() => (deepQuery(card.card, '.notification') ? null : true),
'the notification to be removed',
);
expect(getFocusedElement()).toBe(elsewhere);
});
it('should activate a notification control from the keyboard', async () => {
const card = await mount({
...NOTIFICATION,
controls: [
{
icon: 'mdi:refresh',
tooltip: 'Retry',
dismiss: true,
actions: { tap_action: createLogAction(CONTROL_TAPPED_MESSAGE.source) },
},
],
});
await card.console.waitForMessage(CARD_INITIALIZED_MESSAGE);
await showNotification(card);
await pressTab();
expect(getFocusedElement()).toBe(deepQuery(card.card, '.notification .control'));
await pressKey('Enter');
await card.console.waitForMessage(CONTROL_TAPPED_MESSAGE);
});
});