You've already forked homehub
Release 1.3.0
This commit is contained in:
155
packages/homehub_tradfri/tests/TradfriService.spec.js
Normal file
155
packages/homehub_tradfri/tests/TradfriService.spec.js
Normal file
@@ -0,0 +1,155 @@
|
||||
import * as HomeHubCore from '@bthlabs/homehub-core';
|
||||
|
||||
import * as TradfriService from 'src/TradfriService';
|
||||
|
||||
import {TradfriDataFactory} from 'tests/__fixtures__/tradfri';
|
||||
|
||||
describe('src/TradfriService', () => {
|
||||
describe('TradfriService', () => {
|
||||
let fakeCharacteristics = null;
|
||||
let fakeResult = null;
|
||||
|
||||
beforeEach(() => {
|
||||
fakeCharacteristics = {
|
||||
host: 'thisisntright.local',
|
||||
key: 'thisisntright',
|
||||
};
|
||||
fakeResult = TradfriDataFactory();
|
||||
|
||||
spyOn(HomeHubCore.API.Services, 'start').and.returnValue(fakeResult);
|
||||
spyOn(HomeHubCore.API.Services, 'stop').and.returnValue('ok');
|
||||
spyOn(HomeHubCore.API.Services, 'use').and.returnValue(
|
||||
fakeResult.lights
|
||||
);
|
||||
});
|
||||
|
||||
describe('emptyCharacteristics', () => {
|
||||
it('returns empty characteristics', () => {
|
||||
// Given
|
||||
const result = TradfriService.TradfriService.emptyCharacteristics();
|
||||
|
||||
// Then
|
||||
expect(result).toEqual({
|
||||
key: '',
|
||||
host: '',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('start', () => {
|
||||
it('notifies subscribers with the result of start service API call', async () => {
|
||||
// Given
|
||||
const service = new TradfriService.TradfriService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'notify');
|
||||
|
||||
// When
|
||||
await service.start();
|
||||
|
||||
// Then
|
||||
expect(HomeHubCore.API.Services.start).toHaveBeenCalledWith(
|
||||
service.kind, 'testing', fakeCharacteristics
|
||||
);
|
||||
expect(service.notify).toHaveBeenCalledWith(fakeResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stop', () => {
|
||||
it('calls the stop service API method', async () => {
|
||||
// Given
|
||||
const service = new TradfriService.TradfriService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
await service.stop();
|
||||
|
||||
// Then
|
||||
expect(HomeHubCore.API.Services.stop).toHaveBeenCalledWith(
|
||||
service.kind, 'testing'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setCharacteristics', () => {
|
||||
it('updates the service characteristics', () => {
|
||||
// Given
|
||||
const newCharacteristics = {
|
||||
host: 'thisisntrighttoo.local',
|
||||
key: 'thisisntrighttoo',
|
||||
};
|
||||
const service = new TradfriService.TradfriService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'restart');
|
||||
|
||||
// When
|
||||
service.setCharacteristics(newCharacteristics);
|
||||
|
||||
// Then
|
||||
expect(service.characteristics).toEqual(newCharacteristics);
|
||||
});
|
||||
|
||||
it('restarts the service if host characteristic changed', () => {
|
||||
// Given
|
||||
const newCharacteristics = {
|
||||
...fakeCharacteristics,
|
||||
host: 'thisisntrighttoo.local',
|
||||
};
|
||||
const service = new TradfriService.TradfriService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'restart');
|
||||
|
||||
// When
|
||||
service.setCharacteristics(newCharacteristics);
|
||||
|
||||
// Then
|
||||
expect(service.restart).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('restarts the service if key characteristic changed', () => {
|
||||
// Given
|
||||
const newCharacteristics = {
|
||||
...fakeCharacteristics,
|
||||
key: 'thisisntrighttoo',
|
||||
};
|
||||
const service = new TradfriService.TradfriService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'restart');
|
||||
|
||||
// When
|
||||
service.setCharacteristics(newCharacteristics);
|
||||
|
||||
// Then
|
||||
expect(service.restart).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setLightsState', () => {
|
||||
it('calls the use service capability API method', async () => {
|
||||
// Given
|
||||
const service = new TradfriService.TradfriService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
const result = await service.setLightsState(['light1'], true);
|
||||
|
||||
// Then
|
||||
expect(result).toEqual(fakeResult.lights);
|
||||
expect(HomeHubCore.API.Services.use).toHaveBeenCalledWith(
|
||||
service.kind, 'testing', 'set_lights_state', [['light1'], true],
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
420
packages/homehub_tradfri/tests/TradfriWidgetView.spec.js
Normal file
420
packages/homehub_tradfri/tests/TradfriWidgetView.spec.js
Normal file
@@ -0,0 +1,420 @@
|
||||
import {FatalError, Widget} from '@bthlabs/homehub-components';
|
||||
import {ServiceState} from '@bthlabs/homehub-core';
|
||||
import {shallow} from 'enzyme';
|
||||
import React from 'react';
|
||||
import {Form} from 'react-bootstrap';
|
||||
|
||||
import {TradfriService} from 'src/TradfriService';
|
||||
import * as TradfriWidgetView from 'src/TradfriWidgetView';
|
||||
|
||||
import {TradfriDataFactory} from 'tests/__fixtures__/tradfri';
|
||||
|
||||
describe('src/widgets/TradfriWidgetView', () => {
|
||||
describe('TradfriWidgetSettingsView', () => {
|
||||
let fakeNextCharacteristics = null;
|
||||
let mockSetNextCharacteristics = null;
|
||||
|
||||
beforeEach(() => {
|
||||
fakeNextCharacteristics = {
|
||||
host: '',
|
||||
key: '',
|
||||
};
|
||||
mockSetNextCharacteristics = jasmine.createSpy();
|
||||
});
|
||||
|
||||
it('calls the setNextCharacteristics callback when host input changes', () => {
|
||||
// Given
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetSettingsView
|
||||
nextCharacteristics={fakeNextCharacteristics}
|
||||
setNextCharacteristics={mockSetNextCharacteristics}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
component.find(Form.Control).at(0).simulate('change', {
|
||||
target: {value: 'thisisntright.local'},
|
||||
});
|
||||
|
||||
// Then
|
||||
expect(mockSetNextCharacteristics).toHaveBeenCalledWith({
|
||||
...fakeNextCharacteristics,
|
||||
host: 'thisisntright.local',
|
||||
});
|
||||
});
|
||||
|
||||
it('calls the setNextCharacteristics callback when key input changes', () => {
|
||||
// Given
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetSettingsView
|
||||
nextCharacteristics={fakeNextCharacteristics}
|
||||
setNextCharacteristics={mockSetNextCharacteristics}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
component.find(Form.Control).at(1).simulate('change', {
|
||||
target: {value: 'thisisntright'},
|
||||
});
|
||||
|
||||
// Then
|
||||
expect(mockSetNextCharacteristics).toHaveBeenCalledWith({
|
||||
...fakeNextCharacteristics,
|
||||
key: 'thisisntright',
|
||||
});
|
||||
});
|
||||
|
||||
it('renders empty when nextCharacteristics is empty', () => {
|
||||
// Given
|
||||
fakeNextCharacteristics = null;
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetSettingsView
|
||||
nextCharacteristics={fakeNextCharacteristics}
|
||||
setNextCharacteristics={mockSetNextCharacteristics}
|
||||
/>
|
||||
);
|
||||
|
||||
// Then
|
||||
expect(component.isEmptyRender()).toBe(true);
|
||||
});
|
||||
|
||||
it('configures and renders the host input', () => {
|
||||
// Given
|
||||
fakeNextCharacteristics = {
|
||||
...fakeNextCharacteristics,
|
||||
host: 'thisisntright.local',
|
||||
key: 'thisisntright',
|
||||
};
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetSettingsView
|
||||
nextCharacteristics={fakeNextCharacteristics}
|
||||
setNextCharacteristics={mockSetNextCharacteristics}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
const input = component.find(Form.Control).at(0);
|
||||
|
||||
// Then
|
||||
expect(input.exists()).toBe(true);
|
||||
expect(input.prop('value')).toEqual(fakeNextCharacteristics.host);
|
||||
});
|
||||
|
||||
it('configures and renders the key input', () => {
|
||||
// Given
|
||||
fakeNextCharacteristics = {
|
||||
...fakeNextCharacteristics,
|
||||
host: 'thisisntright.local',
|
||||
key: 'thisisntright',
|
||||
};
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetSettingsView
|
||||
nextCharacteristics={fakeNextCharacteristics}
|
||||
setNextCharacteristics={mockSetNextCharacteristics}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
const input = component.find(Form.Control).at(1);
|
||||
|
||||
// Then
|
||||
expect(input.exists()).toBe(true);
|
||||
expect(input.prop('value')).toEqual(fakeNextCharacteristics.key);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Group', () => {
|
||||
let fakeData = null;
|
||||
let mockOnSetLightsState = null;
|
||||
|
||||
beforeEach(() => {
|
||||
fakeData = TradfriDataFactory();
|
||||
mockOnSetLightsState = jasmine.createSpy();
|
||||
});
|
||||
|
||||
it('calls the onSetLightsState callback when it is clicked', () => {
|
||||
// Given
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.Group
|
||||
group={fakeData.groups[0]}
|
||||
lights={fakeData.lights}
|
||||
onSetLightsState={mockOnSetLightsState}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
component.simulate('click');
|
||||
|
||||
// Then
|
||||
expect(mockOnSetLightsState).toHaveBeenCalledWith(
|
||||
['light1', 'light2'], false
|
||||
);
|
||||
});
|
||||
|
||||
it('renders as on when all the lights in the the group are on', () => {
|
||||
// Given
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.Group
|
||||
group={fakeData.groups[0]}
|
||||
lights={fakeData.lights}
|
||||
onSetLightsState={mockOnSetLightsState}
|
||||
/>
|
||||
);
|
||||
|
||||
// Then
|
||||
expect(component.hasClass('group-on')).toBe(true);
|
||||
});
|
||||
|
||||
it('does not render as of when some of the lights in the the group are off', () => {
|
||||
// Given
|
||||
fakeData.lights[0].state = false;
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.Group
|
||||
group={fakeData.groups[0]}
|
||||
lights={fakeData.lights}
|
||||
onSetLightsState={mockOnSetLightsState}
|
||||
/>
|
||||
);
|
||||
|
||||
// Then
|
||||
expect(component.hasClass('group-on')).toBe(false);
|
||||
});
|
||||
|
||||
it('renders the group name', () => {
|
||||
// Given
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.Group
|
||||
group={fakeData.groups[0]}
|
||||
lights={fakeData.lights}
|
||||
onSetLightsState={mockOnSetLightsState}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
const groupName = component.find('span[_hint="GroupName"]').at(0);
|
||||
|
||||
// Then
|
||||
expect(groupName.exists()).toBe(true);
|
||||
expect(groupName.text()).toEqual(fakeData.groups[0].name);
|
||||
});
|
||||
});
|
||||
|
||||
describe('TradfriWidgetView', () => {
|
||||
let fakeAppearance = null;
|
||||
let fakeService = null;
|
||||
let fakeServiceState = null;
|
||||
let fakeData = null;
|
||||
let mockSetServiceState = null;
|
||||
|
||||
beforeEach(() => {
|
||||
fakeAppearance = {color: 'red'};
|
||||
fakeService = new TradfriService({
|
||||
instance: 'testing',
|
||||
layout: {x: 0, y: 0, h: 1, w: 1},
|
||||
});
|
||||
fakeData = TradfriDataFactory();
|
||||
fakeServiceState = new ServiceState({
|
||||
data: fakeData,
|
||||
});
|
||||
mockSetServiceState = jasmine.createSpy();
|
||||
|
||||
spyOn(fakeService, 'setLightsState').and.resolveTo('ok');
|
||||
});
|
||||
|
||||
it('defines the widget attributes', () => {
|
||||
// Then
|
||||
expect(TradfriWidgetView.TradfriWidgetView.defaultLayout).toEqual({
|
||||
h: jasmine.any(Number),
|
||||
w: jasmine.any(Number),
|
||||
});
|
||||
expect(TradfriWidgetView.TradfriWidgetView.icon).toBeDefined();
|
||||
expect(TradfriWidgetView.TradfriWidgetView.layoutConstraints).toEqual({
|
||||
minH: jasmine.any(Number),
|
||||
minW: jasmine.any(Number),
|
||||
});
|
||||
expect(TradfriWidgetView.TradfriWidgetView.settingsView).toEqual(
|
||||
TradfriWidgetView.TradfriWidgetSettingsView
|
||||
);
|
||||
expect(TradfriWidgetView.TradfriWidgetView.title).toEqual('Tradfri');
|
||||
});
|
||||
|
||||
it('handles group lights state change', () => {
|
||||
// Given
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetView
|
||||
appearance={fakeAppearance}
|
||||
service={fakeService}
|
||||
serviceState={fakeServiceState}
|
||||
setServiceState={mockSetServiceState}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
component.find(TradfriWidgetView.Group).at(0).invoke('onSetLightsState')(
|
||||
['light1'], false
|
||||
);
|
||||
|
||||
// Then
|
||||
expect(fakeService.setLightsState).toHaveBeenCalledWith(
|
||||
['light1'], false
|
||||
);
|
||||
|
||||
const expectedNewState = {data: {...fakeData}};
|
||||
expectedNewState.data.lights[0].state = false;
|
||||
expect(mockSetServiceState).toHaveBeenCalledWith(expectedNewState);
|
||||
});
|
||||
|
||||
it('renders empty when service state is null', () => {
|
||||
// Given
|
||||
fakeServiceState = null;
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetView
|
||||
appearance={fakeAppearance}
|
||||
service={fakeService}
|
||||
serviceState={fakeServiceState}
|
||||
setServiceState={mockSetServiceState}
|
||||
/>
|
||||
);
|
||||
|
||||
// Then
|
||||
expect(component.isEmptyRender()).toBe(true);
|
||||
});
|
||||
|
||||
it('configures and renders the Widget', () => {
|
||||
// Given
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetView
|
||||
appearance={fakeAppearance}
|
||||
service={fakeService}
|
||||
serviceState={fakeServiceState}
|
||||
setServiceState={mockSetServiceState}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
const widget = component.find(Widget).at(0);
|
||||
|
||||
// Then
|
||||
expect(widget.exists()).toBe(true);
|
||||
expect(widget.prop('appearance')).toEqual(fakeAppearance);
|
||||
});
|
||||
|
||||
it('renders the loader when state is loading', () => {
|
||||
// Given
|
||||
spyOn(fakeServiceState, 'isLoading').and.returnValue(true);
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetView
|
||||
appearance={fakeAppearance}
|
||||
service={fakeService}
|
||||
serviceState={fakeServiceState}
|
||||
setServiceState={mockSetServiceState}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
const loader = component.find('Icon[_hint="Loader"]').at(0);
|
||||
|
||||
// Then
|
||||
expect(loader.exists()).toBe(true);
|
||||
expect(loader.prop('icon')).toBeDefined();
|
||||
});
|
||||
|
||||
it('does not render the loader when state is not loading', () => {
|
||||
// Given
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetView
|
||||
appearance={fakeAppearance}
|
||||
service={fakeService}
|
||||
serviceState={fakeServiceState}
|
||||
setServiceState={mockSetServiceState}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
const loader = component.find('Icon[_hint="Loader"]').at(0);
|
||||
|
||||
// Then
|
||||
expect(loader.exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not compute and render groups when service state has no data', () => {
|
||||
// Given
|
||||
spyOn(fakeServiceState, 'hasData').and.returnValue(false);
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetView
|
||||
appearance={fakeAppearance}
|
||||
service={fakeService}
|
||||
serviceState={fakeServiceState}
|
||||
setServiceState={mockSetServiceState}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
const groups = component.find(TradfriWidgetView.Group);
|
||||
|
||||
// Then
|
||||
expect(groups.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('configures and renders a Group for every group', () => {
|
||||
// Given
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetView
|
||||
appearance={fakeAppearance}
|
||||
service={fakeService}
|
||||
serviceState={fakeServiceState}
|
||||
setServiceState={mockSetServiceState}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
const groups = component.find(TradfriWidgetView.Group);
|
||||
|
||||
// Then
|
||||
expect(groups.length).toEqual(1);
|
||||
|
||||
const group = groups.at(0);
|
||||
expect(group.prop('group')).toEqual(fakeData.groups[0]);
|
||||
expect(group.prop('lights')).toEqual(fakeData.lights);
|
||||
});
|
||||
|
||||
it('does not render FatalError if service state has no fatal error', () => {
|
||||
// Given
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetView
|
||||
appearance={fakeAppearance}
|
||||
service={fakeService}
|
||||
serviceState={fakeServiceState}
|
||||
setServiceState={mockSetServiceState}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
const fatalError = component.find(FatalError).at(0);
|
||||
|
||||
// Then
|
||||
expect(fatalError.exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('configures and renders FatalError if service state has fatal error', () => {
|
||||
// Given
|
||||
spyOn(fakeServiceState, 'hasFatalError').and.returnValue(true);
|
||||
const component = shallow(
|
||||
<TradfriWidgetView.TradfriWidgetView
|
||||
appearance={fakeAppearance}
|
||||
service={fakeService}
|
||||
serviceState={fakeServiceState}
|
||||
setServiceState={mockSetServiceState}
|
||||
/>
|
||||
);
|
||||
|
||||
// When
|
||||
const fatalError = component.find(FatalError).at(0);
|
||||
|
||||
// Then
|
||||
expect(fatalError.exists()).toBe(true);
|
||||
expect(fatalError.prop('service')).toEqual(fakeService);
|
||||
expect(fatalError.prop('serviceState')).toEqual(fakeServiceState);
|
||||
});
|
||||
});
|
||||
});
|
||||
6
packages/homehub_tradfri/tests/__entry__.js
Normal file
6
packages/homehub_tradfri/tests/__entry__.js
Normal file
@@ -0,0 +1,6 @@
|
||||
require('regenerator-runtime');
|
||||
|
||||
require('tests/__setup__/enzyme.setup.js');
|
||||
|
||||
let testsContext = require.context('.', true, /\.spec\.js$/);
|
||||
testsContext.keys().forEach(testsContext);
|
||||
34
packages/homehub_tradfri/tests/__fixtures__/tradfri.js
Normal file
34
packages/homehub_tradfri/tests/__fixtures__/tradfri.js
Normal file
@@ -0,0 +1,34 @@
|
||||
export const TradfriDataFactory = () => {
|
||||
return {
|
||||
lights: [
|
||||
{
|
||||
'id': 'light1',
|
||||
'name': 'Light 1',
|
||||
'state': true,
|
||||
'reachable': false,
|
||||
'dimmer': 128,
|
||||
},
|
||||
{
|
||||
'id': 'light2',
|
||||
'name': 'Light 2',
|
||||
'state': true,
|
||||
'reachable': false,
|
||||
'dimmer': 128,
|
||||
},
|
||||
{
|
||||
'id': 'light3',
|
||||
'name': 'Light 3',
|
||||
'state': true,
|
||||
'reachable': false,
|
||||
'dimmer': 128,
|
||||
},
|
||||
],
|
||||
groups: [
|
||||
{
|
||||
'id': 'group1',
|
||||
'name': 'Group 1',
|
||||
'member_ids': ['light1', 'light2'],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
7
packages/homehub_tradfri/tests/__setup__/enzyme.setup.js
Normal file
7
packages/homehub_tradfri/tests/__setup__/enzyme.setup.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import Enzyme from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
|
||||
Enzyme.configure({
|
||||
adapter: new Adapter(),
|
||||
disableLifecycleMethods: true,
|
||||
});
|
||||
Reference in New Issue
Block a user