Unit testing an Amazon Alexa skill with Node.js and Jasmine.

Intro

I recently launched my first Amazon Alexa skill Chef Basil. I spent hours verbally trying different phrases on my Amazon Echo and even after launch, wasn’t sure the code had been 100% tested. Did I really test what happens when the API times out? Or when an intent passes a slot that I wasn’t expecting?

I decided it was time to write some unit tests.

As a web developer my go to tools are Javascript, Node.js, and Jasmine. I was excited to use my favorite technologies to build and test my skill. While writing my first test, I realized some basic infrastructure would need to be built that is unique to an Alexa skill.

You can follow along and download the code from this article here.

By the end of this article we will have gone over:

  1. How to write a unit test around an Amazon Alexa skill intent.
  2. Mocking requests and responses.
  3. Testing if SSML responses are valid.

Setup

We will be using the node module jasmine-node for testing. It can be downloaded using NPM:

npm install jasmine-node -g

I used the Hello World code example from Amazon. Once you have downloaded the code, expose the HelloWorld intent located in src/index.js so it can be unit tested. For any intent or method to be testable, you need to be able to require it in your test file.

module.exports.HelloWorld = HelloWorld;

The file structure stays the same, except we added a new directory where the tests go.

- src
- spec
- json
- src

Mocking Requests and Responses

When the user invokes your skill, a request is routed to your intent function with intent, session, and response variables.

The intent and session are JSON objects, that we can mock in the JSON folder.

intent = { “slots”: {} }
session = { “attributes”: {} }

The response is a Javascript object used to tell the Alexa what speech to say to the user. We will create a spy around the response to verify that our intents pass the correct parameters to it.

response = jasmine.createSpyObj(
‘response’, [ ‘tell’, ‘tellWithCard’, ‘ask’, ‘askWithCard’ ]
);

Validating SSML

Speech synthesis markup language (SSML) is used to express speech as text. One of my pet peeves with testing a skill is that even though your code works flawlessly, if you mess up the SSML, Alexa silently shuts down with no errors. Forgetting to close a tag can change your hot new skill to a hot mess.

In order to make this issue more manageable I created an SSML validator that is added as a Jasmine custom matcher. Currently it validates for:

beforeEach(function() {
this.addMatchers({
isSSML: function(expected) {
return validator.test(this.actual, expected);
}
});
});

Tests

Great, we have some components to help with validating an intent. Let’s look at an actual unit test and see how it all comes together.

In the test we call the HelloWorldIntent that we previously exposed and pass in the mock parameters. Since the response is a spy, we verify that the correct response function is called. We also check that the speech is valid SSML with the custom matcher.

All you have left to do is run the test and watch the assertions pass!

jasmine-node spec/

Conclusion

At this point you should have discovered how to make your Alexa skill more maintainable with unit tests. Now go forth and write some tests around your awesome skills.

The code in this article is only meant to be a prototype of how a larger framework could be constructed for testing an Alexa skill. Every part of the code could be expanded upon to be more robust and useful. For instance there should be a card matcher, more JSON session examples, and unit tests around the validators.

I am very excited about the direction the open source project alexa-app is heading in. They are working on abstracting a lot of the Alexa code so it feels more like working with an Express app. Future testing components should be built independently of the alexa-app, but easily able to integrate with similar modules. This is an exciting time for the Javascript community with a lot of work ahead of us to make the Alexa code base more robust and maintainable.

Download the code from this article here.