Testing a REST API with Frisby.js

When our web app depends on pulling data through a REST API, we need to test that the endpoints well. Thats where things become more complicated and tedious to do manually. Two great libraries, Jasmine.js and Frisby.js, can help us out here.

What is Frisby and how does it work?

We are software developers and we strive to write good code.  We try to ensure the quality of every line and workflow which in turn means testing.  Manual testing works to a point but without automated testing of REST APIs and Ajax endpoint regression testing becomes cumbersome.  Are you really going to test all the possibilities/permutations with Postman?  I didn’t think so.

Testing a REST API is not so different to testing modules, but to create “end-to-end” test cases we needed make real endpoints calls. A manual testing job quickly becomes a tedious task, so we need to find a way to make things automated.

Frisby is a REST testing framework built on node.js and jasmine, and makes testing API endpoints a very flexible and easy task.

As any normal npm package running in node, Frisby needs node.js installed first, after that you can install Frisby as a common package:

npm install -g frisby

By convention, the file name containing the Test Suite, should include the trailing word “_spec.js”, node.js runs in javascript so logically js is the extension.

In order to continue our intrduction we will study the roleAPI_spec.js, a test suite part of the package Users of Erdiko Framework:

var frisby = require('../node_modules/frisby/lib/frisby');

This is the “kickoff” for our test suite, we instance the library in a Frisby variable, it will be our object to along  the suite.

describe('Role api test suite', function() {
  var baseURL = 'http://docker.local:8088/ajax/users/roles/';
  /**---This case test the api response and check the result----*/

  frisby.create('Get all roles')
        .get(baseURL + 'roles')
        .expectStatus(200)
        .expectHeader('Content-Type', 'application/json')
        .afterJSON(function (response) {          
            expect(response.body.method).toBe('roles');
            expect(response.body.success).toBe(true);          
            expect(response.errors).toBe(false);
            expect(response.body.roles).toBeDefined();
        })     
        .toss()
});

All  Frisby test starts with frisby.create(‘A gently worded description of test’) and next we must specify the verb to make the call to our endpoint. It is obvious but must match with the endpoint structure.

In our case we used .get(baseURL + ‘roles’)

Differences between using post or get.

There are differences between verbs post and get. When we create post test cases, we should pass objects as arguments, let’s see an example grabbed from userAPI_spec.js from Users package of Erdiko framework:

/*---------------------------------------------------------*/
/*-----------------Create User success --------------------*/
frisby.create('Creation will success.')
 .post(baseURL + 'register',
 {"name":"NameTest",
  "email":"test@email.com",
  "password":"secret"},
 { json: true },
 post_header)
 .expectStatus(200)
 .toss()

By default, Frisby sends POST and PUT requests as application/x-www-form-urlencoded parameters. If we want to send a raw request content, we must use { json: true } as the third argument to the .post().

Using Expectations.

/**--checking creation with expectations --*/
frisby.create('Checking user created exist.')
    .get(baseURL + 'retrieve?id=' + USER_ID)
    .expectStatus(200)
    .afterJSON(function (response) {
        expect(response.body.method).toBe('retrieve');
        expect(response.body.success).toBe(true);
        expect(response.body.user.id).toBe(response.body.user.id);
        expect(response.body.user.email).toBe(newUser.email);
        expect(response.body.user.name).toBe(newUser.name);
        expect(response.body.user.role.id).toBe(newUser.role);
    })
   .toss()

In comparison with our traditional phpunit, the framework to create unit test cases in php, we could say that phpunit Asserts are analog to Frisby Expectations. In particular, we are interested by that expectations to handle json code. Because that we are use the ‘expect’ clause that compare the API response with a parameter provided by us:

expect(response.body.method).toBe('retrieve')

Here we expect that ‘response.body.method’ be equals to the string ‘retrieve’. It’s important to mention that the comparison is by type and value at same time and both should match to result ‘true’.

After explain that we have a few expectations used:

  • expectJSON( [path], json )
  • expectJSONTypes( [path], json )

