Skip to content

Instantly share code, notes, and snippets.

@jonnyreeves
Created June 2, 2012 13:32
Show Gist options
  • Save jonnyreeves/2858452 to your computer and use it in GitHub Desktop.
Save jonnyreeves/2858452 to your computer and use it in GitHub Desktop.
Unit Testing Promises with Sinon.js
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link rel="stylesheet" href="http://code.jquery.com/qunit/git/qunit.css" type="text/css" media="screen" />
<!-- when.js Promises implementation -->
<script src="https://raw.github.com/cujojs/when/master/when.js"></script>
<!-- Unit testing and mocking framework -->
<script type="text/javascript" src="http://code.jquery.com/qunit/git/qunit.js"></script>
<script type="text/javascript" src="http://sinonjs.org/releases/sinon-1.3.4.js"></script>
<script type="text/javascript" src="http://sinonjs.org/releases/sinon-qunit-1.0.0.js"></script>
<!-- test suite -->
<script src="whenjs-examples.js"></script>
</head>
<body>
<h1 id="qunit-header">Unit Testing when.js Promises with QUnit and SinonJS</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture"></div>
</body>
</html>
function createClient() {
return {
// Classic async method which returns an un-resolved promise.
fetchAsync: function () {
var dfd = when.defer();
// This contrived example isn't the important bit, replace this
// with a jQuery.get call, or any other async action which yeilds
// a promise to the caller.
setTimeout(function () {
dfd.resolve("Response");
}, 1500);
return dfd.promise;
},
// Slightly different take, this time a Promise resolver is supplied
// to the method.
asyncInit: function (completionPromise) {
// Again, the implementation isn't important - but after an async
// delay this method will either resolve, or reject the supplied
// connection promise.
setTimeout(function () {
completionPromise.resolve("I'm done!");
}, 1500);
// Note the lack of return statement.
}
}
};
// QUnit's way of defining a TestSuite. The 'setup' method below will be
// invoked before each 'test' case.
module("when.js examples", {
// Setup is invoked before each test run.
setup: function () {
// Create a fresh test client instance to work with.
this.client = createClient();
}
});
test("Stub a promise to always return a resolved Promise", function () {
// Stub the promise so it returns a fully resolved promise.
var expectedResponse = "what we expect to get back... eventaully";
sinon.stub(this.client, 'fetchAsync').returns(when(expectedResponse));
// Call the method and run the assertion
this.client.fetchAsync().then(function (actualResponse) {
strictEqual(actualResponse, expectedResponse, "fetchAsync() returned a"
+ " resolved Promise with the expected response");
});
});
test("Stub a promise to always return a rejected Promise", function () {
// This time we make 'fetchAsync' return a rejected promise
var expectedError = new Error("KaBOOM!");
sinon.stub(this.client, 'fetchAsync').returns(when.reject(expectedError));
// Call the method and expect it to fail.
this.client.fetchAsync().otherwise(function (actualError) {
strictEqual(actualError, expectedError, "fetchAsync() returned a"
+ " rejected Promise with the expected error");
});
});
test("Stub a promise so the testcase has control over it", function () {
// Sometimes you want the testcase to hold onto the Promise so you can
// assert the state of other parts of the system while the Promise is
// still un-resolved. Start by creating a new Promise.
var fetchPromise = when.defer();
// Now stub fetchAsync so it returns this Promise.
sinon.stub(this.client, 'fetchAsync').returns(fetchPromise);
// Some example state, just to show we have control over the Promise.
var didWeResolveThePromiseYet = false;
// Call the method, but it won't have resolved yet...
this.client.fetchAsync().then(function () {
equal(didWeResolveThePromiseYet, true, "Test case dictated when the"
+ " Promise resolved");
});
// Ok, now let's flip that flag.
didWeResolveThePromiseYet = true;
// ... and resolve the promise.
fetchPromise.resolve("Go for it!");
});
test("Stub a method so it resolves the supplied promise", function () {
// Stub the asyncInit method so it calls the 'resolve' method of the
// supplied promise.
var expectedResult = "we get this back once asyncInit's done it's thing";
sinon.stub(this.client, 'asyncInit').yieldsTo("resolve", expectedResult);
// This is the promise we supply to asyncInit().
var initDeffered = when.defer();
// Attach our assertion to the completion handler.
initDeffered.promise.then(function (actualResult) {
strictEqual(actualResult, expectedResult, "asyncInit() resolves the"
+ " supplied Promise with the expected result");
});
// Invoke the client supplying the resolver
this.client.asyncInit(initDeffered.resolver);
});
test("Stub a method is it rejects the supplied promise", function () {
// This time asyncInit will always reject the supplied Promise.
var expectedError = new Error("Ain't gonna happen");
sinon.stub(this.client, 'asyncInit').yieldsTo("reject", expectedError);
// This is the deffered we supply to asyncInit().
var initDeffered = when.defer();
// Attach our assertion to the error handler.
initDeffered.promise.otherwise(function (actualError) {
strictEqual(actualError, expectedError, "asyncInit() rejects the"
+ " supplied Promise with the expected error");
});
// Invoke the client supplying the resolver.
this.client.asyncInit(initDeffered.resolver);
});
@muhammadghazali
Copy link

@jonnyreeves This gist really is helpful for me. I was struggled to unit testing the promises method until I found this gist. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment