You've already forked homehub
Release 1.3.0
This commit is contained in:
273
packages/homehub_app/tests/services/time.spec.js
Normal file
273
packages/homehub_app/tests/services/time.spec.js
Normal file
@@ -0,0 +1,273 @@
|
||||
import {DateTime} from 'luxon';
|
||||
|
||||
import {Clock} from 'src/lib/clock';
|
||||
import * as TimeService from 'src/services/time';
|
||||
|
||||
describe('src/services/time', () => {
|
||||
describe('TimeService', () => {
|
||||
let fakeClock = null;
|
||||
|
||||
beforeEach(() => {
|
||||
fakeClock = jasmine.createSpyObj('FakeClock', [
|
||||
'addEventListener', 'removeEventListener',
|
||||
]);
|
||||
fakeClock.now = DateTime.local();
|
||||
spyOn(Clock, 'instance').and.returnValue(fakeClock);
|
||||
});
|
||||
|
||||
describe('emptyCharacteristics', () => {
|
||||
it('returns empty characteristics', () => {
|
||||
// Given
|
||||
const result = TimeService.TimeService.emptyCharacteristics();
|
||||
|
||||
// Then
|
||||
expect(result).toEqual({
|
||||
locale: '',
|
||||
timeFormat: '',
|
||||
dateFormat: 'DATE_HUGE',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('payloadFromDateTime', () => {
|
||||
let now = null;
|
||||
|
||||
beforeEach(() => {
|
||||
now = DateTime.local(1985, 10, 3, 8, 0, 0);
|
||||
spyOn(now, 'setLocale').and.callFake(() => {
|
||||
return now;
|
||||
});
|
||||
spyOn(now, 'toFormat').and.returnValue('Formatted Time String');
|
||||
|
||||
spyOn(now, 'toLocaleString');
|
||||
now.toLocaleString.withArgs(DateTime.TIME_SIMPLE).and.returnValue(
|
||||
'Simple Time String'
|
||||
);
|
||||
now.toLocaleString.withArgs(DateTime.DATE_HUGE).and.returnValue(
|
||||
'Huge Date String'
|
||||
);
|
||||
now.toLocaleString.withArgs(DateTime.DATE_FULL).and.returnValue(
|
||||
'Full Date String'
|
||||
);
|
||||
});
|
||||
|
||||
it('sets locale if it is specified', () => {
|
||||
// Given
|
||||
const characteristics = TimeService.TimeService.emptyCharacteristics();
|
||||
characteristics.locale = 'en-us';
|
||||
const service = new TimeService.TimeService({
|
||||
instance: 'testing',
|
||||
characteristics: characteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
service.payloadFromDateTime(now);
|
||||
|
||||
// Then
|
||||
expect(now.setLocale).toHaveBeenCalledWith('en-us');
|
||||
});
|
||||
|
||||
it('does not set locale if it is not specified', () => {
|
||||
// Given
|
||||
const characteristics = TimeService.TimeService.emptyCharacteristics();
|
||||
const service = new TimeService.TimeService({
|
||||
instance: 'testing',
|
||||
characteristics: characteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
service.payloadFromDateTime(now);
|
||||
|
||||
// Then
|
||||
expect(now.setLocale).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('uses timeFormat to format the time string if it is specified', () => {
|
||||
// Given
|
||||
const characteristics = TimeService.TimeService.emptyCharacteristics();
|
||||
characteristics.timeFormat = 'hh:mm a';
|
||||
const service = new TimeService.TimeService({
|
||||
instance: 'testing',
|
||||
characteristics: characteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
const result = service.payloadFromDateTime(now);
|
||||
|
||||
// Then
|
||||
expect(result.data.time).toEqual('Formatted Time String');
|
||||
expect(now.toFormat).toHaveBeenCalledWith('hh:mm a');
|
||||
expect(now.toLocaleString).not.toHaveBeenCalledWith(
|
||||
DateTime.TIME_SIMPLE
|
||||
);
|
||||
});
|
||||
|
||||
it('uses default time format to format the time string if timeFormat is not specified', () => {
|
||||
// Given
|
||||
const characteristics = TimeService.TimeService.emptyCharacteristics();
|
||||
const service = new TimeService.TimeService({
|
||||
instance: 'testing',
|
||||
characteristics: characteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
const result = service.payloadFromDateTime(now);
|
||||
|
||||
// Then
|
||||
expect(result.data.time).toEqual('Simple Time String');
|
||||
expect(now.toFormat).not.toHaveBeenCalled();
|
||||
expect(now.toLocaleString).toHaveBeenCalledWith(DateTime.TIME_SIMPLE);
|
||||
});
|
||||
|
||||
it('uses default date format to format the date string if dateFormat is not specified', () => {
|
||||
// Given
|
||||
const characteristics = TimeService.TimeService.emptyCharacteristics();
|
||||
characteristics.dateFormat = '';
|
||||
const service = new TimeService.TimeService({
|
||||
instance: 'testing',
|
||||
characteristics: characteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
const result = service.payloadFromDateTime(now);
|
||||
|
||||
// Then
|
||||
expect(result.data.date).toEqual('Huge Date String');
|
||||
expect(now.toLocaleString).toHaveBeenCalledWith(DateTime.DATE_HUGE);
|
||||
});
|
||||
|
||||
it('uses dateFormat to format the date string if it is specified', () => {
|
||||
// Given
|
||||
const characteristics = TimeService.TimeService.emptyCharacteristics();
|
||||
characteristics.dateFormat = 'DATE_FULL';
|
||||
const service = new TimeService.TimeService({
|
||||
instance: 'testing',
|
||||
characteristics: characteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
const result = service.payloadFromDateTime(now);
|
||||
|
||||
// Then
|
||||
expect(result.data.date).toEqual('Full Date String');
|
||||
expect(now.toLocaleString).toHaveBeenCalledWith(DateTime.DATE_FULL);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onClockTick', () => {
|
||||
it('notfies subscribers with payload', () => {
|
||||
// Given
|
||||
const characteristics = TimeService.TimeService.emptyCharacteristics();
|
||||
const fakePayload = {
|
||||
data: {
|
||||
date: '1987-10-03',
|
||||
time: '08:00 AM',
|
||||
},
|
||||
};
|
||||
const service = new TimeService.TimeService({
|
||||
instance: 'testing',
|
||||
characteristics: characteristics,
|
||||
});
|
||||
spyOn(service, 'payloadFromDateTime').and.returnValue(fakePayload);
|
||||
spyOn(service, 'notify');
|
||||
|
||||
// When
|
||||
service.onClockTick(fakeClock);
|
||||
|
||||
// Then
|
||||
expect(service.notify).toHaveBeenCalledWith(fakePayload);
|
||||
expect(service.payloadFromDateTime).toHaveBeenCalledWith(
|
||||
fakeClock.now
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('initialState', () => {
|
||||
it('returns payload from the current timestamp', () => {
|
||||
// Given
|
||||
const characteristics = TimeService.TimeService.emptyCharacteristics();
|
||||
const fakePayload = {
|
||||
data: {
|
||||
date: '1987-10-03',
|
||||
time: '08:00 AM',
|
||||
},
|
||||
};
|
||||
const service = new TimeService.TimeService({
|
||||
instance: 'testing',
|
||||
characteristics: characteristics,
|
||||
});
|
||||
spyOn(service, 'payloadFromDateTime').and.returnValue(fakePayload);
|
||||
|
||||
// When
|
||||
const result = service.initialState();
|
||||
|
||||
// Then
|
||||
expect(result).toEqual(fakePayload);
|
||||
expect(service.payloadFromDateTime).toHaveBeenCalledWith(
|
||||
fakeClock.now
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setCharacteristics', () => {
|
||||
it('triggers the onClockTick to update', () => {
|
||||
// Given
|
||||
const characteristics = TimeService.TimeService.emptyCharacteristics();
|
||||
const newCharacteristics = {
|
||||
...characteristics,
|
||||
locale: 'en-us',
|
||||
};
|
||||
const service = new TimeService.TimeService({
|
||||
instance: 'testing',
|
||||
characteristics: characteristics,
|
||||
});
|
||||
spyOn(service, 'onClockTick');
|
||||
|
||||
// When
|
||||
service.setCharacteristics(newCharacteristics);
|
||||
|
||||
// Then
|
||||
expect(service.characteristics).toEqual(newCharacteristics);
|
||||
expect(service.onClockTick).toHaveBeenCalledWith(fakeClock);
|
||||
});
|
||||
});
|
||||
|
||||
describe('start', () => {
|
||||
it('adds event listener for the clock tick event', async () => {
|
||||
// Given
|
||||
const characteristics = TimeService.TimeService.emptyCharacteristics();
|
||||
const service = new TimeService.TimeService({
|
||||
instance: 'testing',
|
||||
characteristics: characteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
await service.start();
|
||||
|
||||
// Then
|
||||
expect(fakeClock.addEventListener).toHaveBeenCalledWith(
|
||||
'tick', service.onClockTick
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('start', () => {
|
||||
it('removes event listener for the clock tick event', async () => {
|
||||
// Given
|
||||
const characteristics = TimeService.TimeService.emptyCharacteristics();
|
||||
const service = new TimeService.TimeService({
|
||||
instance: 'testing',
|
||||
characteristics: characteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
await service.stop();
|
||||
|
||||
// Then
|
||||
expect(fakeClock.removeEventListener).toHaveBeenCalledWith(
|
||||
'tick', service.onClockTick
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
56
packages/homehub_app/tests/services/uptime.spec.js
Normal file
56
packages/homehub_app/tests/services/uptime.spec.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import * as HomeHubCore from '@bthlabs/homehub-core';
|
||||
|
||||
import * as UptimeService from 'src/services/uptime';
|
||||
|
||||
describe('src/services/uptime', () => {
|
||||
describe('UptimeService', () => {
|
||||
let fakeResult = null;
|
||||
|
||||
beforeEach(() => {
|
||||
fakeResult = {
|
||||
data: 123,
|
||||
};
|
||||
|
||||
spyOn(HomeHubCore.API.Services, 'start').and.returnValue(fakeResult);
|
||||
spyOn(HomeHubCore.API.Services, 'stop').and.returnValue('ok');
|
||||
});
|
||||
|
||||
describe('start', () => {
|
||||
it('notifies subscribers with the result of start service API call', async () => {
|
||||
// Given
|
||||
const service = new UptimeService.UptimeService({
|
||||
instance: 'testing',
|
||||
characteristics: {},
|
||||
});
|
||||
spyOn(service, 'notify');
|
||||
|
||||
// When
|
||||
await service.start();
|
||||
|
||||
// Then
|
||||
expect(HomeHubCore.API.Services.start).toHaveBeenCalledWith(
|
||||
service.kind, 'testing', {}
|
||||
);
|
||||
expect(service.notify).toHaveBeenCalledWith(fakeResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stop', () => {
|
||||
it('calls the stop service API method', async () => {
|
||||
// Given
|
||||
const service = new UptimeService.UptimeService({
|
||||
instance: 'testing',
|
||||
characteristics: {},
|
||||
});
|
||||
|
||||
// When
|
||||
await service.stop();
|
||||
|
||||
// Then
|
||||
expect(HomeHubCore.API.Services.stop).toHaveBeenCalledWith(
|
||||
service.kind, 'testing'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
578
packages/homehub_app/tests/services/weather.spec.js
Normal file
578
packages/homehub_app/tests/services/weather.spec.js
Normal file
@@ -0,0 +1,578 @@
|
||||
import * as HomeHubCore from '@bthlabs/homehub-core';
|
||||
import noop from 'lodash/noop';
|
||||
import {DateTime} from 'luxon';
|
||||
|
||||
import {Clock} from 'src/lib/clock';
|
||||
import * as WeatherService from 'src/services/weather';
|
||||
|
||||
import {WeatherFactory} from 'tests/__fixtures__/weather';
|
||||
|
||||
describe('src/services/weather', () => {
|
||||
describe('WeatherService', () => {
|
||||
let fakeCharacteristics = null;
|
||||
let fakeResult = null;
|
||||
|
||||
beforeEach(() => {
|
||||
fakeCharacteristics = {
|
||||
city: 'Wroclaw,PL',
|
||||
units: 'metric',
|
||||
};
|
||||
fakeResult = {
|
||||
data: WeatherFactory(),
|
||||
};
|
||||
|
||||
spyOn(HomeHubCore.API.Services, 'start').and.returnValue(fakeResult);
|
||||
spyOn(HomeHubCore.API.Services, 'stop').and.returnValue('ok');
|
||||
});
|
||||
|
||||
describe('emptyCharacteristics', () => {
|
||||
it('returns empty characteristics', () => {
|
||||
// Given
|
||||
const result = WeatherService.WeatherService.emptyCharacteristics();
|
||||
|
||||
// Then
|
||||
expect(result).toEqual({
|
||||
city: '',
|
||||
units: 'metric',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('start', () => {
|
||||
it('notifies subscribers with the result of start service API call', async () => {
|
||||
// Given
|
||||
const service = new WeatherService.WeatherService({
|
||||
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 WeatherService.WeatherService({
|
||||
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 = {
|
||||
city: 'Poznan,PL',
|
||||
units: 'imperial',
|
||||
};
|
||||
const service = new WeatherService.WeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'restart');
|
||||
|
||||
// When
|
||||
service.setCharacteristics(newCharacteristics);
|
||||
|
||||
// Then
|
||||
expect(service.characteristics).toEqual(newCharacteristics);
|
||||
});
|
||||
|
||||
it('restarts the service if city characteristic changed', () => {
|
||||
// Given
|
||||
const newCharacteristics = {
|
||||
...fakeCharacteristics,
|
||||
city: 'Poznan,PL',
|
||||
};
|
||||
const service = new WeatherService.WeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'restart');
|
||||
|
||||
// When
|
||||
service.setCharacteristics(newCharacteristics);
|
||||
|
||||
// Then
|
||||
expect(service.restart).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('restarts the service if units characteristic changed', () => {
|
||||
// Given
|
||||
const newCharacteristics = {
|
||||
...fakeCharacteristics,
|
||||
units: 'imperial',
|
||||
};
|
||||
const service = new WeatherService.WeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'restart');
|
||||
|
||||
// When
|
||||
service.setCharacteristics(newCharacteristics);
|
||||
|
||||
// Then
|
||||
expect(service.restart).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('OfflineWeatherService', () => {
|
||||
let fakeCharacteristics = null;
|
||||
let fakeClock = null;
|
||||
let fakeDateTime = null;
|
||||
let fakeResult = null;
|
||||
|
||||
beforeEach(() => {
|
||||
fakeCharacteristics = {
|
||||
city: 'Wroclaw,PL',
|
||||
units: 'metric',
|
||||
apiKey: 'API_KEY',
|
||||
};
|
||||
|
||||
fakeClock = jasmine.createSpyObj(
|
||||
'FakeClock', ['addEventListener', 'removeEventListener']
|
||||
);
|
||||
fakeClock.now = DateTime.local(1987, 10, 3, 8, 0, 0);
|
||||
spyOn(Clock, 'instance').and.returnValue(fakeClock);
|
||||
|
||||
fakeDateTime = DateTime.local(1987, 10, 3, 8, 0, 0);
|
||||
spyOn(DateTime, 'fromSeconds').and.returnValue(fakeDateTime);
|
||||
|
||||
fakeResult = {
|
||||
data: WeatherFactory(),
|
||||
};
|
||||
|
||||
spyOn(document, 'createElement');
|
||||
spyOn(document.body, 'appendChild');
|
||||
spyOn(document.body, 'removeChild');
|
||||
spyOn(HomeHubCore.LocalStorage, 'getItem').and.returnValue(null);
|
||||
spyOn(HomeHubCore.LocalStorage, 'setItem');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
const kind = WeatherService.OfflineWeatherService.kind;
|
||||
const callbackKey = `${kind}_testing_callback`;
|
||||
window[callbackKey] = undefined;
|
||||
});
|
||||
|
||||
it('defines availability properties', () => {
|
||||
// Then
|
||||
expect(WeatherService.OfflineWeatherService.availableOnline).toBe(false);
|
||||
expect(WeatherService.OfflineWeatherService.availableOffline).toBe(true);
|
||||
});
|
||||
|
||||
describe('emptyCharacteristics', () => {
|
||||
it('returns empty characteristics', () => {
|
||||
// Given
|
||||
const result = WeatherService.OfflineWeatherService.emptyCharacteristics();
|
||||
|
||||
// Then
|
||||
expect(result).toEqual({
|
||||
city: '',
|
||||
units: 'metric',
|
||||
apiKey: '',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('constructor', () => {
|
||||
it('initializes an instance', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'this-should-be-an-uuid4',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
|
||||
// Then
|
||||
expect(service.instanceKey).toEqual(
|
||||
`${service.kind}_this_should_be_an_uuid4`
|
||||
);
|
||||
expect(service.callbackKey).toEqual(
|
||||
`${service.kind}_this_should_be_an_uuid4_callback`
|
||||
);
|
||||
expect(service.lastScriptElement).toBe(null);
|
||||
expect(service.lastData).toBe(null);
|
||||
expect(service.lastRefreshDt).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('start', () => {
|
||||
it('installs the JSONP callback', async () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'refresh');
|
||||
|
||||
// When
|
||||
await service.start();
|
||||
|
||||
// Then
|
||||
expect(window[service.callbackKey]).toEqual(service.onWeatherCallback);
|
||||
});
|
||||
|
||||
it('does not initialize the last data if it is missing from local storage', async () => {
|
||||
// Given
|
||||
HomeHubCore.LocalStorage.getItem.and.returnValue(null);
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'refresh');
|
||||
|
||||
// When
|
||||
await service.start();
|
||||
|
||||
// Then
|
||||
expect(service.lastData).toBe(null);
|
||||
expect(service.lastRefreshDt).toBe(null);
|
||||
expect(HomeHubCore.LocalStorage.getItem).toHaveBeenCalledWith(
|
||||
`${service.instanceKey}_lastData`
|
||||
);
|
||||
});
|
||||
|
||||
it('initializes last data if it is present in local storage', async () => {
|
||||
// Given
|
||||
HomeHubCore.LocalStorage.getItem.and.returnValue(fakeResult);
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'refresh');
|
||||
|
||||
// When
|
||||
await service.start();
|
||||
|
||||
// Then
|
||||
expect(service.lastData).toEqual(fakeResult);
|
||||
expect(service.lastRefreshDt).toEqual(fakeDateTime);
|
||||
expect(DateTime.fromSeconds).toHaveBeenCalledWith(fakeResult.dt);
|
||||
});
|
||||
|
||||
it('triggers a refresh', async () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'refresh');
|
||||
|
||||
// When
|
||||
await service.start();
|
||||
|
||||
// Then
|
||||
expect(service.refresh).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('adds event listener for the clock tick event', async () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'refresh');
|
||||
|
||||
// When
|
||||
await service.start();
|
||||
|
||||
// Then
|
||||
expect(Clock.instance().addEventListener).toHaveBeenCalledWith(
|
||||
'tick', service.onClockTick
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stop', () => {
|
||||
it('replaces the JSONP callback with a noop', async () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
await service.stop();
|
||||
|
||||
// Then
|
||||
expect(window[service.callbackKey]).toEqual(noop);
|
||||
});
|
||||
|
||||
it('removes event listener for the clock tick event', async () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
await service.stop();
|
||||
|
||||
// Then
|
||||
expect(Clock.instance().removeEventListener).toHaveBeenCalledWith(
|
||||
'tick', service.onClockTick
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('initialState', () => {
|
||||
it('returns the initial state', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
const result = service.initialState();
|
||||
|
||||
// Then
|
||||
expect(result).toEqual({
|
||||
error: null,
|
||||
data: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns state with last data if it is present', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
service.lastData = fakeResult;
|
||||
|
||||
// When
|
||||
const result = service.initialState();
|
||||
|
||||
// Then
|
||||
expect(result).toEqual({
|
||||
error: null,
|
||||
data: fakeResult,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onClockTick', () => {
|
||||
it('does not request a refresh when it should not refresh', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'shouldRefresh').and.returnValue(false);
|
||||
spyOn(service, 'refresh');
|
||||
|
||||
// When
|
||||
service.onClockTick();
|
||||
|
||||
// Then
|
||||
expect(service.refresh).not.toHaveBeenCalled();
|
||||
expect(service.shouldRefresh).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('requests a refresh when it should refresh', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'shouldRefresh').and.returnValue(true);
|
||||
spyOn(service, 'refresh');
|
||||
|
||||
// When
|
||||
service.onClockTick();
|
||||
|
||||
// Then
|
||||
expect(service.refresh).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldRefresh', () => {
|
||||
it('returns true if last data is null', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
|
||||
// When
|
||||
const result = service.shouldRefresh();
|
||||
|
||||
// Then
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true if last refresh was more than 600 secs ago', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
service.lastData = fakeResult;
|
||||
service.lastRefreshDt = DateTime.local(1987, 10, 3, 7, 50, 0);
|
||||
|
||||
// When
|
||||
const result = service.shouldRefresh();
|
||||
|
||||
// Then
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false if last refresh was less than 600 secs ago', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
service.lastData = fakeResult;
|
||||
service.lastRefreshDt = DateTime.local(1987, 10, 3, 7, 50, 1);
|
||||
|
||||
// When
|
||||
const result = service.shouldRefresh();
|
||||
|
||||
// Then
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onWeatherCallback', () => {
|
||||
it('removes the last script element', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
service.lastScriptElement = jasmine.createSpy();
|
||||
spyOn(service, 'notify');
|
||||
|
||||
// When
|
||||
service.onWeatherCallback(fakeResult);
|
||||
|
||||
// Then
|
||||
expect(document.body.removeChild).toHaveBeenCalledWith(
|
||||
service.lastScriptElement
|
||||
);
|
||||
});
|
||||
|
||||
it('stores the data in local storage and instance', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
service.lastScriptElement = jasmine.createSpy();
|
||||
spyOn(service, 'notify');
|
||||
|
||||
// When
|
||||
service.onWeatherCallback(fakeResult);
|
||||
|
||||
// Then
|
||||
expect(service.lastData).toEqual(fakeResult);
|
||||
expect(service.lastRefreshDt).toEqual(fakeClock.now);
|
||||
expect(HomeHubCore.LocalStorage.setItem).toHaveBeenCalledWith(
|
||||
`${service.instanceKey}_lastData`, fakeResult
|
||||
);
|
||||
});
|
||||
|
||||
it('notifies subscribers with the loaded data', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
service.lastScriptElement = jasmine.createSpy();
|
||||
spyOn(service, 'notify');
|
||||
|
||||
// When
|
||||
service.onWeatherCallback(fakeResult);
|
||||
|
||||
// Then
|
||||
expect(service.notify).toHaveBeenCalledWith({
|
||||
error: null,
|
||||
data: fakeResult,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('refresh', () => {
|
||||
it('is a noop when it should not refresh', () => {
|
||||
// Given
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'shouldRefresh').and.returnValue(false);
|
||||
|
||||
// When
|
||||
service.refresh();
|
||||
|
||||
// Then
|
||||
expect(document.createElement).not.toHaveBeenCalled();
|
||||
expect(document.body.appendChild).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls the API via JSONP when it should refresh', () => {
|
||||
// Given
|
||||
const fakeScriptElement = jasmine.createSpy();
|
||||
document.createElement.and.returnValue(fakeScriptElement);
|
||||
|
||||
const service = new WeatherService.OfflineWeatherService({
|
||||
instance: 'testing',
|
||||
characteristics: fakeCharacteristics,
|
||||
});
|
||||
spyOn(service, 'shouldRefresh').and.returnValue(true);
|
||||
|
||||
// When
|
||||
service.refresh();
|
||||
|
||||
// Then
|
||||
expect(document.createElement).toHaveBeenCalledWith('script');
|
||||
expect(fakeScriptElement.async).toBe(true);
|
||||
expect(fakeScriptElement.src).toBeDefined();
|
||||
expect(fakeScriptElement.type).toEqual('text/javascript');
|
||||
expect(service.lastScriptElement).toEqual(fakeScriptElement);
|
||||
expect(document.body.appendChild).toHaveBeenCalledWith(
|
||||
fakeScriptElement
|
||||
);
|
||||
|
||||
expect(fakeScriptElement.src.startsWith(
|
||||
WeatherService.OfflineWeatherService.apiURL
|
||||
)).toBe(
|
||||
true
|
||||
);
|
||||
|
||||
const scriptSrcURL = new URL(fakeScriptElement.src);
|
||||
const scriptSrcURLParams = {};
|
||||
for (let pair of scriptSrcURL.searchParams.entries()) {
|
||||
scriptSrcURLParams[pair[0]] = pair[1];
|
||||
}
|
||||
expect(scriptSrcURLParams).toEqual({
|
||||
APPID: fakeCharacteristics.apiKey,
|
||||
callback: service.callbackKey,
|
||||
q: fakeCharacteristics.city,
|
||||
units: fakeCharacteristics.units,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user