Add track view model
This commit is contained in:
parent
0039ecdd4f
commit
a516ff104f
45
js/src/state.js
Normal file
45
js/src/state.js
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* μlogger
|
||||
*
|
||||
* Copyright(C) 2019 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 uObserve from './observe.js';
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @property {?uTrack} currentTrack
|
||||
* @property {?uUser} currentUser
|
||||
* @property {boolean} showLatest
|
||||
* @property {boolean} showAllUsers
|
||||
*/
|
||||
export default class uState {
|
||||
|
||||
constructor() {
|
||||
this.currentTrack = null;
|
||||
this.currentUser = null;
|
||||
this.showLatest = false;
|
||||
this.showAllUsers = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} property
|
||||
* @param {ObserveCallback} callback
|
||||
*/
|
||||
onChanged(property, callback) {
|
||||
uObserve.observe(this, property, callback);
|
||||
}
|
||||
}
|
316
js/src/trackviewmodel.js
Normal file
316
js/src/trackviewmodel.js
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* μlogger
|
||||
*
|
||||
* Copyright(C) 2019 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 './initializer.js';
|
||||
import ViewModel from './viewmodel.js';
|
||||
import uObserve from './observe.js';
|
||||
import uPositionSet from './positionset.js';
|
||||
import uSelect from './select.js';
|
||||
import uTrack from './track.js';
|
||||
import uUtils from './utils.js';
|
||||
|
||||
/**
|
||||
* @class TrackViewModel
|
||||
*/
|
||||
export default class TrackViewModel extends ViewModel {
|
||||
|
||||
/**
|
||||
* @param {uState} state
|
||||
*/
|
||||
constructor(state) {
|
||||
super({
|
||||
/** @type {uTrack[]} */
|
||||
trackList: [],
|
||||
/** @type {string} */
|
||||
currentTrackId: '',
|
||||
/** @type {boolean} */
|
||||
showLatest: false,
|
||||
/** @type {boolean} */
|
||||
autoReload: false,
|
||||
/** @type {string} */
|
||||
inputFile: false,
|
||||
// click handlers
|
||||
/** @type {function} */
|
||||
onReload: null,
|
||||
/** @type {function} */
|
||||
onExportGpx: null,
|
||||
/** @type {function} */
|
||||
onExportKml: null,
|
||||
/** @type {function} */
|
||||
onImportGpx: null,
|
||||
/** @type {function} */
|
||||
onSetInterval: null
|
||||
});
|
||||
this.setClickHandlers();
|
||||
/** @type HTMLSelectElement */
|
||||
const listEl = document.querySelector('#track');
|
||||
this.summaryEl = document.querySelector('#summary');
|
||||
this.importEl = document.querySelector('#input-file');
|
||||
this.intervalEl = document.querySelector('#interval');
|
||||
this.select = new uSelect(listEl);
|
||||
this.state = state;
|
||||
this.timerId = 0;
|
||||
this.setObservers();
|
||||
this.init();
|
||||
}
|
||||
|
||||
setClickHandlers() {
|
||||
this.model.onReload = () => this.onReload();
|
||||
const exportCb = (type) => () => {
|
||||
if (this.state.currentTrack) {
|
||||
this.state.currentTrack.export(type);
|
||||
}
|
||||
};
|
||||
this.model.onExportGpx = exportCb('gpx');
|
||||
this.model.onExportKml = exportCb('kml');
|
||||
this.model.onImportGpx = () => this.importEl.click();
|
||||
this.model.onSetInterval = () => this.setAutoReloadInterval();
|
||||
}
|
||||
|
||||
setObservers() {
|
||||
this.onChanged('trackList', (list) => { this.select.setOptions(list); });
|
||||
this.onChanged('currentTrackId', (listValue) => {
|
||||
this.onTrackSelect(listValue);
|
||||
});
|
||||
this.onChanged('inputFile', (file) => {
|
||||
if (file) { this.onImport(); }
|
||||
});
|
||||
this.onChanged('autoReload', (reload) => {
|
||||
this.autoReload(reload);
|
||||
});
|
||||
this.onChanged('showLatest', (showLatest) => {
|
||||
this.state.showLatest = showLatest;
|
||||
this.onReload(true);
|
||||
});
|
||||
this.state.onChanged('currentUser', (user) => {
|
||||
if (user) {
|
||||
this.loadTrackList();
|
||||
} else {
|
||||
this.model.currentTrackId = '';
|
||||
this.model.trackList = [];
|
||||
}
|
||||
});
|
||||
this.state.onChanged('currentTrack', (track) => {
|
||||
this.renderSummary();
|
||||
if (track) {
|
||||
uObserve.observe(track, 'positions', () => {
|
||||
this.renderSummary();
|
||||
});
|
||||
}
|
||||
});
|
||||
this.state.onChanged('showAllUsers', (showAll) => {
|
||||
if (showAll) {
|
||||
this.loadAllUsersPosition();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload or update track view
|
||||
* @param {boolean} clear Reload if true, update current track otherwise
|
||||
*/
|
||||
onReload(clear = false) {
|
||||
if (this.state.showLatest) {
|
||||
if (this.state.showAllUsers) {
|
||||
this.loadAllUsersPosition();
|
||||
} else if (this.state.currentUser) {
|
||||
this.onUserLastPosition();
|
||||
}
|
||||
} else if (this.state.currentTrack instanceof uTrack) {
|
||||
this.onTrackUpdate(clear);
|
||||
} else if (this.state.currentTrack instanceof uPositionSet) {
|
||||
this.state.currentTrack = null;
|
||||
} else if (this.state.currentUser) {
|
||||
this.loadTrackList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle import
|
||||
*/
|
||||
onImport() {
|
||||
const form = this.importEl.parentElement;
|
||||
const sizeMax = form.elements['MAX_FILE_SIZE'].value;
|
||||
if (this.importEl.files && this.importEl.files.length === 1 && this.importEl.files[0].size > sizeMax) {
|
||||
uUtils.error(uUtils.sprintf(lang.strings['isizefailure'], sizeMax));
|
||||
return;
|
||||
}
|
||||
uTrack.import(form)
|
||||
.then((trackList) => {
|
||||
if (trackList.length) {
|
||||
if (trackList.length > 1) {
|
||||
alert(uUtils.sprintf(lang.strings['imultiple'], trackList.length));
|
||||
}
|
||||
this.model.trackList = trackList.concat(this.model.trackList);
|
||||
this.model.currentTrackId = trackList[0].listValue;
|
||||
}
|
||||
})
|
||||
.catch((e) => uUtils.error(e, `${lang.strings['actionfailure']}\n${e.message}`))
|
||||
.finally(() => {
|
||||
this.model.inputFile = '';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle track change
|
||||
* @param {string} listValue Track list selected option
|
||||
*/
|
||||
onTrackSelect(listValue) {
|
||||
/** @type {(uTrack|undefined)} */
|
||||
const track = this.model.trackList.find((_track) => _track.listValue === listValue);
|
||||
if (!track) {
|
||||
this.state.currentTrack = null;
|
||||
} else if (!track.isEqualTo(this.state.currentTrack)) {
|
||||
track.fetchPositions().then(() => {
|
||||
console.log(`currentTrack id: ${track.id}, loaded ${track.length} positions`);
|
||||
this.state.currentTrack = track;
|
||||
if (this.model.showLatest) {
|
||||
this.model.showLatest = false;
|
||||
}
|
||||
})
|
||||
.catch((e) => { uUtils.error(e, `${lang.strings['actionfailure']}\n${e.message}`); });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle track update
|
||||
* @param {boolean=} clear
|
||||
*/
|
||||
onTrackUpdate(clear) {
|
||||
if (clear) {
|
||||
this.state.currentTrack.clear();
|
||||
}
|
||||
this.state.currentTrack.fetchPositions()
|
||||
.catch((e) => { uUtils.error(e, `${lang.strings['actionfailure']}\n${e.message}`); });
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle user last position request
|
||||
*/
|
||||
onUserLastPosition() {
|
||||
this.state.currentUser.fetchLastPosition()
|
||||
.then((_track) => {
|
||||
if (_track) {
|
||||
if (!this.model.trackList.find((listItem) => listItem.listValue === _track.listValue)) {
|
||||
this.model.trackList.unshift(_track);
|
||||
}
|
||||
this.state.currentTrack = _track;
|
||||
this.model.currentTrackId = _track.listValue;
|
||||
}
|
||||
})
|
||||
.catch((e) => { uUtils.error(e, `${lang.strings['actionfailure']}\n${e.message}`); });
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle last position of all users request
|
||||
*/
|
||||
loadAllUsersPosition() {
|
||||
uPositionSet.fetchLatest()
|
||||
.then((_track) => {
|
||||
if (_track) {
|
||||
this.model.trackList = [];
|
||||
this.model.currentTrackId = '';
|
||||
this.state.currentTrack = _track;
|
||||
}
|
||||
})
|
||||
.catch((e) => { uUtils.error(e, `${lang.strings['actionfailure']}\n${e.message}`); });
|
||||
}
|
||||
|
||||
loadTrackList() {
|
||||
uTrack.fetchList(this.state.currentUser)
|
||||
.then((_tracks) => {
|
||||
this.model.trackList = _tracks;
|
||||
if (_tracks.length) {
|
||||
if (this.state.showLatest) {
|
||||
this.onUserLastPosition();
|
||||
} else {
|
||||
// autoload first track in list
|
||||
this.model.currentTrackId = _tracks[0].listValue;
|
||||
}
|
||||
} else {
|
||||
this.model.currentTrackId = '';
|
||||
}
|
||||
})
|
||||
.catch((e) => { uUtils.error(e, `${lang.strings['actionfailure']}\n${e.message}`); });
|
||||
}
|
||||
|
||||
init() {
|
||||
this.bindAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} start
|
||||
*/
|
||||
autoReload(start) {
|
||||
if (start) {
|
||||
this.startAutoReload();
|
||||
} else {
|
||||
this.stopAutoReload();
|
||||
}
|
||||
}
|
||||
|
||||
startAutoReload() {
|
||||
this.timerId = setInterval(() => this.onReload(), config.interval * 1000);
|
||||
}
|
||||
|
||||
stopAutoReload() {
|
||||
clearInterval(this.timerId);
|
||||
this.timerId = 0;
|
||||
this.model.autoReload = false;
|
||||
}
|
||||
|
||||
setAutoReloadInterval() {
|
||||
const interval = parseInt(prompt(lang.strings['newinterval']));
|
||||
if (!isNaN(interval) && interval !== config.interval) {
|
||||
config.interval = interval;
|
||||
this.intervalEl.innerHTML = config.interval.toString();
|
||||
// if live tracking on, reload with new interval
|
||||
if (this.timerId) {
|
||||
this.stopAutoReload();
|
||||
this.startAutoReload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderSummary() {
|
||||
if (!this.state.currentTrack || !this.state.currentTrack.hasPositions) {
|
||||
this.summaryEl.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
const last = this.state.currentTrack.positions[this.state.currentTrack.length - 1];
|
||||
|
||||
if (this.state.showLatest) {
|
||||
const today = new Date();
|
||||
const date = new Date(last.timestamp * 1000);
|
||||
const dateTime = uUtils.getTimeString(date);
|
||||
const dateString = (date.toDateString() !== today.toDateString()) ? `${dateTime.date}<br>` : '';
|
||||
const timeString = `${dateTime.time}<span style="font-weight:normal">${dateTime.zone}</span>`;
|
||||
this.summaryEl.innerHTML = `
|
||||
<div class="menu-title">${lang.strings['latest']}:</div>
|
||||
${dateString}
|
||||
${timeString}`;
|
||||
} else {
|
||||
this.summaryEl.innerHTML = `
|
||||
<div class="menu-title">${lang.strings['summary']}</div>
|
||||
<div><img class="icon" alt="${lang.strings['tdistance']}" title="${lang.strings['tdistance']}" src="images/distance.svg"> ${lang.getLocaleDistanceMajor(last.totalMeters, true)}</div>
|
||||
<div><img class="icon" alt="${lang.strings['ttime']}" title="${lang.strings['ttime']}" src="images/time.svg"> ${lang.getLocaleDuration(last.totalSeconds)}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -296,11 +296,18 @@ export default class uUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Error} e
|
||||
* @param {string} message
|
||||
* @param {(Error|string)} e
|
||||
* @param {string=} message
|
||||
*/
|
||||
static error(e, message) {
|
||||
console.error(`${e.name}: ${e.message} (${e.stack})`);
|
||||
let details;
|
||||
if (e instanceof Error) {
|
||||
details = `${e.name}: ${e.message} (${e.stack})`;
|
||||
} else {
|
||||
details = e;
|
||||
message = e;
|
||||
}
|
||||
console.error(details);
|
||||
alert(message);
|
||||
}
|
||||
}
|
||||
|
@ -40,14 +40,15 @@ export default class TrackFactory {
|
||||
track = new uPositionSet();
|
||||
}
|
||||
if (length) {
|
||||
track.positions = [];
|
||||
const positions = [];
|
||||
let lat = 21.01;
|
||||
let lon = 52.23;
|
||||
for (let i = 0; i < length; i++) {
|
||||
track.positions.push(this.getPosition(i + 1, lat, lon));
|
||||
positions.push(this.getPosition(i + 1, lat, lon));
|
||||
lat += 0.5;
|
||||
lon += 0.5;
|
||||
}
|
||||
track.fromJson(positions, true);
|
||||
}
|
||||
return track;
|
||||
}
|
||||
|
753
js/test/trackviewmodel.test.js
Normal file
753
js/test/trackviewmodel.test.js
Normal file
@ -0,0 +1,753 @@
|
||||
/*
|
||||
* μlogger
|
||||
*
|
||||
* Copyright(C) 2019 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 TrackFactory from './helpers/trackfactory.js';
|
||||
import TrackViewModel from '../src/trackviewmodel.js';
|
||||
import ViewModel from '../src/viewmodel.js';
|
||||
import uObserve from '../src/observe.js';
|
||||
import uPositionSet from '../src/positionset.js';
|
||||
import uState from '../src/state.js';
|
||||
import uTrack from '../src/track.js';
|
||||
import uUser from '../src/user.js';
|
||||
import uUtils from '../src/utils.js';
|
||||
|
||||
describe('TrackViewModel tests', () => {
|
||||
|
||||
let vm;
|
||||
let state;
|
||||
/** @type {HTMLSelectElement} */
|
||||
let trackEl;
|
||||
/** @type {HTMLDivElement} */
|
||||
let summaryEl;
|
||||
/** @type {HTMLInputElement} */
|
||||
let latestEl;
|
||||
/** @type {HTMLAnchorElement} */
|
||||
let exportKmlEl;
|
||||
/** @type {HTMLAnchorElement} */
|
||||
let exportGpxEl;
|
||||
/** @type {HTMLAnchorElement} */
|
||||
let importGpxEl;
|
||||
/** @type {HTMLAnchorElement} */
|
||||
let forceReloadEl;
|
||||
/** @type {HTMLInputElement} */
|
||||
let autoReloadEl;
|
||||
/** @type {HTMLInputElement} */
|
||||
let inputFileEl;
|
||||
/** @type {HTMLSpanElement} */
|
||||
let intervalEl;
|
||||
/** @type {HTMLAnchorElement} */
|
||||
let setIntervalEl;
|
||||
let tracks;
|
||||
let track1;
|
||||
let track2;
|
||||
let positions;
|
||||
let user;
|
||||
const interval = 10;
|
||||
const MAX_FILE_SIZE = 10;
|
||||
|
||||
beforeEach(() => {
|
||||
const fixture = `<div id="fixture">
|
||||
<div class="section">
|
||||
<select id="track" data-bind="currentTrackId" name="track"></select>
|
||||
<input id="latest" type="checkbox" data-bind="showLatest">
|
||||
<input id="auto-reload" type="checkbox" data-bind="autoReload">
|
||||
(<a id="set-interval" data-bind="onSetInterval"><span id="interval">${interval}</span></a> s)
|
||||
<a id="set-interval">setInterval</a>
|
||||
<a id="force-reload" data-bind="onReload">reload</a>
|
||||
</div>
|
||||
<div id="summary" class="section"></div>
|
||||
<div class="section">
|
||||
<a id="export-kml" class="menu-link" data-bind="onExportKml">kml</a>
|
||||
<a id="export-gpx" class="menu-link" data-bind="onExportGpx">gpx</a>
|
||||
</div>
|
||||
<div class="section">
|
||||
<form id="import-form" enctype="multipart/form-data" method="post">
|
||||
<input type="hidden" name="MAX_FILE_SIZE" value="${MAX_FILE_SIZE}" />
|
||||
<input type="file" id="input-file" name="gpx" data-bind="inputFile"/>
|
||||
</form>
|
||||
<a id="import-gpx" class="menu-link" data-bind="onImportGpx">gpx</a>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
document.body.insertAdjacentHTML('afterbegin', fixture);
|
||||
config.initialize();
|
||||
lang.init(config);
|
||||
trackEl = document.querySelector('#track');
|
||||
summaryEl = document.querySelector('#summary');
|
||||
latestEl = document.querySelector('#latest');
|
||||
exportKmlEl = document.querySelector('#export-kml');
|
||||
exportGpxEl = document.querySelector('#export-gpx');
|
||||
importGpxEl = document.querySelector('#import-gpx');
|
||||
forceReloadEl = document.querySelector('#force-reload');
|
||||
inputFileEl = document.querySelector('#input-file');
|
||||
intervalEl = document.querySelector('#interval');
|
||||
setIntervalEl = document.querySelector('#set-interval');
|
||||
autoReloadEl = document.querySelector('#auto-reload');
|
||||
state = new uState();
|
||||
vm = new TrackViewModel(state);
|
||||
track1 = TrackFactory.getTrack(0, { id: 1, name: 'track1' });
|
||||
track2 = TrackFactory.getTrack(0, { id: 2, name: 'track2' });
|
||||
tracks = [
|
||||
track1,
|
||||
track2
|
||||
];
|
||||
positions = [ TrackFactory.getPosition() ];
|
||||
user = new uUser(1, 'testUser');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.removeChild(document.querySelector('#fixture'));
|
||||
});
|
||||
|
||||
it('should create instance with state as parameter', () => {
|
||||
// when
|
||||
const trackViewModel = new TrackViewModel(state);
|
||||
// then
|
||||
expect(trackViewModel).toBeInstanceOf(ViewModel);
|
||||
expect(trackViewModel.summaryEl).toBeInstanceOf(HTMLDivElement);
|
||||
expect(trackViewModel.importEl).toBeInstanceOf(HTMLInputElement);
|
||||
expect(trackViewModel.select.element).toBeInstanceOf(HTMLSelectElement);
|
||||
expect(trackViewModel.state).toBe(state);
|
||||
});
|
||||
|
||||
it('should load track list and fetch first track on current user change', (done) => {
|
||||
// given
|
||||
spyOn(uTrack, 'fetchList').and.returnValue(Promise.resolve(tracks));
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
// when
|
||||
state.currentUser = user;
|
||||
// then
|
||||
expect(uObserve.isObserved(vm.model, 'trackList')).toBe(true);
|
||||
setTimeout(() => {
|
||||
expect(uTrack.fetchList).toHaveBeenCalledWith(state.currentUser);
|
||||
expect(uPositionSet.fetch).toHaveBeenCalledWith({ userid: user.id, trackid: track1.id });
|
||||
expect(trackEl.options.length).toBe(tracks.length);
|
||||
expect(trackEl.options[0].selected).toBe(true);
|
||||
expect(trackEl.options[0].value).toBe(track1.listValue);
|
||||
expect(state.currentTrack).toBe(track1);
|
||||
expect(state.currentTrack.length).toBe(positions.length);
|
||||
expect(vm.model.currentTrackId).toBe(track1.listValue);
|
||||
expect(summaryEl.innerText.length).not.toBe(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should clear current track on empty track list loaded on current user change', (done) => {
|
||||
// given
|
||||
spyOn(uTrack, 'fetchList').and.returnValue(Promise.resolve([]));
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
// when
|
||||
state.currentUser = user;
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uTrack.fetchList).toHaveBeenCalledWith(state.currentUser);
|
||||
expect(uPositionSet.fetch).not.toHaveBeenCalled();
|
||||
expect(trackEl.options.length).toBe(0);
|
||||
expect(state.currentTrack).toBe(null);
|
||||
expect(vm.model.currentTrackId).toBe('');
|
||||
expect(summaryEl.innerText.length).toBe(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should load track list, load user latest position and select coresponding track on current user change', (done) => {
|
||||
// given
|
||||
positions[0].trackid = track2.id;
|
||||
positions[0].trackname = track2.name;
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
spyOn(uTrack, 'fetchList').and.returnValue(Promise.resolve(tracks));
|
||||
uObserve.setSilently(vm.model, 'showLatest', true);
|
||||
uObserve.setSilently(state, 'showLatest', true);
|
||||
// when
|
||||
state.currentUser = user;
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uTrack.fetchList).toHaveBeenCalledWith(state.currentUser);
|
||||
expect(uPositionSet.fetch).toHaveBeenCalledWith({ userid: user.id, last: true });
|
||||
expect(trackEl.options.length).toBe(tracks.length);
|
||||
expect(trackEl.options[1].selected).toBe(true);
|
||||
expect(trackEl.options[1].value).toBe(track2.listValue);
|
||||
expect(state.currentTrack.id).toEqual(track2.id);
|
||||
expect(state.currentTrack.name).toEqual(track2.name);
|
||||
expect(state.currentTrack.length).toBe(positions.length);
|
||||
expect(vm.model.currentTrackId).toBe(track2.listValue);
|
||||
expect(summaryEl.innerText.length).not.toBe(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should clear track when no user is selected on user list', (done) => {
|
||||
// given
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
uObserve.setSilently(vm.model, 'trackList', tracks);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
// when
|
||||
state.currentUser = null;
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(trackEl.options.length).toBe(0);
|
||||
expect(state.currentTrack).toBe(null);
|
||||
expect(vm.model.currentTrackId).toBe('');
|
||||
expect(summaryEl.innerText.length).toBe(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should load track when selected in form select options', (done) => {
|
||||
// given
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
uObserve.setSilently(vm.model, 'trackList', tracks);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
// when
|
||||
trackEl.value = track2.listValue;
|
||||
trackEl.dispatchEvent(new Event('change'));
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uPositionSet.fetch).toHaveBeenCalledWith({ userid: user.id, trackid: track2.id });
|
||||
expect(trackEl.options.length).toBe(tracks.length);
|
||||
expect(trackEl.options[0].value).toBe(track1.listValue);
|
||||
expect(trackEl.options[1].value).toBe(track2.listValue);
|
||||
expect(trackEl.options[1].selected).toBe(true);
|
||||
expect(state.currentTrack).toBe(track2);
|
||||
expect(state.currentTrack.length).toBe(positions.length);
|
||||
expect(vm.model.currentTrackId).toBe(track2.listValue);
|
||||
expect(summaryEl.innerText.length).not.toBe(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should load user latest position when "show latest" is checked and insert new track to track list', (done) => {
|
||||
// given
|
||||
positions[0].trackid = 100;
|
||||
positions[0].trackname = 'new track';
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
const optLength = trackEl.options.length;
|
||||
uObserve.setSilently(vm.model, 'trackList', tracks);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
// when
|
||||
latestEl.checked = true;
|
||||
latestEl.dispatchEvent(new Event('change'));
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uPositionSet.fetch).toHaveBeenCalledWith({ userid: user.id, last: true });
|
||||
expect(state.currentTrack.id).toBe(positions[0].trackid);
|
||||
expect(state.currentTrack.name).toBe(positions[0].trackname);
|
||||
expect(state.currentTrack.length).toBe(positions.length);
|
||||
expect(trackEl.options.length).toBe(optLength + 1);
|
||||
expect(trackEl.options.length).toBe(tracks.length);
|
||||
expect(trackEl.value).toBe(state.currentTrack.listValue);
|
||||
expect(trackEl.options[0].value).toBe(state.currentTrack.listValue);
|
||||
expect(trackEl.options[0].selected).toBe(true);
|
||||
expect(state.showLatest).toBe(true);
|
||||
expect(vm.model.currentTrackId).toBe(state.currentTrack.listValue);
|
||||
expect(summaryEl.innerText.length).not.toBe(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
|
||||
it('should load user latest position when "show latest" is checked and select respective track in list', (done) => {
|
||||
// given
|
||||
positions[0].trackid = track2.id;
|
||||
positions[0].trackname = track2.name;
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
const optLength = trackEl.options.length;
|
||||
uObserve.setSilently(vm.model, 'trackList', tracks);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
// when
|
||||
latestEl.checked = true;
|
||||
latestEl.dispatchEvent(new Event('change'));
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uPositionSet.fetch).toHaveBeenCalledWith({ userid: user.id, last: true });
|
||||
expect(state.currentTrack.id).toBe(track2.id);
|
||||
expect(state.currentTrack.name).toBe(track2.name);
|
||||
expect(state.currentTrack.length).toBe(positions.length);
|
||||
expect(trackEl.options.length).toBe(optLength);
|
||||
expect(trackEl.options.length).toBe(tracks.length);
|
||||
expect(trackEl.value).toBe(state.currentTrack.listValue);
|
||||
expect(trackEl.options[1].value).toBe(state.currentTrack.listValue);
|
||||
expect(trackEl.options[1].selected).toBe(true);
|
||||
expect(state.showLatest).toBe(true);
|
||||
expect(vm.model.currentTrackId).toBe(state.currentTrack.listValue);
|
||||
expect(summaryEl.innerText.length).not.toBe(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should load all current track positions when "show latest" is unchecked', (done) => {
|
||||
// given
|
||||
positions[0].trackid = track1.id;
|
||||
positions[0].trackname = track1.name;
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
const optLength = trackEl.options.length;
|
||||
uObserve.setSilently(vm.model, 'trackList', tracks);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(vm.model, 'showLatest', true);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
uObserve.setSilently(state, 'showLatest', true);
|
||||
state.currentTrack = track1;
|
||||
latestEl.checked = true;
|
||||
// when
|
||||
latestEl.checked = false;
|
||||
latestEl.dispatchEvent(new Event('change'));
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uPositionSet.fetch).toHaveBeenCalledWith({ userid: user.id, trackid: track1.id });
|
||||
expect(state.currentTrack.id).toBe(track1.id);
|
||||
expect(state.currentTrack.name).toBe(track1.name);
|
||||
expect(state.currentTrack.length).toBe(positions.length);
|
||||
expect(trackEl.options.length).toBe(optLength);
|
||||
expect(trackEl.options.length).toBe(tracks.length);
|
||||
expect(trackEl.value).toBe(state.currentTrack.listValue);
|
||||
expect(trackEl.options[0].value).toBe(state.currentTrack.listValue);
|
||||
expect(trackEl.options[0].selected).toBe(true);
|
||||
expect(state.showLatest).toBe(false);
|
||||
expect(vm.model.currentTrackId).toBe(state.currentTrack.listValue);
|
||||
expect(summaryEl.innerText.length).not.toBe(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should clear track list and fetch all users positions on "all users" option selected', (done) => {
|
||||
// given
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
uObserve.setSilently(vm.model, 'trackList', tracks);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
uObserve.setSilently(state, 'showLatest', true);
|
||||
latestEl.checked = true;
|
||||
// when
|
||||
state.showAllUsers = true;
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uPositionSet.fetch).toHaveBeenCalledWith({ last: true });
|
||||
expect(trackEl.options.length).toBe(0);
|
||||
// noinspection JSUnresolvedFunction
|
||||
expect(state.currentTrack).not.toBeInstanceOf(uTrack);
|
||||
expect(state.currentTrack).toBeInstanceOf(uPositionSet);
|
||||
expect(state.currentTrack.positions.length).toBe(positions.length);
|
||||
expect(state.currentTrack.positions[0].id).toBe(positions[0].id);
|
||||
expect(state.currentTrack.length).toBe(positions.length);
|
||||
expect(vm.model.currentTrackId).toBe('');
|
||||
expect(summaryEl.innerText.length).not.toBe(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should clear current track if "show latest" is unchecked when "all users" is set', (done) => {
|
||||
// given
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
uObserve.setSilently(vm.model, 'trackList', []);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', '');
|
||||
uObserve.setSilently(vm.model, 'showLatest', true);
|
||||
uObserve.setSilently(state, 'currentUser', null);
|
||||
uObserve.setSilently(state, 'showLatest', true);
|
||||
uObserve.setSilently(state, 'showAllUsers', true);
|
||||
state.currentTrack = TrackFactory.getPositionSet(1);
|
||||
latestEl.checked = true;
|
||||
// when
|
||||
latestEl.checked = false;
|
||||
latestEl.dispatchEvent(new Event('change'));
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uPositionSet.fetch).not.toHaveBeenCalled();
|
||||
expect(state.currentTrack).toBe(null);
|
||||
expect(vm.model.currentTrackId).toBe('');
|
||||
expect(trackEl.options.length).toBe(0);
|
||||
expect(state.showLatest).toBe(false);
|
||||
expect(summaryEl.innerText.length).toBe(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should uncheck "show latest" when selected track in form select options', (done) => {
|
||||
// given
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
uObserve.setSilently(vm.model, 'trackList', tracks);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(vm.model, 'showLatest', true);
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
uObserve.setSilently(state, 'showLatest', true);
|
||||
latestEl.checked = true;
|
||||
// when
|
||||
trackEl.value = track2.listValue;
|
||||
trackEl.dispatchEvent(new Event('change'));
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(state.showLatest).toBe(false);
|
||||
expect(vm.model.showLatest).toBe(false);
|
||||
expect(latestEl.checked).toBe(false);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should export track to KML on link click', (done) => {
|
||||
// given
|
||||
spyOn(track1, 'export');
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
// when
|
||||
exportKmlEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(track1.export).toHaveBeenCalledWith('kml');
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should export track to GPX on link click', (done) => {
|
||||
// given
|
||||
spyOn(track1, 'export');
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
// when
|
||||
exportGpxEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(track1.export).toHaveBeenCalledWith('gpx');
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should import tracks on link click', (done) => {
|
||||
// given
|
||||
const imported = [
|
||||
TrackFactory.getTrack(0, { id: 3, name: 'track3', user: user }),
|
||||
TrackFactory.getTrack(0, { id: 4, name: 'track4', user: user })
|
||||
];
|
||||
const file = new File([ 'blob' ], '/path/filepath.gpx');
|
||||
spyOn(uTrack, 'import').and.callFake((form) => {
|
||||
expect(form.elements['gpx'].files[0]).toEqual(file);
|
||||
return Promise.resolve(imported);
|
||||
});
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
spyOn(uUtils, 'sprintf');
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
const optLength = trackEl.options.length;
|
||||
uObserve.setSilently(vm.model, 'trackList', tracks);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
inputFileEl.onclick = () => {
|
||||
const dt = new DataTransfer();
|
||||
dt.items.add(file);
|
||||
inputFileEl.files = dt.files;
|
||||
inputFileEl.dispatchEvent(new Event('change'));
|
||||
};
|
||||
// when
|
||||
importGpxEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uTrack.import).toHaveBeenCalledTimes(1);
|
||||
expect(uTrack.import).toHaveBeenCalledWith(jasmine.any(HTMLFormElement));
|
||||
expect(state.currentTrack).toBe(imported[0]);
|
||||
expect(vm.model.currentTrackId).toBe(imported[0].listValue);
|
||||
expect(state.currentTrack.length).toBe(positions.length);
|
||||
expect(uUtils.sprintf.calls.mostRecent().args[1]).toBe(imported.length);
|
||||
expect(trackEl.options.length).toBe(optLength + imported.length);
|
||||
expect(vm.model.trackList.length).toBe(optLength + imported.length);
|
||||
expect(vm.model.inputFile).toBe('');
|
||||
expect(inputFileEl.files.length).toBe(0);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should raise error on file size above MAX_FILE_SIZE limit on link click', (done) => {
|
||||
// given
|
||||
const imported = [
|
||||
TrackFactory.getTrack(0, { id: 3, name: 'track3', user: user }),
|
||||
TrackFactory.getTrack(0, { id: 4, name: 'track4', user: user })
|
||||
];
|
||||
spyOn(uTrack, 'import').and.returnValue(Promise.resolve(imported));
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
spyOn(uUtils, 'sprintf');
|
||||
spyOn(uUtils, 'error');
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
const optLength = trackEl.options.length;
|
||||
uObserve.setSilently(vm.model, 'trackList', tracks);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
inputFileEl.onclick = () => {
|
||||
const dt = new DataTransfer();
|
||||
dt.items.add(new File([ '12345678901' ], 'filepath.gpx'));
|
||||
inputFileEl.files = dt.files;
|
||||
inputFileEl.dispatchEvent(new Event('change'));
|
||||
};
|
||||
// when
|
||||
importGpxEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uTrack.import).not.toHaveBeenCalled();
|
||||
expect(state.currentTrack).toBe(track1);
|
||||
expect(vm.model.currentTrackId).toBe(track1.listValue);
|
||||
expect(uUtils.sprintf.calls.mostRecent().args[1]).toBe(MAX_FILE_SIZE.toString());
|
||||
expect(trackEl.options.length).toBe(optLength);
|
||||
expect(vm.model.trackList.length).toBe(optLength);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should get interval value from user prompt on interval click', (done) => {
|
||||
// given
|
||||
const newInterval = 99;
|
||||
spyOn(window, 'prompt').and.returnValue(newInterval);
|
||||
spyOn(vm, 'stopAutoReload');
|
||||
spyOn(vm, 'startAutoReload');
|
||||
config.interval = interval;
|
||||
vm.timerId = 0;
|
||||
// when
|
||||
setIntervalEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(intervalEl.innerHTML).toBe(newInterval.toString());
|
||||
expect(config.interval).toBe(newInterval);
|
||||
expect(vm.stopAutoReload).not.toHaveBeenCalled();
|
||||
expect(vm.startAutoReload).not.toHaveBeenCalled();
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should get interval value from user prompt on interval click and restart running auto-reload', (done) => {
|
||||
// given
|
||||
const newInterval = 99;
|
||||
spyOn(window, 'prompt').and.returnValue(newInterval);
|
||||
spyOn(vm, 'stopAutoReload');
|
||||
spyOn(vm, 'startAutoReload');
|
||||
config.interval = interval;
|
||||
vm.timerId = 1;
|
||||
// when
|
||||
setIntervalEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(intervalEl.innerHTML).toBe(newInterval.toString());
|
||||
expect(config.interval).toBe(newInterval);
|
||||
expect(vm.stopAutoReload).toHaveBeenCalledTimes(1);
|
||||
expect(vm.startAutoReload).toHaveBeenCalledTimes(1);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should start auto-reload on checkbox checked and stop on checkbox unchecked', (done) => {
|
||||
// given
|
||||
spyOn(vm, 'onReload').and.callFake(() => {
|
||||
// then
|
||||
expect(vm.model.autoReload).toBe(true);
|
||||
autoReloadEl.checked = false;
|
||||
autoReloadEl.dispatchEvent(new Event('change'));
|
||||
});
|
||||
autoReloadEl.checked = false;
|
||||
config.interval = 0.001;
|
||||
vm.timerId = 0;
|
||||
// when
|
||||
autoReloadEl.checked = true;
|
||||
autoReloadEl.dispatchEvent(new Event('change'));
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(vm.onReload).toHaveBeenCalledTimes(1);
|
||||
expect(vm.model.autoReload).toBe(false);
|
||||
expect(autoReloadEl.checked).toBe(false);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
describe('on reload clicked', () => {
|
||||
|
||||
it('should reload selected track', (done) => {
|
||||
// given
|
||||
track1 = TrackFactory.getTrack(2, { id: 1, name: 'track1' });
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
const optLength = trackEl.options.length;
|
||||
const posLength = track1.length;
|
||||
uObserve.setSilently(vm.model, 'trackList', [ track1, track2 ]);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
// when
|
||||
forceReloadEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uPositionSet.fetch).toHaveBeenCalledWith({ userid: user.id, trackid: track1.id, afterid: track1.maxId });
|
||||
expect(state.currentTrack.length).toBe(posLength + positions.length);
|
||||
expect(trackEl.options.length).toBe(optLength);
|
||||
expect(trackEl.value).toBe(track1.listValue);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should fetch user latest position if "show latest" is checked', (done) => {
|
||||
// given
|
||||
track1 = TrackFactory.getTrack(1, { id: 1, name: 'track1' });
|
||||
positions[0].trackid = track1.id;
|
||||
positions[0].trackname = track1.name;
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
const optLength = trackEl.options.length;
|
||||
uObserve.setSilently(vm.model, 'trackList', [ track1, track2 ]);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(vm.model, 'showLatest', true);
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
uObserve.setSilently(state, 'showLatest', true);
|
||||
latestEl.checked = true;
|
||||
// when
|
||||
forceReloadEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uPositionSet.fetch).toHaveBeenCalledWith({ userid: user.id, last: true });
|
||||
expect(state.currentTrack.id).toEqual(track1.id);
|
||||
expect(state.currentTrack.name).toEqual(track1.name);
|
||||
expect(state.currentTrack.length).toBe(1);
|
||||
expect(trackEl.options.length).toBe(optLength);
|
||||
expect(trackEl.value).toBe(positions[0].trackid.toString());
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should fetch user latest position if "show latest" is checked and add track if position is on a new track', (done) => {
|
||||
// given
|
||||
track1 = TrackFactory.getTrack(1, { id: 1, name: 'track1' });
|
||||
positions[0].trackid = 100;
|
||||
positions[0].trackname = 'track100';
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(positions));
|
||||
const options = '<option selected value="1">track1</option><option value="2">track2</option>';
|
||||
trackEl.insertAdjacentHTML('afterbegin', options);
|
||||
const optLength = trackEl.options.length;
|
||||
uObserve.setSilently(vm.model, 'trackList', [ track1, track2 ]);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', track1.listValue);
|
||||
uObserve.setSilently(vm.model, 'showLatest', true);
|
||||
uObserve.setSilently(state, 'currentTrack', track1);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
uObserve.setSilently(state, 'showLatest', true);
|
||||
latestEl.checked = true;
|
||||
// when
|
||||
forceReloadEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uPositionSet.fetch).toHaveBeenCalledWith({ userid: user.id, last: true });
|
||||
expect(state.currentTrack.id).toEqual(positions[0].trackid);
|
||||
expect(state.currentTrack.name).toEqual(positions[0].trackname);
|
||||
expect(state.currentTrack.length).toBe(1);
|
||||
expect(trackEl.options.length).toBe(optLength + 1);
|
||||
expect(trackEl.value).toBe(positions[0].trackid.toString());
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should fetch all users latest position if "all users" is selected', (done) => {
|
||||
// given
|
||||
const set = TrackFactory.getPositionSet(2, { id: 1, name: 'track1' });
|
||||
set.positions[0].trackid = track1.id;
|
||||
set.positions[0].trackname = track1.name;
|
||||
set.positions[1].trackid = track2.id;
|
||||
set.positions[1].trackname = track2.name;
|
||||
spyOn(uPositionSet, 'fetch').and.returnValue(Promise.resolve(set.positions));
|
||||
uObserve.setSilently(vm.model, 'trackList', []);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', '');
|
||||
uObserve.setSilently(vm.model, 'showLatest', true);
|
||||
uObserve.setSilently(state, 'currentTrack', null);
|
||||
uObserve.setSilently(state, 'currentUser', null);
|
||||
uObserve.setSilently(state, 'showLatest', true);
|
||||
uObserve.setSilently(state, 'showAllUsers', true);
|
||||
latestEl.checked = true;
|
||||
// when
|
||||
forceReloadEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uPositionSet.fetch).toHaveBeenCalledWith({ last: true });
|
||||
expect(state.currentTrack.length).toEqual(set.length);
|
||||
expect(state.currentTrack.positions[0]).toEqual(set.positions[0]);
|
||||
expect(state.currentTrack.positions[1]).toEqual(set.positions[1]);
|
||||
expect(trackEl.options.length).toBe(0);
|
||||
expect(trackEl.value).toBe('');
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should fetch track list if user is selected and no track is selected', (done) => {
|
||||
// given
|
||||
spyOn(uTrack, 'fetchList').and.returnValue(Promise.resolve([]));
|
||||
uObserve.setSilently(vm.model, 'trackList', []);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', '');
|
||||
uObserve.setSilently(state, 'currentTrack', null);
|
||||
uObserve.setSilently(state, 'currentUser', user);
|
||||
// when
|
||||
forceReloadEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uTrack.fetchList).toHaveBeenCalledWith(user);
|
||||
expect(state.currentTrack).toBe(null);
|
||||
expect(trackEl.options.length).toBe(0);
|
||||
expect(trackEl.value).toBe('');
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should do nothing if no user is selected and no track is selected', (done) => {
|
||||
// given
|
||||
spyOn(uTrack, 'fetchList');
|
||||
spyOn(uPositionSet, 'fetch');
|
||||
uObserve.setSilently(vm.model, 'trackList', []);
|
||||
uObserve.setSilently(vm.model, 'currentTrackId', '');
|
||||
uObserve.setSilently(state, 'currentTrack', null);
|
||||
uObserve.setSilently(state, 'currentUser', null);
|
||||
// when
|
||||
forceReloadEl.click();
|
||||
// then
|
||||
setTimeout(() => {
|
||||
expect(uTrack.fetchList).not.toHaveBeenCalled();
|
||||
expect(uPositionSet.fetch).not.toHaveBeenCalled();
|
||||
expect(state.currentTrack).toBe(null);
|
||||
expect(trackEl.options.length).toBe(0);
|
||||
expect(trackEl.value).toBe('');
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user