Set timeline to now not to most recent event.

This commit is contained in:
Dermot Duffy committed 2024-04-07 20:21:09 -07:00
1 parent 14a4f89726
commit f67620397f
22 files changed
+828 -336

No files matched your search

@@ -0,0 +1,377 @@
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import { LiveController } from '../../../src/components-lib/live/live-controller';
import { dispatchMessageEvent } from '../../../src/components/message';
import {
changeViewToRecentEventsForCameraAndDependents,
changeViewToRecentRecordingForCameraAndDependents,
} from '../../../src/utils/media-to-view';
import { EventMediaQueries } from '../../../src/view/media-queries';
import {
IntersectionObserverMock,
callIntersectionHandler,
createCameraManager,
createConfig,
createLitElement,
createMediaLoadedInfo,
createMediaLoadedInfoEvent,
createParent,
createView,
createViewChangeEvent,
} from '../../test-utils';
vi.mock('../../../src/utils/media-to-view');
// @vitest-environment jsdom
describe('LiveController', () => {
beforeEach(() => {
vi.clearAllMocks();
vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);
});
it('should be constructable', () => {
const controller = new LiveController(createLitElement());
expect(controller).toBeTruthy();
});
it('should connect and disconnect', () => {
const host = createLitElement();
const parent = createParent({ children: [host] });
const eventListener = vi.fn();
parent.addEventListener('frigate-card:message', eventListener);
const controller = new LiveController(host);
controller.hostConnected();
callIntersectionHandler(false);
dispatchMessageEvent(host, 'message', 'info');
expect(eventListener).toBeCalledTimes(0);
controller.hostDisconnected();
dispatchMessageEvent(host, 'message', 'info');
expect(eventListener).toBeCalledTimes(1);
});
describe('should handle background / foreground', () => {
it('should start in the foreground', () => {
const controller = new LiveController(createLitElement());
expect(controller.isInBackground()).toBeFalsy();
});
it('should handle changing to background', () => {
const element = createLitElement();
const controller = new LiveController(element);
expect(controller.isInBackground()).toBeFalsy();
expect(element.requestUpdate).toBeCalledTimes(0);
callIntersectionHandler(true);
expect(controller.isInBackground()).toBeFalsy();
expect(element.requestUpdate).toBeCalledTimes(0);
callIntersectionHandler(false);
expect(controller.isInBackground()).toBeTruthy();
expect(element.requestUpdate).toBeCalledTimes(1);
});
it('should dispatch media loaded on background change', () => {
const host = createLitElement();
const parent = createParent({ children: [host] });
const eventListener = vi.fn();
parent.addEventListener('frigate-card:media:loaded', eventListener);
const controller = new LiveController(host);
const mediaLoadedInfo = createMediaLoadedInfo();
controller.hostConnected();
callIntersectionHandler(false);
expect(controller.isInBackground()).toBeTruthy();
host.dispatchEvent(createMediaLoadedInfoEvent(mediaLoadedInfo));
expect(eventListener).toBeCalledTimes(0);
callIntersectionHandler(true);
expect(eventListener).toBeCalledTimes(1);
expect(eventListener).toHaveBeenLastCalledWith(
expect.objectContaining({
detail: mediaLoadedInfo,
}),
);
host.dispatchEvent(createMediaLoadedInfoEvent(mediaLoadedInfo));
expect(eventListener).toBeCalledTimes(2);
callIntersectionHandler(false);
dispatchMessageEvent(host, 'message', 'info');
callIntersectionHandler(true);
expect(eventListener).toBeCalledTimes(2);
controller.clearMessageReceived();
callIntersectionHandler(true);
expect(eventListener).toBeCalledTimes(3);
});
});
describe('should correctly allow updates', () => {
it('when not in background', () => {
const controller = new LiveController(createLitElement());
expect(controller.shouldUpdate()).toBeTruthy();
});
it('when in background without message', () => {
const host = createLitElement();
const controller = new LiveController(host);
controller.hostConnected();
callIntersectionHandler(false);
expect(controller.shouldUpdate()).toBeTruthy();
});
it('when in background with message', () => {
const host = createLitElement();
const controller = new LiveController(host);
controller.hostConnected();
callIntersectionHandler(false);
dispatchMessageEvent(host, 'message', 'info');
expect(controller.shouldUpdate()).toBeFalsy();
});
});
it('should handle message', () => {
const host = createLitElement();
const parent = createParent({ children: [host] });
const eventListener = vi.fn();
parent.addEventListener('frigate-card:message', eventListener);
const controller = new LiveController(host);
controller.hostConnected();
callIntersectionHandler(false);
expect(controller.isInBackground()).toBeTruthy();
const firstRenderEpoch = controller.getRenderEpoch();
dispatchMessageEvent(host, 'message', 'info');
expect(eventListener).toBeCalledTimes(0);
const secondRenderEpoch = controller.getRenderEpoch();
expect(secondRenderEpoch).not.toBe(firstRenderEpoch);
callIntersectionHandler(true);
dispatchMessageEvent(host, 'message', 'info');
expect(eventListener).toBeCalledTimes(1);
expect(controller.getRenderEpoch()).toBe(secondRenderEpoch);
});
it('should handle view change', () => {
const host = createLitElement();
const parent = createParent({ children: [host] });
const eventListener = vi.fn();
parent.addEventListener('frigate-card:view:change', eventListener);
const controller = new LiveController(host);
controller.hostConnected();
const view = createView();
callIntersectionHandler(false);
expect(controller.isInBackground()).toBeTruthy();
host.dispatchEvent(createViewChangeEvent(view));
expect(eventListener).toBeCalledTimes(0);
callIntersectionHandler(true);
expect(controller.isInBackground()).toBeFalsy();
host.dispatchEvent(createViewChangeEvent(view));
expect(eventListener).toBeCalledTimes(1);
});
describe('should fetch media', () => {
it('when in background', async () => {
const controller = new LiveController(createLitElement());
callIntersectionHandler(false);
await controller.fetchMediaInBackgroundIfNecessary(
createView(),
createCameraManager(),
{},
createConfig().live,
);
expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled();
expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled();
});
it('when has existing query', async () => {
const controller = new LiveController(createLitElement());
await controller.fetchMediaInBackgroundIfNecessary(
createView({ query: new EventMediaQueries() }),
createCameraManager(),
{},
createConfig().live,
);
expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled();
expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled();
});
it('when has no thumbnails', async () => {
const controller = new LiveController(createLitElement());
await controller.fetchMediaInBackgroundIfNecessary(
createView(),
createCameraManager(),
{},
createConfig({
live: {
controls: {
thumbnails: {
mode: 'none',
},
},
},
}).live,
);
expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled();
expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled();
});
it('when fetch disabled in context', async () => {
const controller = new LiveController(createLitElement());
await controller.fetchMediaInBackgroundIfNecessary(
createView({
context: {
live: {
fetchThumbnails: false,
},
},
}),
createCameraManager(),
{},
createConfig().live,
);
expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled();
expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled();
});
describe('with fetch', () => {
const now = new Date('2024-04-07T19:43');
beforeAll(() => {
vi.useFakeTimers();
vi.setSystemTime(now);
});
afterAll(() => {
vi.useRealTimers();
});
it('events', async () => {
const host = createLitElement();
const controller = new LiveController(host);
const view = createView();
const cameraManager = createCameraManager();
const cardWideConfig = {};
await controller.fetchMediaInBackgroundIfNecessary(
view,
cameraManager,
cardWideConfig,
createConfig({
live: {
controls: {
thumbnails: {
media_type: 'events',
events_media_type: 'all',
},
timeline: {
window_seconds: 3600,
},
},
},
}).live,
);
expect(changeViewToRecentEventsForCameraAndDependents).toBeCalledWith(
host,
cameraManager,
cardWideConfig,
view,
expect.objectContaining({
allCameras: false,
targetView: 'live',
eventsMediaType: 'all',
select: 'latest',
viewContext: expect.objectContaining({
timeline: {
window: {
start: new Date('2024-04-07T18:43'),
end: now,
},
},
}),
}),
);
expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled();
});
it('recordings', async () => {
const host = createLitElement();
const controller = new LiveController(host);
const view = createView();
const cameraManager = createCameraManager();
const cardWideConfig = {};
await controller.fetchMediaInBackgroundIfNecessary(
view,
cameraManager,
cardWideConfig,
createConfig({
live: {
controls: {
thumbnails: {
media_type: 'recordings',
},
timeline: {
window_seconds: 3600,
},
},
},
}).live,
);
expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled();
expect(changeViewToRecentRecordingForCameraAndDependents).toBeCalledWith(
host,
cameraManager,
cardWideConfig,
view,
expect.objectContaining({
allCameras: false,
targetView: 'live',
select: 'latest',
viewContext: expect.objectContaining({
timeline: {
window: {
start: new Date('2024-04-07T18:43'),
end: now,
},
},
}),
}),
);
});
});
});
});
@@ -1,7 +1,6 @@
import endOfDay from 'date-fns/endOfDay';
import startOfDay from 'date-fns/startOfDay';
import sub from 'date-fns/sub';
import { LitElement } from 'lit';
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import { Capabilities } from '../../src/camera-manager/capabilities';
import { CameraManagerStore } from '../../src/camera-manager/store';
@@ -23,6 +22,7 @@ import {
createCameraConfig,
createCameraManager,
createCapabilities,
createLitElement,
createPerformanceConfig,
createStore,
createView,
@@ -30,12 +30,6 @@ import {
vi.mock('../../src/utils/media-to-view');
const createHost = (): LitElement => {
const host = document.createElement('div') as unknown as LitElement;
host.requestUpdate = vi.fn();
return host;
};
const createCameraStore = (options?: {
capabilities: Capabilities;
}): CameraManagerStore => {
@@ -64,7 +58,7 @@ describe('MediaFilterController', () => {
describe('should have correct default options', () => {
it('media type', () => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getMediaTypeOptions()).toEqual([
{
value: MediaFilterMediaType.Clips,
@@ -82,7 +76,7 @@ describe('MediaFilterController', () => {
});
it('favorite', () => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getFavoriteOptions()).toEqual([
{
value: MediaFilterCoreFavoriteSelection.Favorite,
@@ -96,7 +90,7 @@ describe('MediaFilterController', () => {
});
it('when', () => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getWhenOptions()).toEqual([
{
value: MediaFilterCoreWhen.Today,
@@ -122,22 +116,22 @@ describe('MediaFilterController', () => {
});
it('cameras', () => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getCameraOptions()).toEqual([]);
});
it('what', () => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getWhatOptions()).toEqual([]);
});
it('where', () => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getWhereOptions()).toEqual([]);
});
it('tags', () => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getTagsOptions()).toEqual([]);
});
});
@@ -152,7 +146,7 @@ describe('MediaFilterController', () => {
});
vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore());
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
controller.computeCameraOptions(cameraManager);
expect(controller.getCameraOptions()).toEqual([
{
@@ -178,7 +172,7 @@ describe('MediaFilterController', () => {
}),
);
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
controller.computeCameraOptions(cameraManager);
expect(controller.getCameraOptions()).toEqual([]);
});
@@ -188,7 +182,7 @@ describe('MediaFilterController', () => {
vi.mocked(cameraManager.getCameraMetadata).mockReturnValue(null);
vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore());
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
controller.computeCameraOptions(cameraManager);
expect(controller.getCameraOptions()).toEqual([
{
@@ -206,7 +200,7 @@ describe('MediaFilterController', () => {
const cameraManager = createCameraManager();
vi.mocked(cameraManager.getMediaMetadata).mockRejectedValue(new Error('error'));
const host = createHost();
const host = createLitElement();
const controller = new MediaFilterController(host);
await controller.computeMetadataOptions(cameraManager);
expect(host.requestUpdate).not.toBeCalled();
@@ -218,7 +212,7 @@ describe('MediaFilterController', () => {
what: new Set(['person', 'car']),
});
const host = createHost();
const host = createLitElement();
const controller = new MediaFilterController(host);
await controller.computeMetadataOptions(cameraManager);
expect(controller.getWhatOptions()).toEqual([
@@ -240,7 +234,7 @@ describe('MediaFilterController', () => {
where: new Set(['front_door', 'back_yard']),
});
const host = createHost();
const host = createLitElement();
const controller = new MediaFilterController(host);
await controller.computeMetadataOptions(cameraManager);
expect(controller.getWhereOptions()).toEqual([
@@ -262,7 +256,7 @@ describe('MediaFilterController', () => {
tags: new Set(['tag-1', 'tag-2']),
});
const host = createHost();
const host = createLitElement();
const controller = new MediaFilterController(host);
await controller.computeMetadataOptions(cameraManager);
expect(controller.getTagsOptions()).toEqual([
@@ -284,7 +278,7 @@ describe('MediaFilterController', () => {
days: new Set(['2024-02-04', '2024-02-05']),
});
const host = createHost();
const host = createLitElement();
const controller = new MediaFilterController(host);
await controller.computeMetadataOptions(cameraManager);
@@ -306,7 +300,7 @@ describe('MediaFilterController', () => {
const view = createView({ query: new EventMediaQueries() });
const cameraManager = createCameraManager();
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({
events: true,
recordings: false,
@@ -317,7 +311,7 @@ describe('MediaFilterController', () => {
const view = createView({ query: new RecordingMediaQueries() });
const cameraManager = createCameraManager();
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({
events: false,
recordings: true,
@@ -331,7 +325,7 @@ describe('MediaFilterController', () => {
createCapabilities({ 'favorite-events': true }),
);
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({
favorites: true,
});
@@ -344,7 +338,7 @@ describe('MediaFilterController', () => {
createCapabilities({ 'favorite-recordings': true }),
);
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({
favorites: true,
});
@@ -354,7 +348,7 @@ describe('MediaFilterController', () => {
const view = createView();
const cameraManager = createCameraManager();
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({
favorites: false,
});
@@ -363,7 +357,7 @@ describe('MediaFilterController', () => {
describe('should handle value change', () => {
it('must have visible cameras', async () => {
const host = createHost();
const host = createLitElement();
const controller = new MediaFilterController(host);
await controller.valueChangeHandler(
createCameraManager(),
@@ -380,7 +374,7 @@ describe('MediaFilterController', () => {
'%s',
async (viewName: 'clips' | 'snapshots') => {
const eventListener = vi.fn();
const host = createHost();
const host = createLitElement();
host.addEventListener('frigate-card:view:change', eventListener);
const controller = new MediaFilterController(host);
@@ -458,7 +452,7 @@ describe('MediaFilterController', () => {
it('with recordings media type', async () => {
const eventListener = vi.fn();
const host = createHost();
const host = createLitElement();
host.addEventListener('frigate-card:view:change', eventListener);
const controller = new MediaFilterController(host);
@@ -522,7 +516,7 @@ describe('MediaFilterController', () => {
});
it('without favorites', async () => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
const cameraManager = createCameraManager();
vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore());
@@ -583,7 +577,7 @@ describe('MediaFilterController', () => {
new Date('2024-02-29T23:59:59.999'),
],
])('%s', async (value: MediaFilterCoreWhen | string, from: Date, to: Date) => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
const cameraManager = createCameraManager();
vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore());
@@ -614,7 +608,7 @@ describe('MediaFilterController', () => {
});
it('custom without values', async () => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
const cameraManager = createCameraManager();
vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore());
@@ -646,7 +640,7 @@ describe('MediaFilterController', () => {
describe('should calculate correct defaults', () => {
it('with no queries', () => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
controller.computeInitialDefaultsFromView(createCameraManager(), createView());
@@ -654,7 +648,7 @@ describe('MediaFilterController', () => {
});
it('with no cameras', () => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
controller.computeInitialDefaultsFromView(
createCameraManager(),
@@ -956,7 +950,7 @@ describe('MediaFilterController', () => {
mediaQueries: MediaQueries,
defaults: MediaFilterCoreDefaults | null,
) => {
const controller = new MediaFilterController(createHost());
const controller = new MediaFilterController(createLitElement());
const cameraManager = createCameraManager();
vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore());
+21 -31
View File
@@ -1,25 +1,15 @@
import {
HASSDomEvent,
handleActionConfig,
} from '@dermotduffy/custom-card-helpers';
import { LitElement } from 'lit';
import { HASSDomEvent, handleActionConfig } from '@dermotduffy/custom-card-helpers';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { FRIGATE_ICON_SVG_PATH } from '../../src/camera-manager/frigate/icon';
import { MenuController } from '../../src/components-lib/menu-controller';
import { ActionsConfig, MenuConfig, menuConfigSchema } from '../../src/config/types';
import { StateParameters } from '../../src/types';
import { refreshDynamicStateParameters } from '../../src/utils/ha';
import { createHASS } from '../test-utils';
import { createHASS, createLitElement } from '../test-utils';
vi.mock('@dermotduffy/custom-card-helpers');
vi.mock('../../src/utils/ha');
const createHost = (): LitElement => {
const host = document.createElement('div') as unknown as LitElement;
host.requestUpdate = vi.fn();
return host;
};
const createMenuConfig = (config: unknown): MenuConfig => {
return menuConfigSchema.parse(config);
};
@@ -59,7 +49,7 @@ describe('MenuController', () => {
});
it('should set and get menu config', () => {
const host = createHost();
const host = createLitElement();
const controller = new MenuController(host);
const config = createMenuConfig({
@@ -79,7 +69,7 @@ describe('MenuController', () => {
describe('should set and sort buttons', () => {
it('by priority', () => {
const controller = new MenuController(createHost());
const controller = new MenuController(createLitElement());
controller.setButtons([
{
type: 'custom:frigate-card-menu-icon',
@@ -146,7 +136,7 @@ describe('MenuController', () => {
});
it('with frigate button first', () => {
const controller = new MenuController(createHost());
const controller = new MenuController(createLitElement());
controller.setMenuConfig(
createMenuConfig({
style: 'hidden',
@@ -197,7 +187,7 @@ describe('MenuController', () => {
describe('should get buttons', () => {
it('with matching alignment', () => {
const controller = new MenuController(createHost());
const controller = new MenuController(createLitElement());
controller.setButtons([
{
type: 'custom:frigate-card-menu-icon',
@@ -229,7 +219,7 @@ describe('MenuController', () => {
});
it('with disabled buttons', () => {
const controller = new MenuController(createHost());
const controller = new MenuController(createLitElement());
controller.setButtons([
{
type: 'custom:frigate-card-menu-icon',
@@ -261,7 +251,7 @@ describe('MenuController', () => {
});
it('with hidden non-expanded menu', () => {
const controller = new MenuController(createHost());
const controller = new MenuController(createLitElement());
controller.setMenuConfig(
createMenuConfig({
style: 'hidden',
@@ -303,7 +293,7 @@ describe('MenuController', () => {
describe('should get fresh button state', () => {
it('on state icon', () => {
const controller = new MenuController(createHost());
const controller = new MenuController(createLitElement());
const stateButton = {
type: 'custom:frigate-card-menu-state-icon' as const,
icon: 'mdi:sheep',
@@ -322,7 +312,7 @@ describe('MenuController', () => {
});
it('on non state icon', () => {
const controller = new MenuController(createHost());
const controller = new MenuController(createLitElement());
const button = {
type: 'custom:frigate-card-menu-icon' as const,
icon: 'mdi:sheep',
@@ -335,7 +325,7 @@ describe('MenuController', () => {
describe('should get svg path', () => {
it('frigate icon', () => {
const controller = new MenuController(createHost());
const controller = new MenuController(createLitElement());
const button = {
type: 'custom:frigate-card-menu-icon' as const,
icon: 'frigate',
@@ -344,7 +334,7 @@ describe('MenuController', () => {
});
it('non-frigate icon', () => {
const controller = new MenuController(createHost());
const controller = new MenuController(createLitElement());
const button = {
type: 'custom:frigate-card-menu-icon' as const,
icon: 'mdi:cow',
@@ -355,13 +345,13 @@ describe('MenuController', () => {
describe('should handle actions', () => {
it('should bail without config', () => {
const controller = new MenuController(createHost());
const controller = new MenuController(createLitElement());
controller.actionHandler(createHASS(), createEvent('tap'));
expect(vi.mocked(handleActionConfig)).not.toBeCalled();
});
it('should execute simple action in non-hidden menu', () => {
const host = createHost();
const host = createLitElement();
const hass = createHASS();
const controller = new MenuController(host);
@@ -377,7 +367,7 @@ describe('MenuController', () => {
});
it('should execute simple action in with config in event', () => {
const host = createHost();
const host = createLitElement();
const hass = createHASS();
const controller = new MenuController(host);
@@ -391,7 +381,7 @@ describe('MenuController', () => {
});
it('should execute simple array of actions in non-hidden menu', () => {
const host = createHost();
const host = createLitElement();
const hass = createHASS();
const controller = new MenuController(host);
@@ -401,7 +391,7 @@ describe('MenuController', () => {
describe('should close menu', () => {
it('tap', () => {
const host = createHost();
const host = createLitElement();
const hass = createHASS();
const controller = new MenuController(host);
controller.setMenuConfig(
@@ -418,7 +408,7 @@ describe('MenuController', () => {
});
it('end_tap', () => {
const host = createHost();
const host = createLitElement();
const hass = createHASS();
const controller = new MenuController(host);
controller.setMenuConfig(
@@ -439,7 +429,7 @@ describe('MenuController', () => {
describe('should not close menu', () => {
it('start_tap with later action', () => {
const host = createHost();
const host = createLitElement();
const hass = createHASS();
const controller = new MenuController(host);
controller.setMenuConfig(
@@ -459,7 +449,7 @@ describe('MenuController', () => {
});
it('with a menu toggle action', () => {
const host = createHost();
const host = createLitElement();
const hass = createHASS();
const controller = new MenuController(host);
controller.setMenuConfig(
@@ -479,7 +469,7 @@ describe('MenuController', () => {
});
it('when no action is actually taken', () => {
const host = createHost();
const host = createLitElement();
const hass = createHASS();
const controller = new MenuController(host);
controller.setMenuConfig(