Blog

REST 2016 - Testing your API with Jasmine

Gavin Pickin March 25, 2016

Spread the word

Gavin Pickin

March 25, 2016

Spread the word


Share your thoughts

Are you writing APIs? Going to start writing APIs? Now is the time to start testing. Sounds familiar, it should, because you’ll be hearing that a LOT. Do it early, and often, and reap the benefits as the project grows. Whether you are using CFML or not, TestBox is a great way to test your APIs, like I showed you in a previous blog post ( Testing your API with TestBox ). Today, we’ll look at Jasmine, and see how you can test your APIs with Javascript… and a couple of “gotchas” I ran into as well.

One great thing about TextBox and Jasmine, is they use almost identical syntax, so a lot of your tests are essentially interchangeable. Thank you smart people at Ortus for studying other languages and standards, it helps.

I’ll assume you have got Jasmine installed and setup. There is a lot of good information on that, but if you are attending dev.Objective() in Bloomington MN this year, I am presenting on “How to write Testable Javascript” where I go into other Javascript Testing tools, and installing Jasmine.

In this tests, we’re firing the login button event handler, which hits an API with some data, and returns a result to the processLoginAjaxDone() function. If the API fails, it calls processLoginAjaxFail().

The first attempt at writing this test looks like this

describe("Login API", function() {
   it("should return a failing Ajax Response", function() {
       spyOn( window, "processLoginAjaxDone");
       spyOn( window, "processLoginAjaxFail");
       loginButtonEventHandlerProcess( 'gavin@gavin.co.nz', 'password');
       expect(processLoginAjaxDone).toHaveBeenCalled();
       expect(processLoginAjaxDone).toHaveBeenCalledWith( ‘{"RESULT":400}' );
       expect(processLoginAjaxFail).not.toHaveBeenCalled();
   });
});

 

Looking at this, we’re spying on the functions we’re expecting to be called.
Lets run this… and we’ll get an unexpected result… why?

loginButtonEventHandlerProcess( 'gavin@gavin.co.nz', 'password');

This line makes an ajax call, which is async, so the tests keep running, without waiting for the response from that ajax call. So our tests run fast, but this is not what we want in our full API test. This is not a Unit Test, it’s an integration test.

How does Jasmine help with Async tests?

Jasmine allows you a neat function on a spy, called ‘callFake()’. In your beforeEach, you can setup the functions to spyOn, but you can also add a callFake, which when that function is called, it also calls this new function. This allows you to inject a call into the end of the function, and in that, you can tell Jasmine the test is done, by calling done().

Note: This was not easy to figure out, there is a lot of documentation, but not too many people spelled it out like this. This is why I present on it, and this is why I’m sharing this blog post with you today.

Below is what it looks like. Inside the beforeEach, which accepts a function with the done object (this is what tells Jasmine its async), and then you setup your spies, with the callFake(), both spies waiting for a response, before calling done() so Jasmine knows the test is ready, and can process to the ‘it’ block. The last item in the beforeEach is the actual call you’re testing.

describe("Login API", function() {
   beforeEach(function( done ) {
       spyOn( window, "processLoginAjaxDone").and.callFake(
           function(){ done(); });
       spyOn( window, "processLoginAjaxFail").and.callFake(
           function(){ done(); });
       loginButtonEventHandlerProcess('gavin@gavin.co.nz', 'password');
   });
   it("should return a failing Ajax Response", function() {
       expect(processLoginAjaxDone).toHaveBeenCalled();
       expect(processLoginAjaxDone).toHaveBeenCalledWith('{"RESULT":400}');
       expect(processLoginAjaxFail).not.toHaveBeenCalled();
   });
});

 

So jasmine sets up the spies, calls your function, when the ajax async call returns, it calls one of the two functions you are spying on, when they are called, they also call done() and then the tests in the it block are run.

This solves the async problem, and when you know how to do it, its simple.
So now, there is no excuse.

Get out there, and start testing your API… on the client, with Jasmine, and on the server, with TestBox

Add Your Comment

Recent Entries

Into the Box Round 1 of Sessions and Workshops are now out!

Into the Box Round 1 of Sessions and Workshops are now out!

Our first round of sessions and workshops for Into the Box 2025 is here! Get ready to dive into a world of modern web development with hands-on workshops and engaging sessions led by Ortus Solutions and Community CFML and BoxLang experts. Visit intothebox.org to explore what’s in store—this is just the beginning, with much more content coming soon!

Maria Jose Herrera
Maria Jose Herrera
January 20, 2025
BoxLang 1.0.0 Beta 26 Launched

BoxLang 1.0.0 Beta 26 Launched

We’re thrilled to announce the release of BoxLang 1.0.0 Beta 26, a monumental update that takes performance and functionality to the next level. This beta officially certifies the ColdBox HMVC Framework to run on BoxLang, marking a significant milestone in compatibility. Not only can you now run all ColdBox applications seamlessly on BoxLang, but with the latest ColdBox snapshot, you can also build your entire applications in BoxLang, unlocking the full potential of this dynamic and expressive language for modern application development.

Luis Majano
Luis Majano
January 20, 2025