appcenter-cli
Version:
Command line tool for Visual Studio App Center
363 lines (362 loc) • 15.5 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const os = require("os");
const path = require("path");
const interaction_1 = require("../../util/interaction");
const commandline_1 = require("../../util/commandline");
const help_messages_1 = require("./lib/help-messages");
const deviceConfigurationSort_1 = require("./lib/deviceConfigurationSort");
const espresso_1 = require("./lib/wizard/espresso");
const appium_1 = require("./lib/wizard/appium");
const uitest_1 = require("./lib/wizard/uitest");
const xcuitest_1 = require("./lib/wizard/xcuitest");
const misc_1 = require("../../util/misc");
const profile_1 = require("../../util/profile");
var TestFramework;
(function (TestFramework) {
TestFramework[TestFramework["Espresso"] = 1] = "Espresso";
TestFramework[TestFramework["Appium"] = 2] = "Appium";
TestFramework[TestFramework["XCUITest"] = 3] = "XCUITest";
TestFramework[TestFramework["Xamarin.UITest"] = 4] = "Xamarin.UITest";
TestFramework[TestFramework["Calabash"] = 5] = "Calabash";
TestFramework[TestFramework["Manifest"] = 6] = "Manifest";
})(TestFramework || (TestFramework = {}));
let WizardTestCommand = class WizardTestCommand extends commandline_1.AppCommand {
constructor(args) {
super(args);
this.interactiveArgs = [];
this._selectedApp = null;
this._args = args;
}
selectApp(client) {
const _super = Object.create(null, {
app: { get: () => super.app }
});
return __awaiter(this, void 0, void 0, function* () {
if (!this._selectedApp) {
try {
this._selectedApp = _super.app;
}
catch (e) {
// no app was provided/found, so we will prompt the user
this._selectedApp = yield this.getApps(client);
this.interactiveArgs.push("--app", this._selectedApp.identifier);
}
}
return this._selectedApp;
});
}
run(client, portalBaseUrl) {
return __awaiter(this, void 0, void 0, function* () {
const app = yield this.selectApp(client);
const getDeviceSets = client.test.listDeviceSetsOfOwner(app.ownerName, app.appName);
const appResult = yield client.apps.get(app.ownerName, app.appName);
this.isAndroidApp = appResult.os.toLowerCase() === "android";
const frameworkName = yield this.promptFramework();
const searchApps = this.scanFolder();
const devices = yield this.promptDevices(yield getDeviceSets, app, client);
this.interactiveArgs.push("--devices", devices);
const async = yield this.isAsync();
if (async) {
this.interactiveArgs.push("--async");
}
const listOfAppFiles = yield searchApps;
const appPath = yield this.promptAppFile(listOfAppFiles);
this.interactiveArgs.push("--app-path", appPath);
switch (frameworkName) {
case TestFramework.Espresso: {
const testApkPath = yield this.promptAppFile(listOfAppFiles, true);
this.interactiveArgs.push("--test-apk-path", testApkPath);
return new espresso_1.default(this._args, this.interactiveArgs).run(client, portalBaseUrl);
}
case TestFramework.XCUITest: {
const testIpaPath = yield this.promptAppFile(listOfAppFiles, true);
this.interactiveArgs.push("--test-ipa-path", testIpaPath);
return new xcuitest_1.default(this._args, this.interactiveArgs).run(client, portalBaseUrl);
}
case TestFramework.Appium: {
return new appium_1.default(this._args, this.interactiveArgs).run(client, portalBaseUrl);
}
case TestFramework["Xamarin.UITest"]: {
return new uitest_1.default(this._args, this.interactiveArgs).run(client, portalBaseUrl);
}
case TestFramework.Calabash: {
this.printCalabashHelp();
return { succeeded: true };
}
case TestFramework.Manifest: {
this.printManifestHelp();
return { succeeded: true };
}
default:
throw new Error("Unknown framework name!");
}
});
}
promptFramework() {
return __awaiter(this, void 0, void 0, function* () {
const choices = Object.keys(TestFramework)
.filter((framework) => {
if (this.isAndroidApp && framework === "XCUITest") {
return false;
}
if (!this.isAndroidApp && framework === "Espresso") {
return false;
}
return typeof TestFramework[framework] === "number";
})
.map((framework) => {
return {
name: framework,
value: TestFramework[framework],
};
});
const questions = [
{
type: "list",
name: "framework",
message: "Pick a test framework",
choices: choices,
},
];
const answers = yield interaction_1.prompt.question(questions);
return answers.framework;
});
}
promptAppFile(listOfAppFiles, forTest = false) {
return __awaiter(this, void 0, void 0, function* () {
if (listOfAppFiles.length === 0) {
return yield interaction_1.prompt(`We could not find any app files inside the current folder. Please provide the path to the ${forTest ? "test app" : "app"}.`);
}
const choices = listOfAppFiles.map((appName) => {
return {
name: appName.name,
value: appName.path,
};
});
choices.push({
name: "Enter path manually",
value: "manual",
});
const questions = [
{
type: "list",
name: "appPath",
message: forTest ? "Pick a test app" : "Pick an app",
choices: choices,
},
];
const answers = yield interaction_1.prompt.question(questions);
if (answers.appPath === "manual") {
let pathIsValid;
let filePath;
while (!pathIsValid) {
filePath = yield interaction_1.prompt(`Please provide the path to the ${forTest ? "test app" : "app"}.`);
if (filePath.length === 0) {
pathIsValid = false;
}
else {
pathIsValid = misc_1.fileExistsSync(path.resolve(filePath));
}
}
return filePath;
}
return answers.appPath;
});
}
isAsync() {
return __awaiter(this, void 0, void 0, function* () {
const questions = [
{
type: "list",
name: "isAsync",
message: "Should tests run in async mode?",
choices: [
{
name: "Yes",
value: "true",
},
{
name: "No",
value: "false",
},
],
},
];
const answers = yield interaction_1.prompt.question(questions);
return answers.isAsync === "true" ? true : false;
});
}
sortDeviceSets(a, b) {
if (a.name > b.name) {
return 1;
}
if (a.name < b.name) {
return -1;
}
return 0;
}
getDevices(client, app) {
return __awaiter(this, void 0, void 0, function* () {
const configs = yield client.test.getDeviceConfigurations(app.ownerName, app.appName);
// Sort devices list like it is done on AppCenter Portal
return configs.sort(deviceConfigurationSort_1.DeviceConfigurationSort.compare);
});
}
getApps(client) {
return __awaiter(this, void 0, void 0, function* () {
const apps = yield interaction_1.out.progress("Getting list of apps...", client.apps.list());
const choices = apps.map((app) => {
return {
name: app.name,
value: `${app.owner.name}/${app.name}`,
};
});
const question = [
{
type: "list",
name: "app",
message: "Pick an app to use",
choices: choices,
},
];
const answer = yield interaction_1.prompt.question(question);
return profile_1.toDefaultApp(answer.app);
});
}
promptDevices(deviceSets, app, client) {
return __awaiter(this, void 0, void 0, function* () {
let choices;
const noDeviceSets = deviceSets.length === 0;
if (noDeviceSets) {
const devices = yield interaction_1.out.progress("Getting list of devices...", this.getDevices(client, app));
choices = devices.map((config) => {
return {
name: config.name,
value: config.id,
};
});
}
else {
deviceSets = deviceSets.sort(this.sortDeviceSets);
choices = deviceSets.map((config) => {
return {
name: config.name,
value: config.slug,
};
});
choices.push({
name: "I want to use a single device",
value: "manual",
});
}
const questions = [
{
type: "list",
name: "deviceSlug",
message: noDeviceSets ? "Pick a device to use" : "Pick a device set to use",
choices: choices,
},
];
const answers = yield interaction_1.prompt.question(questions);
let deviceId;
if (noDeviceSets) {
const deviceSelection = yield client.test.createDeviceSelection(app.ownerName, app.appName, [answers.deviceSlug]);
deviceId = deviceSelection.shortId;
}
else {
if (answers.deviceSlug === "manual") {
return yield this.promptDevices([], app, client);
}
else {
deviceId = `${app.ownerName}/${answers.deviceSlug}`;
}
}
return deviceId;
});
}
scanFolder() {
return __awaiter(this, void 0, void 0, function* () {
const appNames = [];
this.scanRecurse(process.cwd(), appNames);
return appNames;
});
}
scanRecurse(dirname, appNames) {
const dirContent = fs.readdirSync(dirname);
for (const dir of dirContent) {
const fullDir = path.join(dirname, dir);
if (fs.lstatSync(fullDir).isDirectory()) {
if (dir !== "node_modules") {
this.scanRecurse(fullDir, appNames);
}
}
else {
if (this.isApplicationFile(dir)) {
const foundApp = {
name: path.relative(process.cwd(), fullDir),
path: fullDir,
};
if (!appNames) {
appNames = [foundApp];
}
else {
appNames.push(foundApp);
}
}
}
}
}
isApplicationFile(file) {
const fileExtension = path.parse(file).ext;
return (this.isAndroidApp && fileExtension === ".apk") || (!this.isAndroidApp && fileExtension === ".ipa");
}
printCalabashHelp() {
interaction_1.out.text(os.EOL +
`Interactive mode is not supported. Usage: appcenter test run calabash ${this.interactiveArgs.join(" ")}` +
os.EOL +
os.EOL +
"Additional parameters: " +
os.EOL +
`--project-dir: ${help_messages_1.Messages.TestCloud.Arguments.CalabashProjectDir}` +
os.EOL +
`--sign-info: ${help_messages_1.Messages.TestCloud.Arguments.CalabashSignInfo}` +
os.EOL +
`--config-path: ${help_messages_1.Messages.TestCloud.Arguments.CalabashConfigPath}` +
os.EOL +
`--profile: ${help_messages_1.Messages.TestCloud.Arguments.CalabashProfile}` +
os.EOL +
`--skip-config-check: ${help_messages_1.Messages.TestCloud.Arguments.CalabashSkipConfigCheck}`);
}
printManifestHelp() {
interaction_1.out.text(os.EOL +
`Interactive mode is not supported. Usage: appcenter test run manifest ${this.interactiveArgs.join(" ")}` +
os.EOL +
os.EOL +
"Additional parameters: " +
os.EOL +
`--manifest-path: Path to manifest file` +
os.EOL +
`--merged-file-name: ${help_messages_1.Messages.TestCloud.Arguments.MergedFileName}`);
}
};
WizardTestCommand = __decorate([
commandline_1.help(help_messages_1.Messages.TestCloud.Commands.Wizard)
], WizardTestCommand);
exports.default = WizardTestCommand;