@auto-wiz/dom 1.0.1 → 1.1.0
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.
|
@@ -3,9 +3,8 @@ import type { Step } from "@auto-wiz/core";
|
|
|
3
3
|
* Step execution 유틸리티
|
|
4
4
|
* 각 Step 타입별 실행 로직
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* - step.locator
|
|
8
|
-
* - 없으면 기존 step.selector 사용 (하위 호환성)
|
|
6
|
+
* locator 시스템 사용:
|
|
7
|
+
* - step.locator의 다중 selector fallback 사용
|
|
9
8
|
*/
|
|
10
9
|
export interface ExecutionResult {
|
|
11
10
|
success: boolean;
|
|
@@ -1,30 +1,23 @@
|
|
|
1
|
-
import { querySelector } from "../selectors/selectorGenerator";
|
|
2
1
|
import { waitForLocator, isInteractable } from "../selectors/locatorUtils";
|
|
3
2
|
/**
|
|
4
|
-
* Step에서 요소 찾기 (locator
|
|
3
|
+
* Step에서 요소 찾기 (locator 시스템 사용)
|
|
5
4
|
*/
|
|
6
5
|
async function findElement(step) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
try {
|
|
10
|
-
const element = await waitForLocator(step.locator, {
|
|
11
|
-
timeout: step.timeoutMs || 5000,
|
|
12
|
-
visible: true,
|
|
13
|
-
interactable: true,
|
|
14
|
-
});
|
|
15
|
-
return { element, usedSelector: step.locator.primary };
|
|
16
|
-
}
|
|
17
|
-
catch (error) {
|
|
18
|
-
// Locator로 찾지 못하면 selector로 폴백
|
|
19
|
-
console.warn("Locator failed, falling back to selector", error);
|
|
20
|
-
}
|
|
6
|
+
if (!("locator" in step) || !step.locator) {
|
|
7
|
+
return { element: null, usedSelector: "none" };
|
|
21
8
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
9
|
+
try {
|
|
10
|
+
const element = await waitForLocator(step.locator, {
|
|
11
|
+
timeout: step.timeoutMs || 5000,
|
|
12
|
+
visible: true,
|
|
13
|
+
interactable: true,
|
|
14
|
+
});
|
|
15
|
+
return { element, usedSelector: step.locator.primary };
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
console.warn("Locator failed:", error);
|
|
19
|
+
return { element: null, usedSelector: step.locator.primary };
|
|
26
20
|
}
|
|
27
|
-
return { element: null, usedSelector: "none" };
|
|
28
21
|
}
|
|
29
22
|
/**
|
|
30
23
|
* Click step 실행
|
|
@@ -191,8 +184,23 @@ export async function executeExtractStep(step) {
|
|
|
191
184
|
extractedData = element.textContent?.trim() || "";
|
|
192
185
|
}
|
|
193
186
|
else if (prop === "outerHTML") {
|
|
194
|
-
// XML 구조를 보기 좋게
|
|
195
|
-
const
|
|
187
|
+
// XML 구조를 보기 좋게 포맷팅하기 전에 base64 이미지 제거
|
|
188
|
+
const cloned = element.cloneNode(true);
|
|
189
|
+
const processImage = (img) => {
|
|
190
|
+
const src = img.getAttribute("src");
|
|
191
|
+
if (src && src.startsWith("data:image")) {
|
|
192
|
+
img.removeAttribute("src");
|
|
193
|
+
img.setAttribute("data-image-removed", "true");
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
if (cloned.tagName.toLowerCase() === "img") {
|
|
197
|
+
processImage(cloned);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
const images = cloned.querySelectorAll("img");
|
|
201
|
+
images.forEach((img) => processImage(img));
|
|
202
|
+
}
|
|
203
|
+
const rawHtml = cloned.outerHTML;
|
|
196
204
|
extractedData = formatXml(rawHtml);
|
|
197
205
|
}
|
|
198
206
|
else {
|
|
@@ -216,7 +224,7 @@ export async function executeWaitForStep(step) {
|
|
|
216
224
|
return { success: false, error: "Invalid waitFor step" };
|
|
217
225
|
}
|
|
218
226
|
// 단순 timeout인 경우
|
|
219
|
-
if (!("
|
|
227
|
+
if (!("locator" in step) && step.timeoutMs) {
|
|
220
228
|
await new Promise((resolve) => setTimeout(resolve, step.timeoutMs));
|
|
221
229
|
return { success: true };
|
|
222
230
|
}
|
|
@@ -230,25 +238,9 @@ export async function executeWaitForStep(step) {
|
|
|
230
238
|
});
|
|
231
239
|
return { success: true, usedSelector: step.locator.primary };
|
|
232
240
|
}
|
|
233
|
-
// selector가 있으면 기존 방식 (하위 호환성)
|
|
234
|
-
if ("selector" in step && step.selector) {
|
|
235
|
-
const startTime = Date.now();
|
|
236
|
-
const pollInterval = 100;
|
|
237
|
-
while (Date.now() - startTime < timeout) {
|
|
238
|
-
const element = querySelector(step.selector);
|
|
239
|
-
if (element) {
|
|
240
|
-
return { success: true, usedSelector: step.selector };
|
|
241
|
-
}
|
|
242
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
243
|
-
}
|
|
244
|
-
return {
|
|
245
|
-
success: false,
|
|
246
|
-
error: `Timeout waiting for element: ${step.selector}`,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
241
|
return {
|
|
250
242
|
success: false,
|
|
251
|
-
error: "WaitFor step requires
|
|
243
|
+
error: "WaitFor step requires locator or timeoutMs",
|
|
252
244
|
};
|
|
253
245
|
}
|
|
254
246
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@auto-wiz/dom",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "JaeSang",
|
|
6
6
|
"repository": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@auto-wiz/core": "1.0
|
|
26
|
+
"@auto-wiz/core": "1.2.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"typescript": "^5.0.0"
|