Uses angular-locker to store settings in localStorage
- settings.js now has its own module : 'jamstash.settings.controller'. This makes it easier to test it and identify what dependencies it has. - Renames 'jamstash.settings' module into 'jamstash.settings.service' - Adds an angular constant to hold the current Jamstash version in app.js. - Adds a way to upgrade incrementally what was in localStorage : in 4.4.5, DefaultSearchType will no longer be an object but an int, so we must init it with an int value, otherwise a blank option will be displayed. We detect what version we are using and what version was stored using persistence-service.js and run the upgrade accordingly. - Refactors almost completely persistence-service_test.js - Unit-tests some of settings.js's methods.
This commit is contained in:
parent
f98740d613
commit
a97e5159bc
17 changed files with 383 additions and 150 deletions
|
@ -1,8 +1,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/* Declare app level module */
|
/* Declare app level module */
|
||||||
angular.module('JamStash', ['ngCookies', 'ngRoute', 'ngSanitize', 'ui.keypress',
|
angular.module('JamStash', ['ngCookies', 'ngRoute', 'ngSanitize', 'ui.keypress', 'angular-underscore/utils',
|
||||||
'jamstash.subsonic.controller', 'jamstash.archive.controller', 'jamstash.player.controller', 'jamstash.queue.controller', 'jamstash.persistence'])
|
'jamstash.subsonic.controller', 'jamstash.archive.controller', 'jamstash.player.controller', 'jamstash.queue.controller', 'jamstash.settings.controller', 'jamstash.persistence'])
|
||||||
|
|
||||||
.config(['$routeProvider',function($routeProvider) {
|
.config(['$routeProvider',function($routeProvider) {
|
||||||
$routeProvider
|
$routeProvider
|
||||||
|
@ -48,4 +48,6 @@ angular.module('JamStash', ['ngCookies', 'ngRoute', 'ngSanitize', 'ui.keypress',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}]);
|
}]);
|
||||||
}]);
|
}])
|
||||||
|
|
||||||
|
.constant('jamstashVersion', '4.4.5');
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Access Archive.org
|
* Access Archive.org
|
||||||
*/
|
*/
|
||||||
angular.module('jamstash.archive.service', ['jamstash.settings', 'jamstash.model', 'jamstash.notifications',
|
angular.module('jamstash.archive.service', ['jamstash.settings.service', 'jamstash.model', 'jamstash.notifications',
|
||||||
'jamstash.player.service'])
|
'jamstash.player.service'])
|
||||||
|
|
||||||
.factory('archive', ['$rootScope', '$http', '$q', '$sce', 'globals', 'model', 'utils', 'map', 'notifications', 'player',
|
.factory('archive', ['$rootScope', '$http', '$q', '$sce', 'globals', 'model', 'utils', 'map', 'notifications', 'player',
|
||||||
|
|
|
@ -32,19 +32,12 @@ angular.module('JamStash')
|
||||||
$scope.loadSettings = function () {
|
$scope.loadSettings = function () {
|
||||||
// Temporary Code to Convert Cookies added 2/2/2014
|
// Temporary Code to Convert Cookies added 2/2/2014
|
||||||
if ($cookieStore.get('Settings')) {
|
if ($cookieStore.get('Settings')) {
|
||||||
utils.setValue('Settings', $cookieStore.get('Settings'), false);
|
persistence.saveSettings($cookieStore.get('Settings'));
|
||||||
$cookieStore.remove('Settings');
|
$cookieStore.remove('Settings');
|
||||||
}
|
}
|
||||||
if (utils.getValue('Settings')) {
|
var settings = persistence.getSettings();
|
||||||
$.each(utils.getValue('Settings'), function (k, v) {
|
if (settings !== undefined) {
|
||||||
if (v == 'false') { v = false; }
|
globals.settings = _(settings).omit('Url');
|
||||||
if (v == 'true') { v = true; }
|
|
||||||
var exclude = ['Url'];
|
|
||||||
var idx = exclude.indexOf(k);
|
|
||||||
if (idx === -1) {
|
|
||||||
globals.settings[k] = v;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (utils.getValue("SavedCollections")) { globals.SavedCollections = utils.getValue("SavedCollections").split(","); }
|
if (utils.getValue("SavedCollections")) { globals.SavedCollections = utils.getValue("SavedCollections").split(","); }
|
||||||
if (utils.getValue("DefaultCollection")) { globals.DefaultCollection = utils.getValue("DefaultCollection"); }
|
if (utils.getValue("DefaultCollection")) { globals.DefaultCollection = utils.getValue("DefaultCollection"); }
|
||||||
|
|
|
@ -21,7 +21,14 @@ describe("Main controller", function() {
|
||||||
player.queue = [];
|
player.queue = [];
|
||||||
|
|
||||||
// Mock the persistence service
|
// Mock the persistence service
|
||||||
persistence = jasmine.createSpyObj("persistence", ["loadQueue", "loadTrackPosition", "getVolume", "saveVolume"]);
|
persistence = jasmine.createSpyObj("persistence", [
|
||||||
|
"loadQueue",
|
||||||
|
"loadTrackPosition",
|
||||||
|
"getVolume",
|
||||||
|
"saveVolume",
|
||||||
|
"getSettings",
|
||||||
|
"saveSettings"
|
||||||
|
]);
|
||||||
|
|
||||||
inject(function (_$controller_, $rootScope, _$document_, _$window_, _$location_, _$cookieStore_, _utils_, globals, _model_, _notifications_, _Page_) {
|
inject(function (_$controller_, $rootScope, _$document_, _$window_, _$location_, _$cookieStore_, _utils_, globals, _model_, _notifications_, _Page_) {
|
||||||
scope = $rootScope.$new();
|
scope = $rootScope.$new();
|
||||||
|
@ -166,6 +173,24 @@ describe("Main controller", function() {
|
||||||
expect(player.previousTrack).not.toHaveBeenCalled();
|
expect(player.previousTrack).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("loadSettings() -", function() {
|
||||||
|
it("Given user settings were saved using persistence, when I load the settings, the globals object will be completed with them, excluding the Url setting", function() {
|
||||||
|
persistence.getSettings.and.returnValue({
|
||||||
|
"Url": "http://gmelinite.com/contrastive/hypercyanotic?a=overdrive&b=chirpling#postjugular",
|
||||||
|
"Username": "Hollingshead",
|
||||||
|
"AutoPlaylistSize": 25,
|
||||||
|
"AutoPlay": true
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.loadSettings();
|
||||||
|
expect(mockGlobals.settings.Username).toEqual("Hollingshead");
|
||||||
|
expect(mockGlobals.settings.AutoPlaylistSize).toBe(25);
|
||||||
|
expect(mockGlobals.settings.AutoPlay).toBe(true);
|
||||||
|
expect(mockGlobals.settings.Url).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("When starting up,", function() {
|
describe("When starting up,", function() {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Set the page's title from anywhere, the angular way
|
* Set the page's title from anywhere, the angular way
|
||||||
*/
|
*/
|
||||||
angular.module('jamstash.page', ['jamstash.settings', 'jamstash.utils'])
|
angular.module('jamstash.page', ['jamstash.settings.service', 'jamstash.utils'])
|
||||||
|
|
||||||
.factory('Page', ['$interval', 'globals', 'utils', function($interval, globals, utils){
|
.factory('Page', ['$interval', 'globals', 'utils', function($interval, globals, utils){
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
* Provides load, save and delete operations for the current song and queue.
|
* Provides load, save and delete operations for the current song and queue.
|
||||||
* Data storage provided by HTML5 localStorage.
|
* Data storage provided by HTML5 localStorage.
|
||||||
*/
|
*/
|
||||||
angular.module('jamstash.persistence', ['jamstash.settings', 'jamstash.player.service', 'jamstash.notifications', 'angular-locker'])
|
angular.module('jamstash.persistence', ['angular-locker',
|
||||||
|
'jamstash.settings.service', 'jamstash.player.service', 'jamstash.notifications'])
|
||||||
|
|
||||||
.config(['lockerProvider', function (lockerProvider) {
|
.config(['lockerProvider', function (lockerProvider) {
|
||||||
lockerProvider.setDefaultDriver('local')
|
lockerProvider.setDefaultDriver('local')
|
||||||
|
@ -13,7 +14,9 @@ angular.module('jamstash.persistence', ['jamstash.settings', 'jamstash.player.se
|
||||||
.setEventsEnabled(false);
|
.setEventsEnabled(false);
|
||||||
}])
|
}])
|
||||||
|
|
||||||
.service('persistence', ['globals', 'player', 'notifications', 'locker', function (globals, player, notifications, locker) {
|
.service('persistence', ['globals', 'player', 'notifications', 'locker', 'jamstashVersion',
|
||||||
|
function (globals, player, notifications, locker, jamstashVersion) {
|
||||||
|
/* Manage current track */
|
||||||
this.loadTrackPosition = function () {
|
this.loadTrackPosition = function () {
|
||||||
// Load Saved Song
|
// Load Saved Song
|
||||||
var song = locker.get('CurrentSong');
|
var song = locker.get('CurrentSong');
|
||||||
|
@ -33,6 +36,7 @@ angular.module('jamstash.persistence', ['jamstash.settings', 'jamstash.player.se
|
||||||
if (globals.settings.Debug) { console.log('Removing Current Position from localStorage'); }
|
if (globals.settings.Debug) { console.log('Removing Current Position from localStorage'); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Manage playing queue */
|
||||||
this.loadQueue = function () {
|
this.loadQueue = function () {
|
||||||
// load Saved queue
|
// load Saved queue
|
||||||
var queue = locker.get('CurrentQueue');
|
var queue = locker.get('CurrentQueue');
|
||||||
|
@ -55,6 +59,7 @@ angular.module('jamstash.persistence', ['jamstash.settings', 'jamstash.player.se
|
||||||
if (globals.settings.Debug) { console.log('Removing Play Queue from localStorage'); }
|
if (globals.settings.Debug) { console.log('Removing Play Queue from localStorage'); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Manage player volume */
|
||||||
this.getVolume = function () {
|
this.getVolume = function () {
|
||||||
return locker.get('Volume');
|
return locker.get('Volume');
|
||||||
};
|
};
|
||||||
|
@ -66,5 +71,37 @@ angular.module('jamstash.persistence', ['jamstash.settings', 'jamstash.player.se
|
||||||
this.deleteVolume = function () {
|
this.deleteVolume = function () {
|
||||||
locker.forget('Volume');
|
locker.forget('Volume');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Manage user settings */
|
||||||
|
this.getSettings = function () {
|
||||||
|
if(this.getVersion() !== jamstashVersion) {
|
||||||
|
this.upgradeToVersion(jamstashVersion);
|
||||||
|
}
|
||||||
|
return locker.get('Settings');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.saveSettings = function (settings) {
|
||||||
|
locker.put('Settings', settings);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.deleteSettings = function () {
|
||||||
|
locker.forget('Settings');
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Manage Jamstash Version */
|
||||||
|
this.getVersion = function () {
|
||||||
|
return locker.get('version');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.upgradeToVersion = function (version) {
|
||||||
|
locker.put('version', version);
|
||||||
|
switch (version) {
|
||||||
|
case '4.4.5':
|
||||||
|
var settings = locker.get('Settings');
|
||||||
|
settings.DefaultSearchType = 0;
|
||||||
|
this.saveSettings(settings);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
describe("Persistence service", function() {
|
describe("Persistence service", function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var persistence, player, notifications, locker;
|
var persistence, player, notifications, locker,
|
||||||
var song;
|
song, fakeStorage;
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
module('jamstash.persistence');
|
module('jamstash.persistence', function ($provide) {
|
||||||
|
// Mock locker
|
||||||
|
$provide.decorator('locker', function () {
|
||||||
|
return jasmine.createSpyObj("locker", ["get", "put", "forget"]);
|
||||||
|
});
|
||||||
|
$provide.constant("jamstashVersion", "1.0.1");
|
||||||
|
});
|
||||||
|
|
||||||
inject(function (_persistence_, _player_, _notifications_, _locker_) {
|
inject(function (_persistence_, _player_, _notifications_, _locker_) {
|
||||||
persistence = _persistence_;
|
persistence = _persistence_;
|
||||||
|
@ -20,135 +26,196 @@ describe("Persistence service", function() {
|
||||||
album: 'Tammanyize'
|
album: 'Tammanyize'
|
||||||
};
|
};
|
||||||
player.queue = [];
|
player.queue = [];
|
||||||
|
|
||||||
|
fakeStorage = {};
|
||||||
|
|
||||||
|
locker.get.and.callFake(function(key) {
|
||||||
|
return fakeStorage[key];
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("load from localStorage -", function() {
|
describe("loadTrackPosition() -", function() {
|
||||||
var fakeStorage;
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
fakeStorage = {};
|
spyOn(player, "load");
|
||||||
|
});
|
||||||
|
|
||||||
spyOn(locker, "get").and.callFake(function(key) {
|
it("Given a previously saved song in local storage, when I load the song, the player will load it", function() {
|
||||||
return fakeStorage[key];
|
fakeStorage = { 'CurrentSong': song };
|
||||||
|
|
||||||
|
persistence.loadTrackPosition();
|
||||||
|
|
||||||
|
expect(locker.get).toHaveBeenCalledWith('CurrentSong');
|
||||||
|
expect(player.load).toHaveBeenCalledWith(song);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Given that no song was previously saved in local storage, it doesn't do anything", function() {
|
||||||
|
persistence.loadTrackPosition();
|
||||||
|
expect(locker.get).toHaveBeenCalledWith('CurrentSong');
|
||||||
|
expect(player.load).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("saveTrackPosition() - saves the current track's position in local storage", function() {
|
||||||
|
persistence.saveTrackPosition(song);
|
||||||
|
expect(locker.put).toHaveBeenCalledWith('CurrentSong', song);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("deleteTrackPosition() - deletes the current track from local storage", function() {
|
||||||
|
persistence.deleteTrackPosition();
|
||||||
|
expect(locker.forget).toHaveBeenCalledWith('CurrentSong');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("loadQueue() -", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
spyOn(notifications, "updateMessage");
|
||||||
|
spyOn(player, "addSongs").and.callFake(function (songs) {
|
||||||
|
// Update the queue length so that notifications work
|
||||||
|
player.queue.length += songs.length;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("loadTrackPosition -", function() {
|
it("Given a previously saved queue in local storage, when I load the queue, the player's queue will be filled with the retrieved queue and the user will be notified", function() {
|
||||||
beforeEach(function() {
|
var queue = [
|
||||||
spyOn(player, "load");
|
{ id: 8705 },
|
||||||
});
|
{ id: 1617 },
|
||||||
|
{ id: 9812 }
|
||||||
|
];
|
||||||
|
fakeStorage = { 'CurrentQueue': queue };
|
||||||
|
|
||||||
it("Given that we previously saved the current track's position in local Storage, it loads the song we saved into the player", function() {
|
persistence.loadQueue();
|
||||||
fakeStorage = { 'CurrentSong': song };
|
|
||||||
|
|
||||||
persistence.loadTrackPosition();
|
expect(locker.get).toHaveBeenCalledWith('CurrentQueue');
|
||||||
|
expect(player.addSongs).toHaveBeenCalledWith(queue);
|
||||||
|
expect(notifications.updateMessage).toHaveBeenCalledWith('3 Saved Song(s)', true);
|
||||||
|
});
|
||||||
|
|
||||||
expect(locker.get).toHaveBeenCalledWith('CurrentSong');
|
it("Given that no queue was previously saved in local storage, when I load the queue, the player's queue will stay the same and no notification will be displayed", function() {
|
||||||
expect(player.load).toHaveBeenCalledWith(song);
|
persistence.loadQueue();
|
||||||
});
|
|
||||||
|
|
||||||
it("Given that we didn't save anything in local Storage, it doesn't load anything", function() {
|
expect(locker.get).toHaveBeenCalledWith('CurrentQueue');
|
||||||
persistence.loadTrackPosition();
|
expect(player.addSongs).not.toHaveBeenCalled();
|
||||||
expect(locker.get).toHaveBeenCalledWith('CurrentSong');
|
expect(notifications.updateMessage).not.toHaveBeenCalled();
|
||||||
expect(player.load).not.toHaveBeenCalled();
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("saveQueue() - saves the playing queue in local storage", function() {
|
||||||
|
player.queue = [
|
||||||
|
{ id: 1245 },
|
||||||
|
{ id: 7465 },
|
||||||
|
{ id: 948 }
|
||||||
|
];
|
||||||
|
persistence.saveQueue();
|
||||||
|
expect(locker.put).toHaveBeenCalledWith('CurrentQueue', player.queue);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("deleteQueue() - deletes the saved playing queue from local storage", function() {
|
||||||
|
persistence.deleteQueue();
|
||||||
|
expect(locker.forget).toHaveBeenCalledWith('CurrentQueue');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getVolume() -", function() {
|
||||||
|
it("Given a previously saved volume value in local storage, it retrieves it", function() {
|
||||||
|
fakeStorage = { 'Volume': 0.46582 };
|
||||||
|
|
||||||
|
var volume = persistence.getVolume();
|
||||||
|
|
||||||
|
expect(locker.get).toHaveBeenCalledWith('Volume');
|
||||||
|
expect(volume).toBe(0.46582);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Given that no volume value was previously saved in local storage, it returns undefined", function() {
|
||||||
|
var volume = persistence.getVolume();
|
||||||
|
|
||||||
|
expect(locker.get).toHaveBeenCalledWith('Volume');
|
||||||
|
expect(volume).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("saveVolume() - given a volume, it will be saved in local storage", function() {
|
||||||
|
persistence.saveVolume(0.05167);
|
||||||
|
expect(locker.put).toHaveBeenCalledWith('Volume', 0.05167);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("deleteVolume() - deletes the saved volume from local storage", function() {
|
||||||
|
persistence.deleteVolume();
|
||||||
|
expect(locker.forget).toHaveBeenCalledWith('Volume');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getSettings() -", function() {
|
||||||
|
it("Given previously saved user settings in local storage, it retrieves them", function() {
|
||||||
|
fakeStorage = {
|
||||||
|
"Settings": {
|
||||||
|
"url": "https://headed.com/aleurodidae/taistrel?a=roquet&b=trichophoric#cathole",
|
||||||
|
"Username": "Haupert"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var settings = persistence.getSettings();
|
||||||
|
|
||||||
|
expect(locker.get).toHaveBeenCalledWith('Settings');
|
||||||
|
expect(settings).toEqual({
|
||||||
|
"url": "https://headed.com/aleurodidae/taistrel?a=roquet&b=trichophoric#cathole",
|
||||||
|
"Username": "Haupert"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("loadQueue -", function() {
|
it("Given that the previously stored Jamstash version was '1.0.0' and given the current constant jamstash.version was '1.0.1', when I get the settings, then upgradeToVersion will be called", function() {
|
||||||
|
spyOn(persistence, 'upgradeToVersion');
|
||||||
|
|
||||||
|
persistence.getSettings();
|
||||||
|
|
||||||
|
expect(persistence.upgradeToVersion).toHaveBeenCalledWith('1.0.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Given that no user settings had been saved in local storage, it returns undefined", function() {
|
||||||
|
var settings = persistence.getSettings();
|
||||||
|
|
||||||
|
expect(locker.get).toHaveBeenCalledWith('Settings');
|
||||||
|
expect(settings).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("saveSettings() - given a user settings object, it will be saved in local storage", function() {
|
||||||
|
persistence.saveSettings({
|
||||||
|
"url": "http://crotalic.com/cabernet/coelenteron?a=dayshine&b=pantaletless#sus",
|
||||||
|
"Username": "Herrig"
|
||||||
|
});
|
||||||
|
expect(locker.put).toHaveBeenCalledWith('Settings', {
|
||||||
|
"url": "http://crotalic.com/cabernet/coelenteron?a=dayshine&b=pantaletless#sus",
|
||||||
|
"Username": "Herrig"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("deleteSettings() - deletes the saved user settings from local storage", function() {
|
||||||
|
persistence.deleteSettings();
|
||||||
|
expect(locker.forget).toHaveBeenCalledWith('Settings');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("upgradeToVersion() -", function() {
|
||||||
|
describe("Given that Jamstash version '1.0.0' was previously stored in local storage,", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
spyOn(notifications, "updateMessage");
|
fakeStorage.version = '1.0.0';
|
||||||
spyOn(player, "addSongs").and.callFake(function (songs) {
|
});
|
||||||
// Update the queue length so that notifications work
|
|
||||||
player.queue.length += songs.length;
|
it("when I upgrade the storage version to '1.0.1', Jamstash version '1.0.1' will be in local storage", function() {
|
||||||
|
persistence.upgradeToVersion('1.0.1');
|
||||||
|
expect(locker.put).toHaveBeenCalledWith('version', '1.0.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("that settings.DefaultSearchType was stored as an object and that a changeset for version '4.4.5' was defined that changes it to an int, when I upgrade the storage version to '4.4.5', settings.DefaultSearch will be stored as an int", function() {
|
||||||
|
fakeStorage = {
|
||||||
|
Settings: {
|
||||||
|
DefaultSearchType: {
|
||||||
|
id: "song",
|
||||||
|
name: "Song"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
persistence.upgradeToVersion('4.4.5');
|
||||||
|
expect(locker.put).toHaveBeenCalledWith('Settings', {
|
||||||
|
DefaultSearchType: 0
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Given that we previously saved the playing queue in local Storage, it fills the player's queue with what we saved and notifies the user", function() {
|
|
||||||
var queue = [
|
|
||||||
{ id: 8705 },
|
|
||||||
{ id: 1617 },
|
|
||||||
{ id: 9812 }
|
|
||||||
];
|
|
||||||
fakeStorage = { 'CurrentQueue': queue };
|
|
||||||
|
|
||||||
persistence.loadQueue();
|
|
||||||
|
|
||||||
expect(locker.get).toHaveBeenCalledWith('CurrentQueue');
|
|
||||||
expect(player.addSongs).toHaveBeenCalledWith(queue);
|
|
||||||
expect(notifications.updateMessage).toHaveBeenCalledWith('3 Saved Song(s)', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Given that we didn't save anything in local Storage, it doesn't load anything", function() {
|
|
||||||
persistence.loadQueue();
|
|
||||||
|
|
||||||
expect(locker.get).toHaveBeenCalledWith('CurrentQueue');
|
|
||||||
expect(player.addSongs).not.toHaveBeenCalled();
|
|
||||||
expect(notifications.updateMessage).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("getVolume -", function() {
|
|
||||||
it("Given that we previously saved the volume in local Storage, it retrieves it", function() {
|
|
||||||
fakeStorage = { 'Volume': 0.46582 };
|
|
||||||
|
|
||||||
var volume = persistence.getVolume();
|
|
||||||
|
|
||||||
expect(locker.get).toHaveBeenCalledWith('Volume');
|
|
||||||
expect(volume).toBe(0.46582);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Given that we didn't save the volume in local Storage, it returns undefined", function() {
|
|
||||||
var volume = persistence.getVolume();
|
|
||||||
|
|
||||||
expect(locker.get).toHaveBeenCalledWith('Volume');
|
|
||||||
expect(volume).toBeUndefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("save to localStorage -", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
spyOn(locker, "put");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("saves the current track's position in local Storage", function() {
|
|
||||||
persistence.saveTrackPosition(song);
|
|
||||||
expect(locker.put).toHaveBeenCalledWith('CurrentSong', song);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("saves the playing queue in local Storage", function() {
|
|
||||||
player.queue = [
|
|
||||||
{ id: 1245 },
|
|
||||||
{ id: 7465 },
|
|
||||||
{ id: 948 }
|
|
||||||
];
|
|
||||||
persistence.saveQueue();
|
|
||||||
expect(locker.put).toHaveBeenCalledWith('CurrentQueue', player.queue);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("saves the volume in local Storage", function() {
|
|
||||||
persistence.saveVolume(0.05167);
|
|
||||||
expect(locker.put).toHaveBeenCalledWith('Volume', 0.05167);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("remove from localStorage -", function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
spyOn(locker, "forget");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("deletes the current track from local Storage", function() {
|
|
||||||
persistence.deleteTrackPosition();
|
|
||||||
expect(locker.forget).toHaveBeenCalledWith('CurrentSong');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("deletes the saved playing queue from local Storage", function() {
|
|
||||||
persistence.deleteQueue();
|
|
||||||
expect(locker.forget).toHaveBeenCalledWith('CurrentQueue');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("deletes the saved volume from local Storage", function() {
|
|
||||||
persistence.deleteVolume();
|
|
||||||
expect(locker.forget).toHaveBeenCalledWith('Volume');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Provides generally useful functions, like sorts, date-related functions, localStorage access, etc.
|
* Provides generally useful functions, like sorts, date-related functions, localStorage access, etc.
|
||||||
*/
|
*/
|
||||||
angular.module('jamstash.utils', ['jamstash.settings'])
|
angular.module('jamstash.utils', ['jamstash.settings.service'])
|
||||||
|
|
||||||
.service('utils', ['$rootScope', 'globals', function ($rootScope, globals) {
|
.service('utils', ['$rootScope', 'globals', function ($rootScope, globals) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* Encapsulates the jPlayer plugin. It watches the player service for the song to play, load or restart.
|
* Encapsulates the jPlayer plugin. It watches the player service for the song to play, load or restart.
|
||||||
* It also enables jPlayer to attach event handlers to our UI through css Selectors.
|
* It also enables jPlayer to attach event handlers to our UI through css Selectors.
|
||||||
*/
|
*/
|
||||||
angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstash.settings', 'jamstash.subsonic.service', 'jamstash.notifications', 'jamstash.persistence', 'jamstash.page'])
|
angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstash.settings.service', 'jamstash.subsonic.service', 'jamstash.notifications', 'jamstash.persistence', 'jamstash.page'])
|
||||||
|
|
||||||
.directive('jplayer', ['$interval', 'player', 'globals', 'subsonic', 'notifications', 'persistence', 'Page',
|
.directive('jplayer', ['$interval', 'player', 'globals', 'subsonic', 'notifications', 'persistence', 'Page',
|
||||||
function($interval, playerService, globals, subsonic, notifications, persistence, Page) {
|
function($interval, playerService, globals, subsonic, notifications, persistence, Page) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ describe("jplayer directive", function() {
|
||||||
return $delegate;
|
return $delegate;
|
||||||
});
|
});
|
||||||
$provide.value('globals', mockGlobals);
|
$provide.value('globals', mockGlobals);
|
||||||
|
$provide.constant('jamstashVersion', '1.0.0');
|
||||||
});
|
});
|
||||||
|
|
||||||
spyOn($.fn, "jPlayer").and.callThrough();
|
spyOn($.fn, "jPlayer").and.callThrough();
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Manages the player and playing queue. Use it to play a song, go to next track or add songs to the queue.
|
* Manages the player and playing queue. Use it to play a song, go to next track or add songs to the queue.
|
||||||
*/
|
*/
|
||||||
angular.module('jamstash.player.service', ['angular-underscore/utils', 'jamstash.settings'])
|
angular.module('jamstash.player.service', ['jamstash.settings.service', 'angular-underscore/utils'])
|
||||||
|
|
||||||
.factory('player', ['globals', function (globals) {
|
.factory('player', ['globals', function (globals) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* jamstash.settings Module
|
* jamstash.settings.service Module
|
||||||
*
|
*
|
||||||
* Houses Jamstash's global settings and a few utility functions.
|
* Houses Jamstash's global settings and a few utility functions.
|
||||||
*/
|
*/
|
||||||
angular.module('jamstash.settings', [])
|
angular.module('jamstash.settings.service', [])
|
||||||
|
|
||||||
.service('globals', function () {
|
.service('globals', function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
describe("settings service", function() {
|
describe("Settings service", function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var globals;
|
var globals;
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
module('jamstash.settings');
|
module('jamstash.settings.service');
|
||||||
inject(function (_globals_) {
|
inject(function (_globals_) {
|
||||||
globals = _globals_;
|
globals = _globals_;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
angular.module('JamStash')
|
angular.module('jamstash.settings.controller', ['jamstash.settings.service', 'jamstash.persistence'])
|
||||||
|
|
||||||
.controller('SettingsController', ['$rootScope', '$scope', '$routeParams', '$location', 'utils', 'globals', 'json', 'notifications', 'persistence', 'subsonic',
|
.controller('SettingsController', ['$rootScope', '$scope', '$location', 'utils', 'globals', 'json', 'notifications', 'persistence', 'subsonic',
|
||||||
function ($rootScope, $scope, $routeParams, $location, utils, globals, json, notifications, persistence, subsonic) {
|
function ($rootScope, $scope, $location, utils, globals, json, notifications, persistence, subsonic) {
|
||||||
'use strict';
|
'use strict';
|
||||||
$rootScope.hideQueue();
|
$rootScope.hideQueue();
|
||||||
$scope.settings = globals.settings; /* See service.js */
|
$scope.settings = globals.settings; /* See service.js */
|
||||||
|
@ -28,8 +28,9 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$scope.reset = function () {
|
$scope.reset = function () {
|
||||||
utils.setValue('Settings', null, true);
|
persistence.deleteSettings();
|
||||||
$scope.loadSettings();
|
$scope.loadSettings();
|
||||||
|
// TODO: Hyz: reload the page
|
||||||
};
|
};
|
||||||
$scope.save = function () {
|
$scope.save = function () {
|
||||||
if ($scope.settings.Password !== '' && globals.settings.Password.substring(0, 4) != 'enc:') { $scope.settings.Password = 'enc:' + utils.HexEncode($scope.settings.Password); }
|
if ($scope.settings.Password !== '' && globals.settings.Password.substring(0, 4) != 'enc:') { $scope.settings.Password = 'enc:' + utils.HexEncode($scope.settings.Password); }
|
||||||
|
@ -60,7 +61,7 @@
|
||||||
} else {
|
} else {
|
||||||
$rootScope.hideQueue();
|
$rootScope.hideQueue();
|
||||||
}
|
}
|
||||||
utils.setValue('Settings', $scope.settings, true);
|
persistence.saveSettings($scope.settings);
|
||||||
notifications.updateMessage('Settings Updated!', true);
|
notifications.updateMessage('Settings Updated!', true);
|
||||||
$scope.loadSettings();
|
$scope.loadSettings();
|
||||||
if (globals.settings.Server !== '' && globals.settings.Username !== '' && globals.settings.Password !== '') {
|
if (globals.settings.Server !== '' && globals.settings.Username !== '' && globals.settings.Password !== '') {
|
||||||
|
|
106
app/settings/settings_test.js
Normal file
106
app/settings/settings_test.js
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
describe("Settings controller", function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var scope, $rootScope, $controller, $location, $q,
|
||||||
|
controllerParams, utils, persistence, mockGlobals, json, notifications, subsonic, deferred;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
jasmine.addCustomEqualityTester(angular.equals);
|
||||||
|
|
||||||
|
module('jamstash.settings.controller');
|
||||||
|
|
||||||
|
mockGlobals = {
|
||||||
|
settings: {
|
||||||
|
Password: '',
|
||||||
|
Server: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Mock all the services
|
||||||
|
utils = jasmine.createSpyObj("utils", ["HexEncode"]);
|
||||||
|
persistence = jasmine.createSpyObj("persistence", ["saveQueue", "deleteQueue", "deleteTrackPosition", "saveSettings", "deleteSettings"]);
|
||||||
|
json = jasmine.createSpyObj("json", ["getChangeLog"]);
|
||||||
|
notifications = jasmine.createSpyObj("notifications", ["requestPermissionIfRequired", "isSupported", "updateMessage"]);
|
||||||
|
|
||||||
|
|
||||||
|
inject(function (_$controller_, _$rootScope_, _$location_, _$q_) {
|
||||||
|
$rootScope = _$rootScope_;
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
$location = _$location_;
|
||||||
|
$q = _$q_;
|
||||||
|
deferred = $q.defer();
|
||||||
|
|
||||||
|
$rootScope.hideQueue = jasmine.createSpy("hideQueue");
|
||||||
|
$rootScope.loadSettings = jasmine.createSpy("loadSettings");
|
||||||
|
|
||||||
|
// Mock subsonic-service using $q
|
||||||
|
subsonic = jasmine.createSpyObj("subsonic", ["ping"]);
|
||||||
|
|
||||||
|
$controller = _$controller_;
|
||||||
|
controllerParams = {
|
||||||
|
$rootScope: $rootScope,
|
||||||
|
$scope: scope,
|
||||||
|
$location: $location,
|
||||||
|
utils: utils,
|
||||||
|
globals: mockGlobals,
|
||||||
|
json: json,
|
||||||
|
notifications: notifications,
|
||||||
|
persistence: persistence,
|
||||||
|
subsonic: subsonic
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
$controller('SettingsController', controllerParams);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("save() -", function() {
|
||||||
|
it("Given the settings have been set, when I save them, then the settings will be saved using the persistence service and the user will be notified", function() {
|
||||||
|
scope.save();
|
||||||
|
|
||||||
|
expect(persistence.saveSettings).toHaveBeenCalledWith(scope.settings);
|
||||||
|
expect(notifications.updateMessage).toHaveBeenCalledWith('Settings Updated!', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Given that the SaveTrackPosition setting was true, when I save the settings, then the current queue will be saved using the persistence service", function() {
|
||||||
|
scope.settings.SaveTrackPosition = true;
|
||||||
|
|
||||||
|
scope.save();
|
||||||
|
|
||||||
|
expect(persistence.saveQueue).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Given that the SaveTrackPosition setting was false, when I save the settings, then the saved queue and track will be deleted from the persistence service", function() {
|
||||||
|
scope.settings.SaveTrackPosition = false;
|
||||||
|
|
||||||
|
scope.save();
|
||||||
|
|
||||||
|
expect(persistence.deleteTrackPosition).toHaveBeenCalled();
|
||||||
|
expect(persistence.deleteQueue).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Given that the Server, Username and Password settings weren't empty, when I save the settings, then subsonic service will be pinged", function() {
|
||||||
|
scope.settings.Server = 'http://hexagram.com/malacobdella/liposis?a=platybasic&b=enantiopathia#stratoplane';
|
||||||
|
scope.settings.Username = 'Mollura';
|
||||||
|
scope.settings.Password = 'FPTVjZtBwEyq';
|
||||||
|
subsonic.ping.and.returnValue(deferred.promise);
|
||||||
|
|
||||||
|
scope.save();
|
||||||
|
|
||||||
|
expect(subsonic.ping).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reset() - When I reset the settings, they will be deleted from the persistence service and will be reloaded with default values", function() {
|
||||||
|
scope.reset();
|
||||||
|
|
||||||
|
expect(persistence.deleteSettings).toHaveBeenCalled();
|
||||||
|
expect(scope.loadSettings).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("On startup", function() {
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
|
@ -4,8 +4,8 @@
|
||||||
* Provides access through $http to the Subsonic server's API.
|
* Provides access through $http to the Subsonic server's API.
|
||||||
* Also offers more fine-grained functionality that is not part of Subsonic's API.
|
* Also offers more fine-grained functionality that is not part of Subsonic's API.
|
||||||
*/
|
*/
|
||||||
angular.module('jamstash.subsonic.service', ['jamstash.settings', 'jamstash.utils', 'jamstash.model',
|
angular.module('jamstash.subsonic.service', ['angular-underscore/utils',
|
||||||
'jamstash.notifications', 'jamstash.player.service', 'angular-underscore/utils'])
|
'jamstash.settings.service', 'jamstash.utils', 'jamstash.model', 'jamstash.notifications', 'jamstash.player.service'])
|
||||||
|
|
||||||
.factory('subsonic', ['$rootScope', '$http', '$q', 'globals', 'utils', 'map', 'notifications', 'player',
|
.factory('subsonic', ['$rootScope', '$http', '$q', 'globals', 'utils', 'map', 'notifications', 'player',
|
||||||
function ($rootScope, $http, $q, globals, utils, map, notifications, player) {
|
function ($rootScope, $http, $q, globals, utils, map, notifications, player) {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
describe("Subsonic controller", function() {
|
describe("Subsonic controller", function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var scope, $rootScope, $controller, $window, subsonic, notifications, player, controllerParams, deferred;
|
var scope, $rootScope, $controller, $window,
|
||||||
|
subsonic, notifications, player, controllerParams, deferred;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
jasmine.addCustomEqualityTester(angular.equals);
|
jasmine.addCustomEqualityTester(angular.equals);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue