Adds back scrobbling and loading a track and the queue from localStorage.

- Splits loadTrackPosition into two functions : one for the track (which isn't finished), one for the queue.
- Adds main-controller.js' first unit tests for both these functions.
- Adds scrobbling functionnality. It is now a part of the Subsonic service, since we it's Subsonic that ultimately does the scroblling.
- Adds unit tests for both the service and the directive. The test for updatetime was crazy hard to do because I had to find a way to trigger my own fake event and it wasn't permitted by jplayer.
- Adds the load function to the player, it is used only when loading a song from localStorage.
- Removes ng-click from play/pause in the player template. jPlayer adds its own handlers on them, no need to do it twice.
This commit is contained in:
Hyzual 2014-12-21 20:25:54 +01:00
parent 59762ae423
commit 834e67946c
10 changed files with 447 additions and 187 deletions

View file

@ -443,27 +443,33 @@
return $sce.trustAsHtml(html); return $sce.trustAsHtml(html);
}; };
function loadTrackPosition() { $scope.loadTrackPosition = function () {
//TODO: HYZ: Unit test
if (utils.browserStorageCheck()) { if (utils.browserStorageCheck()) {
// Load Saved Song // Load Saved Song
var song = angular.fromJson(localStorage.getItem('CurrentSong')); var song = angular.fromJson(localStorage.getItem('CurrentSong'));
if (song) { if (song) {
player.load(song); player.load(song);
// Load Saved Queue }
var items = angular.fromJson(localStorage.getItem('CurrentQueue')); } else {
if (items) { if (globals.settings.Debug) { console.log('HTML5::loadStorage not supported on your browser'); }
player.queue = items; }
};
$scope.loadQueue = function () {
if(utils.browserStorageCheck()) {
// load Saved queue
var queue = angular.fromJson(localStorage.getItem('CurrentQueue'));
if (queue) {
player.queue = queue;
if (player.queue.length > 0) { if (player.queue.length > 0) {
notifications.updateMessage(player.queue.length + ' Saved Song(s)', true); notifications.updateMessage(player.queue.length + ' Saved Song(s)', true);
} }
if (globals.settings.Debug) { console.log('Play Queue Loaded From localStorage: ' + player.queue.length + ' song(s)'); } if (globals.settings.Debug) { console.log('Play Queue Loaded From localStorage: ' + player.queue.length + ' song(s)'); }
} }
}
} else { } else {
if (globals.settings.Debug) { console.log('HTML5::loadStorage not supported on your browser'); } if (globals.settings.Debug) { console.log('HTML5::loadStorage not supported on your browser'); }
} }
} };
/* Launch on Startup */ /* Launch on Startup */
$scope.loadSettings(); $scope.loadSettings();
@ -476,7 +482,8 @@
if ($scope.loggedIn()) { if ($scope.loggedIn()) {
//$scope.ping(); //$scope.ping();
if (globals.settings.SaveTrackPosition) { if (globals.settings.SaveTrackPosition) {
loadTrackPosition(); $scope.loadQueue();
$scope.loadTrackPosition();
//FIXME: HYZ: player.startSaveTrackPosition(); //FIXME: HYZ: player.startSaveTrackPosition();
} }
} }

View file

@ -1,30 +1,132 @@
describe("Main controller", function() { describe("Main controller", function() {
'use strict'; 'use strict';
describe("updateFavorite -", function() { var scope, $rootScope, utils, globals, model, notifications, player;
beforeEach(function() {
module('JamStash');
it("when starring a song, it notifies the user that the star was saved", function() { inject(function ($controller, _$rootScope_, _$document_, _$window_, _$location_, _$cookieStore_, _utils_, _globals_, _model_, _notifications_, _player_) {
$rootScope = _$rootScope_;
scope = $rootScope.$new();
utils = _utils_;
globals = _globals_;
model = _model_;
notifications = _notifications_;
player = _player_;
$controller('AppController', {
$scope: scope,
$rootScope: $rootScope,
$document: _$document_,
$window: _$window_,
$location: _$location_,
$cookieStore: _$cookieStore_,
utils: utils,
globals: globals,
model: model,
notifications: notifications,
player: player
});
});
});
xdescribe("updateFavorite -", function() {
xit("when starring a song, it notifies the user that the star was saved", function() {
}); });
it("when starring an album, it notifies the user that the star was saved", function() { xit("when starring an album, it notifies the user that the star was saved", function() {
}); });
it("when starring an artist, it notifies the user that the star was saved", function() { xit("when starring an artist, it notifies the user that the star was saved", function() {
}); });
it("given that the Subsonic server returns an error, when starring something, it notifies the user with the error message", function() { xit("given that the Subsonic server returns an error, when starring something, it notifies the user with the error message", function() {
//TODO: move to higher level //TODO: move to higher level
}); });
it("given that the Subsonic server is unreachable, when starring something, it notifies the user with the HTTP error code", function() { xit("given that the Subsonic server is unreachable, when starring something, it notifies the user with the HTTP error code", function() {
//TODO: move to higher level //TODO: move to higher level
}); });
}); });
describe("toggleSetting -", function() { xdescribe("toggleSetting -", function() {
}); });
describe("load from localStorage -", function() {
var fakeStorage;
beforeEach(function() {
fakeStorage = {};
spyOn(localStorage, "getItem").and.callFake(function(key) {
return fakeStorage[key];
});
spyOn(utils, "browserStorageCheck").and.returnValue(true);
});
describe("loadTrackPosition -", function() {
beforeEach(function() {
spyOn(player, "load");
});
it("Given that we previously saved the current track's position in local Storage, it loads the song we saved into the player", function() {
var song = {
id: 8626,
name: 'Pectinatodenticulate',
artist: 'Isiah Hosfield',
album: 'Tammanyize'
};
fakeStorage = {
'CurrentSong': song
};
scope.loadTrackPosition();
expect(localStorage.getItem).toHaveBeenCalledWith('CurrentSong');
expect(player.load).toHaveBeenCalledWith(song);
});
it("Given that we didn't save anything in local Storage, it doesn't load anything", function() {
scope.loadTrackPosition();
expect(localStorage.getItem).toHaveBeenCalledWith('CurrentSong');
expect(player.load).not.toHaveBeenCalled();
});
});
describe("loadQueue -", function() {
beforeEach(function() {
spyOn(notifications, "updateMessage");
player.queue = [];
});
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
};
scope.loadQueue();
expect(localStorage.getItem).toHaveBeenCalledWith('CurrentQueue');
expect(player.queue).toEqual(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() {
scope.loadQueue();
expect(localStorage.getItem).toHaveBeenCalledWith('CurrentQueue');
expect(player.queue).toEqual([]);
expect(notifications.updateMessage).not.toHaveBeenCalled();
});
});
});
}); });

