npm i snips-toolkitThen use it in your package.json file scripts.
"scripts": {
"build": "snips-toolkit build",
"dev": "snips-toolkit dev",
"test": "snips-toolkit test '^.*\\.spec\\.[jt]s$'",
"launch": "snips-toolkit run"
}Assumes that your action is structured in the following way by default:
.
├── src # sources folder| └── index.[jt]s # the action code entry point|
├── dist # the action build output folder|
├── tests # tests folder| └── *.spec.[tj]s # any number of test files|
├── package.json # with an extra "sandbox" key, highlighted lower in the documentation|
├── config.ini # action configuration file|
└── assets
└── i18n # internationalization folder
└── <locale>.json # translation file for a given languageDisplays a help message and exits.
Builds your action to ./dist/index.js using webpack.
This command will warn if your action code uses node.js native modules, and they will be automatically added to your package.json file under the sandbox key.
// Example:"sandbox": [
"fs",
"http",
"https",
"os",
"path",
"stream",
"tty",
"url",
"util",
"zlib"
]Automatically rebuilds and run the Snips action on file change.
You can debug the action by connecting a debugger to the 9229 port. Check the node.js website for more details.
Use the -c/--config-path if you need to use custom hermes options.
Use the -ns/--no-sandbox to disable the sandbox.
Runs your test suite with jest.
Use the -s/--sandbox flag to run the tests in a sandboxed environment.
Runs your Snips action.
Use the -c/--config-path if you need to use custom hermes options.
Use the -ns/--no-sandbox to disable the sandbox.
Initialize once by calling .init, then use .get to retrieve the configuration.
// Reads the configuration file located at `./config.ini`.config.init()// Get the configuration.constconfiguration=config.get()Depends on node.js modules fs, path.
Initialize once by calling .init.
Uses the i18next library under the hood.
// Reads the `./assets/i18n/en.json` translation file and initializes an i18next instance.awaiti18n.init('en')// Get a translation. (see https://www.i18next.com/overview/api#t)consttranslation=i18n.translate(keys,options)// Get the translation for an error message.// Assumes that the translation file contains the key 'error.<error message>'.consterrorTranslation=awaiti18n.errorMessage(error)// Get a random translation for a given key.// Assumes that the translation file maps an array of possible translations to the key.consttranslation=i18n.randomTranslation(keys,options)Depends on node.js modules fs, path.
An http client using wretch.
constpokeapi=http('https://pokeapi.co/api/v2')constbulbasaur=awaitpokeapi.url('/pokemon/1').get().json()Depends on node.js modules http, https, stream, zlib, url.
A logger using debug.
// Enables error printing. You can use * as a wildcard.logger.enable('error')// Logs to <actionName>:errorlogger.debug('error')// Logs to <actionName>:infologger.info('info')// Logs to <actionName>:debuglogger.error('debug')Depends on node.js modules tty, util, os.
Utilities for handling hermes callbacks.
// Wrap a dialogue handler to gracefully capture and log errors.handler.wrap((msg,flow)=>{// ... //})Depends on internal modules i18n, logger.
Utilities for parsing hermes messages.
// Get slots matching the slot name.constmySlot=message.getSlotsByName(// The message instancemsg,// The slot name'mySlotName',{// If true, returns only the slot with the highest confidence.onlyMostConfident: true,// If specified, returns only slots having a confidence higher than this threshold.threshold: 0.5})// Calculates the ASR confidence.constconfidence=message.getAsrConfidence(msg)Camelcase utilities using the camelcase package.
// Camelize a stringconstcamelizedKey=camelize(key)// Returns a cloned object having camelized keys.constcamelizedObject=camelizeKeys(object)In order to pass custom hermes options, you can use the -c flag to specify the path to a configuration file.
For instance, if you are using an mqtt broker running on a different machine, you could add options in a file named hermes_config.json.
{
"address": "ip:port"
}And add the -c flag in the package.json file.
"scripts": {
"dev": "snips-toolkit dev -c ./hermes_config.json",
"launch": "snips-toolkit run -c ./hermes_config.json"
}During unit tests, your action code is run is parallel with the tests and i18n/http utils are mocked.
You can use the provided SnipsToolkit.mock.http global function to override http calls automatically during tests.
// Place this code in the root of the test file to mock.SnipsToolkit.mock.http(fetchMock=>{// Define as many mocks as you need.// See http://www.wheresrhys.co.uk/fetch-mock for API detailsfetchMock.mock('https://my.super.api/route',{hello: "world"})})The i18n.translate output is not the translation but a stringified JSON reprensentation of the key/options.
This call:
// This call:i18n.translate('pokemon.info',{name: 'Pikachu',weight: 10,height: 20})Returns when mocked: (in stringified form)
{
"key": "pokemon.info",
"options": {
"name": "Pikachu",
"weight": 10,
"height": 20
}
}You can use the provided SnipsToolkit.mock.globals global function to override or define global variables.
SnipsToolkit.mock.globals(globals=>{// Mocks the Date object in a crude way.constBackupedDate=global.DateconstfreezedTime=1550835788763constmockedDate=functionDate(arg: string|number|Date){returnnewBackupedDate(arg||freezedTime)}mockedDate.now=()=>freezedTimemockedDate.parse=BackupedDate.parsemockedDate.UTC=BackupedDate.UTC// Assign the mocked Date to the globals objectglobals.Date=mockedDate})To simulate dialogue session rounds, you can use the Session helper that will pass hermes messages between your test and action code.
import{Test}from'snips-toolkit'/* ... */// Initialize a session instanceconstsession=newTest.Session()// Publish an intent message that is expected by the action code to start a sessionawaitsession.start({intentName: 'pokemon_details',input: 'Give me the details for Pokemon 1',slots: [// Function that creates a custom slot, omitted for the sake of brevity.createPokemonIdSlot('1')]})// Expect the action code to publish a continue session message// and reply with the following intent message (here we simulate a confirmation message)constcontinuation=awaitsession.continue({intentName: 'pokemon_confirm',input: 'Yes please'})// Expect the action to end the session and retrieve the end session message valueconstendSessionMessage=awaitsession.end()// Extract the key/options of the TTS spoken by the end session messageconst{ key, options }=JSON.parse(endSessionMessage.text||'')// Assert that the values are correctexpect(key).toBe('pokemon.info')expect(options.name).toBe('bulbasaur')expect(options.weight).toBe(69)expect(options.height).toBe(7)