Merge pull request #744 from jodal/feature/js-updates
Various updates to Mopidy.js
This commit is contained in:
commit
af238d5259
131
docs/api/js.rst
131
docs/api/js.rst
@ -74,7 +74,7 @@ development setup in the ``js/`` dir in our repo. The instructions in
|
||||
Creating an instance
|
||||
====================
|
||||
|
||||
Once you got Mopidy.js loaded, you need to create an instance of the wrapper:
|
||||
Once you have Mopidy.js loaded, you need to create an instance of the wrapper:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
@ -100,6 +100,31 @@ later:
|
||||
// ... do other stuff, like hooking up events ...
|
||||
mopidy.connect();
|
||||
|
||||
When creating an instance, you can specify the following settings:
|
||||
|
||||
``autoConnect``
|
||||
Whether or not to connect to the WebSocket on instance creation. Defaults
|
||||
to true.
|
||||
|
||||
``backoffDelayMin``
|
||||
The minimum number of milliseconds to wait after a connection error before
|
||||
we try to reconnect. For every failed attempt, the backoff delay is doubled
|
||||
until it reaches ``backoffDelayMax``. Defaults to 1000.
|
||||
|
||||
``backoffDelayMax``
|
||||
The maximum number of milliseconds to wait after a connection error before
|
||||
we try to reconnect. Defaults to 64000.
|
||||
|
||||
``webSocket``
|
||||
An existing WebSocket object to be used instead of creating a new
|
||||
WebSocket. Defaults to undefined.
|
||||
|
||||
``webSocketUrl``
|
||||
URL used when creating new WebSocket objects. Defaults to
|
||||
``ws://<document.location.host>/mopidy/ws``, or
|
||||
``ws://localhost/mopidy/ws`` if ``document.location.host`` isn't
|
||||
available, like it is in the browser environment.
|
||||
|
||||
|
||||
Hooking up to events
|
||||
====================
|
||||
@ -145,7 +170,8 @@ Once your Mopidy.js object has connected to the Mopidy server and emits the
|
||||
|
||||
Any calls you make before the ``state:online`` event is emitted will fail. If
|
||||
you've hooked up an errback (more on that a bit later) to the promise returned
|
||||
from the call, the errback will be called with an error message.
|
||||
from the call, the errback will be called with a ``Mopidy.ConnectionError``
|
||||
instance.
|
||||
|
||||
All methods in Mopidy's :ref:`core-api` is available via Mopidy.js. The core
|
||||
API attributes is *not* available, but that shouldn't be a problem as we've
|
||||
@ -204,22 +230,34 @@ Instead, typical usage will look like this:
|
||||
}
|
||||
};
|
||||
|
||||
mopidy.playback.getCurrentTrack().then(
|
||||
printCurrentTrack, console.error.bind(console));
|
||||
mopidy.playback.getCurrentTrack()
|
||||
.done(printCurrentTrack);
|
||||
|
||||
The first function passed to ``then()``, ``printCurrentTrack``, is the callback
|
||||
that will be called if the method call succeeds. The second function,
|
||||
``console.error``, is the errback that will be called if anything goes wrong.
|
||||
If you don't hook up an errback, debugging will be hard as errors will silently
|
||||
go missing.
|
||||
The function passed to ``done()``, ``printCurrentTrack``, is the callback
|
||||
that will be called if the method call succeeds. If anything goes wrong,
|
||||
``done()`` will throw an exception.
|
||||
|
||||
For debugging, you may be interested in errors from function without
|
||||
interesting return values as well. In that case, you can pass ``null`` as the
|
||||
callback:
|
||||
If you want to explicitly handle any errors and avoid an exception being
|
||||
thrown, you can register an error handler function anywhere in a promise
|
||||
chain. The function will be called with the error object as the only argument:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
mopidy.playback.next().then(null, console.error.bind(console));
|
||||
mopidy.playback.getCurrentTrack()
|
||||
.catch(console.error.bind(console));
|
||||
.done(printCurrentTrack);
|
||||
|
||||
You can also register the error handler at the end of the promise chain by
|
||||
passing it as the second argument to ``done()``:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
mopidy.playback.getCurrentTrack()
|
||||
.done(printCurrentTrack, console.error.bind(console));
|
||||
|
||||
If you don't hook up an error handler function and never call ``done()`` on the
|
||||
promise object, when.js will log warnings to the console that you have
|
||||
unhandled errors. In general, unhandled errors will not go silently missing.
|
||||
|
||||
The promise objects returned by Mopidy.js adheres to the `CommonJS Promises/A
|
||||
<http://wiki.commonjs.org/wiki/Promises/A>`_ standard. We use the
|
||||
@ -283,44 +321,38 @@ Example to get started with
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
var consoleError = console.error.bind(console);
|
||||
|
||||
var trackDesc = function (track) {
|
||||
return track.name + " by " + track.artists[0].name +
|
||||
" from " + track.album.name;
|
||||
};
|
||||
|
||||
var queueAndPlayFirstPlaylist = function () {
|
||||
mopidy.playlists.getPlaylists().then(function (playlists) {
|
||||
var playlist = playlists[0];
|
||||
var queueAndPlay = function (playlistNum, trackNum) {
|
||||
playlistNum = playlistNum || 0;
|
||||
trackNum = trackNum || 0;
|
||||
mopidy.playlists.getPlaylists().done(function (playlists) {
|
||||
var playlist = playlists[playlistNum];
|
||||
console.log("Loading playlist:", playlist.name);
|
||||
mopidy.tracklist.add(playlist.tracks).then(function (tlTracks) {
|
||||
mopidy.playback.play(tlTracks[0]).then(function () {
|
||||
mopidy.playback.getCurrentTrack().then(function (track) {
|
||||
mopidy.tracklist.add(playlist.tracks).done(function (tlTracks) {
|
||||
mopidy.playback.play(tlTracks[trackNum]).done(function () {
|
||||
mopidy.playback.getCurrentTrack().done(function (track) {
|
||||
console.log("Now playing:", trackDesc(track));
|
||||
}, consoleError);
|
||||
}, consoleError);
|
||||
}, consoleError);
|
||||
}, consoleError);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var mopidy = new Mopidy(); // Connect to server
|
||||
mopidy.on(console.log.bind(console)); // Log all events
|
||||
mopidy.on("state:online", queueAndPlayFirstPlaylist);
|
||||
mopidy.on("state:online", queueAndPlay);
|
||||
|
||||
Approximately the same behavior in a more functional style, using chaining
|
||||
of promisies.
|
||||
of promises.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
var consoleError = console.error.bind(console);
|
||||
|
||||
var getFirst = function (list) {
|
||||
return list[0];
|
||||
};
|
||||
|
||||
var extractTracks = function (playlist) {
|
||||
return playlist.tracks;
|
||||
var get = function (key, object) {
|
||||
return object[key];
|
||||
};
|
||||
|
||||
var printTypeAndName = function (model) {
|
||||
@ -339,33 +371,36 @@ Example to get started with
|
||||
// By returning any arguments we get, the function can be inserted
|
||||
// anywhere in the chain.
|
||||
var args = arguments;
|
||||
return mopidy.playback.getCurrentTrack().then(function (track) {
|
||||
console.log("Now playing:", trackDesc(track));
|
||||
return args;
|
||||
});
|
||||
return mopidy.playback.getCurrentTrack()
|
||||
.done(function (track) {
|
||||
console.log("Now playing:", trackDesc(track));
|
||||
return args;
|
||||
});
|
||||
};
|
||||
|
||||
var queueAndPlayFirstPlaylist = function () {
|
||||
var queueAndPlay = function (playlistNum, trackNum) {
|
||||
playlistNum = playlistNum || 0;
|
||||
trackNum = trackNum || 0;
|
||||
mopidy.playlists.getPlaylists()
|
||||
// => list of Playlists
|
||||
.then(getFirst, consoleError)
|
||||
.fold(get, playlistNum)
|
||||
// => Playlist
|
||||
.then(printTypeAndName, consoleError)
|
||||
.then(printTypeAndName)
|
||||
// => Playlist
|
||||
.then(extractTracks, consoleError)
|
||||
.fold(get, 'tracks')
|
||||
// => list of Tracks
|
||||
.then(mopidy.tracklist.add, consoleError)
|
||||
.then(mopidy.tracklist.add)
|
||||
// => list of TlTracks
|
||||
.then(getFirst, consoleError)
|
||||
.fold(get, trackNum)
|
||||
// => TlTrack
|
||||
.then(mopidy.playback.play, consoleError)
|
||||
.then(mopidy.playback.play)
|
||||
// => null
|
||||
.then(printNowPlaying, consoleError);
|
||||
.done(printNowPlaying, console.error.bind(console));
|
||||
};
|
||||
|
||||
var mopidy = new Mopidy(); // Connect to server
|
||||
mopidy.on(console.log.bind(console)); // Log all events
|
||||
mopidy.on("state:online", queueAndPlayFirstPlaylist);
|
||||
mopidy.on("state:online", queueAndPlay);
|
||||
|
||||
9. The web page should now queue and play your first playlist every time your
|
||||
load it. See the browser's console for output from the function, any errors,
|
||||
|
||||
@ -78,6 +78,20 @@ Feature release.
|
||||
Mopidy's HTTP server among other Zeroconf-published HTTP servers on the
|
||||
local network.
|
||||
|
||||
- Update Mopidy.js to use when.js 3. If you maintain a Mopidy client, you
|
||||
should review the `differences between when.js 2 and 3
|
||||
<https://github.com/cujojs/when/blob/master/docs/api.md#upgrading-to-30-from-2x>`_
|
||||
and the `when.js debugging guide
|
||||
<https://github.com/cujojs/when/blob/master/docs/api.md#debugging-promises>`_.
|
||||
This version has been released to npm as Mopidy.js v0.3.0.
|
||||
|
||||
- All of Mopidy.js' promise rejection values are now of the Error type. This
|
||||
ensures that all JavaScript VMs will show a useful stack trace if a rejected
|
||||
promise's value is used to throw an exception. To allow catch clauses to
|
||||
handle different errors differently, server side errors are of the type
|
||||
``Mopidy.ServerError``, and connection related errors are of the type
|
||||
``Mopidy.ConnectionError``.
|
||||
|
||||
**MPD frontend**
|
||||
|
||||
- Proper command tokenization for MPD requests. This replaces the old regex
|
||||
|
||||
@ -26,7 +26,7 @@ module.exports = function (grunt) {
|
||||
},
|
||||
options: {
|
||||
postBundleCB: function (err, src, next) {
|
||||
next(null, grunt.template.process("<%= meta.banner %>") + src);
|
||||
next(err, grunt.template.process("<%= meta.banner %>") + src);
|
||||
},
|
||||
standalone: "Mopidy"
|
||||
}
|
||||
@ -45,7 +45,7 @@ module.exports = function (grunt) {
|
||||
},
|
||||
options: {
|
||||
postBundleCB: function (err, src, next) {
|
||||
next(null, grunt.template.process("<%= meta.banner %>") + src);
|
||||
next(err, grunt.template.process("<%= meta.banner %>") + src);
|
||||
},
|
||||
standalone: "Mopidy"
|
||||
}
|
||||
|
||||
22
js/README.md
22
js/README.md
@ -47,13 +47,9 @@ See the [Mopidy.js documentation](http://docs.mopidy.com/en/latest/api/js/).
|
||||
Building from source
|
||||
--------------------
|
||||
|
||||
1. Install [Node.js](http://nodejs.org/) and npm. There is a PPA if you're
|
||||
running Ubuntu:
|
||||
1. Install [Node.js](http://nodejs.org/) and npm. If you're running Ubuntu:
|
||||
|
||||
sudo apt-get install python-software-properties
|
||||
sudo add-apt-repository ppa:chris-lea/node.js
|
||||
sudo apt-get update
|
||||
sudo apt-get install nodejs
|
||||
sudo apt-get install nodejs-legacy npm
|
||||
|
||||
2. Enter the `js/` in Mopidy's Git repo dir and install all dependencies:
|
||||
|
||||
@ -84,6 +80,20 @@ To run other [grunt](http://gruntjs.com/) targets which isn't predefined in
|
||||
Changelog
|
||||
---------
|
||||
|
||||
### 0.3.0 (UNRELEASED)
|
||||
|
||||
- Upgrade to when.js 3, which brings great performance improvements and better
|
||||
debugging facilities. If you maintain a Mopidy client, you should review the
|
||||
[differences between when.js 2 and 3](https://github.com/cujojs/when/blob/master/docs/api.md#upgrading-to-30-from-2x)
|
||||
and the
|
||||
[when.js debugging guide](https://github.com/cujojs/when/blob/master/docs/api.md#debugging-promises).
|
||||
|
||||
- All promise rejection values are now of the Error type. This ensures that all
|
||||
JavaScript VMs will show a useful stack trace if a rejected promise's value
|
||||
is used to throw an exception. To allow catch clauses to handle different
|
||||
errors differently, server side errors are of the type `Mopidy.ServerError`,
|
||||
and connection related errors are of the type `Mopidy.ConnectionError`.
|
||||
|
||||
### 0.2.0 (2014-01-04)
|
||||
|
||||
- **Backwards incompatible change for Node.js users:**
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mopidy",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"description": "Client lib for controlling a Mopidy music server over a WebSocket",
|
||||
"homepage": "http://www.mopidy.com/",
|
||||
"author": {
|
||||
@ -16,17 +16,18 @@
|
||||
"dependencies": {
|
||||
"bane": "~1.1.0",
|
||||
"faye-websocket": "~0.7.2",
|
||||
"when": "~2.7.1"
|
||||
"when": "~3.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"buster": "~0.7.8",
|
||||
"grunt": "~0.4.2",
|
||||
"buster": "~0.7.13",
|
||||
"browserify": "~3",
|
||||
"grunt": "~0.4.5",
|
||||
"grunt-buster": "~0.3.1",
|
||||
"grunt-browserify": "~1.3.0",
|
||||
"grunt-contrib-jshint": "~0.8.0",
|
||||
"grunt-contrib-uglify": "~0.2.7",
|
||||
"grunt-contrib-watch": "~0.5.3",
|
||||
"phantomjs": "~1.9.2-6"
|
||||
"grunt-browserify": "~1.3.2",
|
||||
"grunt-contrib-jshint": "~0.10.0",
|
||||
"grunt-contrib-uglify": "~0.5.0",
|
||||
"grunt-contrib-watch": "~0.6.1",
|
||||
"phantomjs": "~1.9.7-8"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test",
|
||||
|
||||
@ -24,13 +24,27 @@ function Mopidy(settings) {
|
||||
}
|
||||
}
|
||||
|
||||
Mopidy.ConnectionError = function (message) {
|
||||
this.name = "ConnectionError";
|
||||
this.message = message;
|
||||
};
|
||||
Mopidy.ConnectionError.prototype = new Error();
|
||||
Mopidy.ConnectionError.prototype.constructor = Mopidy.ConnectionError;
|
||||
|
||||
Mopidy.ServerError = function (message) {
|
||||
this.name = "ServerError";
|
||||
this.message = message;
|
||||
};
|
||||
Mopidy.ServerError.prototype = new Error();
|
||||
Mopidy.ServerError.prototype.constructor = Mopidy.ServerError;
|
||||
|
||||
Mopidy.WebSocket = websocket.Client;
|
||||
|
||||
Mopidy.prototype._configure = function (settings) {
|
||||
var currentHost = (typeof document !== "undefined" &&
|
||||
document.location.host) || "localhost";
|
||||
settings.webSocketUrl = settings.webSocketUrl ||
|
||||
"ws://" + currentHost + "/mopidy/ws/";
|
||||
"ws://" + currentHost + "/mopidy/ws";
|
||||
|
||||
if (settings.autoConnect !== false) {
|
||||
settings.autoConnect = true;
|
||||
@ -102,10 +116,9 @@ Mopidy.prototype._cleanup = function (closeEvent) {
|
||||
Object.keys(this._pendingRequests).forEach(function (requestId) {
|
||||
var resolver = this._pendingRequests[requestId];
|
||||
delete this._pendingRequests[requestId];
|
||||
resolver.reject({
|
||||
message: "WebSocket closed",
|
||||
closeEvent: closeEvent
|
||||
});
|
||||
var error = new Mopidy.ConnectionError("WebSocket closed");
|
||||
error.closeEvent = closeEvent;
|
||||
resolver.reject(error);
|
||||
}.bind(this));
|
||||
|
||||
this.emit("state:offline");
|
||||
@ -141,33 +154,25 @@ Mopidy.prototype._handleWebSocketError = function (error) {
|
||||
};
|
||||
|
||||
Mopidy.prototype._send = function (message) {
|
||||
var deferred = when.defer();
|
||||
|
||||
switch (this._webSocket.readyState) {
|
||||
case Mopidy.WebSocket.CONNECTING:
|
||||
deferred.resolver.reject({
|
||||
message: "WebSocket is still connecting"
|
||||
});
|
||||
break;
|
||||
return when.reject(
|
||||
new Mopidy.ConnectionError("WebSocket is still connecting"));
|
||||
case Mopidy.WebSocket.CLOSING:
|
||||
deferred.resolver.reject({
|
||||
message: "WebSocket is closing"
|
||||
});
|
||||
break;
|
||||
return when.reject(
|
||||
new Mopidy.ConnectionError("WebSocket is closing"));
|
||||
case Mopidy.WebSocket.CLOSED:
|
||||
deferred.resolver.reject({
|
||||
message: "WebSocket is closed"
|
||||
});
|
||||
break;
|
||||
return when.reject(
|
||||
new Mopidy.ConnectionError("WebSocket is closed"));
|
||||
default:
|
||||
var deferred = when.defer();
|
||||
message.jsonrpc = "2.0";
|
||||
message.id = this._nextRequestId();
|
||||
this._pendingRequests[message.id] = deferred.resolver;
|
||||
this._webSocket.send(JSON.stringify(message));
|
||||
this.emit("websocket:outgoingMessage", message);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
Mopidy.prototype._nextRequestId = (function () {
|
||||
@ -208,19 +213,22 @@ Mopidy.prototype._handleResponse = function (responseMessage) {
|
||||
return;
|
||||
}
|
||||
|
||||
var error;
|
||||
var resolver = this._pendingRequests[responseMessage.id];
|
||||
delete this._pendingRequests[responseMessage.id];
|
||||
|
||||
if (responseMessage.hasOwnProperty("result")) {
|
||||
resolver.resolve(responseMessage.result);
|
||||
} else if (responseMessage.hasOwnProperty("error")) {
|
||||
resolver.reject(responseMessage.error);
|
||||
error = new Mopidy.ServerError(responseMessage.error.message);
|
||||
error.code = responseMessage.error.code;
|
||||
error.data = responseMessage.error.data;
|
||||
resolver.reject(error);
|
||||
this._console.warn("Server returned error:", responseMessage.error);
|
||||
} else {
|
||||
resolver.reject({
|
||||
message: "Response without 'result' or 'error' received",
|
||||
data: {response: responseMessage}
|
||||
});
|
||||
error = new Error("Response without 'result' or 'error' received");
|
||||
error.data = {response: responseMessage};
|
||||
resolver.reject(error);
|
||||
this._console.warn(
|
||||
"Response without 'result' or 'error' received. Message was:",
|
||||
responseMessage);
|
||||
|
||||
@ -48,7 +48,7 @@ buster.testCase("Mopidy", {
|
||||
document.location.host || "localhost";
|
||||
|
||||
assert.calledOnceWith(this.webSocketConstructorStub,
|
||||
"ws://" + currentHost + "/mopidy/ws/");
|
||||
"ws://" + currentHost + "/mopidy/ws");
|
||||
},
|
||||
|
||||
"does not connect when autoConnect is false": function () {
|
||||
@ -84,7 +84,7 @@ buster.testCase("Mopidy", {
|
||||
document.location.host || "localhost";
|
||||
|
||||
assert.calledOnceWith(this.webSocketConstructorStub,
|
||||
"ws://" + currentHost + "/mopidy/ws/");
|
||||
"ws://" + currentHost + "/mopidy/ws");
|
||||
},
|
||||
|
||||
"does nothing when the WebSocket is open": function () {
|
||||
@ -169,12 +169,18 @@ buster.testCase("Mopidy", {
|
||||
this.mopidy._cleanup(closeEvent);
|
||||
|
||||
assert.equals(Object.keys(this.mopidy._pendingRequests).length, 0);
|
||||
when.join(promise1, promise2).then(done(function () {
|
||||
assert(false, "Promises should be rejected");
|
||||
}), done(function (error) {
|
||||
assert.equals(error.message, "WebSocket closed");
|
||||
assert.same(error.closeEvent, closeEvent);
|
||||
}));
|
||||
when.settle([promise1, promise2]).done(
|
||||
done(function (descriptors) {
|
||||
assert.equals(descriptors.length, 2);
|
||||
descriptors.forEach(function (d) {
|
||||
assert.equals(d.state, "rejected");
|
||||
assert(d.reason instanceof Error);
|
||||
assert(d.reason instanceof Mopidy.ConnectionError);
|
||||
assert.equals(d.reason.message, "WebSocket closed");
|
||||
assert.same(d.reason.closeEvent, closeEvent);
|
||||
});
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
"emits 'state:offline' event when done": function () {
|
||||
@ -388,12 +394,17 @@ buster.testCase("Mopidy", {
|
||||
var promise = this.mopidy._send({method: "foo"});
|
||||
|
||||
refute.called(this.mopidy._webSocket.send);
|
||||
promise.then(done(function () {
|
||||
assert(false);
|
||||
}), done(function (error) {
|
||||
assert.equals(
|
||||
error.message, "WebSocket is still connecting");
|
||||
}));
|
||||
promise.done(
|
||||
done(function () {
|
||||
assert(false);
|
||||
}),
|
||||
done(function (error) {
|
||||
assert(error instanceof Error);
|
||||
assert(error instanceof Mopidy.ConnectionError);
|
||||
assert.equals(
|
||||
error.message, "WebSocket is still connecting");
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
"immediately rejects request if CLOSING": function (done) {
|
||||
@ -402,12 +413,16 @@ buster.testCase("Mopidy", {
|
||||
var promise = this.mopidy._send({method: "foo"});
|
||||
|
||||
refute.called(this.mopidy._webSocket.send);
|
||||
promise.then(done(function () {
|
||||
assert(false);
|
||||
}), done(function (error) {
|
||||
assert.equals(
|
||||
error.message, "WebSocket is closing");
|
||||
}));
|
||||
promise.done(
|
||||
done(function () {
|
||||
assert(false);
|
||||
}),
|
||||
done(function (error) {
|
||||
assert(error instanceof Error);
|
||||
assert(error instanceof Mopidy.ConnectionError);
|
||||
assert.equals(error.message, "WebSocket is closing");
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
"immediately rejects request if CLOSED": function (done) {
|
||||
@ -416,12 +431,16 @@ buster.testCase("Mopidy", {
|
||||
var promise = this.mopidy._send({method: "foo"});
|
||||
|
||||
refute.called(this.mopidy._webSocket.send);
|
||||
promise.then(done(function () {
|
||||
assert(false);
|
||||
}), done(function (error) {
|
||||
assert.equals(
|
||||
error.message, "WebSocket is closed");
|
||||
}));
|
||||
promise.done(
|
||||
done(function () {
|
||||
assert(false);
|
||||
}),
|
||||
done(function (error) {
|
||||
assert(error instanceof Error);
|
||||
assert(error instanceof Mopidy.ConnectionError);
|
||||
assert.equals(error.message, "WebSocket is closed");
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@ -544,7 +563,11 @@ buster.testCase("Mopidy", {
|
||||
"rejects and logs requests which get errors back": function (done) {
|
||||
var stub = this.stub(this.mopidy._console, "warn");
|
||||
var promise = this.mopidy._send({method: "bar"});
|
||||
var responseError = {message: "Error", data: {}};
|
||||
var responseError = {
|
||||
code: -32601,
|
||||
message: "Method not found",
|
||||
data: {}
|
||||
};
|
||||
var responseMessage = {
|
||||
jsonrpc: "2.0",
|
||||
id: Object.keys(this.mopidy._pendingRequests)[0],
|
||||
@ -555,11 +578,49 @@ buster.testCase("Mopidy", {
|
||||
|
||||
assert.calledOnceWith(stub,
|
||||
"Server returned error:", responseError);
|
||||
promise.then(done(function () {
|
||||
assert(false);
|
||||
}), done(function (error) {
|
||||
assert.equals(error, responseError);
|
||||
}));
|
||||
promise.done(
|
||||
done(function () {
|
||||
assert(false);
|
||||
}),
|
||||
done(function (error) {
|
||||
assert(error instanceof Error);
|
||||
assert.equals(error.code, responseError.code);
|
||||
assert.equals(error.message, responseError.message);
|
||||
assert.equals(error.data, responseError.data);
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
"rejects and logs requests which get errors without data": function (done) {
|
||||
var stub = this.stub(this.mopidy._console, "warn");
|
||||
var promise = this.mopidy._send({method: "bar"});
|
||||
var responseError = {
|
||||
code: -32601,
|
||||
message: "Method not found"
|
||||
// 'data' key intentionally missing
|
||||
};
|
||||
var responseMessage = {
|
||||
jsonrpc: "2.0",
|
||||
id: Object.keys(this.mopidy._pendingRequests)[0],
|
||||
error: responseError
|
||||
};
|
||||
|
||||
this.mopidy._handleResponse(responseMessage);
|
||||
|
||||
assert.calledOnceWith(stub,
|
||||
"Server returned error:", responseError);
|
||||
promise.done(
|
||||
done(function () {
|
||||
assert(false);
|
||||
}),
|
||||
done(function (error) {
|
||||
assert(error instanceof Error);
|
||||
assert(error instanceof Mopidy.ServerError);
|
||||
assert.equals(error.code, responseError.code);
|
||||
assert.equals(error.message, responseError.message);
|
||||
refute.defined(error.data);
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
"rejects and logs responses without result or error": function (done) {
|
||||
@ -575,14 +636,18 @@ buster.testCase("Mopidy", {
|
||||
assert.calledOnceWith(stub,
|
||||
"Response without 'result' or 'error' received. Message was:",
|
||||
responseMessage);
|
||||
promise.then(done(function () {
|
||||
assert(false);
|
||||
}), done(function (error) {
|
||||
assert.equals(
|
||||
error.message,
|
||||
"Response without 'result' or 'error' received");
|
||||
assert.equals(error.data.response, responseMessage);
|
||||
}));
|
||||
promise.done(
|
||||
done(function () {
|
||||
assert(false);
|
||||
}),
|
||||
done(function (error) {
|
||||
assert(error instanceof Error);
|
||||
assert.equals(
|
||||
error.message,
|
||||
"Response without 'result' or 'error' received");
|
||||
assert.equals(error.data.response, responseMessage);
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user