<NME> lastfm-session-test.js
<BEF> require('./common.js');
var LastFmSession = require('../lib/lastfm/lastfm-session');
var fakes = require("./fakes");


(function() {
  describe("a new LastFmSession");
  var session;

  before(function() {
     session = new LastFmSession(new LastFmNode());
  });

  it("has no session key", function() {
    assert.ok(!session.key);
  });

  it("has no user", function() {
    assert.ok(!session.user);
  });

  it("is not authorised", function() {
    assert.ok(session.isAuthorised() === false);
  });

  it("can configure key and user", function() {
    var session = new LastFmSession(new LastFmNode(), { user: "user", key: "sessionkey" });
    assert.equal("user", session.user);
    assert.equal("sessionkey", session.key);
  });

  it("is authorised when it has a key", function() {
    var session = new LastFmSession(new LastFmNode(), { user: "user", key: "sessionkey" });
    assert.ok(session.isAuthorised());
  });
})();
    that.error = error;    
  });

  context.whenReceiving = function(returndata) {
    that.returndata = returndata;
    that.session.authorise('token');
  };

  context.expectError = function(errorMessage) {
    assert.ok(that.error);
    assert.equal(errorMessage, that.error.message);
    token = "";
    returndata = null;
    options = null;
    request = new fakes.LastFmRequest();
    lastfm = new LastFmNode();
    gently = new Gently();
    LastFmSession.prototype.scheduleCallback = emptyFn;
  }

  function expectError(message) {
    gently.expect(session, "emit", function(event, error) {
      assert.equal("error", event);
      assert.equal(message, error.message);
    });
    doRequest();
  }

  function doRequest() {
    if (readError) {
      request.emit("error", readError);
    }
    else {
      request.emit("success", returndata);
    }
  }

  function doNotExpectError() {
    doRequest();
  }

  function expectRetry(retry) {
    gently.expect(session, "emit", function(event, details) {
      assert.equal("retrying", event);
      if (retry) {
        assert.deepEqual(details, retry);
      }
    });
    doRequest();
  }


ntest.describe("a completed LastFmSession authorisation request")
ntest.before(function() {
   setupLastFmSessionFixture(this);
});

ntest.it("emits error when authorisation not successful", function() {
  this.whenReceiving(FakeData.AuthorisationError);
  this.expectError('Invalid method signature supplied');
});

ntest.it("emits error when receiving unexpected return data", function() {
  this.whenReceiving(FakeData.SingleRecentTrack);
  this.expectError('Unexpected error');
});

ntest.it("emits authorised when successful", function() {
  this.whenReceiving(FakeData.SuccessfulAuthorisation);
  assert.ok(this.authorisedSession);
  assert.ok(!this.error);
});

ntest.it("updates session key and user when successful", function() {
  this.whenReceiving(FakeData.SuccessfulAuthorisation);
  assert.equal('username', this.session.user);
  assert.equal('sessionkey', this.session.key);
});
    gently.expect(lastfm, "request", function() {
      return request;
    });
  }
  
  function andTokenIs(setToken) {
    session = new LastFmSession(lastfm, { token: setToken });
  }

  assert.equal('Session is not authorised', this.error.message);
});

ntest.describe("an authorised session")
ntest.before(function() {
  setupLastFmSessionFixture(this);
        return request;
    });
    session = new LastFmSession(lastfm, { token: 'token' });
  });
  
  assert.ok(!this.error);
});

ntest.describe("nowPlaying requests")
ntest.before(function() {
  setupLastFmSessionFixture(this);
  this.session.key = 'key';
});