View file

@ -1,14 +1,19 @@
angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstash.settings']) /**
* jamstash.player.directive module
*
* 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.
*/
angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstash.settings', 'jamstash.subsonic.service'])
.directive('jplayer', ['player', 'globals', function(playerService, globals) { .directive('jplayer', ['player', 'globals', 'subsonic', function(playerService, globals, subsonic) {
'use strict'; 'use strict';
return { return {
restrict: 'EA', restrict: 'EA',
template: '<div></div>', template: '<div></div>',
link: function(scope, element, attrs) { link: function(scope, element) {
var $player = element.children('div'); var $player = element.children('div');
console.log($player);
var audioSolution = 'html,flash'; var audioSolution = 'html,flash';
if (globals.settings.ForceFlash) { if (globals.settings.ForceFlash) {
audioSolution = 'flash,html'; audioSolution = 'flash,html';
@ -17,7 +22,7 @@ angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstas
var updatePlayer = function() { var updatePlayer = function() {
$player.jPlayer({ $player.jPlayer({
// Flash fallback for outdated browser not supporting HTML5 audio/video tags // Flash fallback for outdated browser not supporting HTML5 audio/video tags
// http://jplayer.org/download/ // TODO: Hyz: Replace in Grunt !
swfPath: 'bower_components/jplayer/dist/jplayer/jquery.jplayer.swf', swfPath: 'bower_components/jplayer/dist/jplayer/jquery.jplayer.swf',
wmode: 'window', wmode: 'window',
solution: audioSolution, solution: audioSolution,
@ -37,8 +42,8 @@ angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstas
}, },
play: function() { play: function() {
console.log('jplayer play'); console.log('jplayer play');
$('#playermiddle').css('visibility', 'visible'); scope.revealControls();
$('#songdetails').css('visibility', 'visible'); scope.scrobbled = false;
}, },
pause: function() { pause: function() {
console.log('jplayer pause'); console.log('jplayer pause');
@ -47,18 +52,37 @@ angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstas
console.log('jplayer ended'); console.log('jplayer ended');
playerService.nextTrack(); playerService.nextTrack();
scope.$apply(); scope.$apply();
},
timeupdate: function (event) {
// Scrobble song once percentage is reached
var p = event.jPlayer.status.currentPercentAbsolute;
if (!scope.scrobbled && p > 30) {
if (globals.settings.Debug) { console.log('LAST.FM SCROBBLE - Percent Played: ' + p); }
subsonic.scrobble(scope.currentSong);
scope.scrobbled = true;
}
} }
}); });
}; };
updatePlayer(); updatePlayer();
scope.currentSong = {};
scope.scrobbled = false;
scope.$watch(function () { scope.$watch(function () {
return playerService.getPlayingSong(); return playerService.getPlayingSong();
}, function (newVal) { }, function (newVal) {
console.log('playingSong changed !'); console.log('playingSong changed !');
$player.jPlayer('setMedia', {'mp3': newVal.url}) scope.currentSong = newVal;
.jPlayer('play'); $player.jPlayer('setMedia', {'mp3': newVal.url});
if(playerService.loadSong === true) {
// Do not play, only load
playerService.loadSong = false;
scope.revealControls();
} else {
$player.jPlayer('play');
}
}); });
scope.$watch(function () { scope.$watch(function () {
@ -70,6 +94,12 @@ angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstas
playerService.restartSong = false; playerService.restartSong = false;
} }
}); });
scope.revealControls = function () {
$('#playermiddle').css('visibility', 'visible');
$('#songdetails').css('visibility', 'visible');
};
} //end link } //end link
}; };
}]); }]);