Managing Headers, afterJSON()

/**-----------delete user created ----------------*/
frisby.create('removing user created.')
    .get(baseURL + 'cancel?id=' + USER_ID)
    .expectStatus(200)
    .afterJSON(function (response) {
        expect(response.body.method).toBe('cancel');
        expect(response.body.success).toBe(true);
        expect(response.body.user.id).toBe(USER_ID);
    })
   .toss()

As we said previously, Frisby is an extension of Jasmine.node, and afterJSON is a very good evidence because afterJSON is the extension of after() with the convenience of parse the body obtained as response as JSON values automatically. The ‘after’ occurs immediately after the response is sent from the endpoint call and is used as a callback.

Using inspectors, inspectJSON()

Inspector helpers are useful for viewing details about the HTTP response when the test does not pass, or has trouble for some reason. They are also useful for debugging the API itself as a more user-friendly alternative to curl.

// Console output
{ url: 'http://theurl/get?foo=bar',
    headers:
    { 'Content-Length': '',
        'X-Forwarded-Port': '80',
        Connection: 'keep-alive',
        Host: 'httphost.org',
        Cookie: '',
        'Content-Type': 'application/json' },
    args: { foo: 'bar'},
    origin: '127.0.0.1' }

Basically inspectJSON() prints the raw HTTP response, other similar and general inspectors are:

  • inspectBody()
  • inspectHeaders()
  • InspectRequest()
  • InspectStatus()

Conclusion

Frisby makes it possible to write end-to-end tests with a lot of flexible tools and the process of test a complete REST API turns fun and easy. We miss the ability to ‘serialize’ test cases as in a regular test unit framework. Given the nature of javascript its possible to chain nested test cases and mimic, in some aspect, that behaviors.

We haven’t tried Newman yet, but hope to soon.  Let us know about your Frisby (and Newman) experiences.

End to End testing your Vanilla JS App with Protractor

ProtractorJS is a robust and easy to use e2e test framework specifically designed for testing AngularJS applications. With some simple edits and a slight change in thinking, you can also use it to test your non-angular web apps and provide some sanity to your testing strategy across projects.

ProtactorJS is an end to end test framework from Google used to test AngularJS Apps. While similar to existing tools like CasperJS, ProtractorJS is specifically designed for use with AngularJS.
With minimal effort you can use Protractor with your Vanilla JS web app as well. Why would you do this?
For one, using the same test framework for all you apps provides some sanity to writing tests for all of your projects. And you can’t honestly tell me you have all your apps converted to AngularJS already.
Second, it’s gaining popularity and for good reason. It’s a solid testing framework and is relatively easy to set up. Also, it has the backing of a very well known company (cough cough, Google) so it will be around for a long time.
Finally, it’s use of Jasmine and suite structures allow you to write some flexible tests. Encapsulate your logic, group stuff in ways that make sense. No more fragile tests!
Enough stumping, let’s get to the parts you actually care about.

Installation and Set Up

While I’ll point you at the official docs for installation instructions, I’ll provide the basic elements required to installing and running your Protractor tests:
  1. Protractor, Karma & Jasmine
    • Clearly, you need to install Protractor
    • Protractor uses Karma to connect to Selenium
    • Jasmine is used as the testing syntax.
      • You can use other frameworks, but my preference is Jasmine.
  2. Selenium Server & Webdriver
    • Protractor interacts with your tests using Seleniums Server and Webdriver. You can run Selenium locally or use a hosted service like Sauce Labs.
    • Local installation and setup is turn key simple using NPM.
  3. A Web server
    • Since your tests use a real browser to execute, you need a host of some kind.
    • It’s entirely possible to run your tests against an external server (like your staging server), but in practice I like to serve locally. In our example I used the local-web-server NPM package.

Protractor Test Concepts

Again, I’ll point you to the main documentation for longer descriptions of the concepts, I wanted to point out some that need to be discussed when prepping your protractor tests for execution on your VanillaJS app.

