ask-cli
Version:
Alexa Skills Kit (ASK) Command Line Interfaces
587 lines (542 loc) • 23.9 kB
JavaScript
const { expect } = require('chai');
const sinon = require('sinon');
const AuthorizationController = require('@src/controllers/authorization-controller');
const InitCommand = require('@src/commands/init');
const helper = require('@src/commands/init/helper');
const HostedSkillController = require('@src/controllers/hosted-skill-controller');
const httpClient = require('@src/clients/http-client');
const CliWarn = require('@src/exceptions/cli-warn');
const jsonView = require('@src/view/json-view');
const optionModel = require('@src/commands/option-model');
const Messenger = require('@src/view/messenger');
const profileHelper = require('@src/utils/profile-helper');
const ui = require('@src/commands/init/ui');
describe('Commands init test - command class test', () => {
const TEST_PROFILE = 'default';
const TEST_ERROR = 'init error';
const TEST_WARN = new CliWarn('init warn');
const TEST_SKILL_ID = 'skillId';
const TEST_SKILL_NAME = 'TEST_SKILL_NAME';
const TEST_SRC = 'src';
const TEST_SKILL_META = { src: TEST_SRC };
const TEST_SKILL_CODE = { src: TEST_SRC };
const TEST_SKILL_INFRA = {};
const TEST_HOSTED_SKILL_ID = 'hosted skill id';
let infoStub;
let errorStub;
let warnStub;
beforeEach(() => {
infoStub = sinon.stub();
errorStub = sinon.stub();
warnStub = sinon.stub();
sinon.stub(Messenger, 'getInstance').returns({
info: infoStub,
error: errorStub,
warn: warnStub
});
});
afterEach(() => {
sinon.restore();
});
it('| validate command information is set correctly', () => {
const instance = new InitCommand(optionModel);
expect(instance.name()).equal('init');
expect(instance.description()).equal('setup a new or existing Alexa skill project');
expect(instance.requiredOptions()).deep.equal([]);
expect(instance.optionalOptions()).deep.equal(['hosted-skill-id', 'profile', 'debug']);
});
describe('validate command handle', () => {
describe('command handle - pre init check', () => {
let instance;
beforeEach(() => {
instance = new InitCommand(optionModel);
sinon.stub(profileHelper, 'runtimeProfile').returns(TEST_PROFILE);
});
afterEach(() => {
sinon.restore();
});
it('| when profile is not correct, expect throw error', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
profileHelper.runtimeProfile.throws(new Error('error'));
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err.message).equal('error');
expect(errorStub.args[0][0].message).equal('error');
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when pre init check fails, expect throw error', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
sinon.stub(helper, 'preInitCheck').callsArgWith(2, TEST_ERROR);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when pre init check returns CliWarn, expect provide users warnings', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
sinon.stub(helper, 'preInitCheck').callsArgWith(2, TEST_WARN);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).deep.equal(TEST_WARN);
expect(warnStub.args[0][0]).equal(TEST_WARN.message);
expect(infoStub.callCount).equal(0);
expect(errorStub.callCount).equal(0);
done();
});
});
});
describe('command handle - collect ask resources', () => {
let instance;
beforeEach(() => {
instance = new InitCommand(optionModel);
sinon.stub(profileHelper, 'runtimeProfile').returns(TEST_PROFILE);
sinon.stub(helper, 'preInitCheck').callsArgWith(2);
sinon.stub(helper, 'getSkillIdUserInput');
sinon.stub(helper, 'getSkillMetadataUserInput');
sinon.stub(helper, 'getSkillCodeUserInput');
sinon.stub(helper, 'getSkillInfraUserInput');
sinon.stub(helper, 'previewAndWriteAskResources').callsArgWith(3, TEST_ERROR);
});
afterEach(() => {
sinon.restore();
});
it('| when collect skill id fails, expect throw error', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
helper.getSkillIdUserInput.callsArgWith(0, TEST_ERROR);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when collect skill meta src fails, expect throw error', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
helper.getSkillIdUserInput.callsArgWith(0, null, TEST_SKILL_ID);
helper.getSkillMetadataUserInput.callsArgWith(0, TEST_ERROR);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when collect skill code src fails, expect throw error', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
helper.getSkillIdUserInput.callsArgWith(0, null, TEST_SKILL_ID);
helper.getSkillMetadataUserInput.callsArgWith(0, null, TEST_SKILL_META);
helper.getSkillCodeUserInput.callsArgWith(0, TEST_ERROR);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when collect skill code src is not provided, callback without continuing', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
helper.getSkillIdUserInput.callsArgWith(0, null, TEST_SKILL_ID);
helper.getSkillMetadataUserInput.callsArgWith(0, null, TEST_SKILL_META);
helper.getSkillCodeUserInput.callsArgWith(0, null, null);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(helper.previewAndWriteAskResources.args[0][1]).deep.equal({
skillId: TEST_SKILL_ID,
skillMeta: {
src: TEST_SRC
}
});
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when collect skill infra fails, expect throw error', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
helper.getSkillIdUserInput.callsArgWith(0, null, TEST_SKILL_ID);
helper.getSkillMetadataUserInput.callsArgWith(0, null, TEST_SKILL_META);
helper.getSkillCodeUserInput.callsArgWith(0, null, TEST_SKILL_CODE);
helper.getSkillInfraUserInput.callsArgWith(0, TEST_ERROR);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when collect skill info all succeed, expect it passes correct user input', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
helper.getSkillIdUserInput.callsArgWith(0, null, TEST_SKILL_ID);
helper.getSkillMetadataUserInput.callsArgWith(0, null, TEST_SKILL_META);
helper.getSkillCodeUserInput.callsArgWith(0, null, TEST_SKILL_CODE);
helper.getSkillInfraUserInput.callsArgWith(0, null, TEST_SKILL_INFRA);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(helper.previewAndWriteAskResources.args[0][1]).deep.equal({
skillId: TEST_SKILL_ID,
skillMeta: TEST_SKILL_META,
skillCode: TEST_SKILL_CODE,
skillInfra: TEST_SKILL_INFRA
});
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
});
describe('command handle - post user input logics', () => {
let instance;
beforeEach(() => {
instance = new InitCommand(optionModel);
sinon.stub(profileHelper, 'runtimeProfile').returns(TEST_PROFILE);
sinon.stub(helper, 'preInitCheck').callsArgWith(2);
sinon.stub(helper, 'getSkillIdUserInput').callsArgWith(0, null, TEST_SKILL_ID);
sinon.stub(helper, 'getSkillMetadataUserInput').callsArgWith(0, null, TEST_SKILL_META);
sinon.stub(helper, 'getSkillCodeUserInput').callsArgWith(0, null, TEST_SKILL_CODE);
sinon.stub(helper, 'getSkillInfraUserInput').callsArgWith(0, null, TEST_SKILL_INFRA);
sinon.stub(helper, 'previewAndWriteAskResources');
sinon.stub(helper, 'bootstrapSkillInfra');
});
afterEach(() => {
sinon.restore();
});
it('| when preview and write fails, expect throws error', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
helper.previewAndWriteAskResources.callsArgWith(3, TEST_ERROR);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when preview and write returns CliWarn, expect display warnings', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
helper.previewAndWriteAskResources.callsArgWith(3, TEST_WARN);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).deep.equal(TEST_WARN);
expect(warnStub.args[0][0]).equal(TEST_WARN.message);
expect(infoStub.callCount).equal(0);
expect(errorStub.callCount).equal(0);
done();
});
});
it('| when post init executions fails, expect throws error', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
helper.previewAndWriteAskResources.callsArgWith(3);
helper.bootstrapSkillInfra.callsArgWith(3, TEST_ERROR);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when all the steps succeed, expect seeing success message', (done) => {
// setup
const TEST_CMD = {
profile: TEST_PROFILE
};
helper.previewAndWriteAskResources.callsArgWith(3);
helper.bootstrapSkillInfra.callsArgWith(3);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(undefined);
expect(infoStub.args[0][0]).equal('\nSuccess! Run "ask deploy" to deploy your skill.');
expect(infoStub.callCount).equal(1);
expect(errorStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
});
});
describe('command handle - get skill name', () => {
let instance;
const TEST_CMD = {
profile: TEST_PROFILE,
hostedSkillId: TEST_HOSTED_SKILL_ID
};
beforeEach(() => {
instance = new InitCommand(optionModel);
sinon.stub(AuthorizationController.prototype, 'tokenRefreshAndRead').callsArgWith(1);
sinon.stub(profileHelper, 'runtimeProfile').returns(TEST_PROFILE);
});
afterEach(() => {
sinon.restore();
});
it('| get skill manifest fails, expect error thrown', (done) => {
// setup
sinon.stub(httpClient, 'request').callsArgWith(3, TEST_ERROR); // stub getManifest request
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
done();
});
});
it('| get skill manifest response with status code >= 300, expect error thrown', (done) => {
// setup
const GET_MANIFEST_ERROR = {
statusCode: 403,
body: {
error: TEST_ERROR
}
};
sinon.stub(httpClient, 'request').callsArgWith(3, null, GET_MANIFEST_ERROR); // stub getManifest request
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(jsonView.toString({ error: TEST_ERROR }));
expect(errorStub.args[0][0]).equal(jsonView.toString({ error: TEST_ERROR }));
done();
});
});
it('| get skill manifest succeed without locales, expect error thrown', (done) => {
// setup
const TEST_NO_FOUND_ERROR = 'No skill name found.';
const GET_MANIFEST_RESPONSE_NO_LOCALES = {
statusCode: 200,
headers: {},
body: {
manifest: {
publishingInformation: {}
}
}
};
sinon.stub(httpClient, 'request').callsArgWith(3, null, GET_MANIFEST_RESPONSE_NO_LOCALES); // stub getManifest request
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_NO_FOUND_ERROR);
expect(errorStub.args[0][0]).equal(TEST_NO_FOUND_ERROR);
done();
});
});
});
describe('command handle - confirm project folder name', () => {
let instance;
const TEST_CMD = {
profile: TEST_PROFILE,
hostedSkillId: TEST_HOSTED_SKILL_ID
};
const TEST_LOCALE = 'en-US';
beforeEach(() => {
instance = new InitCommand(optionModel);
sinon.stub(AuthorizationController.prototype, 'tokenRefreshAndRead').callsArgWith(1);
sinon.stub(profileHelper, 'runtimeProfile').returns(TEST_PROFILE);
});
afterEach(() => {
sinon.restore();
});
it('| get project name, ui get project folder name fails, expect error thrown', (done) => {
// setup
const GET_MANIFEST_RESPONSE = {
statusCode: 200,
headers: {},
body: {
manifest: {
publishingInformation: {
locales: {
[TEST_LOCALE]: {
name: TEST_SKILL_NAME
}
}
}
}
}
};
const TEST_UI_ERROR = 'TEST_UI_ERROR';
sinon.stub(httpClient, 'request').callsArgWith(3, null, GET_MANIFEST_RESPONSE); // stub getManifest request
sinon.stub(ui, 'getProjectFolderName').callsArgWith(1, TEST_UI_ERROR);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_UI_ERROR);
expect(errorStub.args[0][0]).equal(TEST_UI_ERROR);
done();
});
});
});
describe('command handle - clone', () => {
let instance;
const TEST_CMD = {
profile: TEST_PROFILE,
hostedSkillId: TEST_HOSTED_SKILL_ID
};
const TEST_LOCALE_CA = 'en-CA';
beforeEach(() => {
instance = new InitCommand(optionModel);
sinon.stub(AuthorizationController.prototype, 'tokenRefreshAndRead').callsArgWith(1);
sinon.stub(profileHelper, 'runtimeProfile').returns(TEST_PROFILE);
});
afterEach(() => {
sinon.restore();
});
it('| hosted skill controller clone fails, expect error thrown', (done) => {
// setup
const TEST_FOLDER_NAME = 'TEST_FOLDER_NAME';
const GET_MANIFEST_RESPONSE = {
statusCode: 200,
headers: {},
body: {
manifest: {
publishingInformation: {
locales: {
[TEST_LOCALE_CA]: {
name: TEST_SKILL_NAME
}
}
}
}
}
};
sinon.stub(httpClient, 'request').callsArgWith(3, null, GET_MANIFEST_RESPONSE); // stub getManifest request
sinon.stub(ui, 'getProjectFolderName').callsArgWith(1, null, TEST_FOLDER_NAME);
sinon.stub(HostedSkillController.prototype, 'clone').callsArgWith(3, TEST_ERROR);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
done();
});
});
it('| download Git Hooks Template fails, expect error thrown', (done) => {
// setup
const TEST_FOLDER_NAME = 'TEST_FOLDER_NAME';
const TEST_LOCALE = 'en-US';
const GET_MANIFEST_RESPONSE = {
statusCode: 200,
headers: {},
body: {
manifest: {
publishingInformation: {
locales: {
[TEST_LOCALE]: {
name: TEST_SKILL_NAME
}
}
}
}
}
};
sinon.stub(httpClient, 'request').callsArgWith(3, null, GET_MANIFEST_RESPONSE); // stub getManifest request
sinon.stub(ui, 'getProjectFolderName').callsArgWith(1, null, TEST_FOLDER_NAME);
sinon.stub(HostedSkillController.prototype, 'clone').callsArgWith(3, null);
sinon.stub(HostedSkillController.prototype, 'downloadGitHooksTemplate').callsArgWith(2, TEST_ERROR);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(TEST_ERROR);
expect(errorStub.args[0][0]).equal(TEST_ERROR);
done();
});
});
it('| hosted skill controller clone succeed, expect project initialized', (done) => {
// setup
const TEST_FOLDER_NAME = 'TEST_FOLDER_NAME';
const TEST_LOCALE = 'en-US';
const GET_MANIFEST_RESPONSE = {
statusCode: 200,
headers: {},
body: {
manifest: {
publishingInformation: {
locales: {
[TEST_LOCALE]: {
name: TEST_SKILL_NAME
}
}
}
}
}
};
sinon.stub(httpClient, 'request').callsArgWith(3, null, GET_MANIFEST_RESPONSE); // stub getManifest request
sinon.stub(ui, 'getProjectFolderName').callsArgWith(1, null, TEST_FOLDER_NAME);
sinon.stub(HostedSkillController.prototype, 'clone').callsArgWith(3, null);
sinon.stub(HostedSkillController.prototype, 'downloadGitHooksTemplate').callsArgWith(2, null);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(undefined);
expect(Messenger.getInstance().info.args[0][0]).equal(`\n${TEST_SKILL_NAME} successfully initialized.\n`);
done();
});
});
});
});