View file

@ -1,27 +1,26 @@
describe("jplayer directive", function() { describe("jplayer directive", function() {
'use strict'; 'use strict';
var element, scope, playerService, globalsService, $player, playingSong; var element, scope, playerService, globals, subsonic, $player, playingSong;
function mockGetPlayingSong() {
return playingSong;
}
beforeEach(function() { beforeEach(function() {
playingSong = {}; playingSong = {};
module('jamstash.player.directive', function($provide) { module('jamstash.player.directive', function($provide) {
// Mock the player service // Mock the player service
$provide.decorator('player', function($delegate) { $provide.decorator('player', function($delegate) {
$delegate.getPlayingSong = jasmine.createSpy('getPlayingSong').and.callFake(mockGetPlayingSong); $delegate.getPlayingSong = jasmine.createSpy('getPlayingSong').and.callFake(function() {
return playingSong;
});
$delegate.nextTrack = jasmine.createSpy('nextTrack'); $delegate.nextTrack = jasmine.createSpy('nextTrack');
return $delegate; return $delegate;
}); });
}); });
inject(function($rootScope, $compile, _player_, _globals_) { inject(function($rootScope, $compile, _player_, _globals_, _subsonic_) {
playerService = _player_; playerService = _player_;
globalsService = _globals_; globals = _globals_;
subsonic = _subsonic_;
// Compile the directive // Compile the directive
scope = $rootScope.$new(); scope = $rootScope.$new();
element = '<div id="playdeck_1" jplayer></div>'; element = '<div id="playdeck_1" jplayer></div>';
@ -31,14 +30,38 @@ describe("jplayer directive", function() {
$player = element.children('div'); $player = element.children('div');
}); });
it("When the player service's current playing song changes, it sets jplayer's media and plays the song", function() { describe("When the player service's current song changes,", function() {
spyOn($.fn, "jPlayer").and.returnValue($.fn);
beforeEach(function() {
spyOn($.fn, "jPlayer").and.returnValue($.fn);
playingSong = {url: 'https://gantry.com/antemarital/vigorless?a=oropharyngeal&b=killcrop#eviscerate'}; playingSong = {url: 'https://gantry.com/antemarital/vigorless?a=oropharyngeal&b=killcrop#eviscerate'};
});
it("it sets jPlayer's media and stores the song for future scrobbling", function() {
scope.$apply(); scope.$apply();
expect($player.jPlayer).toHaveBeenCalledWith('setMedia', {'mp3': 'https://gantry.com/antemarital/vigorless?a=oropharyngeal&b=killcrop#eviscerate'}); expect($player.jPlayer).toHaveBeenCalledWith('setMedia', {'mp3': 'https://gantry.com/antemarital/vigorless?a=oropharyngeal&b=killcrop#eviscerate'});
expect(scope.currentSong).toEqual(playingSong);
});
it("if the player service's loadSong flag is true, it does not play the song and it displays the player controls", function() {
spyOn(scope, "revealControls");
playerService.loadSong = true;
scope.$apply();
expect($player.jPlayer).not.toHaveBeenCalledWith('play');
expect(playerService.loadSong).toBeFalsy();
expect(scope.revealControls).toHaveBeenCalled();
});
it("otherwise, it plays it", function() {
playerService.loadSong = false;
scope.$apply();
expect($player.jPlayer).toHaveBeenCalledWith('play'); expect($player.jPlayer).toHaveBeenCalledWith('play');
expect(playerService.loadSong).toBeFalsy();
});
}); });
it("When the player service's restartSong flag is true, it restarts the current song and resets the flag to false", function() { it("When the player service's restartSong flag is true, it restarts the current song and resets the flag to false", function() {
@ -51,7 +74,7 @@ describe("jplayer directive", function() {
expect(playerService.restartSong).toBeFalsy(); expect(playerService.restartSong).toBeFalsy();
}); });
it("When jplayer has finished the current song, it plays the next track using the", function() { it("When jplayer has finished the current song, it asks the player service for the next track", function() {
var e = $.jPlayer.event.ended; var e = $.jPlayer.event.ended;
$player.trigger(e); $player.trigger(e);
@ -59,12 +82,67 @@ describe("jplayer directive", function() {
}); });
it("When jPlayer starts to play the current song, it displays the player controls", function() { it("When jPlayer starts to play the current song, it displays the player controls", function() {
affix('#playermiddle').css('visibility', 'hidden'); spyOn(scope, "revealControls");
affix('#songdetails').css('visibility', 'hidden');
var e = $.jPlayer.event.play; var e = $.jPlayer.event.play;
$player.trigger(e); $player.trigger(e);
expect(scope.revealControls).toHaveBeenCalled();
});
it("When jPlayer starts to play the current song, it resets the scrobbled flag to false", function() {
scope.scrobbled = true;
var e = $.jPlayer.event.play;
$player.trigger(e);
expect(scope.scrobbled).toBeFalsy();
});
it("revealControls - it displays the song details and the player controls", function() {
affix('#playermiddle').css('visibility', 'hidden');
affix('#songdetails').css('visibility', 'hidden');
scope.revealControls();
expect($('#playermiddle').css('visibility')).toEqual('visible'); expect($('#playermiddle').css('visibility')).toEqual('visible');
expect($('#songdetails').css('visibility')).toEqual('visible'); expect($('#songdetails').css('visibility')).toEqual('visible');
}); });
describe("Scrobbling -", function() {
var fakejPlayer, timeUpdate;
beforeEach(function() {
spyOn(subsonic, "scrobble");
scope.currentSong = {
id: 5375
};
// Fake jPlayer's internal _trigger event because I can't trigger a manual timeupdate
fakejPlayer = {
element: $player,
status: { currentPercentAbsolute: 31 }
};
timeUpdate = $.jPlayer.event.timeupdate;
});
it("Given a song that hasn't been scrobbled yet, When jPlayer reaches 30 percent of it, it scrobbles to last.fm using the subsonic service and sets the flag to true", function() {
scope.scrobbled = false;
// Trigger our fake timeupdate
$.jPlayer.prototype._trigger.call(fakejPlayer, timeUpdate);
expect(subsonic.scrobble).toHaveBeenCalledWith(scope.currentSong);
expect(scope.scrobbled).toBeTruthy();
});
it("Given a song that has already been scrobbled, when jPlayer reaches 30 percent of it, it does not scrobble again and leaves the flag to true", function() {
scope.scrobbled = true;
// Trigger our fake timeupdate
$.jPlayer.prototype._trigger.call(fakejPlayer, timeUpdate);
expect(subsonic.scrobble).not.toHaveBeenCalled();
expect(scope.scrobbled).toBeTruthy();
});
});
}); });

View file

@ -1,7 +1,7 @@
/** /**
* jamstash.player.service Module * jamstash.player.service Module
* *
* Enables app-wide control of the behavior of the player directive. * 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', ['jamstash.settings', 'angular-underscore/utils']) angular.module('jamstash.player.service', ['jamstash.settings', 'angular-underscore/utils'])
@ -13,9 +13,9 @@ angular.module('jamstash.player.service', ['jamstash.settings', 'angular-undersc
playingIndex: -1, playingIndex: -1,
playingSong: {}, playingSong: {},
restartSong: false, restartSong: false,
loadSong: false,
play: function(song) { play: function(song) {
console.log('player service - play()', song);
var songIndexInQueue; var songIndexInQueue;
// Find the song's index in the queue, if it's in there // Find the song's index in the queue, if it's in there
songIndexInQueue = player.queue.indexOf(song); songIndexInQueue = player.queue.indexOf(song);
@ -31,22 +31,20 @@ angular.module('jamstash.player.service', ['jamstash.settings', 'angular-undersc
}, },
playFirstSong: function() { playFirstSong: function() {
console.log('player service - playFirstSong()');
player.playingIndex = 0; player.playingIndex = 0;
player.play(player.queue[0]); player.play(player.queue[0]);
}, },
load: function(song) { load: function(song) {
console.log('player service - load()'); player.loadSong = true;
player.play(song);
}, },
restart: function() { restart: function() {
console.log('player service - restart()');
player.restartSong = true; player.restartSong = true;
}, },
nextTrack: function() { nextTrack: function() {
console.log('player service - nextTrack()');
if((player.playingIndex + 1) < player.queue.length) { if((player.playingIndex + 1) < player.queue.length) {
var nextTrack = player.queue[player.playingIndex + 1]; var nextTrack = player.queue[player.playingIndex + 1];
player.playingIndex++; player.playingIndex++;
@ -55,7 +53,6 @@ angular.module('jamstash.player.service', ['jamstash.settings', 'angular-undersc
}, },
previousTrack: function() { previousTrack: function() {
console.log(('player service - previousTrack()'));
if((player.playingIndex - 1) > 0) { if((player.playingIndex - 1) > 0) {
var previousTrack = player.queue[player.playingIndex - 1]; var previousTrack = player.queue[player.playingIndex - 1];
player.playingIndex--; player.playingIndex--;
@ -66,22 +63,18 @@ angular.module('jamstash.player.service', ['jamstash.settings', 'angular-undersc
}, },
emptyQueue: function() { emptyQueue: function() {
console.log('player service - emptyQueue()');
player.queue = []; player.queue = [];
}, },
shuffleQueue: function() { shuffleQueue: function() {
console.log('player service - shuffleQueue()');
player.queue = _.shuffle(player.queue); player.queue = _.shuffle(player.queue);
}, },
addSong: function(song) { addSong: function(song) {
console.log('player service - addSong()');
player.queue.push(song); player.queue.push(song);
}, },
removeSong: function(song) { removeSong: function(song) {
console.log('player service - removeSong()');
var index = player.queue.indexOf(song); var index = player.queue.indexOf(song);
player.queue.splice(index, 1); player.queue.splice(index, 1);
}, },

View file

@ -180,9 +180,18 @@ describe("Player service -", function() {
player.restart(); player.restart();
expect(player.restartSong).toBeTruthy(); expect(player.restartSong).toBeTruthy();
}); });
it("When I load the song, the flag for the directive is set", function() {
spyOn(player, "play");
player.load(song);
expect(player.loadSong).toBeTruthy();
expect(player.play).toHaveBeenCalledWith(song);
});
}); });
describe("Given that there is no song in my playing queue", function() { describe("Given that my playing queue is empty", function() {
beforeEach(function() { beforeEach(function() {
player.queue = []; player.queue = [];

View file

@ -5,10 +5,10 @@
<a class="hover" id="PreviousTrack" title="Previous Track" ng-click="player.previousTrack()"> <a class="hover" id="PreviousTrack" title="Previous Track" ng-click="player.previousTrack()">
<img src="images/first_alt_24x24.png" height="24" width="24" alt="Previous track" /> <img src="images/first_alt_24x24.png" height="24" width="24" alt="Previous track" />
</a> </a>
<a class="hover PlayTrack" title="Play/Pause" ng-click="player.play()"> <a class="hover PlayTrack" title="Play/Pause">
<img src="images/play_alt_24x24.png" height="24" width="24" alt="Play" /> <img src="images/play_alt_24x24.png" height="24" width="24" alt="Play" />
</a> </a>
<a class="hover PauseTrack" title="Play/Pause" ng-click="player.pause()" style="display: none;"> <a class="hover PauseTrack" title="Play/Pause" style="display: none;">
<img src="images/pause_alt_24x24.png" height="24" width="24" alt="Pause" /> <img src="images/pause_alt_24x24.png" height="24" width="24" alt="Pause" />
</a> </a>
<a class="hover" id="NextTrack" title="Next Track" ng-click="player.nextTrack()"> <a class="hover" id="NextTrack" title="Next Track" ng-click="player.nextTrack()">

View file

@ -8,7 +8,6 @@ angular.module('jamstash.queue.controller', ['jamstash.player.service'])
$scope.itemType = 'pl'; // TODO: Hyz: What is this ? $scope.itemType = 'pl'; // TODO: Hyz: What is this ?
$scope.playSong = function (song) { $scope.playSong = function (song) {
console.log('Queue Controller - playSong()', song);
player.play(song); player.play(song);
}; };

View file

@ -793,7 +793,35 @@ angular.module('jamstash.subsonic.service', ['jamstash.settings', 'jamstash.util
} }
}); });
return deferred.promise; return deferred.promise;
},
scrobble: function (song) {
var id = song.id;
//TODO: Hyz: Refactor all this boilerplate into an http interceptor ? or something higher level than this
var exception = {reason: 'Error when contacting the Subsonic server.'};
var deferred = $q.defer();
var httpPromise;
if (globals.settings.Debug) { console.log('Scrobble Song: ' + id); }
if(globals.settings.Protocol === 'jsonp') {
httpPromise = $http.jsonp(globals.BaseURL() + '/scrobble.view?callback=JSON_CALLBACK&' + globals.BaseParams() + '&id=' + id + '&submission=true',
{
timeout: globals.settings.Timeout
});
} else {
httpPromise = $http.get(globals.BaseURL() + '/scrobble.view?' + globals.BaseParams() + '&id=' + id + '&submission=true',
{
timeout: globals.settings.Timeout
});
} }
httpPromise.success(function (data, status) {
console.log(data);
if(globals.settings.Debug) { console.log('Successfully scrobbled song: ' + id); }
}).error(function(data, status) {
exception.httpError = status;
deferred.reject(exception);
});
return deferred.promise;
}
// End subsonic // End subsonic
}; };
}]); }]);

View file

@ -2,10 +2,6 @@ describe("Subsonic service -", function() {
'use strict'; 'use strict';
var subsonic, mockBackend, mockGlobals, response; var subsonic, mockBackend, mockGlobals, response;
var url = 'http://demo.subsonic.com/rest/getStarred.view?'+
'callback=JSON_CALLBACK&u=Hyzual&p=enc:cGFzc3dvcmQ=&v=1.10.2&c=Jamstash&f=jsonp';
beforeEach(function() { beforeEach(function() {
// We redefine it because in some tests we need to alter the settings // We redefine it because in some tests we need to alter the settings
mockGlobals = { mockGlobals = {
@ -37,7 +33,22 @@ describe("Subsonic service -", function() {
mockBackend.verifyNoOutstandingRequest(); mockBackend.verifyNoOutstandingRequest();
}); });
it("scrobble - Given a song, when I scrobble it, it returns true if there was no error", function() {
var song = { id: 45872 };
var url = 'http://demo.subsonic.com/rest/scrobble.view?' +
'callback=JSON_CALLBACK&u=Hyzual&p=enc:cGFzc3dvcmQ=&v=1.10.2&c=Jamstash&f=jsonp&id=45872&submission=true';
mockBackend.whenJSONP(url).respond(200, JSON.stringify(response));
var promise = subsonic.scrobble(song);
mockBackend.flush();
expect(promise).toBeResolved();
});
describe("getStarred -", function() { describe("getStarred -", function() {
var url = 'http://demo.subsonic.com/rest/getStarred.view?'+
'callback=JSON_CALLBACK&u=Hyzual&p=enc:cGFzc3dvcmQ=&v=1.10.2&c=Jamstash&f=jsonp';
it("Given that I have 2 starred albums, 1 starred artist and 3 starred songs in my library, when getting everything starred, it returns them all", function() { it("Given that I have 2 starred albums, 1 starred artist and 3 starred songs in my library, when getting everything starred, it returns them all", function() {
response["subsonic-response"].starred = {artist: [{id: 2245}], album: [{id: 1799},{id: 20987}], song: [{id: 2478},{id: 14726},{id: 742}]}; response["subsonic-response"].starred = {artist: [{id: 2245}], album: [{id: 1799},{id: 20987}], song: [{id: 2478},{id: 14726},{id: 742}]};
@ -83,7 +94,7 @@ describe("Subsonic service -", function() {
expect(promise).toBeRejectedWith({reason: 'Nothing is starred on the Subsonic server.'}); expect(promise).toBeRejectedWith({reason: 'Nothing is starred on the Subsonic server.'});
}); });
// TODO: Hyz: Those tests should be at a higher level, we are repeating them for everything...
it("Given that the Subsonic server is not responding, when getting everything starred, it returns an error object with a message", function() { it("Given that the Subsonic server is not responding, when getting everything starred, it returns an error object with a message", function() {
mockBackend.whenJSONP(url).respond(503, 'Service Unavailable'); mockBackend.whenJSONP(url).respond(503, 'Service Unavailable');
@ -112,6 +123,9 @@ describe("Subsonic service -", function() {
}); //end getStarred }); //end getStarred
describe("getRandomStarredSongs -", function() { describe("getRandomStarredSongs -", function() {
var url = 'http://demo.subsonic.com/rest/getStarred.view?'+
'callback=JSON_CALLBACK&u=Hyzual&p=enc:cGFzc3dvcmQ=&v=1.10.2&c=Jamstash&f=jsonp';
describe("Given that the global setting AutoPlaylist Size is 3", function() { describe("Given that the global setting AutoPlaylist Size is 3", function() {
it("and given that I have more than 3 starred songs in my library, when getting random starred songs, the result should be limited to 3 starred songs", function() { it("and given that I have more than 3 starred songs in my library, when getting random starred songs, the result should be limited to 3 starred songs", function() {