@mablhq/mabl-cli 1.43.1 → 1.43.10
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/browserLauncher/playwrightBrowserLauncher/playwrightPage.js +4 -3
- package/commands/tests/testsUtil.js +1 -35
- package/core/trainer/trainingSessions.js +3 -2
- package/execution/index.js +1 -1
- package/package.json +4 -3
- package/providers/exportRequestProvider.js +19 -3
- package/util/clickUtil.js +53 -0
- package/util/javaScriptStepMigration.js +114 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mablhq/mabl-cli",
|
|
3
|
-
"version": "1.43.
|
|
3
|
+
"version": "1.43.10",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
5
5
|
"description": "The official mabl command line interface tool",
|
|
6
6
|
"main": "index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@mablhq/newman-reporter-mabl-console": "0.1.0",
|
|
24
|
-
"@playwright/test": "1.
|
|
24
|
+
"@playwright/test": "1.27.1",
|
|
25
25
|
"@types/fs-extra": "8.1.1",
|
|
26
26
|
"@types/serve-handler": "6.1.0",
|
|
27
27
|
"@types/tmp": "0.2.0",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"decompress-zip": "0.2.2",
|
|
43
43
|
"encodeurl": "1.0.2",
|
|
44
44
|
"env-paths": "2.2.0",
|
|
45
|
+
"escodegen": "2.0.0",
|
|
45
46
|
"esprima": "4.0.1",
|
|
46
47
|
"estraverse": "4.3.0",
|
|
47
48
|
"fast-json-stable-stringify": "2.1.0",
|
|
@@ -66,7 +67,7 @@
|
|
|
66
67
|
"newman": "5.3.2",
|
|
67
68
|
"open": "6.4.0",
|
|
68
69
|
"ora": "4.0.4",
|
|
69
|
-
"playwright-core": "1.
|
|
70
|
+
"playwright-core": "1.27.1",
|
|
70
71
|
"pluralize": "8.0.0",
|
|
71
72
|
"pngjs": "6.0.0",
|
|
72
73
|
"portfinder": "1.0.28",
|
|
@@ -120,13 +120,29 @@ class ExportRequestProvider {
|
|
|
120
120
|
text: `Downloading export artifact to [${chalk.magenta.bold(outputFilename)}]`,
|
|
121
121
|
}).start();
|
|
122
122
|
const client = await basicApiClient_1.BasicApiClient.create();
|
|
123
|
-
const
|
|
123
|
+
const responseData = await client.makeGetRequest(downloadUrl, undefined, {
|
|
124
124
|
headers: {
|
|
125
125
|
Accept: 'application/zip',
|
|
126
126
|
},
|
|
127
|
-
responseType: '
|
|
127
|
+
responseType: 'stream',
|
|
128
|
+
});
|
|
129
|
+
const writer = fs.createWriteStream(outputFilename);
|
|
130
|
+
await new Promise((resolve, reject) => {
|
|
131
|
+
try {
|
|
132
|
+
responseData.pipe(writer);
|
|
133
|
+
writer.on('error', (err) => {
|
|
134
|
+
writer.close();
|
|
135
|
+
reject(err);
|
|
136
|
+
});
|
|
137
|
+
writer.on('finish', () => {
|
|
138
|
+
writer.close();
|
|
139
|
+
resolve();
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch (exception) {
|
|
143
|
+
reject(exception);
|
|
144
|
+
}
|
|
128
145
|
});
|
|
129
|
-
fs.writeFileSync(outputFilename, response);
|
|
130
146
|
updateSpinnerSuccessStop(this.exportDownloadSpinner);
|
|
131
147
|
return outputFilename;
|
|
132
148
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clickOnElement = exports.ClickType = void 0;
|
|
4
|
+
const messaging_1 = require("../core/messaging/messaging");
|
|
5
|
+
const loggingProvider_1 = require("../providers/logging/loggingProvider");
|
|
6
|
+
const actionabilityUtil_1 = require("./actionabilityUtil");
|
|
7
|
+
const logUtils_1 = require("./logUtils");
|
|
8
|
+
var ClickType;
|
|
9
|
+
(function (ClickType) {
|
|
10
|
+
ClickType[ClickType["LeftClick"] = 0] = "LeftClick";
|
|
11
|
+
ClickType[ClickType["DoubleClick"] = 1] = "DoubleClick";
|
|
12
|
+
})(ClickType = exports.ClickType || (exports.ClickType = {}));
|
|
13
|
+
async function clickOnElement(elementHandle, executionContext, clickType) {
|
|
14
|
+
const trialClickOptions = {
|
|
15
|
+
trial: true,
|
|
16
|
+
minimizeScrollIntoView: executionContext.browserConfig.minimizeScrollIntoView,
|
|
17
|
+
};
|
|
18
|
+
const elementHandleTrialClickAction = clickType === ClickType.LeftClick
|
|
19
|
+
? () => elementHandle.click(trialClickOptions)
|
|
20
|
+
: () => elementHandle.doubleClick(trialClickOptions);
|
|
21
|
+
const noOverlappingElement = await (0, actionabilityUtil_1.checkPopupDismissalOnAction)(elementHandle, elementHandleTrialClickAction, executionContext);
|
|
22
|
+
const elementBoundingBox = await elementHandle.boundingBox();
|
|
23
|
+
const elementHasSurfaceArea = elementBoundingBox
|
|
24
|
+
? elementBoundingBox.height > 0 && elementBoundingBox.width > 0
|
|
25
|
+
: false;
|
|
26
|
+
if (!noOverlappingElement || !elementHasSurfaceArea) {
|
|
27
|
+
const jsClickReasons = [
|
|
28
|
+
!noOverlappingElement && "there is a popup we couldn't dismiss",
|
|
29
|
+
!elementHasSurfaceArea && 'the element is not visible',
|
|
30
|
+
]
|
|
31
|
+
.filter((reason) => reason !== false)
|
|
32
|
+
.join(' and ');
|
|
33
|
+
const clickText = clickType === ClickType.LeftClick ? 'click' : 'double click';
|
|
34
|
+
(0, logUtils_1.logWebUIAndCliOutput)(`Attempting ${clickText} with javascript because ${jsClickReasons}`, loggingProvider_1.LogLevel.Warn, executionContext, {
|
|
35
|
+
executionPhase: messaging_1.ExecutionPhase.DURING_ACTION,
|
|
36
|
+
});
|
|
37
|
+
if (noOverlappingElement) {
|
|
38
|
+
await (0, actionabilityUtil_1.maybeAddPopupLogic)(elementHandle);
|
|
39
|
+
}
|
|
40
|
+
const jsClickEventFirer = clickType === ClickType.LeftClick
|
|
41
|
+
? (element) => window.popupDismissal.fireClickEvent(element)
|
|
42
|
+
: (element) => window.popupDismissal.fireDoubleClickEvent(element);
|
|
43
|
+
return elementHandle.evaluate(jsClickEventFirer);
|
|
44
|
+
}
|
|
45
|
+
const finalClickOptions = {
|
|
46
|
+
timeout: 0,
|
|
47
|
+
minimizeScrollIntoView: executionContext.browserConfig.minimizeScrollIntoView,
|
|
48
|
+
};
|
|
49
|
+
return clickType === ClickType.LeftClick
|
|
50
|
+
? elementHandle.click(finalClickOptions)
|
|
51
|
+
: elementHandle.doubleClick(finalClickOptions);
|
|
52
|
+
}
|
|
53
|
+
exports.clickOnElement = clickOnElement;
|
|
@@ -0,0 +1,114 @@
|
|
|
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.normalizeScript = exports.hasVariableReferences = exports.attemptReusableSnippetParameterization = exports.attemptMigrationToParameterizedStep = void 0;
|
|
27
|
+
const typescript_api_client_nodejs_1 = require("@mablhq/typescript-api-client-nodejs");
|
|
28
|
+
const encodingUtil_1 = require("./encodingUtil");
|
|
29
|
+
const esprima = __importStar(require("esprima"));
|
|
30
|
+
const escodegen = __importStar(require("escodegen"));
|
|
31
|
+
const loggingProvider_1 = require("../providers/logging/loggingProvider");
|
|
32
|
+
function attemptMigrationToParameterizedStep(descriptor) {
|
|
33
|
+
let hasVariables;
|
|
34
|
+
let migrationDisabled;
|
|
35
|
+
try {
|
|
36
|
+
const decodedJS = (0, encodingUtil_1.b64DecodeUnicodeInNode)(descriptor.encodedJS);
|
|
37
|
+
migrationDisabled = isMigrationDisabled(decodedJS);
|
|
38
|
+
hasVariables = hasVariableReferences(decodedJS);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
loggingProvider_1.logger.warn(`Failed to determine if the inline snippet uses variables: ${error}`);
|
|
42
|
+
return descriptor;
|
|
43
|
+
}
|
|
44
|
+
if (migrationDisabled) {
|
|
45
|
+
return descriptor;
|
|
46
|
+
}
|
|
47
|
+
if (hasVariables) {
|
|
48
|
+
return descriptor;
|
|
49
|
+
}
|
|
50
|
+
loggingProvider_1.logger.info('Converting legacy inline JavaScript step to parameterized step.');
|
|
51
|
+
return migrateInlineDescriptor(descriptor);
|
|
52
|
+
}
|
|
53
|
+
exports.attemptMigrationToParameterizedStep = attemptMigrationToParameterizedStep;
|
|
54
|
+
function migrateInlineDescriptor(descriptor) {
|
|
55
|
+
return {
|
|
56
|
+
inlineSnippet: {
|
|
57
|
+
body: descriptor.encodedJS,
|
|
58
|
+
description: '',
|
|
59
|
+
name: 'Unnamed snippet',
|
|
60
|
+
parameters: [],
|
|
61
|
+
snippet_type: typescript_api_client_nodejs_1.Snippet.SnippetTypeEnum.Javascript,
|
|
62
|
+
},
|
|
63
|
+
parameterOverrides: [],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function attemptReusableSnippetParameterization(snippet) {
|
|
67
|
+
if (Array.isArray(snippet.parameters)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (!snippet.body) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
let hasVariables;
|
|
74
|
+
let migrationDisabled;
|
|
75
|
+
try {
|
|
76
|
+
const decodedJS = (0, encodingUtil_1.b64DecodeUnicodeInNode)(snippet.body);
|
|
77
|
+
migrationDisabled = isMigrationDisabled(decodedJS);
|
|
78
|
+
hasVariables = hasVariableReferences(decodedJS);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
loggingProvider_1.logger.warn(`Failed to determine if the reusable snippet uses variables: ${error}`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (migrationDisabled) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (hasVariables) {
|
|
88
|
+
loggingProvider_1.logger.info(`Skipping snippet parameter conversion due to variable usage. Snippet ID: ${snippet.id}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
loggingProvider_1.logger.info(`Migrating legacy snippet to parameterized snippet. Snippet ID: ${snippet.id}`);
|
|
92
|
+
snippet.parameters = [];
|
|
93
|
+
}
|
|
94
|
+
exports.attemptReusableSnippetParameterization = attemptReusableSnippetParameterization;
|
|
95
|
+
function isMigrationDisabled(decodedScript) {
|
|
96
|
+
return decodedScript.indexOf('@mabl-disable-parameterization') >= 0;
|
|
97
|
+
}
|
|
98
|
+
function hasVariableReferences(decodedScript) {
|
|
99
|
+
const normalizedCode = normalizeScript(decodedScript);
|
|
100
|
+
const hasSignature = normalizedCode.indexOf('function mablJavaScriptStep(mablInputs') >= 0;
|
|
101
|
+
if (!hasSignature) {
|
|
102
|
+
throw new Error('Did not find expected mabl JavaScript function signature.');
|
|
103
|
+
}
|
|
104
|
+
const rex = /mablInputs/gi;
|
|
105
|
+
const match = normalizedCode.match(rex);
|
|
106
|
+
const matchCount = match ? match.length : 0;
|
|
107
|
+
return matchCount > 1;
|
|
108
|
+
}
|
|
109
|
+
exports.hasVariableReferences = hasVariableReferences;
|
|
110
|
+
function normalizeScript(decodedScript) {
|
|
111
|
+
const tree = esprima.parseScript(decodedScript, { tolerant: true });
|
|
112
|
+
return escodegen.generate(tree);
|
|
113
|
+
}
|
|
114
|
+
exports.normalizeScript = normalizeScript;
|