Config File

A config file sets up some required variables and tells Protractor how to run its tests. This includes a directory where your tests are held, the testing framework you use to write your tests and the address to the selenium server instance you use to run Karma.

Spec File (Test Suite) – “Describe”

Test suites are groups of testing conditions that focus on a particular section or part of your application. Using Jasmine, these are structure with the “describe” function and a brief string indicating the portion of the application under test.

Test Hooks

Hooks are small functions that are called during test executions. An example is the beforeEach hook we use to set up our tests for use with non-angular code. See the note below on exactly what goes in this hook.

Test Blocks – “It”

Test blocks are identified by an “it” phrase that describes in simple terms what you expect to happen. This is useful for turning user stories into tests like “User Registration Form should validate user input”.
These test blocks do have some minimal setup but are mostly for performing actions and asserting values. Check out our example code to see some of this in action.

Page Objects

Page Objects are similar to test fixtures in other testing frameworks, but thats underselling the usefulness of this concept. Page Objects are small JS objects where you can encapsulate and abstract out common page elements and share between your tests.
Use these to abstract out some commonly tested things, like getting the text or value from a page element. If you use your page object in all your tests, you only have one place to update when a change is made (instead of having to update ALL your test suites).

Running Protractor on your Vanilla JS App

Like we noted above, Protractor was designed for testing AngularJS apps by default. A large difficulty in e2e web app testing is knowing when something has rendered on the page and is ready to have some interaction. AngularJS abstracts how you work with the DOM in JS as well as having some control over how something is determined to be “ready” using Zones.js.
Three major things need to be done to make sure your Protractor test will actually work with out Angular:
  • Expose the web driver in a way you can access the DOM for interaction.
    • Due to the nature of how Angular abstracts the DOM and how it takes over all the app’s event cycles. We need to expose the Selenium Web Driver in a way you won’t hate.
    • Add this line to your onPrepare hook in the config file to assign the web driver to an global variable called “dv”
      • global.dv = browser.driver;
  • Tell the test not to wait for Angular to give the “go ahead, I’m ready” signal.
    • Protractor uses Angular to tell it when the page under test is ready to be tested. We need to skip this in order to test our non-angular app.
    • Add this to each test suite’s beforeEach hook to make sure the test knows to run as we expect
      • dv.ignoreSynchronization = true;
  • Start thinking about your tests with Promises
    • While I’m sure most of us at this point have seen and used Promise style functions. When testing an Angular app, using the default locators is easy. Since we are testing our app using the native web driver, we need to use a promise to allow Selenium to return the DOM element itself. Really though, it’s not that tough.
    • Here is an example where we want to assert the value of an element with the css ID of “foo” using a series of chained promises.
expect(dv.findElement(by.id('foo')).getText()).toEqual(“Bar”);

Plugin – Protractor Utils

Protractor does indeed have a very basic plugin system that gives end users some ways to extend base functionality. I’m still trying to understand this system myself (I haven’t figured out how to use a plugin that isn’t globally installed) I have found one that is very useful called jasmine2-protractor-utils.
I’ll leave some of the longer explanation of this plugin to the author, but my favorite feature is the ability to take a screenshot of the browser in the test on suite or block failure. Once you get things up and running so your tests are running automatically, having some visual artifacts of a failed test will help you replicate and diagnose what and how things went wrong.

Example – Movie Vote

Here is an example (very small) Web App demonstrating a very basic suite of Protractor tests. You can simply clone this repo, install the required packages using the package.json file and run these tests. Simply follow the instructions in the README.md file.
https://github.com/arroyolabs-blog/movie-vote-protractor
For an example of an intentionally failing test, check out the `mv-home-fail.spec.js` test in the tests directory.

Unit testing your Javascipt with Jasmine, KarmaJS & Travis CI

Unit testing is an important part of any software project but until recently it was difficult to test your front-end javascript and oft neglected by developers. Using Jasmine, Karma and TravisCI we will show you how to painlessly automate your JS testing.

