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

751 lines
22 KiB
JavaScript

/* eslint-disable no-unused-vars */
import {shallow} from 'enzyme';
import React from 'react';
import {withContext} from 'shallow-with-context';
import {ServiceContainer} from 'src/containers/ServiceContainer';
import {DEFAULT_DASHBOARDS_CONTEXT} from 'src/context/DashboardsContext';
import {DummyService, ServiceState} from 'src/lib/services';
import {DashboardsFactory} from 'tests/__fixtures__/dashboards';
describe('src/containers/ServiceContainer', () => {
const ServiceContainerWithContext = withContext(
ServiceContainer, DEFAULT_DASHBOARDS_CONTEXT
);
let context = null;
beforeEach(() => {
context = {
...DEFAULT_DASHBOARDS_CONTEXT,
nukeService: jasmine.createSpy(),
saveServiceCharacteristics: jasmine.createSpy(),
saveServiceLayout: jasmine.createSpy(),
addService: jasmine.createSpy(),
setCurrentDashboardId: jasmine.createSpy(),
addDashboard: jasmine.createSpy(),
dashboards: DashboardsFactory(),
};
});
describe('constructor', () => {
it('initializes the state', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
// Then
expect(component.state('serviceState')).toBe(null);
expect(component.state('showSettingsModal')).toBe(false);
expect(component.state('nextCharacteristics')).toBe(null);
});
});
describe('service', () => {
it('looks up the bound service instance', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
// When
const service = component.instance().service();
// Then
expect(service).toEqual(context.dashboards[0].services[0]);
});
});
describe('setServiceState', () => {
it('initializes new state object if the current state is `null`', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
// When
component.instance().setServiceState({data: {spam: true}}, {});
// Then
expect(component.state('serviceState')).toBeInstanceOf(ServiceState);
expect(component.state('serviceState').data()).toEqual({spam: true});
});
it('initializes new state object if reset is requested', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
const oldState = new ServiceState({data: {spam: false}});
component.setState({serviceState: oldState});
// When
component.instance().setServiceState(
{data: {spam: true}}, {reset: true}
);
// Then
expect(component.state('serviceState')).not.toBe(oldState);
});
it('updates the existing state object with new payload', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
const oldState = new ServiceState({data: {spam: false}});
component.setState({serviceState: oldState});
// When
component.instance().setServiceState({data: {spam: true}}, {});
// Then
expect(component.state('serviceState')).not.toBe(oldState);
expect(component.state('serviceState').data()).toEqual({spam: true});
});
});
it('allows setting next characteristics', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
// When
component.instance().setNextCharacteristics({spam: true});
// Then
expect(component.state('nextCharacteristics')).toEqual({spam: true});
});
describe('setNextCharacteristicsFromService', () => {
it('resets the next characteristics if the service is null', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
component.setState({nextCharacteristics: {spam: false}});
// When
component.instance().setNextCharacteristicsFromService(null);
// Then
expect(component.state('nextCharacteristics')).toBe(null);
});
it('resets the next characteristics if the service has no widget', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
component.setState({nextCharacteristics: {spam: false}});
const service = context.dashboards[0].services[0];
service.widgetComponent = null;
// When
component.instance().setNextCharacteristicsFromService(service);
// Then
expect(component.state('nextCharacteristics')).toBe(null);
});
it('resets the next characteristics if the service is dummy', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
component.setState({nextCharacteristics: {spam: false}});
const service = new DummyService();
// When
component.instance().setNextCharacteristicsFromService(service);
// Then
expect(component.state('nextCharacteristics')).toBe(null);
});
it('sets the next characteristics from the service characteristics', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
const service = context.dashboards[0].services[0];
// When
component.instance().setNextCharacteristicsFromService(service);
// Then
expect(component.state('nextCharacteristics')).toEqual(
service.characteristics
);
});
});
describe('showHideSettingsModal', () => {
it('sets next characteristics from the service when modal is to be shown', () => {
// Givem
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
spyOn(component.instance(), 'setNextCharacteristicsFromService');
// When
component.instance().showHideSettingsModal(true);
// Then
expect(component.instance().setNextCharacteristicsFromService).toHaveBeenCalledWith(
context.dashboards[0].services[0]
);
});
it('resets next characteristics when modal is to be hidden', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
spyOn(component.instance(), 'setNextCharacteristicsFromService');
// When
component.instance().showHideSettingsModal(false);
// Then
expect(component.instance().setNextCharacteristicsFromService).toHaveBeenCalledWith(
null
);
});
it('updates the state with new visibility flag', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
spyOn(component.instance(), 'setNextCharacteristicsFromService');
// When
component.instance().showHideSettingsModal(true);
// Then
expect(component.state('showSettingsModal')).toBe(true);
});
});
describe('onSettingsButtonClick', () => {
it('requests the settings modal to be shown', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
spyOn(component.instance(), 'showHideSettingsModal');
// When
component.instance().onSettingsButtonClick();
// Then
expect(component.instance().showHideSettingsModal).toHaveBeenCalledWith(
true
);
});
});
describe('onSettingsModalClose', () => {
it('requests the settings modal to be hidden', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
spyOn(component.instance(), 'showHideSettingsModal');
// When
component.instance().onSettingsModalClose();
// Then
expect(component.instance().showHideSettingsModal).toHaveBeenCalledWith(
false
);
});
});
describe('onSettingsModalSaveButtonClick', () => {
it('requests the next characteristics to be saved', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
component.setState({nextCharacteristics: {spam: true}});
// When
component.instance().onSettingsModalSaveButtonClick();
// Then
expect(context.saveServiceCharacteristics).toHaveBeenCalledWith(
'FakeService', 'fake_instance', {spam: true}
);
});
it('closes the settings modal', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
spyOn(component.instance(), 'onSettingsModalClose');
// When
component.instance().onSettingsModalSaveButtonClick();
// Then
expect(component.instance().onSettingsModalClose).toHaveBeenCalled();
});
});
describe('onSettingsModalNukeButtonClick', () => {
it('requests the service to be nuked', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
// When
component.instance().onSettingsModalNukeButtonClick();
// Then
expect(context.nukeService).toHaveBeenCalledWith(
'FakeService', 'fake_instance'
);
});
it('closes the settings modal', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
spyOn(component.instance(), 'onSettingsModalClose');
// When
component.instance().onSettingsModalNukeButtonClick();
// Then
expect(component.instance().onSettingsModalClose).toHaveBeenCalled();
});
});
describe('onAppearancePopupColorChange', () => {
it('requests the updated characteristics to be saved', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
// When
component.instance().onAppearancePopupColorChange('red');
// Then
expect(context.saveServiceCharacteristics).toHaveBeenCalledWith(
'FakeService', 'fake_instance', {
spam: true,
appearance: {
color: 'red',
},
}
);
});
});
describe('onServiceRestartButtonClick', () => {
it('requests the updated characteristics to be saved', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
const service = context.dashboards[0].services[0];
spyOn(service, 'restart');
// When
component.instance().onServiceRestartButtonClick();
// Then
expect(service.restart).toHaveBeenCalled();
});
});
describe('unsubscribeIfNeeded', () => {
it('calls the unsubscribe callback', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
component.instance().serviceUnsubscribe = jasmine.createSpy();
// When
component.instance().unsubscribeIfNeeded();
// Then
expect(component.instance().serviceUnsubscribe).toHaveBeenCalled();
});
});
describe('componentDidMount', () => {
it('is a noop if the service is null', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
spyOn(component.instance(), 'setServiceState');
spyOn(component.instance(), 'unsubscribeIfNeeded');
spyOn(component.instance(), 'service').and.returnValue(null);
// When
component.instance().componentDidMount();
// Then
expect(component.instance().setServiceState).not.toHaveBeenCalled();
expect(component.instance().unsubscribeIfNeeded).not.toHaveBeenCalled();
expect(component.instance().serviceUnsubscribe).toBe(null);
});
it('is a noop if the service has no widget', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
spyOn(component.instance(), 'setServiceState');
spyOn(component.instance(), 'unsubscribeIfNeeded');
context.dashboards[0].services[0].widgetComponent = null;
// When
component.instance().componentDidMount();
// Then
expect(component.instance().setServiceState).not.toHaveBeenCalled();
expect(component.instance().unsubscribeIfNeeded).not.toHaveBeenCalled();
expect(component.instance().serviceUnsubscribe).toBe(null);
});
it('is a noop if the service is dummy', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
spyOn(component.instance(), 'setServiceState');
spyOn(component.instance(), 'unsubscribeIfNeeded');
spyOn(component.instance(), 'service').and.returnValue(
new DummyService()
);
// When
component.instance().componentDidMount();
// Then
expect(component.instance().setServiceState).not.toHaveBeenCalled();
expect(component.instance().unsubscribeIfNeeded).not.toHaveBeenCalled();
expect(component.instance().serviceUnsubscribe).toBe(null);
});
it('sets itself up for the service', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
spyOn(component.instance(), 'setServiceState');
spyOn(component.instance(), 'unsubscribeIfNeeded');
const service = context.dashboards[0].services[0];
spyOn(service, 'start');
const initialState = new ServiceState({data: {initial: true}});
spyOn(service, 'initialState').and.returnValue(initialState);
const fakeUnsubscribe = jasmine.createSpy();
spyOn(service, 'subscribe').and.returnValue(fakeUnsubscribe);
// When
component.instance().componentDidMount();
// Then
expect(component.instance().setServiceState).toHaveBeenCalledWith(
initialState, true
);
expect(service.start).toHaveBeenCalled();
expect(component.instance().unsubscribeIfNeeded).toHaveBeenCalled();
expect(service.subscribe).toHaveBeenCalledWith(
component.instance().setServiceState
);
expect(component.instance().serviceUnsubscribe).toEqual(fakeUnsubscribe);
});
});
describe('componentWillUnmount', () => {
it('unsubscribes from the service', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{(props) => <span>It works!</span>}
</ServiceContainerWithContext>,
{
context: context,
}
);
const mockUnsubscribeIfNeeded = jasmine.createSpy();
component.instance().unsubscribeIfNeeded = mockUnsubscribeIfNeeded;
// When
component.unmount();
// Then
expect(mockUnsubscribeIfNeeded).toHaveBeenCalled();
});
});
describe('render', () => {
let childrenFunc = null;
beforeEach(() => {
childrenFunc = jasmine.createSpy();
childrenFunc.returnValue = <span>It works!</span>;
});
it('calls the children func with props', () => {
// Given
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{childrenFunc}
</ServiceContainerWithContext>,
{
context: context,
}
);
const serviceState = new ServiceState({data: {spam: true}});
component.setState({
serviceState: serviceState,
showSettingsModal: true,
nextCharacteristics: {eggs: true},
});
// Then
expect(childrenFunc).toHaveBeenCalledWith({
hasSettingsView: true,
service: context.dashboards[0].services[0],
serviceState: serviceState,
setServiceState: component.instance().setServiceState,
settingsViewProps: {
kind: 'FakeService',
instance: 'fake_instance',
nextCharacteristics: {eggs: true},
setNextCharacteristics: component.instance().setNextCharacteristics,
},
showSettingsModal: true,
onAppearancePopupColorChange: component.instance().onAppearancePopupColorChange,
onServiceRestartButtonClick: component.instance().onServiceRestartButtonClick,
onSettingsButtonClick: component.instance().onSettingsButtonClick,
onSettingsModalClose: component.instance().onSettingsModalClose,
onSettingsModalNukeButtonClick: component.instance().onSettingsModalNukeButtonClick,
onSettingsModalSaveButtonClick: component.instance().onSettingsModalSaveButtonClick,
});
});
it('disables settings view if the service is dummy', () => {
// Given
const service = context.dashboards[0].services[0];
spyOn(service, 'isDummy').and.returnValue(true);
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{childrenFunc}
</ServiceContainerWithContext>,
{
context: context,
}
);
// Then
expect(childrenFunc).toHaveBeenCalledWith(jasmine.objectContaining({
hasSettingsView: false,
}));
});
it('disables settings view if the service has no widget', () => {
// Given
const service = context.dashboards[0].services[0];
service.widgetComponent = null;
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{childrenFunc}
</ServiceContainerWithContext>,
{
context: context,
}
);
// Then
expect(childrenFunc).toHaveBeenCalledWith(jasmine.objectContaining({
hasSettingsView: false,
}));
});
it('disables settings view if the service widget has no settings view', () => {
// Given
const service = context.dashboards[0].services[0];
const oldSettingsView = service.widgetComponent.settingsView;
service.widgetComponent.settingsView = undefined;
const component = shallow(
<ServiceContainerWithContext kind="FakeService" instance="fake_instance">
{childrenFunc}
</ServiceContainerWithContext>,
{
context: context,
}
);
// Then
expect(childrenFunc).toHaveBeenCalledWith(jasmine.objectContaining({
hasSettingsView: false,
}));
// After
service.widgetComponent.settingsView = oldSettingsView;
});
});
});