homehub/packages/homehub_core/tests/providers/DashboardsProvider.spec.js
2021-08-26 12:33:15 +02:00

1281 lines
39 KiB
JavaScript

import {shallow} from 'enzyme';
import React from 'react';
import {
DEFAULT_DASHBOARDS_CONTEXT, DashboardsContext,
} from 'src/context/DashboardsContext';
import * as HashLib from 'src/lib/hashlib';
import * as ServicesLib from 'src/lib/services';
import * as WebSocketLib from 'src/lib/websocket';
import {DashboardsProvider} from 'src/providers/DashboardsProvider';
import {
DashboardsFactory, DashboardsJSONFactory,
} from 'tests/__fixtures__/dashboards';
import {FakeService, FakeWidget} from 'tests/__fixtures__/services';
describe('src/providers/DashboardsProvider', () => {
describe('DashboardsProvider', () => {
const Loader = (props) => <span>LOADER</span>; // eslint-disable-line no-unused-vars
const Children = (props) => <span>LOADER</span>; // eslint-disable-line no-unused-vars
let loadDashboards = null;
let saveDashboards = null;
let settings = null;
beforeEach(() => {
loadDashboards = jasmine.createSpy();
saveDashboards = jasmine.createSpy();
settings = {
DEBUG: false,
SERVICES: {
[FakeService.kind]: FakeService,
},
WIDGETS: {
[FakeService.widget]: FakeWidget,
},
WEBSOCKET: {
url: '/backend/websocket',
},
};
});
describe('constructor', () => {
it('initializes the instance', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
// Then
expect(component.instance().webSocket).toBe(null);
expect(component.instance().webSocketUnsubscriber).toBe(null);
expect(component.instance().dashboardsHash).toBe(null);
});
it('initializes the state', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
// Then
expect(component.state('currentDashboardId')).toEqual(
DEFAULT_DASHBOARDS_CONTEXT.currentDashboardId
);
expect(component.state('dashboards')).toEqual(
DEFAULT_DASHBOARDS_CONTEXT.dashboards
);
expect(component.state('isLoading')).toEqual(
DEFAULT_DASHBOARDS_CONTEXT.isLoading
);
expect(component.state('lastSaveTimestamp')).toEqual(
DEFAULT_DASHBOARDS_CONTEXT.lastSaveTimestamp
);
expect(component.state('lastSaveError')).toEqual(
DEFAULT_DASHBOARDS_CONTEXT.lastSaveError
);
expect(component.state('isSaving')).toEqual(
DEFAULT_DASHBOARDS_CONTEXT.isSaving
);
expect(component.state('isWebSocketConnected')).toEqual(
DEFAULT_DASHBOARDS_CONTEXT.isWebSocketConnected
);
});
});
describe('handleSaveError', () => {
beforeEach(() => {
spyOn(console, 'error');
});
it('handles a save error', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
const error = new Error('FIAL');
// When
const result = component.instance().handleSaveError(error);
// Then
expect(result).toEqual('FIAL');
expect(console.error).toHaveBeenCalledWith(jasmine.any(String), error);
});
});
describe('onWebSocketStart', () => {
it('handles websocket start event', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
// When
component.instance().onWebSocketStart();
// Then
expect(component.state('isWebSocketConnected')).toBe(true);
});
});
describe('onWebSocketStop', () => {
it('handles websocket stop event', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
component.setState({isWebSocketConnected: true});
// When
component.instance().onWebSocketStop();
// Then
expect(component.state('isWebSocketConnected')).toBe(false);
});
});
describe('onWebSocketMessage', () => {
let fakeDate = null;
beforeEach(() => {
fakeDate = new Date(1987, 9, 3, 8, 0, 0);
jasmine.clock().install();
jasmine.clock().mockDate(fakeDate);
});
afterEach(() => {
jasmine.clock().uninstall();
});
it('handles a service notification for a single service', async () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
const dashboards = DashboardsFactory();
dashboards[0].services.forEach((service) => {
spyOn(service, 'onMessage');
});
component.instance().setState({dashboards: dashboards});
const data = {spam: true};
// When
await component.instance().onWebSocketMessage({
type: WebSocketLib.kWebSocketMsgTypeServiceNotification,
kind: FakeService.kind,
instance: 'fake_instance',
data: data,
});
// Then
expect(dashboards[0].services[0].onMessage).toHaveBeenCalledWith(data);
expect(dashboards[0].services[1].onMessage).not.toHaveBeenCalled();
});
it('handles a service notification for multiple services', async () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
const dashboards = DashboardsFactory();
dashboards[0].services.forEach((service) => {
spyOn(service, 'onMessage');
});
component.instance().setState({dashboards: dashboards});
const data = {spam: true};
// When
await component.instance().onWebSocketMessage({
type: WebSocketLib.kWebSocketMsgTypeServiceNotification,
kind: FakeService.kind,
data: data,
});
// Then
expect(dashboards[0].services[0].onMessage).toHaveBeenCalledWith(data);
expect(dashboards[0].services[1].onMessage).toHaveBeenCalledWith(data);
});
it('handles a state notification', async () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
const dashboards = DashboardsFactory();
const data = DashboardsJSONFactory(dashboards);
spyOn(component.instance(), 'handleLoadedState').and.resolveTo(dashboards);
// When
await component.instance().onWebSocketMessage({
type: WebSocketLib.kWebSocketMsgTypeStateNotification,
data: data,
});
// Then
expect(component.state('dashboards')).toEqual(dashboards);
expect(component.state('lastSaveTimestamp')).toEqual(fakeDate);
expect(component.instance().handleLoadedState).toHaveBeenCalledWith(data);
});
it('does not handle a state notification if the dashboards hash did not change', async () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
const dashboards = DashboardsFactory();
const data = DashboardsJSONFactory(dashboards);
component.instance().dashboardsHash = await HashLib.sha256(
JSON.stringify(data)
);
spyOn(component.instance(), 'handleLoadedState').and.resolveTo(dashboards);
// When
await component.instance().onWebSocketMessage({
type: WebSocketLib.kWebSocketMsgTypeStateNotification,
data: data,
});
// Then
expect(component.state('dashboards')).not.toEqual(dashboards);
expect(component.state('lastSaveTimestamp')).not.toEqual(fakeDate);
expect(component.instance().handleLoadedState).not.toHaveBeenCalled();
});
});
describe('currentDashboard', () => {
it('returns the current dashboard object', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
const dashboards = DashboardsFactory();
component.setState({
dashboards: dashboards,
currentDashboardId: 'testing',
});
// When
const result = component.instance().currentDashboard();
// Then
expect(result).toEqual(dashboards[0]);
});
});
describe('mutateCurrentDashboardServices', () => {
it('returns the mutated current dashboard object', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
const dashboards = DashboardsFactory();
dashboards.push({
id: 'testing2',
name: 'Testing2',
services: [
new FakeService({
instance: 'other_dashboard_instance',
widgetComponent: FakeWidget,
characteristics: {
spam: true,
},
layout: {
x: 0,
y: 0,
w: 1,
h: 1,
},
}),
],
});
component.setState({
dashboards: dashboards,
currentDashboardId: 'testing',
});
// When
const result = component.instance().mutateCurrentDashboardServices(
(services) => {
return services.map((service) => {
service.setCharacteristics({id: service.instance});
return service;
});
}
);
// Then
expect(result.length).toEqual(2);
expect(result[0].services[0].characteristics).toEqual({
id: result[0].services[0].instance,
});
expect(result[0].services[1].characteristics).toEqual({
id: result[0].services[1].instance,
});
expect(result[1].services[0].characteristics).toEqual({
spam: true,
});
});
});
describe('serviceFromSpec', () => {
let spec = null;
beforeEach(() => {
spec = {
kind: 'FakeService',
instance: 'fake_instance',
characteristics: {
spam: true,
},
layout: {
x: 0,
y: 0,
w: 1,
h: 1,
},
};
});
it('creates a dummy service is the service is uknown', () => {
// Given
settings.SERVICES = {};
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
// When
const result = component.instance().serviceFromSpec(spec);
// Then
expect(result).toBeInstanceOf(ServicesLib.DummyService);
});
it('instantiates a service from the spec', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
// When
const result = component.instance().serviceFromSpec(spec);
// Then
expect(result).toBeInstanceOf(FakeService);
expect(result.instance).toEqual(spec.instance);
expect(result.characteristics).toEqual(spec.characteristics);
expect(result.layout).toEqual(spec.layout);
expect(result.widgetComponent).toEqual(FakeWidget);
});
it('nullifies the widgetComponent if the widget is not known', () => {
// Given
settings.WIDGETS = {};
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
// When
const result = component.instance().serviceFromSpec(spec);
// Then
expect(result).toBeInstanceOf(FakeService);
expect(result.widgetComponent).toBe(null);
});
});
describe('saveDashboards', () => {
let fakeDate = null;
beforeEach(() => {
saveDashboards = jasmine.createSpy().and.resolveTo('ok');
fakeDate = new Date(1987, 9, 3, 8, 0, 0);
jasmine.clock().install();
jasmine.clock().mockDate(fakeDate);
spyOn(console, 'error');
});
afterEach(() => {
jasmine.clock().uninstall();
});
it('does not save the dashboards when dashboards hash did not change', async () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
component.setState({lastSaveError: 'FIAL'});
const dashboards = DashboardsFactory();
const data = DashboardsJSONFactory(dashboards);
component.instance().dashboardsHash = await HashLib.sha256(
JSON.stringify({dashboards: data})
);
// When
await component.instance().saveDashboards(dashboards);
// Then
expect(saveDashboards).not.toHaveBeenCalled();
expect(component.state('lastSaveTimestamp')).not.toEqual(fakeDate);
expect(component.state('lastSaveError')).toEqual('FIAL');
});
it('saves the dashboards', async () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
component.setState({lastSaveError: 'FIAL'});
const dashboards = DashboardsFactory();
// When
await component.instance().saveDashboards(dashboards);
// Then
expect(saveDashboards).toHaveBeenCalled();
const savedDashboards = saveDashboards.calls.first().args[0];
expect(savedDashboards.dashboards.length).toEqual(1);
expect(savedDashboards.dashboards[0].id).toEqual(dashboards[0].id);
expect(savedDashboards.dashboards[0].name).toEqual(dashboards[0].name);
expect(savedDashboards.dashboards[0].services.length).toEqual(2);
expect(savedDashboards.dashboards[0].services[0]).toEqual(
dashboards[0].services[0].toJSON()
);
expect(savedDashboards.dashboards[0].services[1]).toEqual(
dashboards[0].services[1].toJSON()
);
expect(component.state('lastSaveTimestamp')).toEqual(fakeDate);
expect(component.state('lastSaveError')).toBe(null);
});
it('gracefully handles save error', async () => {
// Given
saveDashboards = jasmine.createSpy().and.rejectWith(new Error('FIAL'));
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
const dashboards = DashboardsFactory();
component.instance().dashboardsHash = 'spam';
component.setState({lastSaveTimestamp: fakeDate});
// When
await component.instance().saveDashboards(dashboards);
// Then
expect(component.instance().dashboardsHash).toBe(null);
expect(component.state('lastSaveTimestamp')).toBe(null);
expect(component.state('lastSaveError')).toEqual('FIAL');
});
});
describe('nukeService', () => {
it('stops and removes the specified service', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'saveDashboards');
const dashboards = DashboardsFactory();
const serviceToRemove = dashboards[0].services[0];
spyOn(serviceToRemove, 'stop');
component.setState({
dashboards: dashboards,
currentDashboardId: dashboards[0].id,
});
// When
component.instance().nukeService('FakeService', 'fake_instance');
// Then
const newDashboards = component.state('dashboards');
expect(newDashboards[0].services.length).toEqual(1);
expect(newDashboards[0].services).not.toContain(serviceToRemove);
expect(serviceToRemove.stop).toHaveBeenCalled();
expect(component.instance().saveDashboards).toHaveBeenCalledWith(
newDashboards
);
});
});
describe('saveServiceCharacteristics', () => {
it('saves new characteristics for the specified service', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'saveDashboards');
const dashboards = DashboardsFactory();
const serviceToModify = dashboards[0].services[0];
spyOn(serviceToModify, 'setCharacteristics');
component.setState({
dashboards: dashboards,
currentDashboardId: dashboards[0].id,
});
const newCharacteristics = {spam: false};
// When
component.instance().saveServiceCharacteristics(
'FakeService', 'fake_instance', newCharacteristics
);
// Then
const newDashboards = component.state('dashboards');
expect(newDashboards[0].services.length).toEqual(2);
expect(serviceToModify.setCharacteristics).toHaveBeenCalledWith(
newCharacteristics
);
expect(component.instance().saveDashboards).toHaveBeenCalledWith(
newDashboards
);
});
});
describe('saveServiceLayout', () => {
it('saves new characteristics for the specified service', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'saveDashboards');
const dashboards = DashboardsFactory();
const serviceToModify = dashboards[0].services[0];
spyOn(serviceToModify, 'setLayout');
component.setState({
dashboards: dashboards,
currentDashboardId: dashboards[0].id,
});
const newLayout = {x: 1, y: 1, w: 1, h: 1};
// When
component.instance().saveServiceLayout('fake_instance', newLayout);
// Then
const newDashboards = component.state('dashboards');
expect(newDashboards[0].services.length).toEqual(2);
expect(serviceToModify.setLayout).toHaveBeenCalledWith(newLayout);
expect(component.instance().saveDashboards).toHaveBeenCalledWith(
newDashboards
);
});
});
describe('addService', () => {
it('is a noop if no dashboard is selected', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'saveDashboards');
const dashboards = DashboardsFactory();
component.setState({dashboards: dashboards});
// When
component.instance().addService('FakeService', {new: true});
// Then
expect(component.state('dashboards')).toBe(dashboards);
expect(component.instance().saveDashboards).not.toHaveBeenCalled();
});
it('adds a new service', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'saveDashboards');
const dashboards = DashboardsFactory();
component.setState({
dashboards: dashboards,
currentDashboardId: dashboards[0].id,
});
const newServiceCharacteristics = {new: true};
// When
component.instance().addService(
'FakeService', newServiceCharacteristics
);
// Then
const newDashboards = component.state('dashboards');
expect(newDashboards[0].services.length).toEqual(3);
expect(component.instance().saveDashboards).toHaveBeenCalledWith(
newDashboards
);
const newService = newDashboards[0].services[2];
expect(newService).toBeInstanceOf(FakeService);
expect(newService.instance).toBeUUIDv4();
expect(newService.characteristics).toEqual(newServiceCharacteristics);
expect(newService.layout).toEqual({x: 0, y: 2, w: 1, h: 1});
});
});
describe('handleLoadedState', () => {
it('handles loaded state', async () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'serviceFromSpec').and.returnValue(
new ServicesLib.DummyService()
);
const loadedState = {dashboards: DashboardsJSONFactory()};
const dashboardsHash = await HashLib.sha256(
JSON.stringify(loadedState)
);
// When
const result = await component.instance().handleLoadedState(
loadedState
);
// Then
expect(component.instance().dashboardsHash).toEqual(dashboardsHash);
expect(result.length).toEqual(1);
expect(result[0].id).toEqual(loadedState.dashboards[0].id);
expect(result[0].name).toEqual(loadedState.dashboards[0].name);
expect(result[0].services.length).toEqual(
loadedState.dashboards[0].services.length
);
expect(component.instance().serviceFromSpec.calls.count()).toEqual(2);
expect(component.instance().serviceFromSpec).toHaveBeenCalledWith(
loadedState.dashboards[0].services[0]
);
expect(component.instance().serviceFromSpec).toHaveBeenCalledWith(
loadedState.dashboards[0].services[1]
);
});
});
describe('loadDashboards', () => {
let fakeDate = null;
let loadedDashboards = null;
let loadedState = null;
beforeEach(() => {
loadedDashboards = DashboardsFactory();
loadedState = {dashboards: DashboardsJSONFactory(loadedDashboards)};
loadDashboards = jasmine.createSpy().and.resolveTo(loadedState);
fakeDate = new Date(1987, 9, 3, 8, 0, 0);
jasmine.clock().install();
jasmine.clock().mockDate(fakeDate);
spyOn(console, 'error');
});
afterEach(() => {
jasmine.clock().uninstall();
});
it('loads the dashboards', async () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'handleLoadedState').and.resolveTo(
loadedDashboards
);
// When
await component.instance().loadDashboards();
// Then
expect(component.state('dashboards')).toEqual(loadedDashboards);
expect(component.state('currentDashboardId')).toEqual(
loadedDashboards[0].id
);
expect(component.state('lastSaveTimestamp')).toEqual(fakeDate);
expect(component.instance().handleLoadedState).toHaveBeenCalledWith(
loadedState
);
});
it('gracefully handles load error', async () => {
// Given
loadDashboards = jasmine.createSpy().and.rejectWith(new Error('FIAL'));
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'handleLoadedState').and.resolveTo([]);
// When
await component.instance().loadDashboards();
// Then
expect(component.state('dashboards')).toEqual([]);
expect(component.state('currentDashboardId')).toBe(null);
expect(component.state('lastSaveTimestamp')).toBe(null);
expect(component.state('lastSaveError')).toEqual('FIAL');
expect(component.instance().handleLoadedState).not.toHaveBeenCalled();
});
});
describe('setCurrentDashboardId', () => {
it('sets the current dashboard id', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
// When
component.instance().setCurrentDashboardId('spam');
// Then
expect(component.state('currentDashboardId')).toEqual('spam');
});
});
describe('addDashboard', () => {
it('adds a dashboard', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'saveDashboards');
// When
component.instance().addDashboard('New');
// Then
const newDashboards = component.state('dashboards');
expect(newDashboards.length).toEqual(1);
expect(newDashboards[0].name).toEqual('New');
expect(component.instance().saveDashboards).toHaveBeenCalledWith(
newDashboards
);
});
it('auto selects the first added dashboard', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
component.setState({dashboards: []});
// When
component.instance().addDashboard('New');
// Then
expect(component.state('currentDashboardId')).toEqual(
component.state('dashboards')[0].id
);
});
it('does not auto select the other added dashboard', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
const dashboards = DashboardsFactory();
component.setState({
dashboards: dashboards,
currentDashboardId: 'testing',
});
// When
component.instance().addDashboard('New');
// Then
expect(component.state('currentDashboardId')).toEqual('testing');
});
});
describe('componentDidMount', () => {
let fakeHomeHubWebSocket = null;
let mockWebSocketUnsubscriber = null;
beforeEach(() => {
fakeHomeHubWebSocket = jasmine.createSpyObj('HomeHubWebSocket', [
'start', 'stop', 'addEventListener', 'removeEventListener',
'subscribe',
]);
mockWebSocketUnsubscriber = jasmine.createSpy();
fakeHomeHubWebSocket.subscribe.and.returnValue(
mockWebSocketUnsubscriber
);
spyOn(WebSocketLib, 'HomeHubWebSocket').and.returnValue(
fakeHomeHubWebSocket
);
});
it('sets the isLoading state to true', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'loadDashboards');
// When
component.instance().componentDidMount();
// Then
expect(component.state('isLoading')).toBe(true);
});
it('configures and starts the websocket connection', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'loadDashboards');
// When
component.instance().componentDidMount();
// Then
expect(component.instance().webSocket).toEqual(fakeHomeHubWebSocket);
expect(WebSocketLib.HomeHubWebSocket).toHaveBeenCalledWith(
settings.DEBUG, settings.WEBSOCKET
);
expect(fakeHomeHubWebSocket.addEventListener).toHaveBeenCalledWith(
'start', component.instance().onWebSocketStart
);
expect(fakeHomeHubWebSocket.addEventListener).toHaveBeenCalledWith(
'stop', component.instance().onWebSocketStop
);
expect(component.instance().webSocketUnsubscriber).toEqual(
mockWebSocketUnsubscriber
);
expect(fakeHomeHubWebSocket.subscribe).toHaveBeenCalledWith(
component.instance().onWebSocketMessage
);
expect(fakeHomeHubWebSocket.start).toHaveBeenCalled();
});
it('does not start the websocket in offline mode', () => {
// Given
settings.OFFLINE_MODE = true;
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'loadDashboards');
// When
component.instance().componentDidMount();
// Then
expect(component.instance().webSocket).toEqual(fakeHomeHubWebSocket);
expect(fakeHomeHubWebSocket.start).not.toHaveBeenCalled();
});
it('loads the dashboards', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
spyOn(component.instance(), 'loadDashboards');
// When
component.instance().componentDidMount();
// Then
expect(component.instance().loadDashboards).toHaveBeenCalled();
});
});
describe('componentWillUnmount', () => {
let fakeHomeHubWebSocket = null;
let mockWebSocketUnsubscriber = null;
beforeEach(() => {
fakeHomeHubWebSocket = jasmine.createSpyObj('HomeHubWebSocket', [
'start', 'stop', 'addEventListener', 'removeEventListener',
'subscribe',
]);
mockWebSocketUnsubscriber = jasmine.createSpy();
});
it('unsubscribes from the websocket', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
component.instance().webSocketUnsubscriber = mockWebSocketUnsubscriber;
// When
component.instance().componentWillUnmount();
// Then
expect(component.instance().webSocketUnsubscriber).toBe(null);
expect(mockWebSocketUnsubscriber).toHaveBeenCalled();
});
it('deconfigures and stops the websocket connection', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
component.instance().webSocket = fakeHomeHubWebSocket;
// When
component.instance().componentWillUnmount();
// Then
expect(fakeHomeHubWebSocket.removeEventListener).toHaveBeenCalledWith(
'start', component.instance().onWebSocketStart
);
expect(fakeHomeHubWebSocket.removeEventListener).toHaveBeenCalledWith(
'stop', component.instance().onWebSocketStop
);
expect(fakeHomeHubWebSocket.stop).toHaveBeenCalled();
});
});
describe('render', () => {
it('configures and renders the DashboardsContext provider', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
// When
const provider = component.find(DashboardsContext.Provider);
// Then
expect(provider.exists());
expect(provider.prop('value')).toEqual({
currentDashboardId: component.state('currentDashboardId'),
dashboards: component.state('dashboards'),
nukeService: component.instance().nukeService,
saveServiceCharacteristics: component.instance().saveServiceCharacteristics,
saveServiceLayout: component.instance().saveServiceLayout,
addService: component.instance().addService,
isLoading: component.state('isLoading'),
lastSaveTimestamp: component.state('lastSaveTimestamp'),
lastSaveError: component.state('lastSaveError'),
isSaving: component.state('isSaving'),
isWebSocketConnected: component.state('isWebSocketConnected'),
setCurrentDashboardId: component.instance().setCurrentDashboardId,
dashboardsHash: component.instance().dashboardsHash,
addDashboard: component.instance().addDashboard,
});
});
it('renders the Loader if it is loading dashboards', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
component.setState({isLoading: true});
// Then
expect(component.find(Loader).exists()).toBe(true);
expect(component.find(Children).exists()).toBe(false);
});
it('renders the Children if it is not loading', () => {
// Given
const component = shallow(
<DashboardsProvider
loader={<Loader />}
loadDashboards={loadDashboards}
saveDashboards={saveDashboards}
settings={settings}
>
<Children />
</DashboardsProvider>
);
component.setState({isLoading: false});
// Then
expect(component.find(Loader).exists()).toBe(false);
expect(component.find(Children).exists()).toBe(true);
});
});
});
});