dasdasd
This commit is contained in:
parent
acceddac7b
commit
02d58adbe2
@ -112,10 +112,10 @@ class RetryBlockAction extends BaseAction {
|
|||||||
// 动态加载对应的 Action
|
// 动态加载对应的 Action
|
||||||
const ActionClass = this.getActionClass(actionType);
|
const ActionClass = this.getActionClass(actionType);
|
||||||
|
|
||||||
|
// 修复:BaseAction 构造函数签名是 (context, config)
|
||||||
const action = new ActionClass(
|
const action = new ActionClass(
|
||||||
this.page,
|
this.context, // 第一个参数:context
|
||||||
stepConfig,
|
stepConfig // 第二个参数:config
|
||||||
this.context
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return await action.execute();
|
return await action.execute();
|
||||||
@ -130,7 +130,8 @@ class RetryBlockAction extends BaseAction {
|
|||||||
fillForm: require('./fill-form-action'),
|
fillForm: require('./fill-form-action'),
|
||||||
click: require('./click-action'),
|
click: require('./click-action'),
|
||||||
wait: require('./wait-action'),
|
wait: require('./wait-action'),
|
||||||
custom: require('./custom-action')
|
custom: require('./custom-action'),
|
||||||
|
scroll: require('./scroll-action')
|
||||||
};
|
};
|
||||||
|
|
||||||
const ActionClass = actionMap[actionType];
|
const ActionClass = actionMap[actionType];
|
||||||
|
|||||||
128
src/tools/automation-framework/actions/scroll-action.js
Normal file
128
src/tools/automation-framework/actions/scroll-action.js
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
const BaseAction = require('../core/base-action');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滚动动作 - 页面滚动操作
|
||||||
|
*
|
||||||
|
* 支持多种滚动方式:
|
||||||
|
* 1. 滚动到底部
|
||||||
|
* 2. 滚动到顶部
|
||||||
|
* 3. 滚动到指定元素
|
||||||
|
* 4. 滚动指定距离
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* - action: scroll
|
||||||
|
* type: bottom
|
||||||
|
*
|
||||||
|
* - action: scroll
|
||||||
|
* type: element
|
||||||
|
* selector: '#submit-button'
|
||||||
|
*
|
||||||
|
* - action: scroll
|
||||||
|
* type: distance
|
||||||
|
* x: 0
|
||||||
|
* y: 500
|
||||||
|
*/
|
||||||
|
class ScrollAction extends BaseAction {
|
||||||
|
async execute() {
|
||||||
|
const {
|
||||||
|
type = 'bottom',
|
||||||
|
selector,
|
||||||
|
x = 0,
|
||||||
|
y = 0,
|
||||||
|
behavior = 'smooth'
|
||||||
|
} = this.config;
|
||||||
|
|
||||||
|
this.log('debug', `执行滚动: ${type}`);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'bottom':
|
||||||
|
await this.scrollToBottom(behavior);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'top':
|
||||||
|
await this.scrollToTop(behavior);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'element':
|
||||||
|
if (!selector) {
|
||||||
|
throw new Error('滚动到元素需要提供 selector');
|
||||||
|
}
|
||||||
|
await this.scrollToElement(selector, behavior);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'distance':
|
||||||
|
await this.scrollByDistance(x, y, behavior);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`不支持的滚动类型: ${type}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待滚动完成
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
|
||||||
|
this.log('debug', '✓ 滚动完成');
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滚动到页面底部
|
||||||
|
*/
|
||||||
|
async scrollToBottom(behavior) {
|
||||||
|
await this.page.evaluate((b) => {
|
||||||
|
window.scrollTo({
|
||||||
|
top: document.body.scrollHeight,
|
||||||
|
left: 0,
|
||||||
|
behavior: b
|
||||||
|
});
|
||||||
|
}, behavior);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滚动到页面顶部
|
||||||
|
*/
|
||||||
|
async scrollToTop(behavior) {
|
||||||
|
await this.page.evaluate((b) => {
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
behavior: b
|
||||||
|
});
|
||||||
|
}, behavior);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滚动到指定元素
|
||||||
|
*/
|
||||||
|
async scrollToElement(selector, behavior) {
|
||||||
|
const element = await this.page.$(selector);
|
||||||
|
|
||||||
|
if (!element) {
|
||||||
|
throw new Error(`元素不存在: ${selector}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await element.evaluate((el, b) => {
|
||||||
|
el.scrollIntoView({
|
||||||
|
behavior: b,
|
||||||
|
block: 'center',
|
||||||
|
inline: 'nearest'
|
||||||
|
});
|
||||||
|
}, behavior);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滚动指定距离
|
||||||
|
*/
|
||||||
|
async scrollByDistance(x, y, behavior) {
|
||||||
|
await this.page.evaluate((dx, dy, b) => {
|
||||||
|
window.scrollBy({
|
||||||
|
top: dy,
|
||||||
|
left: dx,
|
||||||
|
behavior: b
|
||||||
|
});
|
||||||
|
}, x, y, behavior);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ScrollAction;
|
||||||
@ -137,9 +137,7 @@ workflow:
|
|||||||
- action: click
|
- action: click
|
||||||
name: "选择计划"
|
name: "选择计划"
|
||||||
selector:
|
selector:
|
||||||
- text: 'Select'
|
- text: 'Select plan'
|
||||||
selector: 'button, a'
|
|
||||||
- text: 'Continue'
|
|
||||||
selector: 'button, a'
|
selector: 'button, a'
|
||||||
timeout: 30000
|
timeout: 30000
|
||||||
waitAfter: 2000
|
waitAfter: 2000
|
||||||
@ -152,22 +150,7 @@ workflow:
|
|||||||
- css: 'input[type="radio"][value="card"]'
|
- css: 'input[type="radio"][value="card"]'
|
||||||
waitAfter: 3000
|
waitAfter: 3000
|
||||||
|
|
||||||
# 6.2 等待支付表单加载
|
# ==================== 步骤 6.2: 提交支付(带重试) ====================
|
||||||
- action: wait
|
|
||||||
name: "等待支付表单"
|
|
||||||
type: element
|
|
||||||
find:
|
|
||||||
- css: '#cardNumber'
|
|
||||||
timeout: 30000
|
|
||||||
|
|
||||||
# 6.3 处理 hCaptcha(只需处理一次)
|
|
||||||
- action: custom
|
|
||||||
name: "hCaptcha 验证"
|
|
||||||
handler: "handleHCaptcha"
|
|
||||||
params:
|
|
||||||
timeout: 120000
|
|
||||||
|
|
||||||
# ==================== 步骤 6.4: 提交支付(带重试) ====================
|
|
||||||
- action: retryBlock
|
- action: retryBlock
|
||||||
name: "提交支付并验证"
|
name: "提交支付并验证"
|
||||||
maxRetries: 5
|
maxRetries: 5
|
||||||
@ -178,6 +161,14 @@ workflow:
|
|||||||
handler: "regenerateCard"
|
handler: "regenerateCard"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
# 等待支付表单加载(每次重试都需要等待)
|
||||||
|
- action: wait
|
||||||
|
name: "等待支付表单"
|
||||||
|
type: element
|
||||||
|
find:
|
||||||
|
- css: '#cardNumber'
|
||||||
|
timeout: 30000
|
||||||
|
|
||||||
# 填写银行卡信息(使用重新生成的卡号)
|
# 填写银行卡信息(使用重新生成的卡号)
|
||||||
- action: fillForm
|
- action: fillForm
|
||||||
name: "填写银行卡信息"
|
name: "填写银行卡信息"
|
||||||
@ -208,15 +199,26 @@ workflow:
|
|||||||
name: "选择澳门地址"
|
name: "选择澳门地址"
|
||||||
handler: "selectBillingAddress"
|
handler: "selectBillingAddress"
|
||||||
|
|
||||||
|
# 滚动到页面底部(确保订阅按钮可见)
|
||||||
|
- action: scroll
|
||||||
|
name: "滚动到订阅按钮"
|
||||||
|
type: bottom
|
||||||
|
|
||||||
# 提交支付
|
# 提交支付
|
||||||
- action: click
|
- action: click
|
||||||
name: "点击提交支付"
|
name: "点击提交支付"
|
||||||
selector:
|
selector:
|
||||||
- text: 'Subscribe'
|
- css: 'button[type="submit"]' # Stripe 订阅按钮
|
||||||
- text: '订阅'
|
|
||||||
timeout: 15000
|
timeout: 15000
|
||||||
waitAfter: 2000
|
waitAfter: 2000
|
||||||
|
|
||||||
|
# 处理 hCaptcha(点击订阅后出现)
|
||||||
|
- action: custom
|
||||||
|
name: "hCaptcha 验证"
|
||||||
|
handler: "handleHCaptcha"
|
||||||
|
params:
|
||||||
|
timeout: 120000
|
||||||
|
|
||||||
# 验证支付结果(轮询检测成功或失败)
|
# 验证支付结果(轮询检测成功或失败)
|
||||||
- action: verify
|
- action: verify
|
||||||
name: "验证支付结果"
|
name: "验证支付结果"
|
||||||
|
|||||||
@ -11,6 +11,7 @@ const CustomAction = require('../actions/custom-action');
|
|||||||
const RetryBlockAction = require('../actions/retry-block-action');
|
const RetryBlockAction = require('../actions/retry-block-action');
|
||||||
const ExtractAction = require('../actions/extract-action');
|
const ExtractAction = require('../actions/extract-action');
|
||||||
const VerifyAction = require('../actions/verify-action');
|
const VerifyAction = require('../actions/verify-action');
|
||||||
|
const ScrollAction = require('../actions/scroll-action');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作流引擎 - 执行配置驱动的自动化流程
|
* 工作流引擎 - 执行配置驱动的自动化流程
|
||||||
@ -51,6 +52,7 @@ class WorkflowEngine {
|
|||||||
this.actionRegistry.register('retryBlock', RetryBlockAction);
|
this.actionRegistry.register('retryBlock', RetryBlockAction);
|
||||||
this.actionRegistry.register('extract', ExtractAction);
|
this.actionRegistry.register('extract', ExtractAction);
|
||||||
this.actionRegistry.register('verify', VerifyAction);
|
this.actionRegistry.register('verify', VerifyAction);
|
||||||
|
this.actionRegistry.register('scroll', ScrollAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user