ntest.it("sends a signed request", function() {
  it("emits error when receiving unexpected return data", function() {
    whenReadRequestReturns(FakeData.SingleRecentTrack);
    andTokenIs("token");
    expectError("Unexpected error");
  });
  
  it("emits authorised when successful", function() {
    whenReadRequestReturns(FakeData.SuccessfulAuthorisation);
    andTokenIs("token");
    expectAuthorisation();
  });
  
  assert.equal('Run To Your Grave', this.params.track);
  assert.equal('key', this.params.sk);
});

  it("will retry on service unavailable", function() {
    whenReadRequestThrowsError(11, "Service temporarily unavailable.");
    andTokenIs("token");
    expectRetry();
  });

  it("can have the retry interval specified", function() {
    whenReadRequestThrowsError(14, "This token has not been authorised");
    andOptionsAre({ token: 'token', retryInterval: 15000 });
    LastFmSession.prototype.scheduleCallback = gently.expect(function(callback, delay) {
      assert.equal(delay, 15000);
    });
    doRequest();
  });

  it("user defined retry interval in retry event", function() {
    whenReadRequestThrowsError(14, "This token has not been authorised");
    andOptionsAre({ token: 'token', retryInterval: 15000 });
    expectRetry({
        error: 14,
        message: "This token has not been authorised",
        delay: 15000
    });
  });

  it("can cancel retries", function() {
    whenReadRequestThrowsError(14, "This token has not been authorised");
    andTokenIs("token");
    session.cancel();
    doNotExpectRetry();
  });
})();

<MSG> Support for scrobbling added. \o/

<DFF> @@ -37,11 +37,6 @@ function setupLastFmSessionFixture(context) {
     that.error = error;    
   });
 
