Add tests
This commit is contained in:
parent
e3a81f7050
commit
e57977f94b
@ -178,6 +178,6 @@ export default class uLang {
|
|||||||
* @return {Object.<string, string>}
|
* @return {Object.<string, string>}
|
||||||
*/
|
*/
|
||||||
getLangList() {
|
getLangList() {
|
||||||
return this.strings['langArr'];
|
return this.strings['langArr'] || {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
|
|
||||||
import uLayer from './layer.js';
|
import uLayer from './layer.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends {Array.<uLayer>}
|
||||||
|
*/
|
||||||
export default class uLayerCollection extends Array {
|
export default class uLayerCollection extends Array {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,6 +56,7 @@ export default class uLayerCollection extends Array {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number|string} id Id or listValue
|
* @param {number|string} id Id or listValue
|
||||||
|
* @return {uLayer}
|
||||||
*/
|
*/
|
||||||
get(id) {
|
get(id) {
|
||||||
if (typeof id === 'string') {
|
if (typeof id === 'string') {
|
||||||
@ -70,6 +74,7 @@ export default class uLayerCollection extends Array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Set layer with given id as priority
|
||||||
* @param {number} id
|
* @param {number} id
|
||||||
*/
|
*/
|
||||||
setPriorityLayer(id) {
|
setPriorityLayer(id) {
|
||||||
|
@ -85,10 +85,6 @@ export default class uPosition {
|
|||||||
return (this.image != null && this.image.length > 0);
|
return (this.image != null && this.image.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
get calculatedSpeed() {
|
|
||||||
return this.seconds ? this.meters / this.seconds : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
get totalSpeed() {
|
get totalSpeed() {
|
||||||
return this.totalSeconds ? this.totalMeters / this.totalSeconds : 0;
|
return this.totalSeconds ? this.totalMeters / this.totalSeconds : 0;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ export default class uUtils {
|
|||||||
const ret = fmt.replace(/%%|%s|%d/g, (match) => {
|
const ret = fmt.replace(/%%|%s|%d/g, (match) => {
|
||||||
if (match === '%%') {
|
if (match === '%%') {
|
||||||
return '%';
|
return '%';
|
||||||
} else if (match === '%d' && isNaN(params[i])) {
|
} else if (match === '%d' && isNaN(params[i]) && typeof params[i] !== 'undefined') {
|
||||||
throw new Error(`Wrong format specifier ${match} for ${params[i]} argument`);
|
throw new Error(`Wrong format specifier ${match} for ${params[i]} argument`);
|
||||||
}
|
}
|
||||||
if (typeof params[i] === 'undefined') {
|
if (typeof params[i] === 'undefined') {
|
||||||
@ -106,6 +106,11 @@ export default class uUtils {
|
|||||||
return Promise.race([ scriptLoaded, timeout ]);
|
return Promise.race([ scriptLoaded, timeout ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Promise rejected after given time
|
||||||
|
* @param {number} ms Time in milliseconds
|
||||||
|
* @return {Promise<void, Error>}
|
||||||
|
*/
|
||||||
static timeoutPromise(ms) {
|
static timeoutPromise(ms) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const tid = setTimeout(() => {
|
const tid = setTimeout(() => {
|
||||||
@ -135,16 +140,17 @@ export default class uUtils {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
static hexToRGBA(hex, opacity) {
|
static hexToRGBA(hex, opacity) {
|
||||||
|
opacity = typeof opacity !== 'undefined' ? opacity : 1;
|
||||||
return `rgba(${(hex = hex.replace('#', ''))
|
return `rgba(${(hex = hex.replace('#', ''))
|
||||||
.match(new RegExp(`(.{${hex.length / 3}})`, 'g'))
|
.match(new RegExp(`(.{${hex.length / 3}})`, 'g'))
|
||||||
.map((l) => parseInt(hex.length % 2 ? l + l : l, 16))
|
.map((l) => parseInt(hex.length % 2 ? l + l : l, 16))
|
||||||
.concat(opacity || 1).join(',')})`;
|
.concat(opacity).join(',')})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add link tag with type css
|
* Add link tag with type css
|
||||||
* @param {string} url attribute
|
* @param {string} url attribute
|
||||||
* @param {string} id attribute
|
* @param {string=} id attribute
|
||||||
*/
|
*/
|
||||||
static addCss(url, id) {
|
static addCss(url, id) {
|
||||||
if (id && document.getElementById(id)) {
|
if (id && document.getElementById(id)) {
|
||||||
@ -166,47 +172,19 @@ export default class uUtils {
|
|||||||
*/
|
*/
|
||||||
static removeElementById(id) {
|
static removeElementById(id) {
|
||||||
const tag = document.getElementById(id);
|
const tag = document.getElementById(id);
|
||||||
if (tag && tag.parentNode) {
|
if (tag) {
|
||||||
tag.parentNode.removeChild(tag);
|
tag.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} html HTML representing a single element
|
* @param {string} html HTML representing a single element
|
||||||
* @return {Node}
|
* @return {Node|NodeList}
|
||||||
*/
|
*/
|
||||||
static nodeFromHtml(html) {
|
static nodeFromHtml(html) {
|
||||||
const template = document.createElement('template');
|
const template = document.createElement('template');
|
||||||
template.innerHTML = html;
|
template.innerHTML = html.trim();
|
||||||
return template.content.firstChild;
|
return template.content.childNodes.length > 1 ? template.content.childNodes : template.content.firstChild;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} html HTML representing a single element
|
|
||||||
* @return {NodeList}
|
|
||||||
*/
|
|
||||||
static nodesFromHtml(html) {
|
|
||||||
const template = document.createElement('template');
|
|
||||||
template.innerHTML = html;
|
|
||||||
return template.content.childNodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {NodeList} nodeList
|
|
||||||
* @param {string} selector
|
|
||||||
* @return {?Element}
|
|
||||||
*/
|
|
||||||
static querySelectorInList(nodeList, selector) {
|
|
||||||
for (const node of nodeList) {
|
|
||||||
if (node instanceof HTMLElement) {
|
|
||||||
const el = node.querySelector(selector);
|
|
||||||
if (el) {
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
293
js/test/configdialogmodel.test.js
Normal file
293
js/test/configdialogmodel.test.js
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
/*
|
||||||
|
* μlogger
|
||||||
|
*
|
||||||
|
* Copyright(C) 2020 Bartek Fabiszewski (www.fabiszewski.net)
|
||||||
|
*
|
||||||
|
* This 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; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { config, lang } from '../src/initializer.js';
|
||||||
|
import ConfigDialogModel from '../src/configdialogmodel.js';
|
||||||
|
import uLayer from '../src/layer.js';
|
||||||
|
import uLayerCollection from '../src/layercollection.js';
|
||||||
|
import uObserve from '../src/observe.js';
|
||||||
|
|
||||||
|
describe('ConfigDialogModel tests', () => {
|
||||||
|
|
||||||
|
let cm;
|
||||||
|
let layers;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
config.reinitialize();
|
||||||
|
lang.init(config);
|
||||||
|
spyOn(lang, '_').and.callFake((arg) => arg);
|
||||||
|
cm = new ConfigDialogModel();
|
||||||
|
layers = new uLayerCollection(new uLayer(0, 'layer0', '', 0), new uLayer(1, 'layer1', '', 0));
|
||||||
|
cm.model.layers = layers;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.innerHTML = '';
|
||||||
|
uObserve.unobserveAll(lang);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show config dialog', () => {
|
||||||
|
// when
|
||||||
|
cm.init();
|
||||||
|
// then
|
||||||
|
expect(document.querySelector('#modal')).toBeInstanceOf(HTMLDivElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
const testElements = [
|
||||||
|
'interval', 'units', 'lang', 'mapApi', 'googleKey', 'layerName', 'layerId', 'layerUrl', 'initLatitude', 'initLongitude',
|
||||||
|
'requireAuth', 'publicTracks', 'passStrength', 'passLenMin', 'strokeWeight', 'strokeColor', 'strokeOpacity',
|
||||||
|
'colorNormal', 'colorStart', 'colorStop', 'colorExtra', 'colorHilite'
|
||||||
|
];
|
||||||
|
testElements.forEach((name) => {
|
||||||
|
it(`should trigger model property change for ${name}`, (done) => {
|
||||||
|
// given
|
||||||
|
cm.init();
|
||||||
|
const element = cm.dialog.element.querySelector(`[data-bind=${name}]`);
|
||||||
|
// when
|
||||||
|
if (element instanceof HTMLSelectElement) {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = `__${name}__test`;
|
||||||
|
opt.text = `__${name}__test`;
|
||||||
|
element.add(opt, null);
|
||||||
|
element.value = `__${name}__test`;
|
||||||
|
} else if (element.type === 'checkbox') {
|
||||||
|
element.checked = !element.checked;
|
||||||
|
} else if (element.type === 'number') {
|
||||||
|
element.value = Math.random().toString();
|
||||||
|
} else {
|
||||||
|
element.value = `__${name}__test`;
|
||||||
|
}
|
||||||
|
element.dispatchEvent(new Event('change'));
|
||||||
|
// then
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(cm.model[name]).not.toBe('');
|
||||||
|
if (element.type === 'checkbox') {
|
||||||
|
expect(cm.model[name]).toBe(element.checked);
|
||||||
|
} else {
|
||||||
|
expect(cm.model[name]).toBe(element.value);
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show layer edit on add button click', (done) => {
|
||||||
|
// given
|
||||||
|
cm.init();
|
||||||
|
const button = cm.getBoundElement('onLayerAdd');
|
||||||
|
cm.layerEditEl.style.display = 'none';
|
||||||
|
// when
|
||||||
|
button.click();
|
||||||
|
// then
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(cm.layerEditEl.style.display).toBe('block');
|
||||||
|
expect(cm.model.layerId).toBe(-1);
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide visible layer edit on add button click', (done) => {
|
||||||
|
// given
|
||||||
|
cm.init();
|
||||||
|
const button = cm.getBoundElement('onLayerAdd');
|
||||||
|
cm.onLayerAdd();
|
||||||
|
// when
|
||||||
|
button.click();
|
||||||
|
// then
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(cm.layerEditEl.style.display).toBe('none');
|
||||||
|
expect(cm.model.layerId).toBe(-1);
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should save config on positive button clicked', (done) => {
|
||||||
|
// given
|
||||||
|
spyOn(cm, 'validate').and.returnValue(true);
|
||||||
|
spyOn(config, 'save').and.returnValue(Promise.resolve());
|
||||||
|
cm.init();
|
||||||
|
const button = cm.dialog.element.querySelector("[data-bind='onSave']");
|
||||||
|
// when
|
||||||
|
button.click();
|
||||||
|
// then
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(cm.validate).toHaveBeenCalledTimes(1);
|
||||||
|
expect(config.save).toHaveBeenCalledTimes(1);
|
||||||
|
expect(document.querySelector('#modal')).toBe(null);
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide dialog on negative button clicked', (done) => {
|
||||||
|
// given
|
||||||
|
cm.init();
|
||||||
|
const button = cm.dialog.element.querySelector("[data-bind='onCancel']");
|
||||||
|
// when
|
||||||
|
button.click();
|
||||||
|
// then
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(document.querySelector('#modal')).toBe(null);
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show edit on non-default layer select', (done) => {
|
||||||
|
// given
|
||||||
|
cm.model.layers = new uLayerCollection(new uLayer(0, 'layer0', '', 0), new uLayer(1, 'layer1', '', 0));
|
||||||
|
cm.init();
|
||||||
|
const element = cm.getBoundElement('layerId');
|
||||||
|
// when
|
||||||
|
element.value = '1';
|
||||||
|
element.dispatchEvent(new Event('change'));
|
||||||
|
// then
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(cm.toggleEditEl.style.visibility).toBe('visible');
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show edit on default layer select', (done) => {
|
||||||
|
// given
|
||||||
|
cm.init();
|
||||||
|
const element = cm.getBoundElement('layerId');
|
||||||
|
// when
|
||||||
|
element.value = '0';
|
||||||
|
element.dispatchEvent(new Event('change'));
|
||||||
|
// then
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(cm.toggleEditEl.style.visibility).toBe('hidden');
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete layer on anchor click', (done) => {
|
||||||
|
// given
|
||||||
|
cm.init();
|
||||||
|
const button = cm.dialog.element.querySelector("[data-bind='onLayerDelete']");
|
||||||
|
const element = cm.getBoundElement('layerId');
|
||||||
|
|
||||||
|
expect(layers.length).toBe(2);
|
||||||
|
// when
|
||||||
|
element.value = '1';
|
||||||
|
element.dispatchEvent(new Event('change'));
|
||||||
|
setTimeout(() => {
|
||||||
|
button.click();
|
||||||
|
setTimeout(() => {
|
||||||
|
// then
|
||||||
|
expect(layers.length).toBe(1);
|
||||||
|
expect(layers[0].id).toBe(0);
|
||||||
|
expect(cm.model.layerId).toBe(0);
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add layer on anchor click', (done) => {
|
||||||
|
// given
|
||||||
|
cm.init();
|
||||||
|
const addBtn = cm.dialog.element.querySelector("[data-bind='onLayerAdd']");
|
||||||
|
const updateBtn = cm.dialog.element.querySelector("[data-bind='onLayerUpdate']");
|
||||||
|
const nameEl = cm.dialog.element.querySelector("[data-bind='layerName']");
|
||||||
|
const urlEl = cm.dialog.element.querySelector("[data-bind='layerUrl']");
|
||||||
|
|
||||||
|
expect(layers.length).toBe(2);
|
||||||
|
// when
|
||||||
|
addBtn.click();
|
||||||
|
setTimeout(() => {
|
||||||
|
nameEl.value = 'test name';
|
||||||
|
nameEl.dispatchEvent(new Event('change'));
|
||||||
|
urlEl.value = 'test url';
|
||||||
|
urlEl.dispatchEvent(new Event('change'));
|
||||||
|
updateBtn.click();
|
||||||
|
setTimeout(() => {
|
||||||
|
// then
|
||||||
|
expect(layers.length).toBe(3);
|
||||||
|
expect(layers[2].id).toBe(2);
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update layer on anchor click', (done) => {
|
||||||
|
// given
|
||||||
|
cm.init();
|
||||||
|
const addBtn = cm.dialog.element.querySelector("[data-bind='onLayerAdd']");
|
||||||
|
const updateBtn = cm.dialog.element.querySelector("[data-bind='onLayerUpdate']");
|
||||||
|
const nameEl = cm.dialog.element.querySelector("[data-bind='layerName']");
|
||||||
|
const urlEl = cm.dialog.element.querySelector("[data-bind='layerUrl']");
|
||||||
|
const layerEl = cm.getBoundElement('layerId');
|
||||||
|
|
||||||
|
expect(layers.length).toBe(2);
|
||||||
|
// when
|
||||||
|
addBtn.click();
|
||||||
|
setTimeout(() => {
|
||||||
|
layerEl.value = '1';
|
||||||
|
layerEl.dispatchEvent(new Event('change'));
|
||||||
|
nameEl.value = 'test name';
|
||||||
|
nameEl.dispatchEvent(new Event('change'));
|
||||||
|
urlEl.value = 'test url';
|
||||||
|
urlEl.dispatchEvent(new Event('change'));
|
||||||
|
updateBtn.click();
|
||||||
|
setTimeout(() => {
|
||||||
|
// then
|
||||||
|
expect(layers.length).toBe(2);
|
||||||
|
expect(layers[1].id).toBe(1);
|
||||||
|
expect(layers[1].name).toBe('test name');
|
||||||
|
expect(layers[1].url).toBe('test url');
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cancel layer edit on anchor click', (done) => {
|
||||||
|
// given
|
||||||
|
cm.init();
|
||||||
|
const addBtn = cm.dialog.element.querySelector("[data-bind='onLayerAdd']");
|
||||||
|
const cancelBtn = cm.dialog.element.querySelector("[data-bind='onLayerCancel']");
|
||||||
|
const nameEl = cm.dialog.element.querySelector("[data-bind='layerName']");
|
||||||
|
const urlEl = cm.dialog.element.querySelector("[data-bind='layerUrl']");
|
||||||
|
const layerEl = cm.getBoundElement('layerId');
|
||||||
|
const layersCount = layers.length;
|
||||||
|
const layerId = 1;
|
||||||
|
const layerName = layers[1].name;
|
||||||
|
const layerUrl = layers[1].url;
|
||||||
|
|
||||||
|
expect(layers.length).toBe(2);
|
||||||
|
// when
|
||||||
|
addBtn.click();
|
||||||
|
setTimeout(() => {
|
||||||
|
layerEl.value = layerId.toString();
|
||||||
|
layerEl.dispatchEvent(new Event('change'));
|
||||||
|
nameEl.value = 'test name';
|
||||||
|
nameEl.dispatchEvent(new Event('change'));
|
||||||
|
urlEl.value = 'test url';
|
||||||
|
urlEl.dispatchEvent(new Event('change'));
|
||||||
|
cancelBtn.click();
|
||||||
|
setTimeout(() => {
|
||||||
|
// then
|
||||||
|
expect(layers.length).toBe(layersCount);
|
||||||
|
expect(layers[1].id).toBe(layerId);
|
||||||
|
expect(layers[1].name).toBe(layerName);
|
||||||
|
expect(layers[1].url).toBe(layerUrl);
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
131
js/test/layercollection.test.js
Normal file
131
js/test/layercollection.test.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* μlogger
|
||||||
|
*
|
||||||
|
* Copyright(C) 2020 Bartek Fabiszewski (www.fabiszewski.net)
|
||||||
|
*
|
||||||
|
* This 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; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import uLayer from '../src/layer.js';
|
||||||
|
import uLayerCollection from '../src/layercollection.js';
|
||||||
|
|
||||||
|
describe('LayerCollection tests', () => {
|
||||||
|
|
||||||
|
let layers;
|
||||||
|
const testId = 5;
|
||||||
|
const testName = 'test name';
|
||||||
|
const testUrl = 'https://layer.url';
|
||||||
|
const testPriority = 0;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
layers = new uLayerCollection();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create instance', () => {
|
||||||
|
// then
|
||||||
|
expect(layers).toBeInstanceOf(Array);
|
||||||
|
expect(layers).toBeInstanceOf(uLayerCollection);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add new layer', () => {
|
||||||
|
// when
|
||||||
|
layers.addNewLayer(testName, testUrl, testPriority);
|
||||||
|
layers.addNewLayer(`${testName}2`, `${testUrl}2`, testPriority + 1);
|
||||||
|
// then
|
||||||
|
expect(layers.length).toBe(2);
|
||||||
|
expect(layers[0]).toBeInstanceOf(uLayer);
|
||||||
|
expect(layers[0].id).toBe(1);
|
||||||
|
expect(layers[0].name).toBe(testName);
|
||||||
|
expect(layers[0].url).toBe(testUrl);
|
||||||
|
expect(layers[0].priority).toBe(testPriority);
|
||||||
|
expect(layers[1].id).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add layer', () => {
|
||||||
|
// when
|
||||||
|
layers.addLayer(testId, testName, testUrl, testPriority);
|
||||||
|
// then
|
||||||
|
expect(layers.length).toBe(1);
|
||||||
|
expect(layers[0]).toBeInstanceOf(uLayer);
|
||||||
|
expect(layers[0].id).toBe(testId);
|
||||||
|
expect(layers[0].name).toBe(testName);
|
||||||
|
expect(layers[0].url).toBe(testUrl);
|
||||||
|
expect(layers[0].priority).toBe(testPriority);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete layer by id', () => {
|
||||||
|
// given
|
||||||
|
layers.addLayer(testId, testName, testUrl, testPriority);
|
||||||
|
layers.addLayer(testId + 1, testName, testUrl, testPriority);
|
||||||
|
|
||||||
|
expect(layers.length).toBe(2);
|
||||||
|
// when
|
||||||
|
layers.delete(testId);
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(layers.length).toBe(1);
|
||||||
|
expect(layers[0].id).toBe(testId + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get layer by id (numeric)', () => {
|
||||||
|
// when
|
||||||
|
layers.addLayer(testId, testName, testUrl, testPriority);
|
||||||
|
layers.addLayer(testId + 1, testName, testUrl, testPriority);
|
||||||
|
// then
|
||||||
|
expect(layers.get(testId).id).toBe(testId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get layer by id (string)', () => {
|
||||||
|
// when
|
||||||
|
layers.addLayer(testId + 1, testName, testUrl, testPriority);
|
||||||
|
layers.addLayer(testId, testName, testUrl, testPriority);
|
||||||
|
// then
|
||||||
|
expect(layers.get(testId.toString()).id).toBe(testId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get max id of all layers in array', () => {
|
||||||
|
// when
|
||||||
|
layers.addLayer(testId + 1, testName, testUrl, testPriority);
|
||||||
|
layers.addLayer(testId, testName, testUrl, testPriority);
|
||||||
|
// then
|
||||||
|
expect(layers.getMaxId()).toBe(testId + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set priority layer by id', () => {
|
||||||
|
// given
|
||||||
|
layers.addLayer(testId + 1, testName, testUrl, testPriority);
|
||||||
|
layers.addLayer(testId, testName, testUrl, testPriority);
|
||||||
|
// when
|
||||||
|
layers.setPriorityLayer(testId);
|
||||||
|
// then
|
||||||
|
expect(layers[0].priority).toBe(0);
|
||||||
|
expect(layers[1].priority).toBe(1);
|
||||||
|
expect(layers.getPriorityLayer()).toBe(testId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load layers from array', () => {
|
||||||
|
// given
|
||||||
|
const arr = [ { id: testId, name: testName, url: testUrl, priority: testPriority } ];
|
||||||
|
// when
|
||||||
|
layers.load(arr);
|
||||||
|
// then
|
||||||
|
expect(layers.length).toBe(1);
|
||||||
|
expect(layers[0]).toBeInstanceOf(uLayer);
|
||||||
|
expect(layers[0].id).toBe(testId);
|
||||||
|
expect(layers[0].name).toBe(testName);
|
||||||
|
expect(layers[0].url).toBe(testUrl);
|
||||||
|
expect(layers[0].priority).toBe(testPriority);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -17,6 +17,7 @@
|
|||||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import uAjax from '../src/ajax.js';
|
||||||
import uPosition from '../src/position.js';
|
import uPosition from '../src/position.js';
|
||||||
|
|
||||||
describe('Position tests', () => {
|
describe('Position tests', () => {
|
||||||
@ -211,4 +212,64 @@ describe('Position tests', () => {
|
|||||||
expect(position.hasImage()).toBe(true);
|
expect(position.hasImage()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should calculate speed', () => {
|
||||||
|
// when
|
||||||
|
const position = uPosition.fromJson(jsonPosition);
|
||||||
|
position.totalMeters = 1000;
|
||||||
|
position.totalSeconds = 10;
|
||||||
|
// then
|
||||||
|
expect(position.totalSpeed).toBe(position.totalMeters / position.totalSeconds);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete position on server', () => {
|
||||||
|
// given
|
||||||
|
spyOn(uPosition, 'update');
|
||||||
|
const position = uPosition.fromJson(jsonPosition);
|
||||||
|
// when
|
||||||
|
position.delete()
|
||||||
|
// then
|
||||||
|
expect(uPosition.update).toHaveBeenCalledWith({ action: 'delete', posid: posId });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should save position on server', () => {
|
||||||
|
// given
|
||||||
|
spyOn(uPosition, 'update');
|
||||||
|
const position = uPosition.fromJson(jsonPosition);
|
||||||
|
// when
|
||||||
|
position.save()
|
||||||
|
// then
|
||||||
|
expect(uPosition.update).toHaveBeenCalledWith({ action: 'update', posid: posId, comment: comment });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call ajax post with url and params', () => {
|
||||||
|
// given
|
||||||
|
const url = 'utils/handleposition.php';
|
||||||
|
spyOn(uAjax, 'post');
|
||||||
|
const data = 'test data';
|
||||||
|
// when
|
||||||
|
uPosition.update(data);
|
||||||
|
// then
|
||||||
|
expect(uAjax.post).toHaveBeenCalledWith(url, data);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calculate distance to another position', () => {
|
||||||
|
// given
|
||||||
|
const position = uPosition.fromJson(jsonPosition);
|
||||||
|
const position2 = uPosition.fromJson(jsonPosition);
|
||||||
|
position2.latitude += 1;
|
||||||
|
position2.longitude += 1;
|
||||||
|
// then
|
||||||
|
expect(position.distanceTo(position2)).toBeCloseTo(155621.15, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should calculate time difference to another position', () => {
|
||||||
|
// given
|
||||||
|
const timeDifference = 1234;
|
||||||
|
const position = uPosition.fromJson(jsonPosition);
|
||||||
|
const position2 = uPosition.fromJson(jsonPosition);
|
||||||
|
position.timestamp += timeDifference;
|
||||||
|
// then
|
||||||
|
expect(position.secondsTo(position2)).toBe(timeDifference);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
270
js/test/utils.test.js
Normal file
270
js/test/utils.test.js
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
/*
|
||||||
|
* μlogger
|
||||||
|
*
|
||||||
|
* Copyright(C) 2020 Bartek Fabiszewski (www.fabiszewski.net)
|
||||||
|
*
|
||||||
|
* This 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; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import uUtils from '../src/utils.js';
|
||||||
|
|
||||||
|
describe('Utils tests', () => {
|
||||||
|
|
||||||
|
const name = 'test_name';
|
||||||
|
const value = 'test_value';
|
||||||
|
const url = 'test_url';
|
||||||
|
const id = 'test_id';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
document.cookie = `ulogger_${name}=${value}; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
|
||||||
|
let head = document.querySelector('head');
|
||||||
|
if (head === null) {
|
||||||
|
head = document.createElement('head');
|
||||||
|
document.appendChild(head);
|
||||||
|
} else if (head.querySelector(`#${id}`) !== null) {
|
||||||
|
head.removeChild(head.querySelector(`#${id}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set cookie', () => {
|
||||||
|
// given
|
||||||
|
const days = 1234;
|
||||||
|
// when
|
||||||
|
uUtils.setCookie(name, value, days);
|
||||||
|
const cookie = document.cookie;
|
||||||
|
// then
|
||||||
|
expect(cookie).toContain(`${name}=${value}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create string with format and params', () => {
|
||||||
|
// given
|
||||||
|
const stringParam = 'test';
|
||||||
|
const numberParam = 1234;
|
||||||
|
// then
|
||||||
|
expect(uUtils.sprintf('-%s-', stringParam)).toBe(`-${stringParam}-`);
|
||||||
|
expect(uUtils.sprintf('-%d-', numberParam)).toBe(`-${numberParam}-`);
|
||||||
|
expect(uUtils.sprintf('-%d%s-', numberParam, stringParam)).toBe(`-${numberParam}${stringParam}-`);
|
||||||
|
expect(uUtils.sprintf('-%%d-')).toBe('-%d-');
|
||||||
|
expect(() => uUtils.sprintf('-%d-')).toThrowError(/Missing argument/);
|
||||||
|
expect(() => uUtils.sprintf('-%d-', stringParam)).toThrowError(/Wrong format/);
|
||||||
|
expect(() => uUtils.sprintf('-%d-', numberParam, stringParam)).toThrowError(/Unused argument/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add script to head tag', (done) => {
|
||||||
|
// given
|
||||||
|
const head = document.querySelector('head');
|
||||||
|
// when
|
||||||
|
uUtils.addScript(url, id, null, () => done());
|
||||||
|
// then
|
||||||
|
expect(head.querySelector(`script#${id}`)).toBeInstanceOf(HTMLScriptElement);
|
||||||
|
expect(head.querySelector(`script#${id}`).src).toContain(url);
|
||||||
|
expect(head.querySelector(`script#${id}`).id).toBe(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add stylesheet link to head tag', () => {
|
||||||
|
// given
|
||||||
|
const head = document.querySelector('head');
|
||||||
|
// when
|
||||||
|
uUtils.addCss(url, id);
|
||||||
|
// then
|
||||||
|
expect(head.querySelector(`link#${id}`)).toBeInstanceOf(HTMLLinkElement);
|
||||||
|
expect(head.querySelector(`link#${id}`).href).toContain(url);
|
||||||
|
expect(head.querySelector(`link#${id}`).id).toBe(id);
|
||||||
|
expect(head.querySelector(`link#${id}`).rel).toBe('stylesheet');
|
||||||
|
expect(head.querySelector(`link#${id}`).type).toBe('text/css');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load script', (done) => {
|
||||||
|
// given
|
||||||
|
spyOn(uUtils, 'addScript').and.callFake((_url, _id, _onload) => _onload());
|
||||||
|
// when
|
||||||
|
uUtils.loadScript(url, id, 100)
|
||||||
|
// then
|
||||||
|
.then(() => done())
|
||||||
|
.catch((e) => done.fail(`reject callback called: ${e}`));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail loading script', (done) => {
|
||||||
|
// given
|
||||||
|
// eslint-disable-next-line max-params
|
||||||
|
spyOn(uUtils, 'addScript').and.callFake((_url, _id, _onload, _onerror) => _onerror(new Error(`error loading ${_id} script`)));
|
||||||
|
// when
|
||||||
|
uUtils.loadScript(url, id, 100)
|
||||||
|
// then
|
||||||
|
.then(() => done.fail('resolve callback called'))
|
||||||
|
.catch((e) => {
|
||||||
|
expect(e.message).toContain('loading');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should timeout loading script', (done) => {
|
||||||
|
// given
|
||||||
|
// eslint-disable-next-line max-params
|
||||||
|
spyOn(uUtils, 'addScript');
|
||||||
|
// when
|
||||||
|
uUtils.loadScript(url, id, 1)
|
||||||
|
// then
|
||||||
|
.then(() => done.fail('resolve callback called'))
|
||||||
|
.catch((e) => {
|
||||||
|
expect(e.message).toContain('timeout');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should timeout promise', (done) => {
|
||||||
|
// when
|
||||||
|
uUtils.timeoutPromise(1)
|
||||||
|
// then
|
||||||
|
.then(() => done.fail('resolve callback called'))
|
||||||
|
.catch((e) => {
|
||||||
|
expect(e.message).toContain('timeout');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should encode html', () => {
|
||||||
|
expect(uUtils.htmlEncode('\'foo\' & "bar" <foobar>'))
|
||||||
|
.toBe(''foo' & "bar" <foobar>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert hex to rgba', () => {
|
||||||
|
expect(uUtils.hexToRGBA('#abcdef', 0.3))
|
||||||
|
.toBe('rgba(171,205,239,0.3)');
|
||||||
|
|
||||||
|
expect(uUtils.hexToRGBA('#abc', 0))
|
||||||
|
.toBe('rgba(170,187,204,0)');
|
||||||
|
|
||||||
|
expect(uUtils.hexToRGBA('#abc'))
|
||||||
|
.toBe('rgba(170,187,204,1)');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove DOM element by id', () => {
|
||||||
|
// given
|
||||||
|
const element = document.createElement('script');
|
||||||
|
element.id = id;
|
||||||
|
document.head.appendChild(element);
|
||||||
|
|
||||||
|
expect(document.getElementById(id)).toBeInstanceOf(HTMLScriptElement);
|
||||||
|
// when
|
||||||
|
uUtils.removeElementById(id);
|
||||||
|
// then
|
||||||
|
expect(document.getElementById(id)).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create node from html string', () => {
|
||||||
|
// given
|
||||||
|
const html = `<div id="${id}"><span>test</span></div>`;
|
||||||
|
// when
|
||||||
|
const node = uUtils.nodeFromHtml(html);
|
||||||
|
// then
|
||||||
|
expect(node).toBeInstanceOf(HTMLDivElement);
|
||||||
|
expect(node.id).toBe(id);
|
||||||
|
expect(node.firstChild).toBeInstanceOf(HTMLSpanElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create multiple nodes from html string', () => {
|
||||||
|
// given
|
||||||
|
const html = `<div id="${id}"><span>test</span></div><div id="${id}_2"><span>test2</span></div>`;
|
||||||
|
// when
|
||||||
|
const nodes = uUtils.nodeFromHtml(html);
|
||||||
|
// then
|
||||||
|
expect(nodes).toBeInstanceOf(NodeList);
|
||||||
|
expect(nodes.length).toBe(2);
|
||||||
|
expect(nodes[0].id).toBe(id);
|
||||||
|
expect(nodes[0].firstChild).toBeInstanceOf(HTMLSpanElement);
|
||||||
|
expect(nodes[1].id).toBe(`${id}_2`);
|
||||||
|
expect(nodes[1].firstChild).toBeInstanceOf(HTMLSpanElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse float values', () => {
|
||||||
|
expect(uUtils.getFloat('1.234')).toEqual(jasmine.any(Number));
|
||||||
|
expect(uUtils.getFloat('1.234')).toBe(1.234);
|
||||||
|
expect(uUtils.getFloat('-1.234')).toBe(-1.234);
|
||||||
|
expect(uUtils.getFloat('-0')).toBe(0);
|
||||||
|
expect(uUtils.getFloat('1')).toBe(1);
|
||||||
|
expect(uUtils.getFloat('1a')).toBe(1);
|
||||||
|
expect(uUtils.getFloat(1.234)).toBe(1.234);
|
||||||
|
expect(uUtils.getFloat(1)).toBe(1);
|
||||||
|
expect(uUtils.getFloat(null, true)).toBeNull();
|
||||||
|
expect(() => uUtils.getFloat(null)).toThrowError(/Invalid value/);
|
||||||
|
// eslint-disable-next-line no-undefined
|
||||||
|
expect(() => uUtils.getFloat(undefined)).toThrowError(/Invalid value/);
|
||||||
|
expect(() => uUtils.getFloat('string')).toThrowError(/Invalid value/);
|
||||||
|
expect(() => uUtils.getFloat('string', true)).toThrowError(/Invalid value/);
|
||||||
|
expect(() => uUtils.getFloat('a1')).toThrowError(/Invalid value/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse integer values', () => {
|
||||||
|
expect(uUtils.getInteger('1234')).toEqual(jasmine.any(Number));
|
||||||
|
expect(uUtils.getInteger('1234')).toBe(1234);
|
||||||
|
expect(uUtils.getInteger('-1234')).toBe(-1234);
|
||||||
|
expect(uUtils.getInteger('-0')).toBe(0);
|
||||||
|
expect(uUtils.getInteger('1')).toBe(1);
|
||||||
|
expect(uUtils.getInteger('1a')).toBe(1);
|
||||||
|
expect(uUtils.getInteger(1234)).toBe(1234);
|
||||||
|
expect(uUtils.getInteger(1.234)).toBe(1);
|
||||||
|
expect(uUtils.getInteger(-1.234)).toBe(-1);
|
||||||
|
expect(uUtils.getInteger(null, true)).toBeNull();
|
||||||
|
expect(() => uUtils.getInteger(null)).toThrowError(/Invalid value/);
|
||||||
|
// eslint-disable-next-line no-undefined
|
||||||
|
expect(() => uUtils.getInteger(undefined)).toThrowError(/Invalid value/);
|
||||||
|
expect(() => uUtils.getInteger('string')).toThrowError(/Invalid value/);
|
||||||
|
expect(() => uUtils.getInteger('string', true)).toThrowError(/Invalid value/);
|
||||||
|
expect(() => uUtils.getInteger('a1')).toThrowError(/Invalid value/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse string values', () => {
|
||||||
|
expect(uUtils.getString('1234')).toEqual(jasmine.any(String));
|
||||||
|
expect(uUtils.getString(1234)).toEqual(jasmine.any(String));
|
||||||
|
expect(uUtils.getString(1.234)).toEqual(jasmine.any(String));
|
||||||
|
expect(uUtils.getString('1234')).toBe('1234');
|
||||||
|
expect(uUtils.getString(1234)).toBe('1234');
|
||||||
|
expect(uUtils.getString(1.234)).toBe('1.234');
|
||||||
|
expect(uUtils.getString(-1.234)).toBe('-1.234');
|
||||||
|
expect(uUtils.getString(null, true)).toBeNull();
|
||||||
|
expect(() => uUtils.getString(null)).toThrowError(/Invalid value/);
|
||||||
|
// eslint-disable-next-line no-undefined
|
||||||
|
expect(() => uUtils.getString(undefined)).toThrowError(/Invalid value/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should format date', () => {
|
||||||
|
// given
|
||||||
|
const date = new Date(2020, 1, 2, 3, 4, 5);
|
||||||
|
spyOn(date, 'toTimeString').and.returnValues(
|
||||||
|
'03:04:05 GMT+0200 (CEST)',
|
||||||
|
'03:04:05 GMT+0200 (Central European Standard Time)',
|
||||||
|
'03:04:05 GMT-0700 (Pacific Daylight Time)'
|
||||||
|
);
|
||||||
|
// when
|
||||||
|
let formatted = uUtils.getTimeString(date);
|
||||||
|
// then
|
||||||
|
expect(formatted.date).toBe('2020-02-02');
|
||||||
|
expect(formatted.time).toBe('03:04:05');
|
||||||
|
expect(formatted.zone).toBe(' GMT+2 CEST');
|
||||||
|
// when
|
||||||
|
formatted = uUtils.getTimeString(date);
|
||||||
|
// then
|
||||||
|
expect(formatted.zone).toBe(' GMT+2 CEST');
|
||||||
|
// when
|
||||||
|
formatted = uUtils.getTimeString(date);
|
||||||
|
// then
|
||||||
|
expect(formatted.zone).toBe(' GMT-7 PDT');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert degrees to radians', () => {
|
||||||
|
expect(uUtils.deg2rad(1)).toBeCloseTo(0.0174533, 7);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user