Files
openstapps/src/app/modules/settings/settings.provider.spec.ts
2019-07-10 12:38:29 +02:00

398 lines
14 KiB
TypeScript

/*
* Copyright (C) 2018, 2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {TestBed} from '@angular/core/testing';
import {SCSetting, SCThingOriginType, SCThingType, SCSettingInputType} from '@openstapps/core';
import {ConfigProvider} from '../config/config.provider';
import {StorageProvider} from '../storage/storage.provider';
import {SettingsProvider, SettingValuesContainer, STORAGE_KEY_SETTING_VALUES} from './settings.provider';
import {Geolocation} from '@ionic-native/geolocation/ngx';
describe('SettingsProvider', () => {
let configProviderSpy: jasmine.SpyObj<ConfigProvider>;
let settingsProvider: SettingsProvider;
let storageProviderSpy: jasmine.SpyObj<StorageProvider>;
beforeEach(async () => {
const storageProviderMethodSpy = jasmine.createSpyObj('StorageProvider', ['init', 'get', 'has', 'put']);
const configProviderMethodSpy = jasmine.createSpyObj('ConfigProvider', ['getValue']);
TestBed.configureTestingModule({
imports: [],
providers: [
SettingsProvider,
{
provide: StorageProvider, useValue: storageProviderMethodSpy,
},
{
provide: ConfigProvider, useValue: configProviderMethodSpy,
},
Geolocation,
],
});
configProviderSpy = TestBed.get(ConfigProvider);
// set settings returned from config
configProviderSpy.getValue.and.returnValue(Promise.resolve(CONFIG_SETTINGS_MOCK));
settingsProvider = TestBed.get(SettingsProvider);
storageProviderSpy = TestBed.get(StorageProvider);
storageProviderMethodSpy.has.and.returnValue(false);
});
it('should provide and get setting', async () => {
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(CONFIG_SETTINGS_MOCK[0])));
const setting: SCSetting = await settingsProvider
.getSetting(CONFIG_SETTINGS_MOCK[0].categories[0], CONFIG_SETTINGS_MOCK[0].name);
await expect(setting.value).toBeDefined();
});
it('should provide and get settings value', async () => {
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(CONFIG_SETTINGS_MOCK[0])));
const value = await settingsProvider
.getValue(CONFIG_SETTINGS_MOCK[0].categories[0], CONFIG_SETTINGS_MOCK[0].name);
await expect(value).toEqual(CONFIG_SETTINGS_MOCK[0].defaultValue);
});
it('should get persisted setting value', async () => {
// set return values of storage
storageProviderSpy.has.and.returnValue(Promise.resolve(true));
storageProviderSpy.get.and.returnValue(Promise.resolve(SETTING_VALUES_MOCK));
const value = await settingsProvider
.getValue(CONFIG_SETTINGS_MOCK[3].categories[0], CONFIG_SETTINGS_MOCK[3].name);
await expect(value).toEqual(SETTING_VALUES_MOCK.profile.group);
});
it('should set default setting value if no persisted value exist', async () => {
// set return values of spy objects
storageProviderSpy.has.and.returnValue(Promise.resolve(true));
storageProviderSpy.get.and.returnValue(Promise.resolve([]));
const value = await settingsProvider
.getValue(CONFIG_SETTINGS_MOCK[3].categories[0], CONFIG_SETTINGS_MOCK[3].name);
await expect(value).toEqual(CONFIG_SETTINGS_MOCK[3].defaultValue);
});
it('should keep persisted setting values from settings that are not contained in loaded config', async () => {
const settings = [
CONFIG_SETTINGS_MOCK[4],
CONFIG_SETTINGS_MOCK[5],
];
configProviderSpy.getValue.and.returnValue(Promise.resolve(settings));
storageProviderSpy.has.and.returnValue(Promise.resolve(true));
storageProviderSpy.get.and.returnValue(Promise.resolve(SETTING_VALUES_MOCK));
await settingsProvider.init();
await expect(storageProviderSpy.put).toHaveBeenCalledWith(STORAGE_KEY_SETTING_VALUES, SETTING_VALUES_MOCK);
});
it('should set value of a provided setting', async () => {
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(CONFIG_SETTINGS_MOCK[1])));
await settingsProvider
.setSettingValue(CONFIG_SETTINGS_MOCK[1].categories[0], CONFIG_SETTINGS_MOCK[1].name, 'updated');
const value = await settingsProvider
.getValue(CONFIG_SETTINGS_MOCK[1].categories[0], CONFIG_SETTINGS_MOCK[1].name);
await expect(value).toEqual('updated');
});
it('should return copy of settingsCache', async () => {
const category = CONFIG_SETTINGS_MOCK[0].categories[0];
const name = CONFIG_SETTINGS_MOCK[0].name;
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(CONFIG_SETTINGS_MOCK[0])));
const settings = await settingsProvider.getCache();
settings[category].settings[name].value = 'testValue';
// cached setting value should still be defaultValue
await expect((await settingsProvider.getValue(category, name)))
.toEqual(CONFIG_SETTINGS_MOCK[0].defaultValue);
});
it('should call storage put on setSettingValue', async () => {
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(CONFIG_SETTINGS_MOCK[0])));
await settingsProvider
.setSettingValue(CONFIG_SETTINGS_MOCK[0].categories[0], CONFIG_SETTINGS_MOCK[0].name, '');
await expect(storageProviderSpy.put).toHaveBeenCalled();
});
it('should clear settings', async () => {
await settingsProvider.reset();
await expect(storageProviderSpy.put).toHaveBeenCalledWith(STORAGE_KEY_SETTING_VALUES, {});
});
it('should reset settings', async () => {
const category = CONFIG_SETTINGS_MOCK[0].categories[0];
const name = CONFIG_SETTINGS_MOCK[0].name;
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(CONFIG_SETTINGS_MOCK[0])));
await settingsProvider.setSettingValue(category, name, 'guest');
await settingsProvider.resetDefault();
const value = await settingsProvider
.getValue(CONFIG_SETTINGS_MOCK[0].categories[0], CONFIG_SETTINGS_MOCK[0].name);
await expect(value).toEqual(CONFIG_SETTINGS_MOCK[0].defaultValue);
});
it('should validate wrong values for inputType text', async () => {
await testValue(CONFIG_SETTINGS_MOCK[0], 123456789);
await testValue(CONFIG_SETTINGS_MOCK[0], false);
await testValue(CONFIG_SETTINGS_MOCK[0], []);
});
it('should validate wrong values for inputType password', async () => {
await testValue(CONFIG_SETTINGS_MOCK[0], 123456789);
await testValue(CONFIG_SETTINGS_MOCK[0], false);
await testValue(CONFIG_SETTINGS_MOCK[0], []);
});
it('should validate wrong values for inputType number', async () => {
await testValue(CONFIG_SETTINGS_MOCK[2], '');
await testValue(CONFIG_SETTINGS_MOCK[2], false);
await testValue(CONFIG_SETTINGS_MOCK[2], []);
});
it('should validate wrong values for inputType singleChoice text', async () => {
await testValue(CONFIG_SETTINGS_MOCK[3], '');
await testValue(CONFIG_SETTINGS_MOCK[3], 123456);
await testValue(CONFIG_SETTINGS_MOCK[3], false);
await testValue(CONFIG_SETTINGS_MOCK[3], []);
});
it('should validate wrong values for inputType singleChoice boolean', async () => {
await testValue(CONFIG_SETTINGS_MOCK[5], '');
await testValue(CONFIG_SETTINGS_MOCK[5], 123456);
await testValue(CONFIG_SETTINGS_MOCK[5], []);
});
it('should validate wrong values for inputType multipleChoice', async () => {
await testValue(CONFIG_SETTINGS_MOCK[6], '');
await testValue(CONFIG_SETTINGS_MOCK[6], 123456);
await testValue(CONFIG_SETTINGS_MOCK[6], false);
await testValue(CONFIG_SETTINGS_MOCK[6], [1, 9]);
});
async function testValue(setting: SCSetting, value: any) {
let error: Error;
await settingsProvider.provideSetting(JSON.parse(JSON.stringify(setting)));
try {
await settingsProvider.setSettingValue(setting.categories[0], setting.name, value);
} catch (err) {
error = err;
}
// @ts-ignore
await expect(error).toBeDefined();
// @ts-ignore
await expect(error.message).toMatch(/is not valid/);
}
const CONFIG_SETTINGS_MOCK: SCSetting[] = [
{
categories: ['credentials'],
defaultValue: '',
inputType: SCSettingInputType.Text,
name: 'username',
order: 0,
origin: {
indexed: '2018-09-11T12:30:00Z',
name: 'Dummy',
type: SCThingOriginType.Remote,
},
translations: {
de: {
categories: ['Anmeldedaten'],
name: 'Benutzername',
},
en: {
categories: ['Credentials'],
name: 'Username',
},
},
type: SCThingType.Setting,
uid: '',
},
{
categories: ['credentials'],
description: '',
defaultValue: '',
inputType: SCSettingInputType.Password,
name: 'password',
order: 1,
origin: {
indexed: '2018-09-11T12:30:00Z',
name: 'Dummy',
type: SCThingOriginType.Remote,
},
translations: {
de: {
categories: ['Anmeldedaten'],
name: 'Passwort',
},
en: {
categories: ['Credentials'],
name: 'Password',
},
},
type: SCThingType.Setting,
uid: '',
},
{
categories: ['profile'],
description: '',
defaultValue: 0,
inputType: SCSettingInputType.Number,
name: 'age',
order: 0,
origin: {
indexed: '2018-09-11T12:30:00Z',
name: 'Dummy',
type: SCThingOriginType.Remote,
},
translations: {
de: {
categories: ['Profil'],
name: 'Alter',
},
en: {
categories: ['Profile'],
name: 'Age',
},
},
type: SCThingType.Setting,
uid: '',
},
{
categories: ['profile'],
description: '',
defaultValue: 'student',
inputType: SCSettingInputType.SingleChoice,
name: 'group',
order: 1,
origin: {
indexed: '2018-09-11T12:30:00Z',
name: 'Dummy',
type: SCThingOriginType.Remote,
},
translations: {
de: {
categories: ['Benutzer'],
description: 'Mit welcher Benutzergruppe soll die App verwendet werden?'
+ ' Die Einstellung wird beispielsweise für die Vorauswahl der Preiskategorie der Mensa verwendet.',
name: 'Gruppe',
},
en: {
categories: ['User'],
description: 'The user group the app is going to be used.'
+ 'This settings for example is getting used for the predefined price category of mensa meals.',
name: 'Group',
},
},
type: SCThingType.Setting,
uid: '',
values: ['student', 'employee', 'guest'],
},
{
categories: ['profile'],
description: '',
defaultValue: 'en',
inputType: SCSettingInputType.SingleChoice,
name: 'language',
order: 0,
origin: {
indexed: '2018-09-11T12:30:00Z',
name: 'Dummy',
type: SCThingOriginType.Remote,
},
translations: {
de: {
categories: ['Benutzer'],
description: 'Die Sprache in der die App angezeigt werden soll',
name: 'Sprache',
},
en: {
categories: ['User'],
description: 'The language this app is going to use',
name: 'Language',
},
},
type: SCThingType.Setting,
uid: '',
values: ['en', 'de'],
},
{
categories: ['privacy'],
description: '',
defaultValue: false,
inputType: SCSettingInputType.SingleChoice,
name: 'geoLocation',
order: 0,
origin: {
indexed: '2018-09-11T12:30:00Z',
name: 'Dummy',
type: SCThingOriginType.Remote,
},
translations: {
de: {
categories: ['Privatsphäre'],
description: 'Berechtigung für die Verwendung des Ortungsdienstes, für die Anzeige der aktuellen ' +
'Position \'\n auf der Karte und zur Berechnung der Entfernung zu Gebäuden und Orten des Campus',
name: 'Position',
},
en: {
categories: ['Privacy'],
description: 'Allow the App to use the device location to provide additional informationsbased ' +
'on your actual location',
name: 'Position',
},
},
type: SCThingType.Setting,
uid: '',
values: [true, false],
},
{
categories: ['others'],
description: '',
defaultValue: [],
inputType: SCSettingInputType.MultipleChoice,
name: 'numbers',
order: 0,
origin: {
indexed: '2018-09-11T12:30:00Z',
name: 'Dummy',
type: SCThingOriginType.Remote,
},
translations: {
de: {
categories: ['Sonstiges'],
description: 'Test für multiple select Feld',
name: 'Nummern',
},
en: {
categories: ['Others'],
description: 'Test for multiple select field',
name: 'Numbers',
},
},
type: SCThingType.Setting,
uid: '',
values: [1, 2, 3, 4, 5, 6, 7, 8],
},
];
});
const SETTING_VALUES_MOCK: SettingValuesContainer = {
foo: {
bar: 'foo-bar',
},
privacy: {
geoLocation: 'true',
},
profile: {
group: 'employee',
language: 'de',
},
};