Skip to content

Commit

Permalink
Merge pull request #8 from marcelobern/master
Browse files Browse the repository at this point in the history
Added test cases for skill simulation & invocation.
  • Loading branch information
tejashah88 committed Sep 10, 2018
2 parents 302236f + 2c82b36 commit 1722dab
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 33 deletions.
3 changes: 0 additions & 3 deletions README.md
Expand Up @@ -6,9 +6,6 @@

A node.js client library for using the Alexa Skill Management API.

# Notice
As of now, the following SMAPI operations in this module are **untested**: skill testing (invocation, simulation), and intent request history. So if there are any problems, please create a new issue or a pull request to fix the issue. Additionally you can help improve this library's stability by adding tests for yet untested SMAPI operations.

## Table Of Contents

* [Documentation](#documentation)
Expand Down
5 changes: 5 additions & 0 deletions test/data/common.js
Expand Up @@ -17,6 +17,11 @@ module.exports = {
locales: [LOCALE],
reason: 'OTHER',
message: 'node-alexa-smapi testing',
endpointRegion: 'Default', // string enum["Default", "NA", "EU", "FE", etc],
skillRequest: {
body: require('./request.json')
},
simulationContent: 'api',
intentRequestParams: {
nextToken: null,
maxResults: 10,
Expand Down
41 changes: 41 additions & 0 deletions test/data/request.json
@@ -0,0 +1,41 @@
{
"version": "1.0",
"session": {
"new": true,
"sessionId": "amzn1.echo-api.session.[unique-value-here]",
"application": {
"applicationId": "TBD"
},
"attributes": {
"key": "string value"
},
"user": {
"userId": "amzn1.ask.account.[unique-value-here]",
"accessToken": "Atza|AAAAAAAA...",
"permissions": {
"consentToken": "ZZZZZZZ..."
}
}
},
"context": {
"System": {
"device": {
"deviceId": "string",
"supportedInterfaces": {}
},
"application": {
"applicationId": "TBD"
},
"user": {
"userId": "amzn1.ask.account.[unique-value-here]",
"accessToken": "Atza|AAAAAAAA...",
"permissions": {
"consentToken": "ZZZZZZZ..."
}
},
"apiEndpoint": "https://api.amazonalexa.com",
"apiAccessToken": "AxThk..."
}
},
"request": {}
}
82 changes: 71 additions & 11 deletions test/data/responses.json
Expand Up @@ -277,6 +277,35 @@
"headers": {},
"data": ""
},
{
"url": "/v0/skills/SKILL_ID/invocations",
"method": "post",
"status": 500,
"headers": {},
"data": {
"message": "An unexpected error occurred."
}
},
{
"url": "/v0/skills/SKILL_ID/simulations",
"method": "post",
"status": 200,
"headers": {},
"data": {
"id": "SIMULATION_ID",
"status": "IN_PROGRESS"
}
},
{
"url": "/v0/skills/SKILL_ID/simulations/SIMULATION_ID",
"method": "get",
"status": 200,
"headers": {},
"data": {
"id": "SIMULATION_ID",
"status": "IN_PROGRESS"
}
},
{
"url": "/v1/skills/SKILL_ID/stages/development/enablement",
"method": "delete",
Expand Down Expand Up @@ -579,13 +608,6 @@
"headers": {},
"data": ""
},
{
"url": "/v1/skills/SKILL_ID/stages/development/enablement",
"method": "delete",
"status": 204,
"headers": {},
"data": ""
},
{
"url": "/v1/skills/SKILL_ID/stages/development/validations",
"method": "post",
Expand All @@ -606,6 +628,42 @@
"status": "IN_PROGRESS"
}
},
{
"url": "/v1/skills/SKILL_ID/invocations",
"method": "post",
"status": 500,
"headers": {},
"data": {
"message": "An unexpected error occurred."
}
},
{
"url": "/v1/skills/SKILL_ID/simulations",
"method": "post",
"status": 200,
"headers": {},
"data": {
"id": "SIMULATION_ID",
"status": "IN_PROGRESS"
}
},
{
"url": "/v1/skills/SKILL_ID/simulations/SIMULATION_ID",
"method": "get",
"status": 200,
"headers": {},
"data": {
"id": "SIMULATION_ID",
"status": "IN_PROGRESS"
}
},
{
"url": "/v1/skills/SKILL_ID/stages/development/enablement",
"method": "delete",
"status": 204,
"headers": {},
"data": ""
},
{
"url": "/v1/skills/SKILL_ID/submit",
"method": "post",
Expand Down Expand Up @@ -674,27 +732,29 @@
"method": "get",
"status": 405,
"headers": {},
"data": ""
"data": "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>405 Method Not Allowed</title>\n</head><body>\n<h1>Method Not Allowed</h1>\n<p>The requested method GET is not allowed for the URL /v1/skills/badSkill.</p>\n</body></html>\n"
},
{
"url": "/v1/skills/badSkill",
"method": "post",
"status": 405,
"headers": {},
"data": ""
"data": "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>405 Method Not Allowed</title>\n</head><body>\n<h1>Method Not Allowed</h1>\n<p>The requested method POST is not allowed for the URL /v1/skills/badSkill.</p>\n</body></html>\n"
},
{
"url": "/v1/skills/badSkill",
"method": "put",
"status": 405,
"headers": {},
"data": ""
"data": "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>405 Method Not Allowed</title>\n</head><body>\n<h1>Method Not Allowed</h1>\n<p>The requested method PUT is not allowed for the URL /v1/skills/badSkill.</p>\n</body></html>\n"
},
{
"url": "/v1/skills/badSkill",
"method": "delete",
"status": 400,
"headers": {},
"data": ""
"data": {
"message": "1 validation error detected: Value 'badSkill' at 'skillStageIdentifiers.1.member.skillId' failed to satisfy constraint: Member must satisfy regular expression pattern: (^amzn1\\.ask\\.skill\\.[0-9a-f\\-]+)|(^amzn1\\.echo-sdk-ams\\.app\\.[0-9a-f\\-]+)"
}
}
]
95 changes: 76 additions & 19 deletions test/test_smapi_client.js
Expand Up @@ -52,12 +52,14 @@ function showError(error) {
}

