UNPKG

appcenter-cli

Version:

Command line tool for Visual Studio App Center

363 lines (362 loc) 15.5 kB
"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;