@dev-blinq/cucumber_client 1.0.1429-dev → 1.0.1429-stage
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/bin/assets/bundled_scripts/recorder.js +73 -73
- package/bin/assets/preload/css_gen.js +10 -10
- package/bin/assets/preload/toolbar.js +27 -29
- package/bin/assets/preload/unique_locators.js +1 -1
- package/bin/assets/preload/yaml.js +288 -275
- package/bin/assets/scripts/aria_snapshot.js +223 -220
- package/bin/assets/scripts/dom_attr.js +329 -329
- package/bin/assets/scripts/dom_parent.js +169 -174
- package/bin/assets/scripts/event_utils.js +94 -94
- package/bin/assets/scripts/pw.js +2050 -1949
- package/bin/assets/scripts/recorder.js +70 -45
- package/bin/assets/scripts/snapshot_capturer.js +147 -147
- package/bin/assets/scripts/unique_locators.js +170 -49
- package/bin/assets/scripts/yaml.js +796 -783
- package/bin/assets/templates/_hooks_template.txt +6 -2
- package/bin/assets/templates/utils_template.txt +16 -16
- package/bin/client/code_cleanup/find_step_definition_references.js +0 -1
- package/bin/client/code_gen/api_codegen.js +2 -2
- package/bin/client/code_gen/code_inversion.js +63 -2
- package/bin/client/code_gen/function_signature.js +4 -0
- package/bin/client/code_gen/page_reflection.js +52 -11
- package/bin/client/code_gen/playwright_codeget.js +28 -22
- package/bin/client/cucumber/feature_data.js +2 -2
- package/bin/client/cucumber/project_to_document.js +8 -2
- package/bin/client/cucumber/steps_definitions.js +19 -3
- package/bin/client/local_agent.js +3 -2
- package/bin/client/parse_feature_file.js +23 -26
- package/bin/client/playground/projects/env.json +2 -2
- package/bin/client/recorderv3/bvt_init.js +363 -0
- package/bin/client/recorderv3/bvt_recorder.js +1009 -47
- package/bin/client/recorderv3/implemented_steps.js +2 -0
- package/bin/client/recorderv3/index.js +3 -283
- package/bin/client/recorderv3/scriptTest.js +1 -1
- package/bin/client/recorderv3/services.js +818 -142
- package/bin/client/recorderv3/step_runner.js +28 -8
- package/bin/client/recorderv3/step_utils.js +514 -39
- package/bin/client/recorderv3/update_feature.js +32 -13
- package/bin/client/recorderv3/wbr_entry.js +61 -0
- package/bin/client/recording.js +1 -0
- package/bin/client/upload-service.js +4 -2
- package/bin/client/utils/socket_logger.js +1 -1
- package/bin/index.js +4 -1
- package/package.json +6 -4
|
@@ -1,235 +1,238 @@
|
|
|
1
1
|
class AriaSnapshotUtils {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
2
|
+
isLeafNode(node) {
|
|
3
|
+
if (node.kind === "text") {
|
|
4
|
+
return true;
|
|
5
|
+
} else {
|
|
6
|
+
return !node.children || node.children.length === 0;
|
|
8
7
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
yamlEscapeKeyIfNeeded(str) {
|
|
41
|
-
if (!this.yamlStringNeedsQuotes(str)) return str;
|
|
42
|
-
return `'` + str.replace(/'/g, `''`) + `'`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
deepClone(node) {
|
|
11
|
+
if (node.kind === "text") {
|
|
12
|
+
return node.text;
|
|
13
|
+
} else {
|
|
14
|
+
const result = {
|
|
15
|
+
kind: "role",
|
|
16
|
+
role: node.role,
|
|
17
|
+
};
|
|
18
|
+
if ("checked" in node) result.checked = node.checked;
|
|
19
|
+
if ("disabled" in node) result.disabled = node.disabled;
|
|
20
|
+
if ("expanded" in node) result.expanded = node.expanded;
|
|
21
|
+
if ("level" in node) result.level = node.level;
|
|
22
|
+
if ("pressed" in node) result.pressed = node.pressed;
|
|
23
|
+
if ("selected" in node) result.selected = node.selected;
|
|
24
|
+
if (node.name !== undefined) {
|
|
25
|
+
result.name = node.name;
|
|
26
|
+
}
|
|
27
|
+
if (node.props) {
|
|
28
|
+
result.props = Object.assign({}, node.props);
|
|
29
|
+
}
|
|
30
|
+
if (node.containerMode) {
|
|
31
|
+
result.containerMode = node.containerMode;
|
|
32
|
+
}
|
|
33
|
+
if (node.children) {
|
|
34
|
+
result.children = node.children.map((child) => this.deepClone(child));
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
43
37
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
yamlEscapeKeyIfNeeded(str) {
|
|
41
|
+
if (!this.yamlStringNeedsQuotes(str)) return str;
|
|
42
|
+
return `'` + str.replace(/'/g, `''`) + `'`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
yamlEscapeValueIfNeeded(str) {
|
|
46
|
+
if (!this.yamlStringNeedsQuotes(str)) return str;
|
|
47
|
+
return (
|
|
48
|
+
'"' +
|
|
49
|
+
str.replace(/[\\"\x00-\x1f\x7f-\x9f]/g, (c) => {
|
|
50
|
+
switch (c) {
|
|
51
|
+
case "\\":
|
|
52
|
+
return "\\\\";
|
|
53
|
+
case '"':
|
|
54
|
+
return '\\"';
|
|
55
|
+
case "\b":
|
|
56
|
+
return "\\b";
|
|
57
|
+
case "\f":
|
|
58
|
+
return "\\f";
|
|
59
|
+
case "\n":
|
|
60
|
+
return "\\n";
|
|
61
|
+
case "\r":
|
|
62
|
+
return "\\r";
|
|
63
|
+
case "\t":
|
|
64
|
+
return "\\t";
|
|
65
|
+
default:
|
|
66
|
+
const code = c.charCodeAt(0);
|
|
67
|
+
return "\\x" + code.toString(16).padStart(2, "0");
|
|
68
|
+
}
|
|
69
|
+
}) +
|
|
70
|
+
'"'
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
yamlStringNeedsQuotes(str) {
|
|
75
|
+
if (!str) return false;
|
|
76
|
+
if (str.length === 0) return true;
|
|
77
|
+
if (/^\s|\s$/.test(str)) return true;
|
|
78
|
+
if (/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]/.test(str)) return true;
|
|
79
|
+
if (/^-/.test(str)) return true;
|
|
80
|
+
if (/[\n:](\s|$)/.test(str)) return true;
|
|
81
|
+
if (/\s#/.test(str)) return true;
|
|
82
|
+
if (/[\n\r]/.test(str)) return true;
|
|
83
|
+
if (/^[&*\],?!>|@"'#%]/.test(str)) return true;
|
|
84
|
+
if (/[{}`]/.test(str)) return true;
|
|
85
|
+
if (/^\[/.test(str)) return true;
|
|
86
|
+
if (
|
|
87
|
+
!isNaN(Number(str)) ||
|
|
88
|
+
["y", "n", "yes", "no", "true", "false", "on", "off", "null"].includes(str.toLowerCase())
|
|
89
|
+
)
|
|
90
|
+
return true;
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
filterParentToChildren(parent, targetChildren) {
|
|
95
|
+
const isDirectMatch = targetChildren.some((child) => JSON.stringify(child) === JSON.stringify(parent));
|
|
96
|
+
if (isDirectMatch || this.isLeafNode(parent)) {
|
|
97
|
+
return isDirectMatch ? this.deepClone(parent) : null;
|
|
72
98
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (/[\n\r]/.test(str)) return true;
|
|
83
|
-
if (/^[&*\],?!>|@"'#%]/.test(str)) return true;
|
|
84
|
-
if (/[{}`]/.test(str)) return true;
|
|
85
|
-
if (/^\[/.test(str)) return true;
|
|
86
|
-
if (!isNaN(Number(str)) || ["y", "n", "yes", "no", "true", "false", "on", "off", "null"].includes(str.toLowerCase()))
|
|
87
|
-
return true;
|
|
88
|
-
return false;
|
|
99
|
+
if (parent.kind === "role" && parent.children && parent.children.length > 0) {
|
|
100
|
+
const filteredChildren = parent.children
|
|
101
|
+
.map((child) => this.filterParentToChildren(child, targetChildren))
|
|
102
|
+
.filter((child) => child !== null);
|
|
103
|
+
if (filteredChildren.length > 0) {
|
|
104
|
+
const result = this.deepClone(parent);
|
|
105
|
+
result.children = filteredChildren;
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
89
108
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
serializeAriaSnapshot(ariaSnapshot, indent = 0) {
|
|
113
|
+
const lines = [];
|
|
114
|
+
const visit = (node, parentNode, indent) => {
|
|
115
|
+
if (typeof node === "string") {
|
|
116
|
+
const text = this.yamlEscapeValueIfNeeded(node);
|
|
117
|
+
if (text) lines.push(indent + "- text: " + text);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
let key = node.role;
|
|
121
|
+
|
|
122
|
+
if (node.name && node.name.length <= 900) {
|
|
123
|
+
const name = node.name;
|
|
124
|
+
if (name) {
|
|
125
|
+
const stringifiedName = name.startsWith("/") && name.endsWith("/") ? name : JSON.stringify(name);
|
|
126
|
+
key += " " + stringifiedName;
|
|
105
127
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (node.level) key += ` [level=${node.level}]`;
|
|
131
|
-
if (node.pressed === "mixed") key += ` [pressed=mixed]`;
|
|
132
|
-
if (node.pressed === true) key += ` [pressed]`;
|
|
133
|
-
if (node.selected === true) key += ` [selected]`;
|
|
134
|
-
|
|
135
|
-
const escapedKey = indent + "- " + this.yamlEscapeKeyIfNeeded(key);
|
|
136
|
-
if (node.props === undefined) node.props = {};
|
|
137
|
-
if (node.children === undefined) node.children = [];
|
|
138
|
-
const hasProps = !!Object.keys(node.props).length;
|
|
139
|
-
if (!node.children.length && !hasProps) {
|
|
140
|
-
lines.push(escapedKey);
|
|
141
|
-
} else if (node.children.length === 1 && typeof node.children[0] === "string" && !hasProps) {
|
|
142
|
-
const text = node.children[0];
|
|
143
|
-
if (text) lines.push(escapedKey + ": " + this.yamlEscapeValueIfNeeded(text));
|
|
144
|
-
else lines.push(escapedKey);
|
|
145
|
-
} else {
|
|
146
|
-
lines.push(escapedKey + ":");
|
|
147
|
-
for (const [name, value] of Object.entries(node.props) || []) {
|
|
148
|
-
lines.push(indent + " - /" + name + ": " + this.yamlEscapeValueIfNeeded(value));
|
|
149
|
-
}
|
|
150
|
-
for (const child of node.children || []) {
|
|
151
|
-
visit(child, node, indent + " ");
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const node = ariaSnapshot;
|
|
157
|
-
if (node.role === "fragment") {
|
|
158
|
-
for (const child of node.children || []) visit(child, node, "");
|
|
159
|
-
} else {
|
|
160
|
-
visit(node, null, "");
|
|
128
|
+
}
|
|
129
|
+
if (node.checked === "mixed") key += ` [checked=mixed]`;
|
|
130
|
+
if (node.checked === true) key += ` [checked]`;
|
|
131
|
+
if (node.disabled) key += ` [disabled]`;
|
|
132
|
+
if (node.expanded) key += ` [expanded]`;
|
|
133
|
+
if (node.level) key += ` [level=${node.level}]`;
|
|
134
|
+
if (node.pressed === "mixed") key += ` [pressed=mixed]`;
|
|
135
|
+
if (node.pressed === true) key += ` [pressed]`;
|
|
136
|
+
if (node.selected === true) key += ` [selected]`;
|
|
137
|
+
|
|
138
|
+
const escapedKey = indent + "- " + this.yamlEscapeKeyIfNeeded(key);
|
|
139
|
+
if (node.props === undefined) node.props = {};
|
|
140
|
+
if (node.children === undefined) node.children = [];
|
|
141
|
+
const hasProps = !!Object.keys(node.props).length;
|
|
142
|
+
if (!node.children.length && !hasProps) {
|
|
143
|
+
lines.push(escapedKey);
|
|
144
|
+
} else if (node.children.length === 1 && typeof node.children[0] === "string" && !hasProps) {
|
|
145
|
+
const text = node.children[0];
|
|
146
|
+
if (text) lines.push(escapedKey + ": " + this.yamlEscapeValueIfNeeded(text));
|
|
147
|
+
else lines.push(escapedKey);
|
|
148
|
+
} else {
|
|
149
|
+
lines.push(escapedKey + ":");
|
|
150
|
+
for (const [name, value] of Object.entries(node.props) || []) {
|
|
151
|
+
lines.push(indent + " - /" + name + ": " + this.yamlEscapeValueIfNeeded(value));
|
|
161
152
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
isSnapshotAvailable(element, elementSet) {
|
|
166
|
-
if (elementSet.has(element)) {
|
|
167
|
-
return element;
|
|
168
|
-
} else {
|
|
169
|
-
return undefined;
|
|
153
|
+
for (const child of node.children || []) {
|
|
154
|
+
visit(child, node, indent + " ");
|
|
170
155
|
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const node = ariaSnapshot;
|
|
160
|
+
if (node.role === "fragment") {
|
|
161
|
+
for (const child of node.children || []) visit(child, node, "");
|
|
162
|
+
} else {
|
|
163
|
+
visit(node, null, "");
|
|
171
164
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
for (const obj of objectSet) {
|
|
181
|
-
const normalizedSubtree = subtreeText.trim();
|
|
182
|
-
const normalizedSnapshot = obj.snapshot
|
|
183
|
-
.split("\n")
|
|
184
|
-
.map((s) => s.trim())
|
|
185
|
-
.join("\n");
|
|
186
|
-
if (normalizedSnapshot === normalizedSubtree) {
|
|
187
|
-
matches.set(subtreeText, obj.element);
|
|
188
|
-
break;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
return matches;
|
|
165
|
+
return lines.join("\n");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
isSnapshotAvailable(element, elementSet) {
|
|
169
|
+
if (elementSet.has(element)) {
|
|
170
|
+
return element;
|
|
171
|
+
} else {
|
|
172
|
+
return undefined;
|
|
194
173
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
subtrees.push(subtree);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
findMatchingElements(inputSnapshot, objectSet) {
|
|
177
|
+
const matches = new Map();
|
|
178
|
+
const lines = inputSnapshot.trim().split("\n");
|
|
179
|
+
const subtrees = this.extractSubtrees(lines);
|
|
180
|
+
|
|
181
|
+
subtrees.forEach((subtree) => {
|
|
182
|
+
const subtreeText = subtree.map((t) => t.trim()).join("\n");
|
|
183
|
+
for (const obj of objectSet) {
|
|
184
|
+
const normalizedSubtree = subtreeText.trim();
|
|
185
|
+
const normalizedSnapshot = obj.snapshot
|
|
186
|
+
.split("\n")
|
|
187
|
+
.map((s) => s.trim())
|
|
188
|
+
.join("\n");
|
|
189
|
+
if (normalizedSnapshot === normalizedSubtree) {
|
|
190
|
+
matches.set(subtreeText, obj.element);
|
|
191
|
+
break;
|
|
214
192
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
return matches;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
extractSubtrees(lines) {
|
|
200
|
+
const subtrees = [];
|
|
201
|
+
const indentSize = this.getIndentSize(lines);
|
|
202
|
+
|
|
203
|
+
for (let i = 0; i < lines.length; i++) {
|
|
204
|
+
const currentLine = lines[i];
|
|
205
|
+
const currentIndent = this.getIndentLevel(currentLine);
|
|
206
|
+
const subtree = [currentLine];
|
|
207
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
208
|
+
const nextLine = lines[j];
|
|
209
|
+
const nextIndent = this.getIndentLevel(nextLine);
|
|
210
|
+
if (nextIndent > currentIndent) {
|
|
211
|
+
subtree.push(nextLine);
|
|
212
|
+
} else {
|
|
213
|
+
break;
|
|
230
214
|
}
|
|
231
|
-
|
|
215
|
+
}
|
|
216
|
+
subtrees.push(subtree);
|
|
217
|
+
}
|
|
218
|
+
subtrees.sort((a, b) => a.length - b.length);
|
|
219
|
+
return subtrees;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
getIndentLevel(line) {
|
|
223
|
+
const match = line.match(/^(\s*)/);
|
|
224
|
+
return match ? match[1].length : 0;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
getIndentSize(lines) {
|
|
228
|
+
for (let i = 1; i < lines.length; i++) {
|
|
229
|
+
const indentLevel = this.getIndentLevel(lines[i]);
|
|
230
|
+
if (indentLevel > 0) {
|
|
231
|
+
return indentLevel - this.getIndentLevel(lines[i - 1]);
|
|
232
|
+
}
|
|
232
233
|
}
|
|
234
|
+
return 2;
|
|
235
|
+
}
|
|
233
236
|
}
|
|
234
237
|
|
|
235
|
-
export default AriaSnapshotUtils
|
|
238
|
+
export default AriaSnapshotUtils;
|