alexa-app
Version:
A module to simplify creation of Alexa (Amazon Echo) apps (Skills) using Node.js
603 lines (513 loc) • 19.2 kB
JavaScript
/*jshint expr: true*/
;
var chai = require("chai");
var chaiAsPromised = require("chai-as-promised");
var mockHelper = require("./helpers/mock_helper");
chai.use(chaiAsPromised);
var expect = chai.expect;
chai.config.includeStack = true;
import * as Alexa from "..";
describe("Alexa", function() {
describe("app", function() {
var testApp = new Alexa.app("testApp");
beforeEach(function() {
testApp = new Alexa.app("testApp");
});
describe("#request", function() {
var mockRequest = mockHelper.load("intent_request_airport_info.json");
context("intent handler with shouldEndSession = false", function() {
/** @type {Alexa.request} */
var reqObject;
beforeEach(function() {
testApp.intent("airportInfoIntent", {}, function(req, res) {
res.say("message").shouldEndSession(false);
res.session("foo", true);
res.session("bar", {
qaz: "woah"
});
reqObject = req;
return true;
});
});
it("reponds with expected context applicationId", function() {
return testApp.request(mockRequest).then(function(response) {
expect(reqObject.context).to
.have.deep.property(
"System.application.applicationId",
"amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe"
);
});
});
it("responds with a session object", function() {
var subject = testApp.request(mockRequest).then(function(response) {
return response.sessionAttributes;
});
return Promise.all([
expect(subject).to.eventually.become({
foo: true,
bar: {
qaz: "woah"
}
})
]);
});
it("has a res object with expected properties", function() {
var subject = testApp.request(mockRequest).then(function(response) {
return reqObject;
});
return Promise.all([
expect(subject).to.eventually.have.property(
"applicationId",
"amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe"
),
expect(subject).to.eventually.have.property(
"userId",
"amzn1.account.AM3B227HF3FAM1B261HK7FFM3A2"
)
]);
});
it("does not update session properties without explicit set", function() {
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
var session = req.getSession();
session.set("foo", true);
session.set("bar", {
qaz: "woah"
});
};
testApp.intent("airportInfoIntent", {}, function(req, res) {
var session = req.getSession();
session.set("foo", true);
session.set("bar", {
qaz: "woah"
});
res.say("message").shouldEndSession(false);
var session = req.getSession();
var bar = session.get("bar");
bar.qaz = "not woah";
return true;
});
var subject = testApp.request(mockRequest).then(function(response) {
return response.sessionAttributes;
});
return Promise.all([
expect(subject).to.eventually.become({
foo: true,
bar: {
qaz: "woah"
}
})
]);
});
it("does not update session properties when clearing non-existant attribute", function() {
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
var session = req.getSession();
session.set("foo", true);
session.set("bar", {
qaz: "woah"
});
};
testApp.intent("airportInfoIntent", {}, function(req, res) {
res.say("message").shouldEndSession(false);
var session = req.getSession();
session.clear("baz");
return true;
});
var subject = testApp.request(mockRequest).then(function(response) {
return response.sessionAttributes;
});
return Promise.all([
expect(subject).to.eventually.become({
foo: true,
bar: {
qaz: "woah"
}
})
]);
});
it("updates session properties with explicit set", function() {
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
var session = req.getSession();
session.set("foo", true);
session.set("bar", {
qaz: "woah"
});
};
testApp.intent("airportInfoIntent", {}, function(req, res) {
res.say("message").shouldEndSession(false);
var session = req.getSession();
var bar = session.get("bar");
bar.qaz = "not woah";
session.set("bar", bar);
session.set("foo", false);
return true;
});
var subject = testApp.request(mockRequest).then(function(response) {
return response.sessionAttributes;
});
return Promise.all([
expect(subject).to.eventually.become({
foo: false,
bar: {
qaz: "not woah"
}
})
]);
});
});
});
describe("#response", function() {
var mockRequest = mockHelper.load("intent_request_airport_info.json");
context("intent handler with shouldEndSession = false", function() {
it("responds with an empty session object after clearing session", function() {
testApp.intent("airportInfoIntent", {}, function(req, res) {
res.say("hi").shouldEndSession(false);
res.session("foo", true);
res.session("bar", {
qaz: "woah"
});
res.clearSession();
return true;
});
var subject = testApp.request(mockRequest).then(function(response) {
return response.sessionAttributes;
});
return Promise.all([
expect(subject).to.eventually.become({})
]);
});
});
context("intent handler without shouldEndSession", function() {
it("responds without shouldEndSession", function() {
testApp.intent("airportInfoIntent", {}, function(req, res) {
res.say("hi").shouldEndSession();
res.session("foo", true);
res.session("bar", {
qaz: "woah"
});
res.clearSession();
return true;
});
var subject = testApp.request(mockRequest).then(function(response) {
return response.sessionAttributes;
});
return Promise.all([
expect(subject).to.eventually.become({})
]);
});
});
});
describe("#response", function() {
var mockRequest = mockHelper.load("intent_request_airport_info.json");
context("intent handler with shouldEndSession = false", function() {
it("responds with session object missing a cleared session variable", function() {
testApp.intent("airportInfoIntent", {}, function(req, res) {
res.say("hi").shouldEndSession(false);
res.session("foo", true);
res.session("bar", {
qaz: "woah"
});
res.clearSession("bar");
return true;
});
var subject = testApp.request(mockRequest).then(function(response) {
return response.sessionAttributes;
});
return Promise.all([
expect(subject).to.eventually.become({
"foo": true
})
]);
});
});
});
describe("#response", function() {
var mockRequest = mockHelper.load("intent_request_airport_info.json");
context("intent handler with shouldEndSession = false", function() {
it("responds with a copied session object", function() {
testApp.intent("airportInfoIntent", {}, function(req, res) {
res.say("hi").shouldEndSession(false);
res.session("bar", {
qaz: "woah"
});
res.session("foo", res.session("bar"));
return true;
});
var subject = testApp.request(mockRequest).then(function(response) {
return response.sessionAttributes["foo"];
});
return Promise.all([
expect(subject).to.eventually.become({
qaz: "woah"
})
]);
});
});
});
describe("#response", function() {
var mockRequest = mockHelper.load("intent_request_airport_info.json");
context("intent handler with shouldEndSession = false", function() {
it("responds reprompted message on shouldEndSession", function() {
var expectedReprompt = "totally";
testApp.intent("airportInfoIntent", {}, function(req, res) {
res.say("hi").shouldEndSession(false, expectedReprompt);
return true;
});
var subject = testApp.request(mockRequest).then(function(response) {
return response.response.reprompt.outputSpeech;
});
return expect(subject).to.eventually.become({
ssml: "<speak>" + expectedReprompt + "</speak>",
type: "SSML"
});
});
});
});
describe("#request", function() {
var mockRequest = mockHelper.load("audio_player_event_request.json");
context("request without session", function() {
it("responds with an empty session object", function() {
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
if (req.hasSession()) {
// unreachable code, because the request doesn't have session
req.getSession().set("foo", "bar");
}
};
var subject = testApp.request(mockRequest).then(function(response) {
return response.sessionAttributes;
});
return Promise.all([
expect(subject).to.eventually.become({})
]);
});
});
});
describe("#request", function() {
context("request without session", function() {
var mockRequest = mockHelper.load("audio_player_event_request.json");
it("session.clear() should fail the app", function() {
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
return req.getSession().clear();
};
var subject = testApp.request(mockRequest);
return expect(subject).to.eventually.be.rejectedWith(testApp.messages.NO_SESSION);
});
});
});
describe("#request", function() {
context("request without session", function() {
var mockRequest = mockHelper.load("audio_player_event_request.json");
it("session.get(key) should fail the app", function() {
var returnedAttributeValue = "overridden";
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
returnedAttributeValue = req.getSession().get("AttributeWhichDoesNotExist");
};
var subject = testApp.request(mockRequest);
return expect(subject).to.eventually.be.rejectedWith(testApp.messages.NO_SESSION);
});
});
});
describe("#request", function() {
context("request with session", function() {
var mockRequest = mockHelper.load("intent_request_airport_info.json");
it("session.get(key) should not throw if attribute is not present", function() {
var returnedAttributeValue = "overridden";
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
returnedAttributeValue = req.getSession().get("AttributeWhichDoesNotExist");
};
return testApp.request(mockRequest).then(function() {
expect(returnedAttributeValue).to.be.undefined;
});
});
});
});
describe("#request", function() {
context("request with session", function() {
var mockRequest = mockHelper.load("intent_request_airport_info.json");
it("should respond to changes to request.type() performed in app.pre", function() {
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
req.data.request.type = 'Some Invalid Request Type';
};
return testApp.request(mockRequest).then(function(result) {
expect(result.response.outputSpeech.ssml).to.equal('<speak>Error: not a valid request</speak>');
});
});
});
});
describe("#request", function() {
context("request with session", function() {
var mockRequest = mockHelper.load("intent_request_airport_info_with_attributes.json");
it("session.get(key) should not throw if attribute is not present", function() {
var returnedAttributeValue = "overridden";
var returnedAirportCode = "overridden";
var returnedAirportCodeBackwardsCompat = "overridden";
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
returnedAttributeValue = req.getSession().get("AttributeWhichDoesNotExist");
returnedAirportCode = req.getSession().get("airportCode");
returnedAirportCodeBackwardsCompat = req.session("airportCode");
};
return testApp.request(mockRequest)
.then(function() {
expect(returnedAttributeValue).to.be.undefined;
expect(returnedAirportCode).to.equal("DAL");
expect(returnedAirportCodeBackwardsCompat).to.equal("DAL");
});
});
});
});
describe("#request", function() {
context("request with session", function() {
var mockRequest = mockHelper.load("intent_request_airport_info.json");
it("session.clear() should not throw", function() {
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
req.getSession().clear();
};
return testApp.request(mockRequest);
});
});
});
describe("#request", function() {
context("request with session and attributes", function() {
var mockRequest = mockHelper.load("intent_request_airport_info_with_attributes.json");
it("session.clear() should not throw", function() {
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
req.getSession().clear();
};
return testApp.request(mockRequest);
});
});
});
describe("#request", function() {
var mockRequest = mockHelper.load("audio_player_event_request.json");
context("request without session", function() {
context("trying to get session variable", function() {
it("it fails with NO_SESSION message", function() {
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
req.getSession().get("foo");
};
var subject = testApp.request(mockRequest).then(function(response) {
return response;
});
return expect(subject).to.eventually.be.rejectedWith(testApp.messages.NO_SESSION);
});
});
context("trying to set session variable", function() {
it("it fails with NO_SESSION message", function() {
/**
* @param {Alexa.request} req
* @param {Alexa.response} res
* @param {string} type
*/
testApp.pre = function(req, res, type) {
req.getSession().set("foo", "bar");
};
var subject = testApp.request(mockRequest).then(function(response) {
return response.response.outputSpeech;
});
return expect(subject).to.eventually.be.rejectedWith(testApp.messages.NO_SESSION);
});
});
});
});
describe("intent request with malformed session", function() {
var mockRequest = mockHelper.load("intent_request_malformed_session.json");
it("responds a valid session object", function() {
testApp.pre = function(req, res, type) {
if (req.hasSession()) {
req.getSession().set("foo", "bar");
}
};
var subject = testApp.request(mockRequest).then(function(response) {
return response.sessionAttributes;
});
return Promise.all([
expect(subject).to.eventually.become({
"foo": "bar"
})
]);
});
});
describe("update session in post()", function() {
var mockRequest = mockHelper.load("intent_request_malformed_session.json");
it("responds with updated session object", function() {
testApp.pre = function(req) {
if (req.hasSession()) {
req.getSession().set("foo", "bar");
}
};
testApp.post = function(req) {
if (req.hasSession()) {
req.getSession().set("foo", "big_bar");
}
};
var subject = testApp.request(mockRequest).then(function(response) {
return response.sessionAttributes;
});
return Promise.all([
expect(subject).to.eventually.become({
"foo": "big_bar"
})
]);
});
});
});
});