Skip to main content

Testing your Components


View full example on Github


As your Botonic project gets bigger, you must test every component of your bot to:

  • Avoid introducing breaking changes.
  • Decide whether the quality of the code is sufficient or not.
  • Find as many bugs as possible.

Botonic provides a way of testing your bot, based on JEST. You can execute your tests by running botonic test or npm run test. We suggest that you use npm run test for a better visualization.

Let's see how you can define your tests by looking at the childs example:

src/routes.js

import Hi from './actions/hi'
import Pizza from './actions/pizza'
import Sausage from './actions/sausage'
import Bacon from './actions/bacon'
import Pasta from './actions/pasta'
import Cheese from './actions/cheese'
import Tomato from './actions/tomato'

export const routes = [
{
path: 'hi',
text: /^hi$/i,
action: Hi,
childRoutes: [
{
path: 'pizza',
payload: /^pizza$/i,
action: Pizza,
childRoutes: [
{ path: 'sausage', payload: /^sausage$/i, action: Sausage },
{ path: 'bacon', payload: /^bacon$/i, action: Bacon },
],
},
{
path: 'pasta',
payload: /^pasta$/i,
action: Pasta,
childRoutes: [
{ path: 'cheese', payload: /^cheese$/i, action: Cheese },
{ path: 'tomato', payload: /^tomato$/i, action: Tomato },
],
},
],
},
]

More concretely, let's focus on testing whether when we pass a payload with the value "pizza", the Pizza action is rendered.

{
path: "hi", text: /^hi$/i, action: Hi,
childRoutes: [
{
path: "pizza", payload: /^pizza$/i, action: Pizza, // <-- input to test
childRoutes: [
{ path: "sausage", payload: /^sausage$/i, action: Sausage },
{ path: "bacon", payload: /^bacon$/i, action: Bacon },
],
},
],
}

You can see the Pizza action will only be rendered after receiving a payload matching the regular expression /^pizza$/i, with an empty session {} and coming from the hi path. This can be defined as follows:

import { BotonicInputTester } from '@botonic/react'
let i = new BotonicInputTester(App)
i.payload('pizza', {}, 'hi')

In this way, the purpose of representing an input can be achieved. Let's have a look now at how to represent an output action to be rendered.

src/actions/pizza.js

import React from 'react'
import { Text, Reply } from '@botonic/react'

export default class extends React.Component {
render() {
return (
<Text>
You chose Pizza! Choose one ingredient:
<Reply payload='sausage'>Sausage</Reply>
<Reply payload='bacon'>Bacon</Reply>
</Text>
)
}
}

Then, this component can be defined in the following way:

import { BotonicOutputTester } from '@botonic/react'
let o = new BotonicOutputTester(App)
o.text(
'You chose Pizza! Choose one ingredient:',
o.replies(
{ text: 'Sausage', payload: 'sausage' },
{ text: 'Bacon', payload: 'bacon' }
)
)

It's that simple! Now, alongside the methods expect and toBe of JEST, you can define the entire test like this:

tests/app.test.js

import { BotonicInputTester, BotonicOutputTester } from '@botonic/react'

import App from '../src/app'

let i = new BotonicInputTester(App)
let o = new BotonicOutputTester(App)

// Put a name to your test
test('TEST: pizza.js', async () => {
await expect(i.payload('pizza', {}, 'hi')) // Expected input
.resolves.toBe(
// Expected output
o.text(
'You chose Pizza! Choose one ingredient:',
o.replies(
{ text: 'Sausage', payload: 'sausage' },
{ text: 'Bacon', payload: 'bacon' }
)
)
)
})