function errorSummary(error) {
const summary = {
const expectedErrorKeywords = /badSkill|invocations/;
// should only add error responses for invoke & custom methods
if (expectedErrorKeywords.test(error.config.url)) responses.add(error);
return {
status: error.status,
statusText: error.statusText,
data: error.data
};
return summary;
}

var sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
Expand Down Expand Up @@ -140,17 +142,19 @@ describe('Testing node-alexa-smapi', function() {
}
}

describe('Testing with SMAPI ' + TEST_VERSION, function() {
describe('Testing with SMAPI ' + TEST_VERSION + ' for region NA', function() {
after(function(){
// Persist response template
if (shouldCapture(TEST_TYPE)) {
if (TEST_VERSION === VERSION_0) responses.sanitize({
VENDOR_ID: testData.vendorId,
SKILL_ID: testData.skillId
SKILL_ID: testData.skillId,
SIMULATION_ID: testData.simulationId
});
else if (TEST_VERSION === VERSION_1) responses.sanitize({
VENDOR_ID: testData.vendorId,
SKILL_ID: testData.skillId,
SIMULATION_ID: testData.simulationId,
VALIDATION_ID: testData.validationId
});
}
Expand All @@ -160,7 +164,8 @@ describe('Testing node-alexa-smapi', function() {
this.retries(MAX_RETRIES);
this.timeout(MOCHA_TIMEOUT);
const smapiClient = SMAPI_CLIENT({
version: TEST_VERSION
version: TEST_VERSION,
region: 'NA'
});
if (shouldCapture(TEST_TYPE)) smapiClient.rest.client.interceptors.response.use(responses.add);

Expand Down Expand Up @@ -464,7 +469,7 @@ describe('Testing node-alexa-smapi', function() {
});
});

context('-> Skill Enablement Operations', function() {
context('-> Skill Enablement Operations (except disable)', function() {
describe('-> Enable a skill', function() {
var subject;

Expand Down Expand Up @@ -496,50 +501,85 @@ describe('Testing node-alexa-smapi', function() {
return expect(subject).to.eventually.have.property('status', 204);
});
});
});

describe('-> Disable a skill', function() {
context('-> Skill Testing Operations', function() {
if (TEST_VERSION === VERSION_1) describe('-> Validate a skill', function() {
var subject;

beforeEach(function() {
subject = smapiClient.skillEnablement.disable(testData.skillId, testData.stage);
subject = smapiClient.skillTesting.validate(testData.skillId, testData.stage, testData.locales);
});

it('responds with validationId', function() {
subject = subject.then(function(response) {
showResponse(response);
testData.validationId = response.id;
return response;
}, retry);
return expect(subject).to.eventually.have.property('id');
});
});

if (TEST_VERSION === VERSION_1) describe('-> Check validation status of a skill', function() {
var subject;

beforeEach(function() {
subject = smapiClient.skillTesting.validationStatus(testData.skillId, testData.stage, testData.validationId);
});

it('responds with no content', function() {
subject = subject.then(function(response) {
showResponse(response);
return response;
}, retry);
return expect(subject).to.eventually.have.property('status', 204);
return expect(subject).to.eventually.have.property('status');
});
});
});

context('-> Skill Testing Operations', function() {
if (TEST_VERSION === VERSION_1) describe('-> Validate a skill', function() {
describe('-> Invoke a skill', function() {
var subject;

beforeEach(function() {
subject = smapiClient.skillTesting.validate(testData.skillId, testData.stage, testData.locales);
testData.skillRequest.body.session.application.applicationId =
testData.skillRequest.body.context.System.application.applicationId = testData.skillId;
subject = smapiClient.skillTesting.invoke(testData.skillId, testData.endpointRegion, testData.skillRequest);
});

it('responds with validationId', function() {
it('responds with internal server error (no reply as skill code is not deployed anywhere)', function() {
subject = subject.then(function(response) {
showResponse(response);
testData.validationId = response.id;
return response;
}, retry);
return expect(subject).to.eventually.have.property('status', 500);
});
});

describe('-> Simulate a skill', function() {
var subject;

beforeEach(function() {
subject = smapiClient.skillTesting.simulate(testData.skillId, testData.simulationContent, testData.locale);
});

it('responds with simulationId', function() {
subject = subject.then(function(response) {
showResponse(response);
testData.simulationId = response.id;
return response;
}, retry);
return expect(subject).to.eventually.have.property('id');
});
});

if (TEST_VERSION === VERSION_1) describe('-> Check validation status of a skill', function() {
describe('-> Check status of a skill simulation', function() {
var subject;

beforeEach(function() {
subject = smapiClient.skillTesting.validationStatus(testData.skillId, testData.stage, testData.validationId);
subject = smapiClient.skillTesting.simulationStatus(testData.skillId, testData.simulationId);
});

it('responds with no content', function() {
it('responds with simulation status', function() {
subject = subject.then(function(response) {
showResponse(response);
return response;
Expand All @@ -549,6 +589,24 @@ describe('Testing node-alexa-smapi', function() {
});
});

context('-> Skill Enablement Operations (disable only)', function() {
describe('-> Disable a skill', function() {
var subject;

beforeEach(function() {
subject = smapiClient.skillEnablement.disable(testData.skillId, testData.stage);
});

it('responds with no content', function() {
subject = subject.then(function(response) {
showResponse(response);
return response;
}, retry);
return expect(subject).to.eventually.have.property('status', 204);
});
});
});

if (shouldCertify(TEST_TYPE)) context('-> Skill Certification Operations', function() {
describe('-> Submit a skill for certification', function() {
var subject;
Expand Down Expand Up @@ -675,7 +733,6 @@ describe('Testing node-alexa-smapi', function() {
});

context('-> Custom Operations with bad skillId, no access_token', function() {
// TODO: troubleshoot why smapiClient.rest.client.interceptors.response.use(responses.add) is not capturing these responses
describe('-> head()', function() {
var subject;

Expand Down

0 comments on commit 1722dab

Please sign in to comment.