Run your own Alexa Skill locally (and test it) [JS]
Tags: javascript, alexa, amazon, todayilearned
Published: 2020-12-05 18:05:31

So you had an Alexa device and you wanna make you own skill, here we will learn how we can make our custom skill and test it locally without depending [Aws Lambda](https://aws.amazon.com/fr/lambda/)


---


First step install the [ASK-CLI](https://www.npmjs.com/package/ask-cli)

```
npm install -g ask-cli
```

We will generate our skill starter with
```
ask new
```

Choose NodeJs, and self-hosted

![Ask new config](https://dev-to-uploads.s3.amazonaws.com/i/1v8itd991yfxyw99sqs5.PNG)

Next step we will add [Virtual-Alexa](https://www.npmjs.com/package/virtual-alexa) dependencies

```
npm install virtual-alexa --save-dev
```

Enter into the created folder and add a new node project with

```
npm init
```

Add this necessary dependencies

```
npm i ask-sdk-core ask-sdk-model
npm i virtual-alexa --save-dev
```

In your package.json file add this start script

```json
 "scripts": {
    "start": "node index.js"
  }
```

And for the last step create a new file called index.js and we will :

* Init an instance of Virtual alexa
* Handle our lamdba function to it and add our options like locales, interaction models, ...
* Start an intents 
* Print the result (alexa speech)

```javascript
const va = require("virtual-alexa");
const _defaultHandler = va.VirtualAlexa.Builder()
  .handler("./lambda/index.js") // Lambda file
  .interactionModelFile("./skill-package/interactionModels/custom/en-US.json") // Interaction file
  .locale("en-US")
  .create();


_defaultHandler.intend("HelloWorldIntent").then((payload) => {
// Print speech to console
  console.log("OutputSpeech: " + payload.response.outputSpeech.ssml);
});

```

Run with 
```
npm run start
```

If everything is ok you should be able to read the alexa's output speech in your console

![Like this](https://dev-to-uploads.s3.amazonaws.com/i/xv2f4prtcy37jjq1b5db.PNG)

And that it, now you can develop your skill and test the output without send your code.

 ![Nice !](https://dev-to-uploads.s3.amazonaws.com/i/j9yyiteb2gmfre9b5d6r.gif)


---
So if we recap, we used the 'hello-world' starter generated by ASK-CLI, we added a node application next to it using the 'virtual-alexa' dependency

As long as we are there we can take the opportunity to add tests, no? 

I promise it will take a minute.

---

We begin with dev dependencies, so wo can add [mocha](https://www.npmjs.com/package/mocha), [chai](https://www.npmjs.com/package/chai) and [nyc](https://www.npmjs.com/package/nyc)

```
npm i mocha chai nyc --save-dev
```

Create a test folder, and a new "index-test.js" file, in your package.json add this test script :

```
"test": "nyc mocha test/*-test.js"
```

----

So now we can add the usual structure of a test file into 'index-test.js'.

```javascript
const expect = require("chai").expect;
const VirtualAlexa = require("virtual-alexa").VirtualAlexa;

describe("Test hello world intent", async function() {
  const alexa = VirtualAlexa.Builder()
    .handler("./lambda/index.js") // Lambda function file and name
    .interactionModelFile("./skill-package/interactionModels/custom/en-US.json") // Path to interaction model file
    .create();

  it("Should be Hello World!", async function() {
    const helloWorldResponse = await alexa.intend("HelloWorldIntent");
    expect(helloWorldResponse.response.outputSpeech.ssml).to.include(
      "Hello World!"
    );
  });
});
```

run with 
```
npm run test
```

If everything is ok you should be able to see our test result

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pe7dmaic9lxr7zmcsqpe.PNG)

And that's it ! Now you can write your skill logic, run and test it.

![Here we go](https://dev-to-uploads.s3.amazonaws.com/i/pz004quoeiph8lstyhyi.gif)

---

You can also take a look to [Ask Toolkit for vscode](https://github.com/alexa/ask-toolkit-for-vscode)

See also : [Secure the endpoint of my Skills Alexa application](https://developer.amazon.com/en-US/docs/alexa/custom-skills/security-testing-for-an-alexa-skill.html) (futur post?)