Uncategorized
Testing web apps on Edge using CodedUI Marcel de Vries 14 Jan, 2017
import { dialogflow } from "actions-on-google"; const app = dialogflow(); app.intent('How are you intent', (conv) => { conv.add(`I'm fine`); });When a user speaks a phrase that is associated with the How are you intent in Dialogflow, our fulfillment will respond with I'm fine. We want to specify this behavior clearly in our unit test. To do this we create some helper functions: getResponseForIntentName and expectResponse. That allows us to specify a unit test that is easy to read:
describe('How are you intent', () => { it('should respond', async () => { const response = await getResponseForIntentName('How are you intent'); expectResponse("I'm fine", response); }); });To build these helpers we need know what a Dialogflow fulfillment request looks like. We can get an example request by having looking at the Diagnostic info in Dialogflow. Another option is to have our fulfillment log its request: console.log(conv.body);. [caption id="attachment_27130" align="aligncenter" width="480" class="center "]
{ queryResult: { intent: { displayName: 'How are you intent', }, }, }Only the displayName of the intent is required for the fulfillment to process its logic. We will create requests like this in the getResponseForIntentName helper. To be able to start the express server and make the request we will use supertest. Because we are using Typescript we get errors when we make typos and get auto completion while typing. The type definitions of the request and response payload are defined in the actions-on-google library. See GoogleCloudDialogflowV2WebhookRequest in the example below.
function getResponseForIntentName(name: string) { const request: GoogleCloudDialogflowV2WebhookRequest = { queryResult: { intent: { displayName: name, }, }, }; return supertest(createApp()) .post('/') .send(request); }Now we want to assert that the response is looking ok. Because we're only interested in the returned text we will use Jests toMatchObject to make an assertion on parts of the response. To make this work in Typescript we can use the Partial<...> type.
function expectResponse(responseText: string, actual: Response) { const conversationResponse: Partial = { richResponse: { items: [{ simpleResponse: { textToSpeech: responseText } }], }, }; const webhookResponse: GoogleCloudDialogflowV2WebhookResponse = { payload: { google: conversationResponse, }, }; expect(actual.status).toBe(200); expect(actual.body).toMatchObject(webhookResponse); }The testing helpers can be extended to support more advanced use cases. Dialogflow can parse parameters from the voice input and make them part of the request. To make this testable, you can extend the getResponseForIntentName helper. A response can store some state across interactions as well, this is called context. To test context you can extend the expectResponse helper. Check out examples with more advanced usecases here. What type of testing this is, depends on who you ask. You could call it unit testing because you get fast feedback and you can test all the branches in the logic. On the other hand you are not isolating a single unit with mocks and we start the whole server. Therefore you could call it integration testing or component testing. In reality it does not matter much, as long as it delivers value.