I'm developing an Alexa skill in node and I'd like to know how I can unit test my code. I'm using the alexa sdk that Amazon released.
I've found many libraries to accomplish this, but they seem to be developed before the alexa sdk was available.
Thanks in advance.
We built our Alexa emulator specifically for the purpose of allowing easy unit-testing and functional-testing of Alexa skills:
http://docs.bespoken.tools/en/latest/tutorials/tutorial_bst_emulator_nodejs/
With it, you can make calls like this:
alexa.launched(function (error, response) {
alexa.spoken('About the podcast', function (error, response) {
assert.equal(response.response.outputSpeech.ssml, '<speak> Some SSML </speak>');
done();
});
});
This test code imitates a user launching the skill and saying "About the Podcast". These interactions are automatically translated to the correct Alexa JSON requests, which in turn are then sent to your skill code.
You can also create more sophisticated unit-tests that rely on mimicking the internal state of Alexa device across interactions. These are described in the tutorial.
I am using alexa-skill-test-framework with mocha for generating the alexa intent json. Can setup AWS services in local PC using localstack, which supports DynamoDB, SQS, Lambda and other services
lex-bot-tester is a framework and tool to create conversational tests for Amazon Alexa and Lex.
Instead of using a simulated version of the Skill it uses the existing SMAPI to deal with Alexa.
The tests can be created manually or automatically generated by a tool included, named urutu. Right now, the code generation is python but the Skill implementation can be in any supported language.
After you interact with the Skill from the command line, defining the conversation, the generated code looks like this
#! /usr/bin/env python
import sys
import unittest
from lex_bot_tester.aws.alexa.alexaskilltest import AlexaSkillTest
verbose = True
class GeneratedTests(AlexaSkillTest):
def test_book_my_trip_reserve_car(self):
"""
Test generated by urutu on 2018-02-21 01:24:51
"""
skill_name = 'BookMyTripSkill'
intent = 'BookCar'
conversation = [{'slot': None, 'text': 'ask book my trip to reserve a car', 'prompt': None},
{'slot': 'CarType', 'text': 'midsize',
'prompt': 'What type of car would you like to rent, Our most popular options are economy, midsize, and luxury'},
{'slot': 'PickUpCity', 'text': 'vancouver',
'prompt': 'In what city do you need to rent a car?'},
{'slot': 'PickUpDate', 'text': 'tomorrow',
'prompt': 'What day do you want to start your rental?'},
{'slot': 'ReturnDate', 'text': 'next week',
'prompt': 'What day do you want to return the car?'},
{'slot': 'DriverAge', 'text': '25', 'prompt': 'How old is the driver for this rental?'}]
simulation_result = self.conversation_text(skill_name, intent, conversation, verbose=verbose)
self.assertSimulationResultIsCorrect(simulation_result, verbose=verbose)
if __name__ == '__main__':
unittest.main()
There is a more detailed explanation and some videos at Testing Alexa Skills — Autogenerated tests.
We are using MochaJs with ChaiJs for testing our Alexa skill in nodeJs
We followed this tutorial to build our environment.
We added dev dependencies in the package.json
"devDependencies": {
"aws-lambda-mock-context": "^3.1.1",
"chai": "^4.1.2",
"chai-as-promised": "^7.1.1",
"mocha": "^5.0.4"
}
And we have a test folder with couple of testing requests from Alexa Developer Console that we run our unit tests against.
our testing test/index.html
var Alexa = require('alexa-sdk');
const handlers = {
'LaunchRequest': require('launchRequest')
//other handlers
};
exports.handler = function(event, context, callback) {
const alexa = Alexa.handler(event, context, callback);
alexa.registerHandlers(handlers);
alexa.execute();
};
To run the test, you just run this cmd
$ mocha
For Java, I created a unit test for my skill this way.
class GetMyRequestHandlerTest {
RequestHandler requestHandler = new GetMyRequestHandler();
#Test
void canHandle(){
HandlerInput input = CreateSampleInput();
boolean result = requestHandler.canHandle(input);
assertTrue(result);
}
#Test
void handle() {
HandlerInput input = CreateSampleInput();
Optional<Response> response = requestHandler.handle(input);
assertFalse(response.equals(null));
}
private HandlerInput CreateSampleInput()
{
HandlerInput.Builder handlerInputBuilder = HandlerInput.builder();
Intent intent = Intent.builder().withName(Constants.GetMyIntent)
.putSlotsItem(Constants.SlotNumber, Slot.builder().withName(Constants.SlotNumber).withValue("4").build())
.build();
Request request = IntentRequest.builder().withIntent(intent).build();
Session session = Session.builder().putAttributesItem(Attributes.STATE_KEY, Attributes.STATE_NUMBER).build();
RequestEnvelope requestEnvelope = RequestEnvelope.builder().withRequest(request)
.withSession(session)
.build();
HandlerInput input = handlerInputBuilder.withRequestEnvelope(requestEnvelope)
.build();
return input;
}
Related
I have an iOS/wOS app that launched last year. Now I want to add complications to it and use the new way of doing complications with WidgetKit. I have everything in place up to the point where I'm supposed to read the data from Health to display it, where it fails with Missing com.apple.developer.healthkit entitlement.
This is the new extension I've added
It's embedded in the WatchKit app NOT in the WatchKit Extension and I've added permission to read health data directly in the info.plist for the extension
I pull the data from the TimelineProvider protocol method
func getTimeline(in context: Context, completion: #escaping (Timeline<Entry>) -> ()) {
let currentDate = Date()
var entries: [WorkoutEntry] = []
ComplicationHealthManager.loadPreviousWorkouts { workout in
let workoutEntry = WorkoutEntry(date: currentDate, workout: workout)
entries.append(workoutEntry)
let timeline = Timeline(entries: entries, policy: .after(currentDate))
completion(timeline)
}
}
with the help of a small manager class
class ComplicationHealthManager: ObservableObject {
static func loadPreviousWorkouts(completion: #escaping (HKWorkout?) -> Void) {
let healthStore: HKHealthStore = HKHealthStore()
let workoutPredicate = HKQuery.predicateForWorkouts(with: .traditionalStrengthTraining)
let compound = NSCompoundPredicate(andPredicateWithSubpredicates:
[workoutPredicate])
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate,
ascending: false)
let query = HKSampleQuery(
sampleType: .workoutType(),
predicate: compound,
limit: 0,
sortDescriptors: [sortDescriptor]) { (query, samples, error) in
guard
let samples = samples as? [HKWorkout],
error == nil
else {
completion(nil)
return
}
let calendar = Calendar.current
let todaysSamples = samples.filter{ calendar.isDateInToday($0.endDate) }.last
completion(todaysSamples)
}
healthStore.execute(query)
}
}
The issue is in the closure for the health query where it returns with no workouts but an error stating
Error Domain=com.apple.healthkit Code=4 "Missing com.apple.developer.healthkit entitlement." UserInfo={NSLocalizedDescription=Missing com.apple.developer.healthkit entitlement.}
The problem here is I don't understand where and how to add an entitlement for the complication extension or the WatchKit app, as none of them have the option for health. I have a health entitlements set for the iPhone app and the WatchKit Extension.
I found the problem to be that I had the old implementation of watchkit apps, with both a Watch app and a Watch extension. That was the problem. I went and used the migration from Xcode 14 to merge the Watch App and Extension into a new watch app and everything works now.
Please file a Feedback at feedback.apple.com for this.
You can manually add the HealthKit entitlement to the Code Signing Entitlements file (create a new one if there isn't one already) associated with the target
<key>com.apple.developer.healthkit</key>
<true/>
How does one E2E test OTP login?
I have set up an OTP login, I want to write a Cypress test for it where the user enters the OTP and gets it in email. How do I write a test for this, given that the OTP changes every time I send an email?
The current solutions I have are:
To create a test account and hardcode a static OTP for it on the server.
To create a mock API with static responses and use that for testing (currently I'm using the actual deployed API for testing)
If I'm understanding your requirement, you can use otplib to bypass the email reading/parsing stage and directly generate the token that would otherwise be sent to the user in an email.
The package cypress-otp is a thin wrapper around otplib, but unfortunately it's not up-to-date and is awfully noisy and hard to follow for such a simple task.
This is how I unraveled the code and updated for Cypress ver 10.10.0:
Install otplib
yarn add -D otplib or npm install otplib --save-dev
Add a task to call otplib from you test
This takes the place of reading a mail and parsing out the token, which you don't need to test because normally a user does that and enters the token into your app under test.
In cypress.config.js
const { defineConfig } = require("cypress");
const otplib = require("otplib");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('task', {
generateToken(secret) {
return otplib.authenticator.generate(secret);
}
})
},
},
});
Example test taken from cypress-otp (simplified)
describe('Example of generating a token for use in OTP tests', () => {
let secret; // in this example, secret is taken from the app page,
// but normally you will pass it in from a fixture
// or an environment variable
beforeEach(() => {
cy.visit('https://otplib.yeojz.dev'); // we use this page as a sample app
// Get the secret
cy.contains("Demo Secret")
.parent().parent()
.find('input').invoke('val')
.should('not.eq', 'Loading...') // simpler than waitUntil()
.then(value => secret = value)
})
it('tests the token entry', () => {
cy.task('generateToken', secret)
.then(token => {
cy.contains('Verify Token').click();
cy.contains('Please input a token')
.parent()
.find('input')
.type(token);
cy.contains('The token is valid in this current window')
.should('be.visible')
})
})
})
This test is the one given in cypress-otp, a simplified version of it which is more easily understood with moderate programming skills.
It's a bit contrived, because the app provides both the secret and the token, and then also verifies it.
The essential part is the cy.task('generateToken', secret) which makes receiving the token very easy.
If your application is sending OTP via emails then I have a solution for you.
Mailhog.
You can point the SMTP to mailhog and all the outbound emails will appear in Mailhog's management console. Something like this.
After that it's a piece of cake. You can access those email inside cypress tests using this plugin.
https://www.npmjs.com/package/cypress-mailhog
It's been two months but I hope this helps.
I'm working on an Alexa skill that sometimes takes a while to respond. Sometimes it is running scripts in the background, turning on a TV, connecting a bluetooth device, etc. etc. A successful response can take up to 20+ seconds once all the automation is completed.
On the web, when there is a long-running request, we are used to seeing a progress bar, or at least an animated spinner with a message telling to please wait, or that the processes is underway. I need something similar for Alexa.
I'd like Alexa to respond TWICE to a SINGLE intent, once before the HTTP request is fired, and one once the response has been received. A sample conversation would be:
[User] : Alexa, tell [app name] to switch to theater mode.
[Alexa] : (Immediately) I'm on it! Hang tight.
(...20 seconds later...)
[Alexa] : Done! Theater mode was successfully activated. Enjoy!
I've got some code running on lambda here: http://jsfiddle.net/9gmszmku/embedded/js/
Excerpt:
// ================
// [TODO] RESPONSE HERE: Alexa says: "I'm on it" or "hang on one second..." before getting the response from the http request
// ================
// this request may take many seconds!!!! Ain't nobody got time for staring at Echo for a response!!!
var req = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
var rawData = '';
res.on('data', (chunk) => rawData += chunk);
res.on('end', () => {
try {
var parsedData = JSON.parse(rawData);
console.log(parsedData);
context.succeed(generateResponse(buildSpeechletResponse(parsedData.message, true), {}));
} catch (e) {
context.succeed(generateResponse(buildSpeechletResponse("Error Parsing", true), {}));
}
});
Basically, I want to have Alexa respond upfront without closing the session, and again once the function is complete.
To the best of my knowledge, you can only have one speech output and I don't think you can inject any sort of wait up one sec logic into it. You could work around it by breaking the task up into smaller pieces, chaining them together and having Alexa notify the user at each stage?
Maybe you could play some music with the audioplayer interface while your task is working and/or you can inform the user about the long running task with a speech output.
Are there ANY code examples of how to use Google Cloud Print (using the new OAuth 2) and how when a document comes into the Google Cloud Print queue to automatically print it?
Pretty much what I am trying to do is not spend thousands of dollars that when an order is submitted to our online store, that the order automatically gets printed to our printer. Any ideas, pointers, code examples.
I have done a bunch of searching, and a lot of examples using C#, use Google's old service, not the OAuth2, documentation.
Pretty much, I need a service that will sent a print command to our printer when we get an order in. I can write the part from the store to the service, it is the service to the printer part I have a ton of trouble with.
Thanks in advance.
There's a brilliant PHP class you can download and use that does exactly that:
https://github.com/yasirsiddiqui/php-google-cloud-print
The problem with what you want to achieve is that Google Cloud Print is meant for authenticated users submitting their own print jobs. If I understand correctly, you want to have the server submit a print job as a callback after receiving an order. Therefore, print jobs need to be submitted by a service account, not a Google user. This can be done (we use it in production at the company I work for) using a little hack, described here:
Share printer with Google API Service Account
I can't help you with C# or PHP code, basically you need to be able to make JWT authenticated calls to Google Cloud Print, here you are a code snippet in NodeJS, hope it helps:
var request = require('google-oauth-jwt').requestWithJWT();
service.submitJob = function(readStream,callback) {
// Build multipart form data
var formData = {
printerid: cloudPrintConfig.googleId,
title: 'My Title',
content: readStream,
contentType: "application/pdf",
tag: 'My tag',
'ticket[version]': '1.0',
'ticket[print]': ''
};
// Submit POST request
request({
uri: cloudPrintConfig.endpoints.submit,
json: true,
method: 'post',
formData: formData,
jwt: cloudPrintConfig.jwt
}, function (err, res, body) {
if (err) {
callback(err,null);
} else {
if (body.success == false) {
callback('unsuccessful submission',null);
} else {
callback(null, body);
}
}
});
}
Details about JWT credentials can be found here
What I'm trying to do:
Add events to a google calendar from my site using javascript.
What I can't do:
Find a good tutorial/walk through/example for the google calendar api. All the documentation I've been able to find links back and forth between v1 and v2 api's, or the v3 api doesn't seem to be client based.
For those that are curious, the site I'm developing this for:
http://infohost.nmt.edu/~bbean/banweb/index.php
Google provides a great JS client library that works with all of Google's discovery-based APIs (such as Calendar API v3). I've written a blog post that covers the basics of setting up the JS client and authorizing a user.
Once you have the basic client enabled in your application, you'll need to get familiar with the specifics of Calendar v3 to write your application. I suggest two things:
The APIs Explorer will show you which calls are available in the API.
The Chrome developer tools' Javascript console will automatically suggest method names when you are manipulating gapi.client. For example, begin typing gapi.client.calendar.events. and you should see a set of possible completions (you'll need the insert method).
Here's an example of what inserting an event into JS would look like:
var resource = {
"summary": "Appointment",
"location": "Somewhere",
"start": {
"dateTime": "2011-12-16T10:00:00.000-07:00"
},
"end": {
"dateTime": "2011-12-16T10:25:00.000-07:00"
}
};
var request = gapi.client.calendar.events.insert({
'calendarId': 'primary',
'resource': resource
});
request.execute(function(resp) {
console.log(resp);
});
Hopefully this is enough to get you started.
this should do the trick
//async function to handle data fetching
async function getData () {
//try catch block to handle promises and errors
try {
const calendarId = ''
const myKey = ''
//using await and fetch together as two standard ES6 client side features to extract the data
let apiCall = await fetch('https://www.googleapis.com/calendar/v3/calendars/' + calendarId+ '/events?key=' + myKey)
//response.json() is a method on the Response object that lets you extract a JSON object from the response
//response.json() returns a promise resolved to a JSON object
let apiResponse = await apiCall.json()
console.log(apiResponse)
} catch (error) {
console.log(error)
}
}
getData()