Javascript is used on over 93% of websites today and used to do all sorts of front end magic. Most likely, your interactions with the web are provided via Javascript.

With any luck you have moved beyond the anti-patterns of yore and you have abstracted your JS functionality into some coherent objects to maintain your sanity. Now it’s time to start testing these pieces of code.

Testing Tools

I explored javascript unit testing using three tools: Jasmine, Karma and TravisCI. Using all three in conjunction seems to get the best results for a larger team.

Jasmine

Jasmine is a very popular javascript unit testing framework, very similar to many other xUnit testing frameworks like phpUnit and jUnit. Many other testing tools like actually use the same syntax (if not use Jasmine outright) so this is a pretty good thing to learn about.

I should note, unlike many other xUnit frameworks, Jasmine is BDD or a Behavior Driven Development framework. This is a fancy way of saying you structure your test suites in a way where you test ‘behavior’ scenarios rather than simple methods and functions.

KarmaJS

Karma is a test runner that executes your unit tests in a ‘real browser’. In short, it runs your Jasmine tests in a real browser via websockets.

This means you can test using a headless browser like PhantomJS or a real browser like Chrome. This really becomes useful when you need to test in multiple browsers, but especially useful when you need to run your tests locally (via Chrome) or remotely on a CI (in our examples below we run the unit tests using Chromium. More on that later).

There’s a little setup involved with Karma, but not too much. Honestly, it took less time to get my Karma config created than it did to write my example unit tests.

Travis CI

Travis CI is a hosted continuous integration tool that will watch your repo and execute your tests on certain conditions like a push or a pull request. It is also is free for your open source, or at least your public, Git Hub repos. Best of all, you can also show a super cool ‘build status’ badges in your github readme page.

Travis CI: Using Chromium

Please note that if you run your KarmaJS tests locally using Chrome, you will need to make sure Travis CI knows to use the open source equivalent Chromium as it fit’s into its ‘free tier’ licensing scheme.

Below are the key things you need to set this up, all of this code can be found in our examples below:

.travis.yml config

We need to tell Travis to install the Chromium browser package when it creates the container. Add the noted entry (‘export CHROME_BIN=chromium-browser’) into the “before_install” section of your travis config.

...
before_install:
 - export CHROME_BIN=chromium-browser
...
karma.conf.js

Next we need to determine if our tests are executed by Travis, and if so, tell Travis to use Chromium (which is aliased to CHROME_BIN from our config above) when exec’ing our tests:

// Config values to allow TravisCI to run chrome in it's container
browsers: ['Chrome', 'ChromeCanary'],
   customLaunchers: {
   // tell TravisCI to use chromium when testing
   Chrome_travis_ci: {
      base: 'Chrome',
      flags: ['--no-sandbox']
   }
},

...

// Detect if this is TravisCI running the tests and tell it to use chromium
if(process.env.TRAVIS){
   config.browsers = ['Chrome_travis_ci'];
}

I think its easiest to look at config from our example code to see exactly where this is placed in your config: https://github.com/arroyolabs-blog/movie-vote/blob/master/karma.conf.js

Example Project: Movie Vote

I created a very basic ‘web app’ (this is a stretch) to learn more about using Jasmine/Karma/CI with javascript.

It’s a simple JS class where a user can up or downvote a movie. While it includes a very basic html page you can run in your browser to see the class in action, the real magic is in the testing.

Here is a link to the Travis CI page showing our passing tests: https://travis-ci.org/arroyolabs-blog/movie-vote

Example Project 2: ng2 3 page SPA

If you are using ng-cli, karma is already configured for you. Running it is super easy and the hardest part is finding a CI solution that works for you.

Check out our super simple example and review the Travis Config to see this in action: https://travis-ci.org/arroyolabs-blog/effective-funicular

Conclusion

Testing is a very important part of software development and can be fun and easy once you get things set up to run automatically. Hopefully after reading this post you will have a good idea of how to integrate unit testing into your JS projects.