@dev-blinq/cucumber_client 1.0.1516-dev → 1.0.1517-dev
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.
|
@@ -2,150 +2,209 @@ import { readdirSync, readFileSync } from "fs";
|
|
|
2
2
|
import { getRunsServiceBaseURL } from "../utils/index.js";
|
|
3
3
|
import { axiosClient } from "../utils/axiosClient.js";
|
|
4
4
|
import path from "path";
|
|
5
|
-
|
|
5
|
+
import { EventEmitter } from "events";
|
|
6
|
+
import socketLogger from "../utils/socket_logger.js";
|
|
6
7
|
export class NamesService {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
screenshot = this.screenshotMap.get(commands[commands.length - 2].inputID);
|
|
8
|
+
screenshotMap;
|
|
9
|
+
TOKEN;
|
|
10
|
+
projectDir;
|
|
11
|
+
logger;
|
|
12
|
+
constructor({ screenshotMap, TOKEN, projectDir, logger }) {
|
|
13
|
+
this.screenshotMap = screenshotMap;
|
|
14
|
+
this.TOKEN = TOKEN;
|
|
15
|
+
this.projectDir = projectDir;
|
|
16
|
+
this.logger = logger;
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const action = await axiosClient({
|
|
41
|
-
url: actionUrl,
|
|
42
|
-
method: "GET",
|
|
43
|
-
headers: {
|
|
44
|
-
Authorization: `Bearer ${this.TOKEN}`,
|
|
45
|
-
"X-Source": "recorder",
|
|
46
|
-
},
|
|
18
|
+
//@ts-expect-error
|
|
19
|
+
async generateStepName({ commands, stepsNames, parameters, map }) {
|
|
20
|
+
let screenshot = this.screenshotMap.get(commands[commands.length - 1].inputID);
|
|
21
|
+
if (!screenshot && commands.length > 1) {
|
|
22
|
+
screenshot = this.screenshotMap.get(commands[commands.length - 2].inputID);
|
|
23
|
+
}
|
|
24
|
+
const url = `${getRunsServiceBaseURL()}/generate-step-information/generate`;
|
|
25
|
+
const TIMEOUT = 120; // 2 minutes
|
|
26
|
+
const { data } = await axiosClient({
|
|
27
|
+
url,
|
|
28
|
+
method: "POST",
|
|
29
|
+
data: {
|
|
30
|
+
commands,
|
|
31
|
+
stepsNames,
|
|
32
|
+
parameters,
|
|
33
|
+
//screenshot,
|
|
34
|
+
map,
|
|
35
|
+
},
|
|
36
|
+
headers: {
|
|
37
|
+
Authorization: `Bearer ${this.TOKEN}`,
|
|
38
|
+
"X-Source": "recorder",
|
|
39
|
+
},
|
|
47
40
|
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
const actionUrl = `${getRunsServiceBaseURL()}/action/get-action?id=${data.id}`;
|
|
42
|
+
let result = { status: 500 };
|
|
43
|
+
for (let i = 0; i < TIMEOUT; i++) {
|
|
44
|
+
try {
|
|
45
|
+
const action = await axiosClient({
|
|
46
|
+
url: actionUrl,
|
|
47
|
+
method: "GET",
|
|
48
|
+
headers: {
|
|
49
|
+
Authorization: `Bearer ${this.TOKEN}`,
|
|
50
|
+
"X-Source": "recorder",
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
if (action.data.status) {
|
|
54
|
+
result = action;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (i === TIMEOUT - 1) {
|
|
60
|
+
this.logger.error("Timeout while generating step details: ", error instanceof Error ? error.message : JSON.stringify(error));
|
|
61
|
+
console.error("Timeout while generating step details: ", error instanceof Error ? error.message : error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
52
65
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.logger.error("Timeout while generating step details: ", error);
|
|
56
|
-
console.error("Timeout while generating step details: ", error);
|
|
66
|
+
if (result.status !== 200) {
|
|
67
|
+
return { success: false, message: "Error while generating step details" };
|
|
57
68
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
69
|
+
return result.data;
|
|
61
70
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
async generateScenarioAndFeatureNames(scenarioAsText) {
|
|
72
|
+
if (!this.projectDir) {
|
|
73
|
+
throw new Error("Project directory not found");
|
|
74
|
+
}
|
|
75
|
+
// read all files with .feature extension into an object {files:[{name: "", content: ""}]}
|
|
76
|
+
const featureFiles = readdirSync(path.join(this.projectDir, "features"));
|
|
77
|
+
const featureFilesContent = featureFiles
|
|
78
|
+
.filter((file) => file.endsWith(".feature"))
|
|
79
|
+
.map((file) => {
|
|
80
|
+
return {
|
|
81
|
+
name: file,
|
|
82
|
+
content: readFileSync(path.join(this.projectDir, "features", file), "utf8"),
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
const genObject = {
|
|
86
|
+
files: featureFilesContent,
|
|
87
|
+
scenario: scenarioAsText,
|
|
88
|
+
};
|
|
89
|
+
// get screenshot for the last command
|
|
90
|
+
const url = `${getRunsServiceBaseURL()}/generate-step-information/generate_scenario_feature`;
|
|
91
|
+
const TIMEOUT = 120; // 2 minutes
|
|
92
|
+
const { data } = await axiosClient({
|
|
93
|
+
url,
|
|
94
|
+
method: "POST",
|
|
95
|
+
data: {
|
|
96
|
+
...genObject,
|
|
97
|
+
},
|
|
98
|
+
headers: {
|
|
99
|
+
Authorization: `Bearer ${this.TOKEN}`,
|
|
100
|
+
"X-Source": "recorder",
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
const actionUrl = `${getRunsServiceBaseURL()}/action/get-action?id=${data.id}`;
|
|
104
|
+
let result = { status: 500 };
|
|
105
|
+
for (let i = 0; i < TIMEOUT; i++) {
|
|
106
|
+
try {
|
|
107
|
+
const action = await axiosClient({
|
|
108
|
+
url: actionUrl,
|
|
109
|
+
method: "GET",
|
|
110
|
+
headers: {
|
|
111
|
+
Authorization: `Bearer ${this.TOKEN}`,
|
|
112
|
+
"X-Source": "recorder",
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
if (action.data.status) {
|
|
116
|
+
result = action;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (i === TIMEOUT - 1) {
|
|
122
|
+
console.error("Timeout while generating step details: ", error);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
126
|
+
}
|
|
127
|
+
if (result.status !== 200) {
|
|
128
|
+
return { success: false, message: "Error while generating step details" };
|
|
129
|
+
}
|
|
130
|
+
return result.data;
|
|
65
131
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
132
|
+
//@ts-expect-error
|
|
133
|
+
async generateCommandName({ command }) {
|
|
134
|
+
const url = `${getRunsServiceBaseURL()}/generate-step-information/generate-element-name`;
|
|
135
|
+
const screenshot = this.screenshotMap.get(command.inputID);
|
|
136
|
+
const result = await axiosClient({
|
|
137
|
+
url,
|
|
138
|
+
method: "POST",
|
|
139
|
+
data: { ...command, screenshot },
|
|
140
|
+
headers: {
|
|
141
|
+
Authorization: `Bearer ${this.TOKEN}`,
|
|
142
|
+
"X-Source": "recorder",
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
if (result.status !== 200) {
|
|
146
|
+
return { success: false, message: "Error while generating command details" };
|
|
147
|
+
}
|
|
148
|
+
return result.data;
|
|
71
149
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
method: "POST",
|
|
93
|
-
data: {
|
|
94
|
-
...genObject,
|
|
95
|
-
},
|
|
96
|
-
headers: {
|
|
97
|
-
Authorization: `Bearer ${this.TOKEN}`,
|
|
98
|
-
"X-Source": "recorder",
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
const actionUrl = `${getRunsServiceBaseURL()}/action/get-action?id=${data.id}`;
|
|
102
|
-
let result = { status: 500 };
|
|
103
|
-
for (let i = 0; i < TIMEOUT; i++) {
|
|
104
|
-
try {
|
|
105
|
-
const action = await axiosClient({
|
|
106
|
-
url: actionUrl,
|
|
107
|
-
method: "GET",
|
|
108
|
-
headers: {
|
|
109
|
-
Authorization: `Bearer ${this.TOKEN}`,
|
|
110
|
-
"X-Source": "recorder",
|
|
111
|
-
},
|
|
150
|
+
}
|
|
151
|
+
export class RemoteBrowserService extends EventEmitter {
|
|
152
|
+
CDP_CONNECT_URL;
|
|
153
|
+
pageMap = new Map();
|
|
154
|
+
_selectedPage;
|
|
155
|
+
logger = socketLogger;
|
|
156
|
+
constructor({ CDP_CONNECT_URL, currentPage }) {
|
|
157
|
+
super();
|
|
158
|
+
this.CDP_CONNECT_URL = CDP_CONNECT_URL;
|
|
159
|
+
this._selectedPage = currentPage;
|
|
160
|
+
this.getDebugURLs()
|
|
161
|
+
.then((debugData) => {
|
|
162
|
+
debugData.forEach((page) => {
|
|
163
|
+
if (page.type === "page") {
|
|
164
|
+
this.pageMap.set(page.url, page.id);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
})
|
|
168
|
+
.catch((error) => {
|
|
169
|
+
this.logger.error("Error fetching debug URLs: ", error instanceof Error ? error.message : error);
|
|
112
170
|
});
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
171
|
+
}
|
|
172
|
+
set selectedPage(page) {
|
|
173
|
+
this._selectedPage = page;
|
|
174
|
+
const pageUrl = page.url();
|
|
175
|
+
const pageEntry = this.pageMap.get(pageUrl);
|
|
176
|
+
if (!pageEntry) {
|
|
177
|
+
this.getDebugURLs()
|
|
178
|
+
.then((debugData) => {
|
|
179
|
+
console.log("Fetched debug data: ", debugData);
|
|
180
|
+
debugData.forEach((page) => {
|
|
181
|
+
this.pageMap.set(page.url, page.id);
|
|
182
|
+
});
|
|
183
|
+
const url = this.pageMap.get(pageUrl);
|
|
184
|
+
this.emit("debugURLChange", url);
|
|
185
|
+
})
|
|
186
|
+
.catch((error) => {
|
|
187
|
+
this.logger.error("Error fetching debug URLs: ", error instanceof Error ? error.message : JSON.stringify(error));
|
|
188
|
+
});
|
|
117
189
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
190
|
+
else {
|
|
191
|
+
const url = this.pageMap.get(pageUrl);
|
|
192
|
+
this.emit("debugURLChange", url);
|
|
121
193
|
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
125
194
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return { success: false, message: "Error while generating step details" };
|
|
195
|
+
get selectedPage() {
|
|
196
|
+
return this._selectedPage;
|
|
129
197
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
headers: {
|
|
142
|
-
Authorization: `Bearer ${this.TOKEN}`,
|
|
143
|
-
"X-Source": "recorder",
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
if (result.status !== 200) {
|
|
147
|
-
return { success: false, message: "Error while generating command details" };
|
|
198
|
+
async getDebugURLs() {
|
|
199
|
+
const url = `${this.CDP_CONNECT_URL}/json`;
|
|
200
|
+
const response = await axiosClient({
|
|
201
|
+
url,
|
|
202
|
+
method: "GET",
|
|
203
|
+
});
|
|
204
|
+
if (response.status !== 200) {
|
|
205
|
+
throw new Error("Error while fetching debug URL");
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
return response.data;
|
|
148
209
|
}
|
|
149
|
-
return result.data;
|
|
150
|
-
}
|
|
151
210
|
}
|
|
@@ -337,7 +337,7 @@ const parameterizeLocators = ({ cmd, locs, isValueVariable, isTargetValueVariabl
|
|
|
337
337
|
const variable = cmd.value.slice(1, -1);
|
|
338
338
|
// const val = parametersMap[variable];
|
|
339
339
|
if (typeof cmd.text === "string") {
|
|
340
|
-
const replacementFromValue = cmd.text.trim().replace(/\s+/, " ") ?? "" // val.trim();
|
|
340
|
+
const replacementFromValue = cmd.text.trim().replace(/\s+/, " ") ?? ""; // val.trim();
|
|
341
341
|
if (replacementFromValue.length > 0) {
|
|
342
342
|
const replacementToValue = `{${variable}}`;
|
|
343
343
|
locs = _parameterizeLocators(locs, replacementFromValue, replacementToValue);
|
|
@@ -348,7 +348,7 @@ const parameterizeLocators = ({ cmd, locs, isValueVariable, isTargetValueVariabl
|
|
|
348
348
|
const variable = cmd.targetValue.slice(1, -1);
|
|
349
349
|
// const val = parametersMap[variable];
|
|
350
350
|
if (typeof cmd.targetText === "string") {
|
|
351
|
-
const replacementFromValue = cmd.targetText.trim().replace(/\s+/, " ") ?? "" // val.trim();
|
|
351
|
+
const replacementFromValue = cmd.targetText.trim().replace(/\s+/, " ") ?? ""; // val.trim();
|
|
352
352
|
if (replacementFromValue.length > 0) {
|
|
353
353
|
const replacementToValue = `{${variable}}`;
|
|
354
354
|
locs = _parameterizeLocators(locs, replacementFromValue, replacementToValue);
|
|
@@ -1,37 +1,35 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import tunnel from "tunnel";
|
|
3
|
-
|
|
4
3
|
const getProxy = () => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
proxyObject.proxyAuth = `${username}:${password}`;
|
|
20
|
-
}
|
|
21
|
-
return tunnel.httpsOverHttp({ proxy: proxyObject });
|
|
4
|
+
if (!process.env.PROXY) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
const proxy = process.env.PROXY;
|
|
8
|
+
const url = new URL(proxy);
|
|
9
|
+
const proxyObject = {
|
|
10
|
+
host: url.hostname,
|
|
11
|
+
port: Number(url.port),
|
|
12
|
+
};
|
|
13
|
+
const { username, password } = url;
|
|
14
|
+
if (username && password) {
|
|
15
|
+
proxyObject.proxyAuth = `${username}:${password}`;
|
|
16
|
+
}
|
|
17
|
+
return tunnel.httpsOverHttp({ proxy: proxyObject });
|
|
22
18
|
};
|
|
23
|
-
|
|
24
19
|
const createAxiosClient = () => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
20
|
+
try {
|
|
21
|
+
const agent = getProxy();
|
|
22
|
+
return axios.create({
|
|
23
|
+
httpsAgent: agent,
|
|
24
|
+
proxy: false,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (error instanceof Error) {
|
|
29
|
+
console.log(error.message);
|
|
30
|
+
}
|
|
31
|
+
//@ts-expect-error
|
|
32
|
+
throw new Error(`Error creating axios client ${error instanceof Error ? error.message : error?.response?.data}`);
|
|
33
|
+
}
|
|
35
34
|
};
|
|
36
|
-
|
|
37
35
|
export const axiosClient = createAxiosClient();
|