-  context.whenReceiving = function(returndata) {
-    that.returndata = returndata;
-    that.session.authorise('token');
-  };
-
   context.expectError = function(errorMessage) {
     assert.ok(that.error);
     assert.equal(errorMessage, that.error.message);
@@ -88,27 +83,34 @@ ntest.it("is signed", function() {
 
 ntest.describe("a completed LastFmSession authorisation request")
 ntest.before(function() {
+   var that = this;
+
    setupLastFmSessionFixture(this);
+
+   this.whenResponseIs = function(returndata) {
+     that.returndata = returndata;
+     that.session.authorise('token');
+   };
 });
 
 ntest.it("emits error when authorisation not successful", function() {
-  this.whenReceiving(FakeData.AuthorisationError);
+  this.whenResponseIs(FakeData.AuthorisationError);
   this.expectError('Invalid method signature supplied');
 });
 
 ntest.it("emits error when receiving unexpected return data", function() {
-  this.whenReceiving(FakeData.SingleRecentTrack);
+  this.whenResponseIs(FakeData.SingleRecentTrack);
   this.expectError('Unexpected error');
 });
 
 ntest.it("emits authorised when successful", function() {
-  this.whenReceiving(FakeData.SuccessfulAuthorisation);
+  this.whenResponseIs(FakeData.SuccessfulAuthorisation);
   assert.ok(this.authorisedSession);
   assert.ok(!this.error);
 });
 
 ntest.it("updates session key and user when successful", function() {
-  this.whenReceiving(FakeData.SuccessfulAuthorisation);
+  this.whenResponseIs(FakeData.SuccessfulAuthorisation);
   assert.equal('username', this.session.user);
   assert.equal('sessionkey', this.session.key);
 });
@@ -124,6 +126,12 @@ ntest.it("emits error when attempting to update nowPlaying", function() {
   assert.equal('Session is not authorised', this.error.message);
 });
 
+ntest.it("emits error when attempting to scrobble", function() {
+  this.session.scrobble(FakeTracks.RunToYourGrave);
+  assert.ok(this.error);
+  assert.equal('Session is not authorised', this.error.message);
+});
+
 ntest.describe("an authorised session")
 ntest.before(function() {
   setupLastFmSessionFixture(this);
@@ -135,10 +143,21 @@ ntest.it("allows updating of nowPlaying", function() {
   assert.ok(!this.error);
 });
 
+ntest.it("allows scrobbling", function() {
+  this.session.key = 'key';
+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);
+  assert.ok(!this.error);
+});
+
 ntest.describe("nowPlaying requests")
 ntest.before(function() {
+  var that = this;
   setupLastFmSessionFixture(this);
   this.session.key = 'key';
+  this.whenResponseIs = function(returndata) {
+    that.returndata = returndata;
+    that.session.updateNowPlaying(FakeTracks.RunToYourGrave);
+  };
 });
 
 ntest.it("sends a signed request", function() {
@@ -157,3 +176,69 @@ ntest.it("sends required parameters", function() {
   assert.equal('Run To Your Grave', this.params.track);
   assert.equal('key', this.params.sk);
 });
+
+ntest.it("emits error when problem updating", function() {
+  this.whenResponseIs(FakeData.UpdateNowPlayingError);
+  this.expectError("Signature is invalid");
+});
+
+ntest.it("emits success when updated", function() {
+  var that = this;
+  var success = false;
+  this.session.addListener('success', function() {
+    success = true;
+  });
+  this.whenResponseIs(FakeData.UpdateNowPlayingSuccess);
+  assert.ok(success);
+  assert.ok(!this.error);
+});
+
+ntest.describe("a scrobble request")
+ntest.before(function() {
+  var that = this;
+  setupLastFmSessionFixture(this);
+  this.session.key = 'key';
+  this.whenResponseIs = function(returndata) {
+    that.returndata = returndata;
+    that.session.scrobble(FakeTracks.RunToYourGrave, 12345678);
+  };
+});
+
+ntest.it("emits error when no timestamp supplied", function() {
+  this.session.scrobble(FakeTracks.RunToYourGrave);
+  this.expectError("Timestamp is required for scrobbling");
+});
+
+ntest.it("sends a signed request", function() {
+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);
+  assert.ok(this.signed);
+});
+
+ntest.it("uses scrobble method", function() {
+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);
+  assert.equal('track.scrobble', this.params.method);
+});
+
+ntest.it("sends required parameters", function() {
+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);
+  assert.equal('The Mae Shi', this.params.artist);
+  assert.equal('Run To Your Grave', this.params.track);
+  assert.equal('key', this.params.sk);
+  assert.equal(12345678, this.params.timestamp);
+});
+
+ntest.it("emits error when problem updating", function() {
+  this.whenResponseIs(FakeData.UpdateNowPlayingError);
+  this.expectError("Signature is invalid");
+});
+
+ntest.it("emits success when updated", function() {
+  var that = this;
+  var success = false;
+  this.session.addListener('success', function() {
+    success = true;
+  });
+  this.whenResponseIs(FakeData.UpdateNowPlayingSuccess);
+  assert.ok(success);
+  assert.ok(!this.error);
+});

{'commit': 'diff --git a/lib/lastfm-node/lastfm-session.js b/lib/lastfm-node/lastfm-session.js\nindex bf7918f..87a457d 100644\n--- a/lib/lastfm-node/lastfm-session.js\n+++ b/lib/lastfm-node/lastfm-session.js\n@@ -37,12 +37,45 @@ LastFmSession.prototype.authorise = function(token) {\n };\n \n LastFmSession.prototype.updateNowPlaying = function(track) {\n-  if (this.key == \'\') {\n+  if (!this.key) {\n     this.emit(\'error\', new Error(\'Session is not authorised\'));\n     return;\n   }\n   var that = this;\n   this.buffer = \'\';\n   this.lastfm.writeRequest({ method: \'user.updateNowPlaying\', artist: track.artist[\'#text\'], track: track.name, sk: this.key }, true, function(data) {\n-   });\n+    var response = JSON.parse(data);\n+    if (!response.lfm) return;\n+    if (response.lfm[\'@status\'] == "failed") {\n+      that.emit(\'error\', new Error(response.lfm.error.$));\n+    }\n+    if (response.lfm[\'@status\'] == "ok") {\n+      that.emit(\'success\', null);\n+    }\n+  });\n+};\n+\n+LastFmSession.prototype.scrobble = function(track, timestamp) {\n+  if (!this.key) {\n+    this.emit(\'error\', new Error(\'Session is not authorised\'));\n+    return;\n+  }\n+\n+  if (!timestamp) {\n+    this.emit(\'error\', new Error(\'Timestamp is required for scrobbling\'));\n+    return;\n+  }\n+\n+  var that = this;\n+  this.buffer = \'\';\n+  this.lastfm.writeRequest({ method: \'track.scrobble\', artist: track.artist[\'#text\'], track: track.name, sk: this.key, timestamp: timestamp }, true, function(data) {\n+    var response = JSON.parse(data);\n+    if (!response.lfm) return;\n+    if (response.lfm[\'@status\'] == "failed") {\n+      that.emit(\'error\', new Error(response.lfm.error.$));\n+    }\n+    if (response.lfm[\'@status\'] == "ok") {\n+      that.emit(\'success\', null);\n+    }\n+  });\n };\ndiff --git a/tests/TestData.js b/tests/TestData.js\nindex 7a4e2d2..7054280 100644\n--- a/tests/TestData.js\n+++ b/tests/TestData.js\n@@ -16,3 +16,7 @@ FakeTracks.NowPlayingAndScrobbled = [{"artist":{"#text":"Super Tennis","mbid":""\n FakeData.AuthorisationError = "{ \\"error\\" : 13, \\"message\\" : \\"Invalid method signature supplied\\" }";\n \n FakeData.SuccessfulAuthorisation = "{ \\"session\\":  { \\"name\\": \\"username\\", \\"key\\": \\"sessionkey\\", \\"subscriber\\": \\"0\\"} }"; \n+\n+FakeData.UpdateNowPlayingError = "{ \\"lfm\\": { \\"@status\\": \\"failed\\", \\"error\\": { \\"@code\\": \\"13\\", \\"$\\": \\"Signature is invalid\\" }, \\"serverTimestamp\\": \\"1287136172\\" }}";\n+\n+FakeData.UpdateNowPlayingSuccess = "{ \\"lfm\\": { \\"@status\\": \\"ok\\", \\"message\\": \\"Now playing track updated\\", \\"serverTimestamp\\": \\"1287136252\\" }}";\ndiff --git a/tests/lastfm-session-test.js b/tests/lastfm-session-test.js\nindex 45d3727..6ab5641 100644\n--- a/tests/lastfm-session-test.js\n+++ b/tests/lastfm-session-test.js\n@@ -37,11 +37,6 @@ function setupLastFmSessionFixture(context) {\n     that.error = error;    \n   });\n \n-  context.whenReceiving = function(returndata) {\n-    that.returndata = returndata;\n-    that.session.authorise(\'token\');\n-  };\n-\n   context.expectError = function(errorMessage) {\n     assert.ok(that.error);\n     assert.equal(errorMessage, that.error.message);\n@@ -88,27 +83,34 @@ ntest.it("is signed", function() {\n \n ntest.describe("a completed LastFmSession authorisation request")\n ntest.before(function() {\n+   var that = this;\n+\n    setupLastFmSessionFixture(this);\n+\n+   this.whenResponseIs = function(returndata) {\n+     that.returndata = returndata;\n+     that.session.authorise(\'token\');\n+   };\n });\n \n ntest.it("emits error when authorisation not successful", function() {\n-  this.whenReceiving(FakeData.AuthorisationError);\n+  this.whenResponseIs(FakeData.AuthorisationError);\n   this.expectError(\'Invalid method signature supplied\');\n });\n \n ntest.it("emits error when receiving unexpected return data", function() {\n-  this.whenReceiving(FakeData.SingleRecentTrack);\n+  this.whenResponseIs(FakeData.SingleRecentTrack);\n   this.expectError(\'Unexpected error\');\n });\n \n ntest.it("emits authorised when successful", function() {\n-  this.whenReceiving(FakeData.SuccessfulAuthorisation);\n+  this.whenResponseIs(FakeData.SuccessfulAuthorisation);\n   assert.ok(this.authorisedSession);\n   assert.ok(!this.error);\n });\n \n ntest.it("updates session key and user when successful", function() {\n-  this.whenReceiving(FakeData.SuccessfulAuthorisation);\n+  this.whenResponseIs(FakeData.SuccessfulAuthorisation);\n   assert.equal(\'username\', this.session.user);\n   assert.equal(\'sessionkey\', this.session.key);\n });\n@@ -124,6 +126,12 @@ ntest.it("emits error when attempting to update nowPlaying", function() {\n   assert.equal(\'Session is not authorised\', this.error.message);\n });\n \n+ntest.it("emits error when attempting to scrobble", function() {\n+  this.session.scrobble(FakeTracks.RunToYourGrave);\n+  assert.ok(this.error);\n+  assert.equal(\'Session is not authorised\', this.error.message);\n+});\n+\n ntest.describe("an authorised session")\n ntest.before(function() {\n   setupLastFmSessionFixture(this);\n@@ -135,10 +143,21 @@ ntest.it("allows updating of nowPlaying", function() {\n   assert.ok(!this.error);\n });\n \n+ntest.it("allows scrobbling", function() {\n+  this.session.key = \'key\';\n+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);\n+  assert.ok(!this.error);\n+});\n+\n ntest.describe("nowPlaying requests")\n ntest.before(function() {\n+  var that = this;\n   setupLastFmSessionFixture(this);\n   this.session.key = \'key\';\n+  this.whenResponseIs = function(returndata) {\n+    that.returndata = returndata;\n+    that.session.updateNowPlaying(FakeTracks.RunToYourGrave);\n+  };\n });\n \n ntest.it("sends a signed request", function() {\n@@ -157,3 +176,69 @@ ntest.it("sends required parameters", function() {\n   assert.equal(\'Run To Your Grave\', this.params.track);\n   assert.equal(\'key\', this.params.sk);\n });\n+\n+ntest.it("emits error when problem updating", function() {\n+  this.whenResponseIs(FakeData.UpdateNowPlayingError);\n+  this.expectError("Signature is invalid");\n+});\n+\n+ntest.it("emits success when updated", function() {\n+  var that = this;\n+  var success = false;\n+  this.session.addListener(\'success\', function() {\n+    success = true;\n+  });\n+  this.whenResponseIs(FakeData.UpdateNowPlayingSuccess);\n+  assert.ok(success);\n+  assert.ok(!this.error);\n+});\n+\n+ntest.describe("a scrobble request")\n+ntest.before(function() {\n+  var that = this;\n+  setupLastFmSessionFixture(this);\n+  this.session.key = \'key\';\n+  this.whenResponseIs = function(returndata) {\n+    that.returndata = returndata;\n+    that.session.scrobble(FakeTracks.RunToYourGrave, 12345678);\n+  };\n+});\n+\n+ntest.it("emits error when no timestamp supplied", function() {\n+  this.session.scrobble(FakeTracks.RunToYourGrave);\n+  this.expectError("Timestamp is required for scrobbling");\n+});\n+\n+ntest.it("sends a signed request", function() {\n+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);\n+  assert.ok(this.signed);\n+});\n+\n+ntest.it("uses scrobble method", function() {\n+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);\n+  assert.equal(\'track.scrobble\', this.params.method);\n+});\n+\n+ntest.it("sends required parameters", function() {\n+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);\n+  assert.equal(\'The Mae Shi\', this.params.artist);\n+  assert.equal(\'Run To Your Grave\', this.params.track);\n+  assert.equal(\'key\', this.params.sk);\n+  assert.equal(12345678, this.params.timestamp);\n+});\n+\n+ntest.it("emits error when problem updating", function() {\n+  this.whenResponseIs(FakeData.UpdateNowPlayingError);\n+  this.expectError("Signature is invalid");\n+});\n+\n+ntest.it("emits success when updated", function() {\n+  var that = this;\n+  var success = false;\n+  this.session.addListener(\'success\', function() {\n+    success = true;\n+  });\n+  this.whenResponseIs(FakeData.UpdateNowPlayingSuccess);\n+  assert.ok(success);\n+  assert.ok(!this.error);\n+});\n', 'commit_subject': 'Support for scrobbling added. \\o/', 'repo_name': 'jammus/lastfm-node', 'committer': {'name': 'jammus', 'email': 'a099b7f4436856f8ac33be426622f7d0d7300d6f@gmail.com', 'time_sec': '1287151956', 'tz_offset': '60', 'date': {'seconds': '1287151956'}}, 'commit_tree': '3e1c476731042ec034129aba05f02525f56cbf08', 'commit_message': 'Support for scrobbling added. \\o/\n', 'language_name': 'Shell', 'license': 'mit', 'hunks': '@@ -37,11 +37,6 @@ function setupLastFmSessionFixture(context) {\n     that.error = error;    \n   });\n \n-  context.whenReceiving = function(returndata) {\n-    that.returndata = returndata;\n-    that.session.authorise(\'token\');\n-  };\n-\n   context.expectError = function(errorMessage) {\n     assert.ok(that.error);\n     assert.equal(errorMessage, that.error.message);\n@@ -88,27 +83,34 @@ ntest.it("is signed", function() {\n \n ntest.describe("a completed LastFmSession authorisation request")\n ntest.before(function() {\n+   var that = this;\n+\n    setupLastFmSessionFixture(this);\n+\n+   this.whenResponseIs = function(returndata) {\n+     that.returndata = returndata;\n+     that.session.authorise(\'token\');\n+   };\n });\n \n ntest.it("emits error when authorisation not successful", function() {\n-  this.whenReceiving(FakeData.AuthorisationError);\n+  this.whenResponseIs(FakeData.AuthorisationError);\n   this.expectError(\'Invalid method signature supplied\');\n });\n \n ntest.it("emits error when receiving unexpected return data", function() {\n-  this.whenReceiving(FakeData.SingleRecentTrack);\n+  this.whenResponseIs(FakeData.SingleRecentTrack);\n   this.expectError(\'Unexpected error\');\n });\n \n ntest.it("emits authorised when successful", function() {\n-  this.whenReceiving(FakeData.SuccessfulAuthorisation);\n+  this.whenResponseIs(FakeData.SuccessfulAuthorisation);\n   assert.ok(this.authorisedSession);\n   assert.ok(!this.error);\n });\n \n ntest.it("updates session key and user when successful", function() {\n-  this.whenReceiving(FakeData.SuccessfulAuthorisation);\n+  this.whenResponseIs(FakeData.SuccessfulAuthorisation);\n   assert.equal(\'username\', this.session.user);\n   assert.equal(\'sessionkey\', this.session.key);\n });\n@@ -124,6 +126,12 @@ ntest.it("emits error when attempting to update nowPlaying", function() {\n   assert.equal(\'Session is not authorised\', this.error.message);\n });\n \n+ntest.it("emits error when attempting to scrobble", function() {\n+  this.session.scrobble(FakeTracks.RunToYourGrave);\n+  assert.ok(this.error);\n+  assert.equal(\'Session is not authorised\', this.error.message);\n+});\n+\n ntest.describe("an authorised session")\n ntest.before(function() {\n   setupLastFmSessionFixture(this);\n@@ -135,10 +143,21 @@ ntest.it("allows updating of nowPlaying", function() {\n   assert.ok(!this.error);\n });\n \n+ntest.it("allows scrobbling", function() {\n+  this.session.key = \'key\';\n+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);\n+  assert.ok(!this.error);\n+});\n+\n ntest.describe("nowPlaying requests")\n ntest.before(function() {\n+  var that = this;\n   setupLastFmSessionFixture(this);\n   this.session.key = \'key\';\n+  this.whenResponseIs = function(returndata) {\n+    that.returndata = returndata;\n+    that.session.updateNowPlaying(FakeTracks.RunToYourGrave);\n+  };\n });\n \n ntest.it("sends a signed request", function() {\n@@ -157,3 +176,69 @@ ntest.it("sends required parameters", function() {\n   assert.equal(\'Run To Your Grave\', this.params.track);\n   assert.equal(\'key\', this.params.sk);\n });\n+\n+ntest.it("emits error when problem updating", function() {\n+  this.whenResponseIs(FakeData.UpdateNowPlayingError);\n+  this.expectError("Signature is invalid");\n+});\n+\n+ntest.it("emits success when updated", function() {\n+  var that = this;\n+  var success = false;\n+  this.session.addListener(\'success\', function() {\n+    success = true;\n+  });\n+  this.whenResponseIs(FakeData.UpdateNowPlayingSuccess);\n+  assert.ok(success);\n+  assert.ok(!this.error);\n+});\n+\n+ntest.describe("a scrobble request")\n+ntest.before(function() {\n+  var that = this;\n+  setupLastFmSessionFixture(this);\n+  this.session.key = \'key\';\n+  this.whenResponseIs = function(returndata) {\n+    that.returndata = returndata;\n+    that.session.scrobble(FakeTracks.RunToYourGrave, 12345678);\n+  };\n+});\n+\n+ntest.it("emits error when no timestamp supplied", function() {\n+  this.session.scrobble(FakeTracks.RunToYourGrave);\n+  this.expectError("Timestamp is required for scrobbling");\n+});\n+\n+ntest.it("sends a signed request", function() {\n+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);\n+  assert.ok(this.signed);\n+});\n+\n+ntest.it("uses scrobble method", function() {\n+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);\n+  assert.equal(\'track.scrobble\', this.params.method);\n+});\n+\n+ntest.it("sends required parameters", function() {\n+  this.session.scrobble(FakeTracks.RunToYourGrave, 12345678);\n+  assert.equal(\'The Mae Shi\', this.params.artist);\n+  assert.equal(\'Run To Your Grave\', this.params.track);\n+  assert.equal(\'key\', this.params.sk);\n+  assert.equal(12345678, this.params.timestamp);\n+});\n+\n+ntest.it("emits error when problem updating", function() {\n+  this.whenResponseIs(FakeData.UpdateNowPlayingError);\n+  this.expectError("Signature is invalid");\n+});\n+\n+ntest.it("emits success when updated", function() {\n+  var that = this;\n+  var success = false;\n+  this.session.addListener(\'success\', function() {\n+    success = true;\n+  });\n+  this.whenResponseIs(FakeData.UpdateNowPlayingSuccess);\n+  assert.ok(success);\n+  assert.ok(!this.error);\n+});\n', 'addition_count': 94, 'deletion_count': 9, 'src_file': 'a/tests/lastfm-session-test.js', 'tgt_file': 'b/tests/lastfm-session-test.js', 'file_extension': '.js', 'before_file': 'require(\'./common.js\');\nvar LastFmSession = require(\'../lib/lastfm/lastfm-session\');\nvar fakes = require("./fakes");\n\n\n(function() {\n  describe("a new LastFmSession");\n  var session;\n\n  before(function() {\n     session = new LastFmSession(new LastFmNode());\n  });\n\n  it("has no session key", function() {\n    assert.ok(!session.key);\n  });\n\n  it("has no user", function() {\n    assert.ok(!session.user);\n  });\n\n  it("is not authorised", function() {\n    assert.ok(session.isAuthorised() === false);\n  });\n\n  it("can configure key and user", function() {\n    var session = new LastFmSession(new LastFmNode(), { user: "user", key: "sessionkey" });\n    assert.equal("user", session.user);\n    assert.equal("sessionkey", session.key);\n  });\n\n  it("is authorised when it has a key", function() {\n    var session = new LastFmSession(new LastFmNode(), { user: "user", key: "sessionkey" });\n    assert.ok(session.isAuthorised());\n  });\n})();\n    that.error = error;    \n  });\n\n  context.whenReceiving = function(returndata) {\n    that.returndata = returndata;\n    that.session.authorise(\'token\');\n  };\n\n  context.expectError = function(errorMessage) {\n    assert.ok(that.error);\n    assert.equal(errorMessage, that.error.message);\n    token = "";\n    returndata = null;\n    options = null;\n    request = new fakes.LastFmRequest();\n    lastfm = new LastFmNode();\n    gently = new Gently();\n    LastFmSession.prototype.scheduleCallback = emptyFn;\n  }\n\n  function expectError(message) {\n    gently.expect(session, "emit", function(event, error) {\n      assert.equal("error", event);\n      assert.equal(message, error.message);\n    });\n    doRequest();\n  }\n\n  function doRequest() {\n    if (readError) {\n      request.emit("error", readError);\n    }\n    else {\n      request.emit("success", returndata);\n    }\n  }\n\n  function doNotExpectError() {\n    doRequest();\n  }\n\n  function expectRetry(retry) {\n    gently.expect(session, "emit", function(event, details) {\n      assert.equal("retrying", event);\n      if (retry) {\n        assert.deepEqual(details, retry);\n      }\n    });\n    doRequest();\n  }\n\n\nntest.describe("a completed LastFmSession authorisation request")\nntest.before(function() {\n   setupLastFmSessionFixture(this);\n});\n\nntest.it("emits error when authorisation not successful", function() {\n  this.whenReceiving(FakeData.AuthorisationError);\n  this.expectError(\'Invalid method signature supplied\');\n});\n\nntest.it("emits error when receiving unexpected return data", function() {\n  this.whenReceiving(FakeData.SingleRecentTrack);\n  this.expectError(\'Unexpected error\');\n});\n\nntest.it("emits authorised when successful", function() {\n  this.whenReceiving(FakeData.SuccessfulAuthorisation);\n  assert.ok(this.authorisedSession);\n  assert.ok(!this.error);\n});\n\nntest.it("updates session key and user when successful", function() {\n  this.whenReceiving(FakeData.SuccessfulAuthorisation);\n  assert.equal(\'username\', this.session.user);\n  assert.equal(\'sessionkey\', this.session.key);\n});\n    gently.expect(lastfm, "request", function() {\n      return request;\n    });\n  }\n  \n  function andTokenIs(setToken) {\n    session = new LastFmSession(lastfm, { token: setToken });\n  }\n\n  assert.equal(\'Session is not authorised\', this.error.message);\n});\n\nntest.describe("an authorised session")\nntest.before(function() {\n  setupLastFmSessionFixture(this);\n        return request;\n    });\n    session = new LastFmSession(lastfm, { token: \'token\' });\n  });\n  \n  assert.ok(!this.error);\n});\n\nntest.describe("nowPlaying requests")\nntest.before(function() {\n  setupLastFmSessionFixture(this);\n  this.session.key = \'key\';\n});\n\nntest.it("sends a signed request", function() {\n  it("emits error when receiving unexpected return data", function() {\n    whenReadRequestReturns(FakeData.SingleRecentTrack);\n    andTokenIs("token");\n    expectError("Unexpected error");\n  });\n  \n  it("emits authorised when successful", function() {\n    whenReadRequestReturns(FakeData.SuccessfulAuthorisation);\n    andTokenIs("token");\n    expectAuthorisation();\n  });\n  \n  assert.equal(\'Run To Your Grave\', this.params.track);\n  assert.equal(\'key\', this.params.sk);\n});\n\n  it("will retry on service unavailable", function() {\n    whenReadRequestThrowsError(11, "Service temporarily unavailable.");\n    andTokenIs("token");\n    expectRetry();\n  });\n\n  it("can have the retry interval specified", function() {\n    whenReadRequestThrowsError(14, "This token has not been authorised");\n    andOptionsAre({ token: \'token\', retryInterval: 15000 });\n    LastFmSession.prototype.scheduleCallback = gently.expect(function(callback, delay) {\n      assert.equal(delay, 15000);\n    });\n    doRequest();\n  });\n\n  it("user defined retry interval in retry event", function() {\n    whenReadRequestThrowsError(14, "This token has not been authorised");\n    andOptionsAre({ token: \'token\', retryInterval: 15000 });\n    expectRetry({\n        error: 14,\n        message: "This token has not been authorised",\n        delay: 15000\n    });\n  });\n\n  it("can cancel retries", function() {\n    whenReadRequestThrowsError(14, "This token has not been authorised");\n    andTokenIs("token");\n    session.cancel();\n    doNotExpectRetry();\n  });\n})();\n', 'message': 'Support for scrobbling added. \\o/\n', 'author_name': 'jammus', 'lang': 'js'}