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

Introducing the BoxLang Spring Boot Starter: Dynamic JVM Templating for Spring

Introducing the BoxLang Spring Boot Starter: Dynamic JVM Templating for Spring

Spring Boot developers know the pain of evaluating view technologies. Thymeleaf is great — until you need more expressiveness. FreeMarker is powerful — until the syntax fights you. What if you could write templates in a dynamic JVM language that gives you the full power of the platform, feels natural, and requires zero setup to integrate?

Meet the BoxLang Spring Boot Starter.

Luis Majano
Luis Majano
March 13, 2026
Why Swiss Banks Are Modernizing CFML Platforms Without Rewrites

Why Swiss Banks Are Modernizing CFML Platforms Without Rewrites

The growing need to evolve legacy financial platforms safely

Many Swiss banks and financial institutions still operate important systems built on ColdFusion and CFML platforms.

These systems manage a wide range of functions, including:

  • internal banking workflows
  • reporting systems
  • client portals
  • data integration platforms
  • compliance and risk management tools

In many cases, thes...

Cristobal Escobar
Cristobal Escobar
March 13, 2026
Reactive vs Proactive ColdFusion Support: Why Waiting for an Outage Is the Most Expensive Strategy

Reactive vs Proactive ColdFusion Support: Why Waiting for an Outage Is the Most Expensive Strategy

Many ColdFusion environments operate in a reactive mode without realizing it.

Everything seems fine… until something breaks.

A server crashes.

Performance drops suddenly.

An integration stops working.

A security audit reveals missing patches.

At that point the response is urgent:

“Can someone help us fix this now?”

Emergency support is sometimes unavoidable. But when reactive intervention becomes the norm, it usually means something deep...

Cristobal Escobar
Cristobal Escobar
March 12, 2026