@mablhq/mabl-cli 1.61.8 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Globals.js +11 -7
- package/api/basicApiClient.js +10 -10
- package/api/mablApiClient.js +39 -1
- package/browserLauncher/playwrightBrowserLauncher/playwrightBrowser.js +6 -6
- package/browserLauncher/playwrightBrowserLauncher/playwrightPage.js +8 -0
- package/cli.js +1 -0
- package/commands/app-files/app-files.js +5 -0
- package/commands/app-files/app-files_cmds/create.js +98 -0
- package/commands/app-files/app-files_cmds/delete.js +31 -0
- package/commands/app-files/app-files_cmds/download.js +50 -0
- package/commands/app-files/app-files_cmds/list.js +72 -0
- package/commands/config/config_cmds/install.js +92 -0
- package/commands/constants.js +10 -3
- package/commands/tests/testsUtil.js +45 -15
- package/commands/tests/tests_cmds/run-mobile.js +218 -0
- package/commands/tests/tests_cmds/run.js +11 -9
- package/core/util.js +36 -2
- package/env/defaultEnv.js +2 -1
- package/env/dev.js +2 -1
- package/env/env.js +3 -1
- package/env/local.js +2 -1
- package/env/prod.js +2 -1
- package/execution/index.js +13 -1
- package/execution/runAppiumServer.js +133 -0
- package/http/MablHttpAgent.js +4 -1
- package/http/RequestFilteringHttpAgent.js +3 -3
- package/http/axiosProxyConfig.js +27 -22
- package/http/httpUtil.js +6 -10
- package/mablApi/index.js +1 -1
- package/mablscript/MablAction.js +1 -1
- package/mablscript/MablStep.js +28 -2
- package/mablscript/MablStepV2.js +51 -0
- package/mablscript/MablSymbol.js +6 -2
- package/mablscript/actions/ExtractAction.js +11 -6
- package/mablscript/actions/FindAction.js +5 -5
- package/mablscript/actions/JavaScriptAction.js +19 -12
- package/mablscript/importer.js +97 -14
- package/mablscript/mobile/steps/CreateVariableMobileStep.js +53 -0
- package/mablscript/mobile/steps/EnterTextStep.js +41 -0
- package/mablscript/mobile/steps/NavigateBackStep.js +20 -0
- package/mablscript/mobile/steps/NavigateHomeStep.js +21 -0
- package/mablscript/mobile/steps/ScrollStep.js +37 -0
- package/mablscript/mobile/steps/SetOrientationStep.js +20 -0
- package/mablscript/mobile/steps/TapStep.js +37 -0
- package/mablscript/mobile/steps/actions/MobileFindAction.js +23 -0
- package/mablscript/mobile/steps/stepUtil.js +71 -0
- package/mablscript/mobile/tests/StepTestsUtil.js +20 -0
- package/mablscript/mobile/tests/TestMobileFindDescriptors.js +215 -0
- package/mablscript/mobile/tests/steps/CreateVariableMobileStep.mobiletest.js +287 -0
- package/mablscript/mobile/tests/steps/EnterTextStep.mobiletest.js +74 -0
- package/mablscript/mobile/tests/steps/GeneralHumanization.mobiletest.js +167 -0
- package/mablscript/mobile/tests/steps/NavigateBackStep.mobiletest.js +22 -0
- package/mablscript/mobile/tests/steps/NavigateHomeStep.mobiletest.js +22 -0
- package/mablscript/mobile/tests/steps/ScrollStep.mobiletest.js +112 -0
- package/mablscript/mobile/tests/steps/SetOrientationStep.mobiletest.js +27 -0
- package/mablscript/mobile/tests/steps/TapStep.mobiletest.js +53 -0
- package/mablscript/steps/AssertStep.js +48 -38
- package/mablscript/steps/AssertStepOld.js +30 -2
- package/mablscript/steps/CreateVariableStep.js +9 -2
- package/mablscript/steps/EchoStep.js +4 -3
- package/mablscript/steps/ElseIfConditionStep.js +8 -2
- package/mablscript/steps/ElseStep.js +2 -1
- package/mablscript/steps/EndStep.js +2 -1
- package/mablscript/steps/EvaluateJavaScriptStep.js +6 -1
- package/mablscript/steps/IfConditionStep.js +17 -10
- package/mablscript/steps/SendHttpRequestStep.js +4 -3
- package/mablscript/steps/WaitStep.js +4 -3
- package/mablscript/types/GetVariableDescriptor.js +8 -3
- package/mablscript/types/mobile/CreateVariableMobileStepDescriptor.js +9 -0
- package/mablscript/types/mobile/EnterTextStepDescriptor.js +2 -0
- package/mablscript/types/mobile/NavigateBackStepDescriptor.js +2 -0
- package/mablscript/types/mobile/NavigateHomeStepDescriptor.js +2 -0
- package/mablscript/types/mobile/ScrollStepDescriptor.js +2 -0
- package/mablscript/types/mobile/SetOrientationStepDescriptor.js +8 -0
- package/mablscript/types/mobile/StepWithMobileFindDescriptor.js +2 -0
- package/mablscript/types/mobile/TapStepDescriptor.js +8 -0
- package/mablscriptFind/index.js +1 -1
- package/package.json +13 -6
- package/resources/pdf-viewer/embeddedPdfDetection.js +1 -14
- package/resources/webdriver.js +21 -0
- package/upload/index.js +5 -0
- package/util/FileCache.js +180 -0
- package/util/Lazy.js +90 -0
- package/util/MobileAppFileCache.js +102 -0
- package/util/RichPromise.js +3 -1
- package/webdriver/index.js +41 -0
package/Globals.js
CHANGED
|
@@ -38,6 +38,15 @@ class Globals {
|
|
|
38
38
|
static setPlaywrightInteractionWarningMs(timeout) {
|
|
39
39
|
Globals.playwrightInteractionWarningMs = timeout;
|
|
40
40
|
}
|
|
41
|
+
static getSslCaDir() {
|
|
42
|
+
return Globals.sslCaDir;
|
|
43
|
+
}
|
|
44
|
+
static getTestMaxAgeMs() {
|
|
45
|
+
return Globals.testMaxAgeMs;
|
|
46
|
+
}
|
|
47
|
+
static setTestMaxAgeMs(age) {
|
|
48
|
+
Globals.testMaxAgeMs = age;
|
|
49
|
+
}
|
|
41
50
|
static getUploadDirectory() {
|
|
42
51
|
return Globals.uploadDirectory;
|
|
43
52
|
}
|
|
@@ -50,16 +59,11 @@ class Globals {
|
|
|
50
59
|
static setUploadDirectoryPrefix(prefix) {
|
|
51
60
|
Globals.uploadDirectoryPrefix = prefix;
|
|
52
61
|
}
|
|
53
|
-
static getTestMaxAgeMs() {
|
|
54
|
-
return Globals.testMaxAgeMs;
|
|
55
|
-
}
|
|
56
|
-
static setTestMaxAgeMs(age) {
|
|
57
|
-
Globals.testMaxAgeMs = age;
|
|
58
|
-
}
|
|
59
62
|
}
|
|
60
63
|
exports.Globals = Globals;
|
|
61
64
|
Globals.findOverallTimeoutMs = 18.5 * 60 * 1000;
|
|
62
65
|
Globals.playwrightInteractionWarningMs = 30 * 1000;
|
|
66
|
+
Globals.sslCaDir = '/usr/local/share/http-proxy-certs';
|
|
67
|
+
Globals.testMaxAgeMs = 1000 * 60 * 60 * 24;
|
|
63
68
|
Globals.uploadDirectory = os.tmpdir();
|
|
64
69
|
Globals.uploadDirectoryPrefix = `mablTestRunUploads-`;
|
|
65
|
-
Globals.testMaxAgeMs = 1000 * 60 * 60 * 24;
|
package/api/basicApiClient.js
CHANGED
|
@@ -55,6 +55,16 @@ const RETRYABLE_NODEJS_ERRORS = [
|
|
|
55
55
|
];
|
|
56
56
|
const DEFAULT_SSL_VERIFY = false;
|
|
57
57
|
class BasicApiClient {
|
|
58
|
+
static async create() {
|
|
59
|
+
const httpConfig = (await cliConfigProvider_1.CliConfigProvider.getCliConfig()).http.mabl;
|
|
60
|
+
return new BasicApiClient({
|
|
61
|
+
authType: types_1.AuthType.None,
|
|
62
|
+
token: '',
|
|
63
|
+
proxyUrl: httpConfig.proxyHost,
|
|
64
|
+
sslVerify: httpConfig.sslVerify,
|
|
65
|
+
proxyType: httpConfig.proxyType,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
58
68
|
constructor(options) {
|
|
59
69
|
var _a, _b, _c, _d, _e;
|
|
60
70
|
const config = (0, axiosProxyConfig_1.axiosProxyConfig)({
|
|
@@ -107,16 +117,6 @@ class BasicApiClient {
|
|
|
107
117
|
this.retryConfig = options.retryConfig;
|
|
108
118
|
this.debugLogger = (_e = options.debugLogger) !== null && _e !== void 0 ? _e : logUtils_1.logInternal;
|
|
109
119
|
}
|
|
110
|
-
static async create() {
|
|
111
|
-
const httpConfig = (await cliConfigProvider_1.CliConfigProvider.getCliConfig()).http.mabl;
|
|
112
|
-
return new BasicApiClient({
|
|
113
|
-
authType: types_1.AuthType.None,
|
|
114
|
-
token: '',
|
|
115
|
-
proxyUrl: httpConfig.proxyHost,
|
|
116
|
-
sslVerify: httpConfig.sslVerify,
|
|
117
|
-
proxyType: httpConfig.proxyType,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
120
|
getNonRetryableRequestConfig(override) {
|
|
121
121
|
const overrideWithTimeout = { ...(override !== null && override !== void 0 ? override : {}) };
|
|
122
122
|
if (!overrideWithTimeout.timeout) {
|
package/api/mablApiClient.js
CHANGED
|
@@ -867,10 +867,48 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
867
867
|
labels,
|
|
868
868
|
});
|
|
869
869
|
}
|
|
870
|
+
async getMobileAppFile(id, sign = false) {
|
|
871
|
+
let url = `${this.baseApiUrl}/mobile/apps/files/${id}`;
|
|
872
|
+
if (sign) {
|
|
873
|
+
url += '?sign=true';
|
|
874
|
+
}
|
|
875
|
+
try {
|
|
876
|
+
return await this.makeGetRequest(url);
|
|
877
|
+
}
|
|
878
|
+
catch (error) {
|
|
879
|
+
throw toApiError(`Failed to get mobile app file ${id}`, error);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
async getMobileAppFiles(workspaceId, limit) {
|
|
883
|
+
try {
|
|
884
|
+
const query = query_string_1.default.stringify({
|
|
885
|
+
workspace_id: workspaceId,
|
|
886
|
+
limit,
|
|
887
|
+
});
|
|
888
|
+
const mobileAppFiles = await this.makeGetRequest(`${this.baseApiUrl}/mobile/apps/files?${query}`).then((result) => { var _a; return (_a = result.mobile_app_files) !== null && _a !== void 0 ? _a : []; });
|
|
889
|
+
sortTemporallyDescending(mobileAppFiles);
|
|
890
|
+
return mobileAppFiles;
|
|
891
|
+
}
|
|
892
|
+
catch (error) {
|
|
893
|
+
throw toApiError(`Failed to get mobile app files`, error);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
async deleteMobileAppFile(id) {
|
|
897
|
+
try {
|
|
898
|
+
const response = await this.makeDeleteRequest(`${this.baseApiUrl}/mobile/apps/files/${id}`);
|
|
899
|
+
return response;
|
|
900
|
+
}
|
|
901
|
+
catch (error) {
|
|
902
|
+
throw toApiError(`Failed to delete mobile app file ${id}`, error);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
870
905
|
}
|
|
871
906
|
exports.MablApiClient = MablApiClient;
|
|
872
907
|
function sortTemporallyAscending(entities) {
|
|
873
|
-
entities.sort((a, b) =>
|
|
908
|
+
entities.sort((a, b) => a.created_time - b.created_time);
|
|
909
|
+
}
|
|
910
|
+
function sortTemporallyDescending(entities) {
|
|
911
|
+
entities.sort((a, b) => b.created_time - a.created_time);
|
|
874
912
|
}
|
|
875
913
|
function toApiError(summary, cause) {
|
|
876
914
|
const errorResponse = cause === null || cause === void 0 ? void 0 : cause.response;
|
|
@@ -41,6 +41,12 @@ const loggingProvider_1 = require("../../providers/logging/loggingProvider");
|
|
|
41
41
|
const playwrightApiResponse_1 = require("./playwrightApiResponse");
|
|
42
42
|
const httpUtil_1 = require("../../http/httpUtil");
|
|
43
43
|
class PlaywrightBrowser extends events_1.default {
|
|
44
|
+
static async create(browserType, defaultContext, downloadDirectory, browserWSEndpoint, preferenceDirectory, disableFocusEmulation) {
|
|
45
|
+
const delegate = getBrowserDelegate(browserType, defaultContext);
|
|
46
|
+
const browser = new PlaywrightBrowser(defaultContext, downloadDirectory, browserWSEndpoint, delegate, preferenceDirectory, disableFocusEmulation);
|
|
47
|
+
await delegate.setDownloadBehavior(downloadDirectory);
|
|
48
|
+
return browser;
|
|
49
|
+
}
|
|
44
50
|
constructor(defaultContext, downloadDirectory, browserWSEndpoint, browserDelegate, preferenceDirectory, disableFocusEmulation) {
|
|
45
51
|
super();
|
|
46
52
|
this.defaultContext = defaultContext;
|
|
@@ -69,12 +75,6 @@ class PlaywrightBrowser extends events_1.default {
|
|
|
69
75
|
await page.delegate.enableScreencastMode();
|
|
70
76
|
});
|
|
71
77
|
}
|
|
72
|
-
static async create(browserType, defaultContext, downloadDirectory, browserWSEndpoint, preferenceDirectory, disableFocusEmulation) {
|
|
73
|
-
const delegate = getBrowserDelegate(browserType, defaultContext);
|
|
74
|
-
const browser = new PlaywrightBrowser(defaultContext, downloadDirectory, browserWSEndpoint, delegate, preferenceDirectory, disableFocusEmulation);
|
|
75
|
-
await delegate.setDownloadBehavior(downloadDirectory);
|
|
76
|
-
return browser;
|
|
77
|
-
}
|
|
78
78
|
getBrowserPreferencesDirectory() {
|
|
79
79
|
return this.preferenceDirectory;
|
|
80
80
|
}
|
|
@@ -28,6 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.PlaywrightPage = void 0;
|
|
30
30
|
const events_1 = __importDefault(require("events"));
|
|
31
|
+
const promises_1 = require("fs/promises");
|
|
31
32
|
const browserLauncher_1 = require("../browserLauncher");
|
|
32
33
|
const playwright = __importStar(require("@playwright/test"));
|
|
33
34
|
const playwrightHttpResponse_1 = require("./playwrightHttpResponse");
|
|
@@ -352,5 +353,12 @@ class PlaywrightPage extends events_1.default {
|
|
|
352
353
|
async getContentAsMhtml() {
|
|
353
354
|
return this.delegate.getContentAsMhtml();
|
|
354
355
|
}
|
|
356
|
+
async download(url, destination, encoding = 'binary') {
|
|
357
|
+
const response = await this.page.request.fetch(url);
|
|
358
|
+
const body = await response.body();
|
|
359
|
+
if (body) {
|
|
360
|
+
await (0, promises_1.writeFile)(destination, body, { encoding });
|
|
361
|
+
}
|
|
362
|
+
}
|
|
355
363
|
}
|
|
356
364
|
exports.PlaywrightPage = PlaywrightPage;
|
package/cli.js
CHANGED
|
@@ -39,6 +39,7 @@ const hasInternalDirectory = fs_1.default.existsSync(path_1.default.resolve(__di
|
|
|
39
39
|
const excludeInternal = !hasInternalDirectory ? { exclude: /.*/gm } : undefined;
|
|
40
40
|
yargs
|
|
41
41
|
.scriptName(env_1.SCRIPT_NAME)
|
|
42
|
+
.commandDir('./commands/app-files')
|
|
42
43
|
.commandDir('./commands/applications')
|
|
43
44
|
.commandDir('./commands/auth')
|
|
44
45
|
.commandDir('./commands/branches')
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const promises_1 = require("node:fs/promises");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const loggingProvider_1 = require("../../../providers/logging/loggingProvider");
|
|
10
|
+
const mablApi_1 = require("../../../mablApi");
|
|
11
|
+
const mablApiClientFactory_1 = require("../../../api/mablApiClientFactory");
|
|
12
|
+
const util_1 = require("../../commandUtil/util");
|
|
13
|
+
const constants_1 = require("../../constants");
|
|
14
|
+
const upload_1 = require("../../../upload");
|
|
15
|
+
const env_1 = require("../../../env/env");
|
|
16
|
+
const authenticationProvider_1 = require("../../../providers/authenticationProvider");
|
|
17
|
+
const types_1 = require("../../../api/types");
|
|
18
|
+
exports.command = `create <${constants_1.CommandArgMobileAppFile}>`;
|
|
19
|
+
exports.describe = 'Upload and create a new mobile app file';
|
|
20
|
+
exports.builder = (yargs) => {
|
|
21
|
+
yargs
|
|
22
|
+
.positional(constants_1.CommandArgMobileAppFile, {
|
|
23
|
+
alias: constants_1.CommandArgAliases.File,
|
|
24
|
+
describe: 'Relative path to mobile app file',
|
|
25
|
+
})
|
|
26
|
+
.option(constants_1.CommandArgBranch, {
|
|
27
|
+
describe: 'Branch from which this mobile app file was built',
|
|
28
|
+
type: 'string',
|
|
29
|
+
})
|
|
30
|
+
.option(constants_1.CommandArgLabels, {
|
|
31
|
+
describe: 'Space delimited labels to save test with',
|
|
32
|
+
type: 'array',
|
|
33
|
+
})
|
|
34
|
+
.option(constants_1.CommandArgMobilePlatform, {
|
|
35
|
+
describe: 'The mobile platform',
|
|
36
|
+
defaultDescription: 'inferred from app binary extension',
|
|
37
|
+
type: 'string',
|
|
38
|
+
choices: [
|
|
39
|
+
mablApi_1.MobilePlatformEnum.Android.toString().toLowerCase(),
|
|
40
|
+
mablApi_1.MobilePlatformEnum.Ios.toString().toLowerCase(),
|
|
41
|
+
],
|
|
42
|
+
})
|
|
43
|
+
.option(constants_1.CommandArgVersion, {
|
|
44
|
+
describe: 'Version of this mobile app file',
|
|
45
|
+
type: 'string',
|
|
46
|
+
})
|
|
47
|
+
.option(constants_1.CommandArgWorkspaceId, {
|
|
48
|
+
alias: constants_1.CommandArgAliases.WorkspaceId,
|
|
49
|
+
describe: `Workspace to create mobile app file in`,
|
|
50
|
+
type: 'string',
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
exports.handler = (0, util_1.failWrapper)(createMobileAppFile);
|
|
54
|
+
async function createMobileAppFile(parsed) {
|
|
55
|
+
const { branch, labels, platform, version } = parsed;
|
|
56
|
+
const file = parsed[constants_1.CommandArgMobileAppFile];
|
|
57
|
+
const workspaceId = await (0, util_1.getWorkspaceId)(parsed);
|
|
58
|
+
const mobileAppFilePrototype = {
|
|
59
|
+
branch,
|
|
60
|
+
labels,
|
|
61
|
+
platform,
|
|
62
|
+
version,
|
|
63
|
+
workspace_id: workspaceId,
|
|
64
|
+
};
|
|
65
|
+
const { httpClient } = await mablApiClientFactory_1.MablApiClientFactory.createApiClient();
|
|
66
|
+
const uploadClient = new upload_1.UploadClient({
|
|
67
|
+
authorizationProvider: createAuthorizationProvider(),
|
|
68
|
+
httpClient,
|
|
69
|
+
uploadServiceUrl: new URL(env_1.UPLOAD_SERVICE_URL),
|
|
70
|
+
});
|
|
71
|
+
loggingProvider_1.logger.info(`Beginning upload of mobile app file ${(0, path_1.basename)((0, path_1.resolve)(file))} to ${workspaceId}`);
|
|
72
|
+
const mobileAppFile = await uploadClient.uploadMobileAppFile(file, mobileAppFilePrototype, await createUploadProgressListener(file));
|
|
73
|
+
loggingProvider_1.logger.info(chalk_1.default.green(`Created mobile app file ${chalk_1.default.bold(mobileAppFile.id)}`));
|
|
74
|
+
}
|
|
75
|
+
function createAuthorizationProvider() {
|
|
76
|
+
const authProvider = new authenticationProvider_1.AuthenticationProvider();
|
|
77
|
+
return async () => {
|
|
78
|
+
const { accessToken, authType } = await authProvider.getAuthConfigWithAutoRenew();
|
|
79
|
+
switch (authType) {
|
|
80
|
+
case types_1.AuthType.ApiKey:
|
|
81
|
+
return { key: `${accessToken}`, type: 'key' };
|
|
82
|
+
case types_1.AuthType.Bearer:
|
|
83
|
+
return { bearer: `${accessToken}`, type: 'bearer' };
|
|
84
|
+
default:
|
|
85
|
+
throw new Error(`Invalid auth type: [${authType}]`);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async function createUploadProgressListener(filePath) {
|
|
90
|
+
const fileName = (0, path_1.basename)((0, path_1.resolve)(filePath));
|
|
91
|
+
const { size } = await (0, promises_1.stat)(filePath);
|
|
92
|
+
let totalBytesSent = 0;
|
|
93
|
+
return ({ chunkSizeBytes }) => {
|
|
94
|
+
totalBytesSent += chunkSizeBytes;
|
|
95
|
+
const completedPercentage = Math.round((totalBytesSent / size) * 100.0);
|
|
96
|
+
loggingProvider_1.logger.info(`Uploaded ${totalBytesSent}b of ${size}b (${completedPercentage}%) of mobile app file ${fileName}`);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const mablApiClientFactory_1 = require("../../../api/mablApiClientFactory");
|
|
7
|
+
const constants_1 = require("../../constants");
|
|
8
|
+
const util_1 = require("../../commandUtil/util");
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const loggingProvider_1 = require("../../../providers/logging/loggingProvider");
|
|
11
|
+
exports.command = `delete <${constants_1.CommandArgId}>`;
|
|
12
|
+
exports.describe = 'Delete a mobile app file.';
|
|
13
|
+
exports.builder = (yargs) => {
|
|
14
|
+
yargs.positional(constants_1.CommandArgId, {
|
|
15
|
+
describe: 'id of the mobile app file',
|
|
16
|
+
type: 'string',
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
exports.handler = (0, util_1.failWrapper)(deleteMobileAppFile);
|
|
20
|
+
async function deleteMobileAppFile(parsed) {
|
|
21
|
+
try {
|
|
22
|
+
const apiClient = await mablApiClientFactory_1.MablApiClientFactory.createApiClient();
|
|
23
|
+
const id = parsed[constants_1.CommandArgId];
|
|
24
|
+
await apiClient.deleteMobileAppFile(id);
|
|
25
|
+
loggingProvider_1.logger.info(chalk_1.default.green(`Mobile app file ${chalk_1.default.bold(id)} DELETED`));
|
|
26
|
+
return id;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
throw new Error(`Error deleting mobile app file: ${error}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const promises_1 = require("fs/promises");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const constants_1 = require("../../constants");
|
|
10
|
+
const util_1 = require("../../commandUtil/util");
|
|
11
|
+
const MobileAppFileCache_1 = require("../../../util/MobileAppFileCache");
|
|
12
|
+
const loggingProvider_1 = require("../../../providers/logging/loggingProvider");
|
|
13
|
+
exports.command = `download <${constants_1.CommandArgId}> <${constants_1.CommandArgDestination}>`;
|
|
14
|
+
exports.describe = 'Download a mobile app file.';
|
|
15
|
+
exports.builder = (yargs) => {
|
|
16
|
+
yargs
|
|
17
|
+
.positional(constants_1.CommandArgId, {
|
|
18
|
+
describe: 'id of the mobile app file',
|
|
19
|
+
type: 'string',
|
|
20
|
+
})
|
|
21
|
+
.positional(constants_1.CommandArgDestination, {
|
|
22
|
+
describe: 'Relative path to destionation directory or file',
|
|
23
|
+
type: 'string',
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
exports.handler = (0, util_1.failWrapper)(downloadMobileAppFile);
|
|
27
|
+
async function downloadMobileAppFile(parsed) {
|
|
28
|
+
try {
|
|
29
|
+
const id = parsed[constants_1.CommandArgId];
|
|
30
|
+
const destination = parsed[constants_1.CommandArgDestination];
|
|
31
|
+
const mobileAppFile = await new MobileAppFileCache_1.MobileAppFileCache().getMobileAppFile(id);
|
|
32
|
+
const downloadPath = await resolveDestination(destination, mobileAppFile);
|
|
33
|
+
await (0, promises_1.copyFile)(mobileAppFile.path, downloadPath);
|
|
34
|
+
loggingProvider_1.logger.info(chalk_1.default.green(`Mobile app file downloaded to ${downloadPath}`));
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
throw new Error(`Error downloading mobile app file: ${error}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function resolveDestination(destination, mobileAppFile) {
|
|
41
|
+
let path = destination;
|
|
42
|
+
try {
|
|
43
|
+
if ((await (0, promises_1.stat)(destination)).isDirectory()) {
|
|
44
|
+
path = (0, path_1.join)(destination, mobileAppFile.name);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
}
|
|
49
|
+
return (0, path_1.resolve)(path);
|
|
50
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const js_yaml_1 = require("js-yaml");
|
|
7
|
+
const mablApiClientFactory_1 = require("../../../api/mablApiClientFactory");
|
|
8
|
+
const util_1 = require("../../commandUtil/util");
|
|
9
|
+
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
10
|
+
const moment = require("moment");
|
|
11
|
+
const list_1 = require("../../commandUtil/list");
|
|
12
|
+
const loggingProvider_1 = require("../../../providers/logging/loggingProvider");
|
|
13
|
+
const constants_1 = require("../../constants");
|
|
14
|
+
exports.command = 'list';
|
|
15
|
+
exports.describe = 'List your mobile app files';
|
|
16
|
+
exports.builder = (0, list_1.getListBuilderOptions)('mobile app files');
|
|
17
|
+
exports.handler = (0, util_1.failWrapper)(listMobileAppFiles);
|
|
18
|
+
async function listMobileAppFiles(parsed) {
|
|
19
|
+
const output = parsed.output;
|
|
20
|
+
const workspaceId = await (0, util_1.getWorkspaceId)(parsed);
|
|
21
|
+
const limit = parsed.limit;
|
|
22
|
+
const apiClient = await mablApiClientFactory_1.MablApiClientFactory.createApiClient();
|
|
23
|
+
const mobileAppFiles = await apiClient.getMobileAppFiles(workspaceId, limit);
|
|
24
|
+
printMobileAppFiles(mobileAppFiles, output);
|
|
25
|
+
return mobileAppFiles.length;
|
|
26
|
+
}
|
|
27
|
+
function printMobileAppFiles(mobileAppFiles, output) {
|
|
28
|
+
switch (output) {
|
|
29
|
+
case 'json':
|
|
30
|
+
loggingProvider_1.logger.info(JSON.stringify(mobileAppFiles, undefined, 2));
|
|
31
|
+
break;
|
|
32
|
+
case 'yaml':
|
|
33
|
+
loggingProvider_1.logger.info((0, js_yaml_1.dump)(mobileAppFiles));
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
const table = new cli_table3_1.default({
|
|
37
|
+
head: [
|
|
38
|
+
'ID',
|
|
39
|
+
'Platform',
|
|
40
|
+
'Name',
|
|
41
|
+
'Version',
|
|
42
|
+
'Branch',
|
|
43
|
+
'Labels',
|
|
44
|
+
'Created time',
|
|
45
|
+
],
|
|
46
|
+
wordWrap: true,
|
|
47
|
+
});
|
|
48
|
+
mobileAppFiles.forEach((mobileAppFile) => {
|
|
49
|
+
table.push([
|
|
50
|
+
{ rowSpan: 1, content: mobileAppFile.id, vAlign: 'center' },
|
|
51
|
+
{ rowSpan: 1, content: mobileAppFile.platform, vAlign: 'center' },
|
|
52
|
+
{ rowSpan: 1, content: mobileAppFile.name, vAlign: 'center' },
|
|
53
|
+
{ rowSpan: 1, content: mobileAppFile.version, vAlign: 'center' },
|
|
54
|
+
{ rowSpan: 1, content: mobileAppFile.branch, vAlign: 'center' },
|
|
55
|
+
{
|
|
56
|
+
rowSpan: 1,
|
|
57
|
+
content: JSON.stringify(mobileAppFile.labels, undefined, 2),
|
|
58
|
+
vAlign: 'center',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
rowSpan: 1,
|
|
62
|
+
content: moment
|
|
63
|
+
.utc(mobileAppFile.created_time)
|
|
64
|
+
.format(constants_1.ListTimeFormat),
|
|
65
|
+
vAlign: 'center',
|
|
66
|
+
},
|
|
67
|
+
]);
|
|
68
|
+
});
|
|
69
|
+
loggingProvider_1.logger.info(table.toString());
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.AddOnOptions = void 0;
|
|
27
|
+
const child_process_1 = require("child_process");
|
|
28
|
+
const loggingProvider_1 = require("../../../providers/logging/loggingProvider");
|
|
29
|
+
const fs = __importStar(require("fs"));
|
|
30
|
+
const path = __importStar(require("path"));
|
|
31
|
+
const resourceUtil_1 = require("../../../util/resourceUtil");
|
|
32
|
+
const OperatingSystemDescriptor_1 = require("../../../mablscript/types/OperatingSystemDescriptor");
|
|
33
|
+
const UI_AUTOMATOR_VERSION = '2.29.5';
|
|
34
|
+
const XCUITEST_VERSION = '4.34.1';
|
|
35
|
+
const addOnConfigKey = 'add-on';
|
|
36
|
+
var AddOnOptions;
|
|
37
|
+
(function (AddOnOptions) {
|
|
38
|
+
AddOnOptions["mobile"] = "mobile-tools";
|
|
39
|
+
})(AddOnOptions = exports.AddOnOptions || (exports.AddOnOptions = {}));
|
|
40
|
+
exports.command = `install <${addOnConfigKey}>`;
|
|
41
|
+
exports.describe = false;
|
|
42
|
+
exports.builder = (yargs) => {
|
|
43
|
+
yargs
|
|
44
|
+
.positional(addOnConfigKey, {
|
|
45
|
+
describe: 'add-on to install',
|
|
46
|
+
type: 'string',
|
|
47
|
+
choices: [AddOnOptions.mobile],
|
|
48
|
+
})
|
|
49
|
+
.option('android', {
|
|
50
|
+
describe: `[${AddOnOptions.mobile}] The android driver version to use`,
|
|
51
|
+
type: 'string',
|
|
52
|
+
})
|
|
53
|
+
.option('ios', {
|
|
54
|
+
describe: `[${AddOnOptions.mobile}] The ios driver version to use`,
|
|
55
|
+
type: 'string',
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
exports.handler = installAddOn;
|
|
59
|
+
function installAddOn(parsed) {
|
|
60
|
+
var _a, _b;
|
|
61
|
+
const addOn = parsed[addOnConfigKey];
|
|
62
|
+
const iosVersion = (_a = parsed.ios) !== null && _a !== void 0 ? _a : XCUITEST_VERSION;
|
|
63
|
+
const androidVersion = (_b = parsed.android) !== null && _b !== void 0 ? _b : UI_AUTOMATOR_VERSION;
|
|
64
|
+
switch (addOn) {
|
|
65
|
+
case AddOnOptions.mobile:
|
|
66
|
+
loggingProvider_1.logger.info('Installing mobile add on tools');
|
|
67
|
+
const operatingSystem = (0, OperatingSystemDescriptor_1.getOperatingSystem)();
|
|
68
|
+
const parentDirOfNodeModulesDir = (0, resourceUtil_1.findNodeModulesDirectories)()[0];
|
|
69
|
+
switch (operatingSystem) {
|
|
70
|
+
case OperatingSystemDescriptor_1.OperatingSystem.MACOS:
|
|
71
|
+
loggingProvider_1.logger.info(`android version: ${androidVersion}`);
|
|
72
|
+
loggingProvider_1.logger.info(`ios version: ${iosVersion}`);
|
|
73
|
+
(0, child_process_1.execSync)(`npm install appium-uiautomator2-driver@${androidVersion} appium-xcuitest-driver@${iosVersion}`, { cwd: parentDirOfNodeModulesDir });
|
|
74
|
+
break;
|
|
75
|
+
default:
|
|
76
|
+
loggingProvider_1.logger.info(`android version: ${androidVersion}`);
|
|
77
|
+
loggingProvider_1.logger.info(`ios driver only supported on Mac OS, ${operatingSystem} platform detected`);
|
|
78
|
+
(0, child_process_1.execSync)(`npm install appium-uiautomator2-driver@${androidVersion}`, {
|
|
79
|
+
cwd: parentDirOfNodeModulesDir,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
console.log(`${parentDirOfNodeModulesDir}/node_modules/.cache/appium/extensions.yaml`);
|
|
83
|
+
const pathToExtenstionsFile = path.resolve(`${parentDirOfNodeModulesDir}/node_modules/.cache/appium/extensions.yaml`);
|
|
84
|
+
if (fs.existsSync(pathToExtenstionsFile)) {
|
|
85
|
+
fs.unlinkSync(pathToExtenstionsFile);
|
|
86
|
+
}
|
|
87
|
+
loggingProvider_1.logger.info('Installation of mobile add on tools complete');
|
|
88
|
+
return;
|
|
89
|
+
default:
|
|
90
|
+
throw new Error(`Invalid add on provided [${addOn}]`);
|
|
91
|
+
}
|
|
92
|
+
}
|
package/commands/constants.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.SCENARIO_ID_HEADER = exports.SCENARIO_NAME_HEADER = exports.ValidBrowserTypesForLocalRuns = exports.BrowserTypeSelections = exports.DefaultBrowserType = exports.DefaultBranchName = exports.DefaultOutputFormatChoices = exports.DetailLevelFormats = exports.ReporterOptions = exports.OutputFormats = exports.CommandArgAliases = exports.CommandArgBrowserEnableExtensions = exports.CommandArgBrowserIgnoreCertificateErrors = exports.CommandArgBrowserDisableIsolation = exports.ListTimeFormat = exports.CommandArgTimezoneID = exports.CommandArgLocale = exports.CommandArgScenarioId = exports.CommandArgReporterOptions = exports.CommandArgReporter = exports.CommandArgWorkspaceId = exports.CommandArgVersion = exports.CommandArgVariables = exports.CommandArgUrlApi = exports.CommandArgUrlApp = exports.CommandArgUrl = exports.CommandArgTrainerVersion = exports.CommandArgTo = exports.CommandArgSilent = exports.CommandArgRevision = exports.CommandArgMaxHeartbeatAge = exports.CommandArgPlanId = void 0;
|
|
3
|
+
exports.CommandArgPrompt = exports.CommandArgPortNumber = exports.CommandArgName = exports.CommandArgMobileDeviceName = exports.CommandArgMobilePlatform = exports.CommandArgMobileAppFileId = exports.CommandArgMobileAppFile = exports.CommandArgMablBranchChangesOnly = exports.CommandArgMablBranch = exports.CommandArgMablAutoLogin = exports.CommandArgMablAutoBranch = exports.CommandArgLinkBypass = exports.CommandArgLinkLabel = exports.CommandArgLimitOutput = exports.CommandArgLabels = exports.CommandArgLabelsInclude = exports.CommandArgLabelsExclude = exports.CommandArgTestInteractionSpeed = exports.CommandArgTestRunId = exports.CommandArgTestFile = exports.CommandArgKeepBrowserOpen = exports.CommandArgInput = exports.CommandArgId = exports.CommandArgUserAgent = exports.CommandArgHttpHeaders = exports.CommandArgHelp = exports.CommandArgHeadless = exports.CommandArgFromPlanId = exports.CommandArgFrom = exports.CommandArgFormat = exports.CommandArgFindPath = exports.CommandArgFastFailure = exports.CommandArgOverrideEnvironmentId = exports.CommandArgExistingReport = exports.CommandArgEnvironmentId = exports.CommandArgDetailLevel = exports.CommandArgDestination = exports.CommandArgDescription = exports.CommandArgDeploymentId = exports.CommandArgDecrypt = exports.CommandArgDataTables = exports.CommandArgDataTableId = exports.CommandArgCredentials = exports.CommandArgBasicAuthCredentials = exports.CommandArgBrowsers = exports.CommandArgBrowser = exports.CommandArgBranch = exports.CommandArgApplicationId = exports.CommandArgApiKey = exports.CommandArgABConfigFile = void 0;
|
|
4
|
+
exports.SCENARIO_ID_HEADER = exports.SCENARIO_NAME_HEADER = exports.ValidBrowserTypesForLocalRuns = exports.BrowserTypeSelections = exports.DefaultBrowserType = exports.DefaultBranchName = exports.DefaultOutputFormatChoices = exports.DetailLevelFormats = exports.ReporterOptions = exports.OutputFormats = exports.CommandArgAliases = exports.CommandArgBrowserEnableExtensions = exports.CommandArgBrowserIgnoreCertificateErrors = exports.CommandArgBrowserDisableIsolation = exports.ListTimeFormat = exports.CommandArgTimezoneID = exports.CommandArgLocale = exports.CommandArgUseTestExecutionProxy = exports.CommandArgScenarioId = exports.CommandArgReporterOptions = exports.CommandArgReporter = exports.CommandArgWorkspaceId = exports.CommandArgVersion = exports.CommandArgVariables = exports.CommandArgUrlApi = exports.CommandArgUrlApp = exports.CommandArgUrl = exports.CommandArgTrainerVersion = exports.CommandArgTo = exports.CommandArgSilent = exports.CommandArgRevision = exports.CommandArgMaxHeartbeatAge = exports.CommandArgPlanId = exports.CommandArgContentTypes = exports.CommandArgPreview = exports.CommandArgOutputFilePath = exports.CommandArgOutput = exports.CommandArgNoPrompt = void 0;
|
|
5
5
|
const browserTypes_1 = require("./browserTypes");
|
|
6
6
|
exports.CommandArgABConfigFile = 'ab-config-file';
|
|
7
7
|
exports.CommandArgApiKey = 'api-key';
|
|
8
8
|
exports.CommandArgApplicationId = 'application-id';
|
|
9
|
+
exports.CommandArgBranch = 'branch';
|
|
9
10
|
exports.CommandArgBrowser = 'browser';
|
|
10
11
|
exports.CommandArgBrowsers = 'browsers';
|
|
11
12
|
exports.CommandArgBasicAuthCredentials = 'basic-auth-credentials-id';
|
|
@@ -15,8 +16,8 @@ exports.CommandArgDataTables = 'data-tables';
|
|
|
15
16
|
exports.CommandArgDecrypt = 'decrypt';
|
|
16
17
|
exports.CommandArgDeploymentId = 'deployment-id';
|
|
17
18
|
exports.CommandArgDescription = 'description';
|
|
19
|
+
exports.CommandArgDestination = 'destination';
|
|
18
20
|
exports.CommandArgDetailLevel = 'detail-level';
|
|
19
|
-
exports.CommandArgEnableLink = 'enable-link';
|
|
20
21
|
exports.CommandArgEnvironmentId = 'environment-id';
|
|
21
22
|
exports.CommandArgExistingReport = 'existing-report';
|
|
22
23
|
exports.CommandArgOverrideEnvironmentId = 'override-environment-id';
|
|
@@ -45,6 +46,10 @@ exports.CommandArgMablAutoBranch = 'auto-branch';
|
|
|
45
46
|
exports.CommandArgMablAutoLogin = 'auto-login';
|
|
46
47
|
exports.CommandArgMablBranch = 'mabl-branch';
|
|
47
48
|
exports.CommandArgMablBranchChangesOnly = 'branch-changes-only';
|
|
49
|
+
exports.CommandArgMobileAppFile = 'app-file';
|
|
50
|
+
exports.CommandArgMobileAppFileId = 'app-file-id';
|
|
51
|
+
exports.CommandArgMobilePlatform = 'platform';
|
|
52
|
+
exports.CommandArgMobileDeviceName = 'device';
|
|
48
53
|
exports.CommandArgName = 'name';
|
|
49
54
|
exports.CommandArgPortNumber = 'port';
|
|
50
55
|
exports.CommandArgPrompt = 'prompt';
|
|
@@ -68,6 +73,7 @@ exports.CommandArgWorkspaceId = 'workspace-id';
|
|
|
68
73
|
exports.CommandArgReporter = 'reporter';
|
|
69
74
|
exports.CommandArgReporterOptions = 'reporter-options';
|
|
70
75
|
exports.CommandArgScenarioId = 'scenario-id';
|
|
76
|
+
exports.CommandArgUseTestExecutionProxy = 'use-test-execution-proxy';
|
|
71
77
|
exports.CommandArgLocale = 'locale';
|
|
72
78
|
exports.CommandArgTimezoneID = 'timezone-id';
|
|
73
79
|
exports.ListTimeFormat = 'MMM Do YYYY, HH:mm:ss';
|
|
@@ -85,6 +91,7 @@ var CommandArgAliases;
|
|
|
85
91
|
CommandArgAliases["Credentials"] = "creds";
|
|
86
92
|
CommandArgAliases["DeploymentId"] = "d";
|
|
87
93
|
CommandArgAliases["EnvironmentId"] = "e";
|
|
94
|
+
CommandArgAliases["File"] = "f";
|
|
88
95
|
CommandArgAliases["LimitOutput"] = "l";
|
|
89
96
|
CommandArgAliases["Name"] = "n";
|
|
90
97
|
CommandArgAliases["NoPrompt"] = "yes";
|