browser-opt 1.0.1
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/dist/browser-opt/index.d.ts +9 -0
- package/dist/browser-opt/index.d.ts.map +1 -0
- package/dist/browser-opt/index.js +7 -0
- package/dist/browser-opt/index.js.map +1 -0
- package/dist/browser-opt/runner/actions/index.d.ts +13 -0
- package/dist/browser-opt/runner/actions/index.d.ts.map +1 -0
- package/dist/browser-opt/runner/actions/index.js +44 -0
- package/dist/browser-opt/runner/actions/index.js.map +1 -0
- package/dist/browser-opt/runner/actions/utils/click-action.d.ts +10 -0
- package/dist/browser-opt/runner/actions/utils/click-action.d.ts.map +1 -0
- package/dist/browser-opt/runner/actions/utils/click-action.js +17 -0
- package/dist/browser-opt/runner/actions/utils/click-action.js.map +1 -0
- package/dist/browser-opt/runner/actions/utils/date-action.d.ts +21 -0
- package/dist/browser-opt/runner/actions/utils/date-action.d.ts.map +1 -0
- package/dist/browser-opt/runner/actions/utils/date-action.js +464 -0
- package/dist/browser-opt/runner/actions/utils/date-action.js.map +1 -0
- package/dist/browser-opt/runner/actions/utils/dom-action.d.ts +8 -0
- package/dist/browser-opt/runner/actions/utils/dom-action.d.ts.map +1 -0
- package/dist/browser-opt/runner/actions/utils/dom-action.js +167 -0
- package/dist/browser-opt/runner/actions/utils/dom-action.js.map +1 -0
- package/dist/browser-opt/runner/actions/utils/fill-action.d.ts +10 -0
- package/dist/browser-opt/runner/actions/utils/fill-action.d.ts.map +1 -0
- package/dist/browser-opt/runner/actions/utils/fill-action.js +20 -0
- package/dist/browser-opt/runner/actions/utils/fill-action.js.map +1 -0
- package/dist/browser-opt/runner/actions/utils/handoff-action.d.ts +10 -0
- package/dist/browser-opt/runner/actions/utils/handoff-action.d.ts.map +1 -0
- package/dist/browser-opt/runner/actions/utils/handoff-action.js +6 -0
- package/dist/browser-opt/runner/actions/utils/handoff-action.js.map +1 -0
- package/dist/browser-opt/runner/actions/utils/open-action.d.ts +10 -0
- package/dist/browser-opt/runner/actions/utils/open-action.d.ts.map +1 -0
- package/dist/browser-opt/runner/actions/utils/open-action.js +9 -0
- package/dist/browser-opt/runner/actions/utils/open-action.js.map +1 -0
- package/dist/browser-opt/runner/actions/utils/select-option-action.d.ts +17 -0
- package/dist/browser-opt/runner/actions/utils/select-option-action.d.ts.map +1 -0
- package/dist/browser-opt/runner/actions/utils/select-option-action.js +532 -0
- package/dist/browser-opt/runner/actions/utils/select-option-action.js.map +1 -0
- package/dist/browser-opt/runner/actions/utils/upload-action.d.ts +7 -0
- package/dist/browser-opt/runner/actions/utils/upload-action.d.ts.map +1 -0
- package/dist/browser-opt/runner/actions/utils/upload-action.js +173 -0
- package/dist/browser-opt/runner/actions/utils/upload-action.js.map +1 -0
- package/dist/browser-opt/runner/evidence.d.ts +18 -0
- package/dist/browser-opt/runner/evidence.d.ts.map +1 -0
- package/dist/browser-opt/runner/evidence.js +116 -0
- package/dist/browser-opt/runner/evidence.js.map +1 -0
- package/dist/browser-opt/runner/handoff.d.ts +28 -0
- package/dist/browser-opt/runner/handoff.d.ts.map +1 -0
- package/dist/browser-opt/runner/handoff.js +132 -0
- package/dist/browser-opt/runner/handoff.js.map +1 -0
- package/dist/browser-opt/runner/index.d.ts +11 -0
- package/dist/browser-opt/runner/index.d.ts.map +1 -0
- package/dist/browser-opt/runner/index.js +244 -0
- package/dist/browser-opt/runner/index.js.map +1 -0
- package/dist/browser-opt/runner/step-executor.d.ts +5 -0
- package/dist/browser-opt/runner/step-executor.d.ts.map +1 -0
- package/dist/browser-opt/runner/step-executor.js +302 -0
- package/dist/browser-opt/runner/step-executor.js.map +1 -0
- package/dist/browser-opt/type.d.ts +120 -0
- package/dist/browser-opt/type.d.ts.map +1 -0
- package/dist/browser-opt/type.js +2 -0
- package/dist/browser-opt/type.js.map +1 -0
- package/dist/browser-opt/utils.d.ts +48 -0
- package/dist/browser-opt/utils.d.ts.map +1 -0
- package/dist/browser-opt/utils.js +885 -0
- package/dist/browser-opt/utils.js.map +1 -0
- package/dist/browser-opt/workflow/index.d.ts +7 -0
- package/dist/browser-opt/workflow/index.d.ts.map +1 -0
- package/dist/browser-opt/workflow/index.js +6 -0
- package/dist/browser-opt/workflow/index.js.map +1 -0
- package/dist/browser-opt/workflow/matcher.d.ts +12 -0
- package/dist/browser-opt/workflow/matcher.d.ts.map +1 -0
- package/dist/browser-opt/workflow/matcher.js +102 -0
- package/dist/browser-opt/workflow/matcher.js.map +1 -0
- package/dist/browser-opt/workflow/store.d.ts +15 -0
- package/dist/browser-opt/workflow/store.d.ts.map +1 -0
- package/dist/browser-opt/workflow/store.js +175 -0
- package/dist/browser-opt/workflow/store.js.map +1 -0
- package/dist/browser-opt/workflow/type.d.ts +43 -0
- package/dist/browser-opt/workflow/type.d.ts.map +1 -0
- package/dist/browser-opt/workflow/type.js +6 -0
- package/dist/browser-opt/workflow/type.js.map +1 -0
- package/dist/cli/browser-opt.d.ts +3 -0
- package/dist/cli/browser-opt.d.ts.map +1 -0
- package/dist/cli/browser-opt.js +11 -0
- package/dist/cli/browser-opt.js.map +1 -0
- package/dist/cli/commands/browser-opt.d.ts +2 -0
- package/dist/cli/commands/browser-opt.d.ts.map +1 -0
- package/dist/cli/commands/browser-opt.js +514 -0
- package/dist/cli/commands/browser-opt.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +10 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +35 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/utils/args.d.ts +17 -0
- package/dist/cli/utils/args.d.ts.map +1 -0
- package/dist/cli/utils/args.js +74 -0
- package/dist/cli/utils/args.js.map +1 -0
- package/dist/cli/utils/constants.d.ts +8 -0
- package/dist/cli/utils/constants.d.ts.map +1 -0
- package/dist/cli/utils/constants.js +18 -0
- package/dist/cli/utils/constants.js.map +1 -0
- package/dist/cli/utils/output.d.ts +7 -0
- package/dist/cli/utils/output.d.ts.map +1 -0
- package/dist/cli/utils/output.js +45 -0
- package/dist/cli/utils/output.js.map +1 -0
- package/package.json +35 -0
- package/skills/browser-opt/SKILL.md +249 -0
- package/skills/browser-opt/manifest.json +75 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser-opt 模块对外导出即时自然语言执行和项目级 Workflow 复用能力。
|
|
3
|
+
* 该目录处理流程存储、匹配、证据采集和执行报告,不承载 E2E 测试代码生成。
|
|
4
|
+
*/
|
|
5
|
+
export { BrowserOptRunner, browserOptTemplate, extractBrowserOptUrl, splitBrowserOptSteps, } from './runner/index.js';
|
|
6
|
+
export { DEFAULT_BROWSER_OPT_WORKFLOW_DIR, findBrowserOptWorkflowById, loadBrowserOptWorkflows, matchBrowserOptWorkflows, normalizeBrowserOptWorkflowQuery, resolveBrowserOptWorkflowDir, safeWorkflowId, saveBrowserOptWorkflow, scoreBrowserOptWorkflow, } from './workflow/index.js';
|
|
7
|
+
export type { BrowserOptStatus, BrowserOptReport, BrowserOptRunResult, BrowserOptRunnerOptions, BrowserOptStepResult, } from './type.js';
|
|
8
|
+
export type { BrowserOptWorkflow, BrowserOptWorkflowCandidate, BrowserOptWorkflowLoadResult, BrowserOptWorkflowMatchResult, BrowserOptWorkflowMatchStatus, SaveBrowserOptWorkflowInput, SaveBrowserOptWorkflowResult, } from './workflow/index.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser-opt/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,gCAAgC,EAChC,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACxB,gCAAgC,EAChC,4BAA4B,EAC5B,cAAc,EACd,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,kBAAkB,EAClB,2BAA2B,EAC3B,4BAA4B,EAC5B,6BAA6B,EAC7B,6BAA6B,EAC7B,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser-opt 模块对外导出即时自然语言执行和项目级 Workflow 复用能力。
|
|
3
|
+
* 该目录处理流程存储、匹配、证据采集和执行报告,不承载 E2E 测试代码生成。
|
|
4
|
+
*/
|
|
5
|
+
export { BrowserOptRunner, browserOptTemplate, extractBrowserOptUrl, splitBrowserOptSteps, } from './runner/index.js';
|
|
6
|
+
export { DEFAULT_BROWSER_OPT_WORKFLOW_DIR, findBrowserOptWorkflowById, loadBrowserOptWorkflows, matchBrowserOptWorkflows, normalizeBrowserOptWorkflowQuery, resolveBrowserOptWorkflowDir, safeWorkflowId, saveBrowserOptWorkflow, scoreBrowserOptWorkflow, } from './workflow/index.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser-opt/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,gCAAgC,EAChC,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACxB,gCAAgC,EAChC,4BAA4B,EAC5B,cAAc,EACd,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser-opt 确定性动作执行器,负责解析自然语言动作并分发到对应 action handler。
|
|
3
|
+
*/
|
|
4
|
+
import type { BrowserAgent } from '@browser-automated/browser-core/agent';
|
|
5
|
+
import type { DeterministicAction, SnapshotEvidence, DeterministicExecutionOptions } from '../../type.js';
|
|
6
|
+
/** 将自然语言动作直接映射到确定性命令,避免默认依赖 agent-browser chat。 */
|
|
7
|
+
export declare function executeDeterministicInstruction(agent: BrowserAgent, instruction: string, snapshot: SnapshotEvidence, outputDir: string, options?: DeterministicExecutionOptions): Promise<string | null>;
|
|
8
|
+
/** 对确定性动作做后置状态确认,防止命令发出但页面没有完成目标状态时误报成功。 */
|
|
9
|
+
export declare function verifyDeterministicActionEffect(agent: BrowserAgent, action: DeterministicAction, afterSnapshot: SnapshotEvidence): {
|
|
10
|
+
passed: boolean;
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/browser-opt/runner/actions/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAS1G,mDAAmD;AACnD,wBAAsB,+BAA+B,CACnD,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,6BAAkC,GAC1C,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmCxB;AAED,4CAA4C;AAC5C,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,mBAAmB,EAC3B,aAAa,EAAE,gBAAgB,GAC9B;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAMtC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { parseDeterministicAction } from '../../utils.js';
|
|
2
|
+
import { executeClickAction } from './utils/click-action.js';
|
|
3
|
+
import { executeFillAction } from './utils/fill-action.js';
|
|
4
|
+
import { executeHandoffAction } from './utils/handoff-action.js';
|
|
5
|
+
import { executeOpenAction } from './utils/open-action.js';
|
|
6
|
+
import { executeSelectOptionAction, verifySelectOptionActionEffect } from './utils/select-option-action.js';
|
|
7
|
+
import { executeUploadAction } from './utils/upload-action.js';
|
|
8
|
+
/** 将自然语言动作直接映射到确定性命令,避免默认依赖 agent-browser chat。 */
|
|
9
|
+
export async function executeDeterministicInstruction(agent, instruction, snapshot, outputDir, options = {}) {
|
|
10
|
+
const action = parseDeterministicAction(instruction);
|
|
11
|
+
if (!action) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
if (action.type === 'open') {
|
|
15
|
+
return executeOpenAction(agent, action, options);
|
|
16
|
+
}
|
|
17
|
+
if (action.type === 'inspect') {
|
|
18
|
+
return agent.inspect();
|
|
19
|
+
}
|
|
20
|
+
if (action.type === 'fill') {
|
|
21
|
+
return executeFillAction(agent, action, snapshot);
|
|
22
|
+
}
|
|
23
|
+
if (action.type === 'click') {
|
|
24
|
+
return executeClickAction(agent, action, snapshot);
|
|
25
|
+
}
|
|
26
|
+
if (action.type === 'select-option') {
|
|
27
|
+
return executeSelectOptionAction(agent, action, snapshot, options);
|
|
28
|
+
}
|
|
29
|
+
if (action.type === 'upload') {
|
|
30
|
+
return executeUploadAction(agent, action, snapshot, outputDir, options);
|
|
31
|
+
}
|
|
32
|
+
if (action.type === 'handoff') {
|
|
33
|
+
return executeHandoffAction(agent, action);
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
/** 对确定性动作做后置状态确认,防止命令发出但页面没有完成目标状态时误报成功。 */
|
|
38
|
+
export function verifyDeterministicActionEffect(agent, action, afterSnapshot) {
|
|
39
|
+
if (action.type !== 'select-option') {
|
|
40
|
+
return { passed: true, message: '动作步骤已完成,已重新 snapshot。' };
|
|
41
|
+
}
|
|
42
|
+
return verifySelectOptionActionEffect(agent, action, afterSnapshot);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/browser-opt/runner/actions/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AAC5G,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,KAAmB,EACnB,WAAmB,EACnB,QAA0B,EAC1B,SAAiB,EACjB,UAAyC,EAAE;IAE3C,MAAM,MAAM,GAAG,wBAAwB,CAAC,WAAW,CAAC,CAAC;IACrD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC3B,OAAO,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC3B,OAAO,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACpD,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC5B,OAAO,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;QACpC,OAAO,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,+BAA+B,CAC7C,KAAmB,EACnB,MAA2B,EAC3B,aAA+B;IAE/B,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;QACpC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC;IAC5D,CAAC;IAED,OAAO,8BAA8B,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser-opt 点击动作执行器,负责从当前快照定位可点击元素并下发 click。
|
|
3
|
+
*/
|
|
4
|
+
import type { BrowserAgent } from '@browser-automated/browser-core/agent';
|
|
5
|
+
import type { DeterministicAction, SnapshotEvidence } from '../../../type.js';
|
|
6
|
+
/** 执行点击动作,只负责从当前快照定位可点击元素并下发 click。 */
|
|
7
|
+
export declare function executeClickAction(agent: BrowserAgent, action: Extract<DeterministicAction, {
|
|
8
|
+
type: 'click';
|
|
9
|
+
}>, snapshot: SnapshotEvidence): string;
|
|
10
|
+
//# sourceMappingURL=click-action.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"click-action.d.ts","sourceRoot":"","sources":["../../../../../src/browser-opt/runner/actions/utils/click-action.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAI9E,uCAAuC;AACvC,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,OAAO,CAAC,mBAAmB,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,EACvD,QAAQ,EAAE,gBAAgB,GACzB,MAAM,CAcR"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { findClickableRef } from '../../../utils.js';
|
|
2
|
+
import { clickFieldScopedDomTarget } from './dom-action.js';
|
|
3
|
+
/** 执行点击动作,只负责从当前快照定位可点击元素并下发 click。 */
|
|
4
|
+
export function executeClickAction(agent, action, snapshot) {
|
|
5
|
+
const ref = findClickableRef(snapshot, action.target, action.field);
|
|
6
|
+
if (ref) {
|
|
7
|
+
const output = agent.click(ref);
|
|
8
|
+
return `click @${ref}\n${output}`.trim();
|
|
9
|
+
}
|
|
10
|
+
const domOutput = action.field ? clickFieldScopedDomTarget(agent, action.field, action.target) : null;
|
|
11
|
+
if (domOutput) {
|
|
12
|
+
return domOutput;
|
|
13
|
+
}
|
|
14
|
+
const scopedTarget = action.field ? `${action.field} -> ${action.target}` : action.target;
|
|
15
|
+
throw new Error(`无法找到可点击元素:${scopedTarget}`);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=click-action.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"click-action.js","sourceRoot":"","sources":["../../../../../src/browser-opt/runner/actions/utils/click-action.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAE5D,uCAAuC;AACvC,MAAM,UAAU,kBAAkB,CAChC,KAAmB,EACnB,MAAuD,EACvD,QAA0B;IAE1B,MAAM,GAAG,GAAG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IACpE,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,UAAU,GAAG,KAAK,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtG,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,OAAO,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;IAC1F,MAAM,IAAI,KAAK,CAAC,aAAa,YAAY,EAAE,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* browser-opt 日期选择动作工具,负责 DatePicker 类控件的日期归一化、填充、面板兜底和结果确认。
|
|
3
|
+
*/
|
|
4
|
+
import type { BrowserAgent } from '@browser-automated/browser-core/agent';
|
|
5
|
+
import type { DeterministicAction, SnapshotEvidence } from '../../../type.js';
|
|
6
|
+
/** 判断 select-option 动作是否应交给日期控件处理,并返回归一化后的 YYYY-MM-DD。 */
|
|
7
|
+
export declare function resolveDateSelectOption(action: Extract<DeterministicAction, {
|
|
8
|
+
type: 'select-option';
|
|
9
|
+
}>): string | null;
|
|
10
|
+
/** 执行 DatePicker 选择动作,优先直接填充,失败时再尝试 DOM setter 和面板点击。 */
|
|
11
|
+
export declare function executeDateSelectOptionAction(agent: BrowserAgent, action: Extract<DeterministicAction, {
|
|
12
|
+
type: 'select-option';
|
|
13
|
+
}>, snapshot: SnapshotEvidence, normalizedDate: string): string;
|
|
14
|
+
/** 校验 DatePicker 选择结果,避免把不可选日期或临时输入态误判成已提交。 */
|
|
15
|
+
export declare function verifyDateSelectOptionActionEffect(agent: BrowserAgent, action: Extract<DeterministicAction, {
|
|
16
|
+
type: 'select-option';
|
|
17
|
+
}>, afterSnapshot: SnapshotEvidence, normalizedDate: string): {
|
|
18
|
+
passed: boolean;
|
|
19
|
+
message: string;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=date-action.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-action.d.ts","sourceRoot":"","sources":["../../../../../src/browser-opt/runner/actions/utils/date-action.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAI9E,0DAA0D;AAC1D,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,CAAC,mBAAmB,EAAE;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC,GAAG,MAAM,GAAG,IAAI,CAGtH;AAED,yDAAyD;AACzD,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,OAAO,CAAC,mBAAmB,EAAE;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC,EAC/D,QAAQ,EAAE,gBAAgB,EAC1B,cAAc,EAAE,MAAM,GACrB,MAAM,CAMR;AAED,+CAA+C;AAC/C,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,OAAO,CAAC,mBAAmB,EAAE;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC,EAC/D,aAAa,EAAE,gBAAgB,EAC/B,cAAc,EAAE,MAAM,GACrB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAetC"}
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
import { findTextboxRef } from '../../../utils.js';
|
|
2
|
+
import { captureTransientSnapshot } from '../../evidence.js';
|
|
3
|
+
/** 判断 select-option 动作是否应交给日期控件处理,并返回归一化后的 YYYY-MM-DD。 */
|
|
4
|
+
export function resolveDateSelectOption(action) {
|
|
5
|
+
const normalizedDate = normalizeDateOption(action.option);
|
|
6
|
+
return normalizedDate && isDateField(action.field) ? normalizedDate : null;
|
|
7
|
+
}
|
|
8
|
+
/** 执行 DatePicker 选择动作,优先直接填充,失败时再尝试 DOM setter 和面板点击。 */
|
|
9
|
+
export function executeDateSelectOptionAction(agent, action, snapshot, normalizedDate) {
|
|
10
|
+
const datePickerOutput = fillDatePickerTarget(agent, action, snapshot, normalizedDate);
|
|
11
|
+
if (datePickerOutput) {
|
|
12
|
+
return datePickerOutput;
|
|
13
|
+
}
|
|
14
|
+
throw new Error(`无法设置日期字段:${action.field ?? '日期'} -> ${action.option}(已转换为 ${normalizedDate})`);
|
|
15
|
+
}
|
|
16
|
+
/** 校验 DatePicker 选择结果,避免把不可选日期或临时输入态误判成已提交。 */
|
|
17
|
+
export function verifyDateSelectOptionActionEffect(agent, action, afterSnapshot, normalizedDate) {
|
|
18
|
+
if (isDatePickerConfirmDisabled(afterSnapshot.text)) {
|
|
19
|
+
return { passed: false, message: formatDateUnavailableMessage(action.field, normalizedDate) };
|
|
20
|
+
}
|
|
21
|
+
if (inspectDateCellAvailability(agent, normalizedDate) === false) {
|
|
22
|
+
return { passed: false, message: formatDateUnavailableMessage(action.field, normalizedDate) };
|
|
23
|
+
}
|
|
24
|
+
const domState = verifyDatePickerDomValue(agent, action.field, normalizedDate);
|
|
25
|
+
if (domState === true) {
|
|
26
|
+
return { passed: true, message: `已确认日期字段:${action.field}=${normalizedDate}` };
|
|
27
|
+
}
|
|
28
|
+
if (isSelectedValueVisible(afterSnapshot.text, action.field, normalizedDate)) {
|
|
29
|
+
return { passed: true, message: `已确认页面显示日期值:${action.field}=${normalizedDate}` };
|
|
30
|
+
}
|
|
31
|
+
return { passed: false, message: `动作后未确认日期字段:${action.field}=${normalizedDate}` };
|
|
32
|
+
}
|
|
33
|
+
/** DatePicker 不是普通选项控件,先归一化日期并直接输入,最后才兜底点击面板。 */
|
|
34
|
+
function fillDatePickerTarget(agent, action, snapshot, normalizedDate) {
|
|
35
|
+
const ref = action.field ? findTextboxRef(snapshot, action.field) : null;
|
|
36
|
+
const candidates = buildDateInputCandidates(normalizedDate, action.field);
|
|
37
|
+
if (ref) {
|
|
38
|
+
for (const candidate of candidates) {
|
|
39
|
+
const output = agent.fill(ref, candidate);
|
|
40
|
+
commitDatePickerDomValue(agent, action.field);
|
|
41
|
+
agent.waitMs(300);
|
|
42
|
+
const confirmation = confirmDatePickerValue(agent, action.field, normalizedDate);
|
|
43
|
+
if (confirmation.unavailable) {
|
|
44
|
+
throw new Error(formatDateUnavailableMessage(action.field, normalizedDate));
|
|
45
|
+
}
|
|
46
|
+
if (confirmation.confirmed) {
|
|
47
|
+
return `datepicker fill @${ref} ${action.field}=${candidate}\n${output}`.trim();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const candidate of candidates) {
|
|
52
|
+
const output = fillDatePickerDomTarget(agent, action.field, candidate, normalizedDate);
|
|
53
|
+
if (output) {
|
|
54
|
+
return output;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (ref) {
|
|
58
|
+
const output = selectDatePickerPanelTarget(agent, ref, action.field, normalizedDate);
|
|
59
|
+
if (output) {
|
|
60
|
+
return output;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
/** 直接输入失败时再点击面板;该路径避免作为主流程,以免跨月跨年翻页过脆。 */
|
|
66
|
+
function selectDatePickerPanelTarget(agent, ref, field, expectedDate) {
|
|
67
|
+
const openOutput = agent.click(ref);
|
|
68
|
+
agent.waitMs(300);
|
|
69
|
+
const script = `(() => {
|
|
70
|
+
const dateHelper = ${datePickerDomHelperSource()};
|
|
71
|
+
const result = dateHelper.clickDateCell(${JSON.stringify(expectedDate)});
|
|
72
|
+
if (!result.clicked) {
|
|
73
|
+
return JSON.stringify(result);
|
|
74
|
+
}
|
|
75
|
+
const okButton = [...document.querySelectorAll('.ant-picker-ok button, .ant-picker-footer button')]
|
|
76
|
+
.find((button) => dateHelper.browserOptDateVisible(button) && !button.disabled && /确|ok/i.test(button.textContent || ''));
|
|
77
|
+
if (okButton) {
|
|
78
|
+
okButton.click();
|
|
79
|
+
result.okClicked = true;
|
|
80
|
+
}
|
|
81
|
+
return JSON.stringify(result);
|
|
82
|
+
})()
|
|
83
|
+
`;
|
|
84
|
+
try {
|
|
85
|
+
const parsed = parseEvalJson(agent.evaluate(script));
|
|
86
|
+
if (parsed.clicked !== true) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
agent.waitMs(500);
|
|
90
|
+
const confirmation = confirmDatePickerValue(agent, field, expectedDate);
|
|
91
|
+
if (confirmation.unavailable) {
|
|
92
|
+
throw new Error(formatDateUnavailableMessage(field, expectedDate));
|
|
93
|
+
}
|
|
94
|
+
if (confirmation.confirmed) {
|
|
95
|
+
return [
|
|
96
|
+
`datepicker open @${ref}`,
|
|
97
|
+
openOutput,
|
|
98
|
+
`datepicker panel click ${field ?? '日期'}=${expectedDate}`,
|
|
99
|
+
].filter(Boolean).join('\n').trim();
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** 有些 DatePicker 无法被 ref fill 稳定控制,使用原生 setter 作为二级兜底。 */
|
|
108
|
+
function fillDatePickerDomTarget(agent, field, value, expectedDate) {
|
|
109
|
+
const script = `(() => {
|
|
110
|
+
const dateHelper = ${datePickerDomHelperSource()};
|
|
111
|
+
const input = dateHelper.findDateInputByField(${JSON.stringify(field)});
|
|
112
|
+
if (!input || input.disabled) {
|
|
113
|
+
return JSON.stringify({ found: Boolean(input), filled: false, disabled: Boolean(input?.disabled), readOnly: Boolean(input?.readOnly) });
|
|
114
|
+
}
|
|
115
|
+
input.focus();
|
|
116
|
+
dateHelper.setNativeInputValue(input, ${JSON.stringify(value)});
|
|
117
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
118
|
+
input.dispatchEvent(new Event('change', { bubbles: true }));
|
|
119
|
+
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', bubbles: true }));
|
|
120
|
+
input.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', code: 'Enter', bubbles: true }));
|
|
121
|
+
input.blur();
|
|
122
|
+
return JSON.stringify({ found: true, filled: true, value: input.value });
|
|
123
|
+
})()
|
|
124
|
+
`;
|
|
125
|
+
try {
|
|
126
|
+
const parsed = parseEvalJson(agent.evaluate(script));
|
|
127
|
+
if (parsed.filled === true) {
|
|
128
|
+
agent.waitMs(300);
|
|
129
|
+
const confirmation = confirmDatePickerValue(agent, field, expectedDate);
|
|
130
|
+
if (confirmation.unavailable) {
|
|
131
|
+
throw new Error(formatDateUnavailableMessage(field, expectedDate));
|
|
132
|
+
}
|
|
133
|
+
if (confirmation.confirmed) {
|
|
134
|
+
return `datepicker dom fill ${field ?? '日期'}=${value}`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** ref fill 后补一次 Enter/blur,触发 rc-picker 对输入内容的解析和提交。 */
|
|
144
|
+
function commitDatePickerDomValue(agent, field) {
|
|
145
|
+
const script = `(() => {
|
|
146
|
+
const dateHelper = ${datePickerDomHelperSource()};
|
|
147
|
+
const input = dateHelper.findDateInputByField(${JSON.stringify(field)}) || document.activeElement;
|
|
148
|
+
if (!input) {
|
|
149
|
+
return JSON.stringify({ found: false });
|
|
150
|
+
}
|
|
151
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
152
|
+
input.dispatchEvent(new Event('change', { bubbles: true }));
|
|
153
|
+
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', bubbles: true }));
|
|
154
|
+
input.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', code: 'Enter', bubbles: true }));
|
|
155
|
+
input.blur?.();
|
|
156
|
+
return JSON.stringify({ found: true, value: input.value || '' });
|
|
157
|
+
})()
|
|
158
|
+
`;
|
|
159
|
+
try {
|
|
160
|
+
agent.evaluate(script);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// 提交动作只是增强兜底,失败时继续让后续验证决定是否成功。
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/** 日期受控组件的 DOM value 可能读不到,补充 transient snapshot 作为动作内确认。 */
|
|
167
|
+
function confirmDatePickerValue(agent, field, expectedDate) {
|
|
168
|
+
if (inspectDatePickerCommitAvailability(agent) === false) {
|
|
169
|
+
return { confirmed: false, unavailable: true };
|
|
170
|
+
}
|
|
171
|
+
if (inspectDateCellAvailability(agent, expectedDate) === false) {
|
|
172
|
+
return { confirmed: false, unavailable: true };
|
|
173
|
+
}
|
|
174
|
+
if (verifyDatePickerDomValue(agent, field, expectedDate) === true) {
|
|
175
|
+
return { confirmed: true, unavailable: false };
|
|
176
|
+
}
|
|
177
|
+
const snapshot = captureTransientSnapshot(agent);
|
|
178
|
+
if (isDatePickerConfirmDisabled(snapshot.text)) {
|
|
179
|
+
return { confirmed: false, unavailable: true };
|
|
180
|
+
}
|
|
181
|
+
return { confirmed: isSelectedValueVisible(snapshot.text, field, expectedDate), unavailable: false };
|
|
182
|
+
}
|
|
183
|
+
/** 日期时间控件的确认按钮不可用时,输入框里的临时值不能作为已提交结果。 */
|
|
184
|
+
function inspectDatePickerCommitAvailability(agent) {
|
|
185
|
+
const script = `(() => {
|
|
186
|
+
const dateHelper = ${datePickerDomHelperSource()};
|
|
187
|
+
return JSON.stringify(dateHelper.inspectDatePickerCommitButton());
|
|
188
|
+
})()
|
|
189
|
+
`;
|
|
190
|
+
try {
|
|
191
|
+
const parsed = parseEvalJson(agent.evaluate(script));
|
|
192
|
+
if (!parsed.found) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
return parsed.disabled !== true;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/** 如果 DatePicker 面板能看到目标日期且它被禁用,则即使 input 短暂显示该值也不能判成功。 */
|
|
202
|
+
function inspectDateCellAvailability(agent, expectedDate) {
|
|
203
|
+
const script = `(() => {
|
|
204
|
+
const dateHelper = ${datePickerDomHelperSource()};
|
|
205
|
+
return JSON.stringify(dateHelper.inspectDateCell(${JSON.stringify(expectedDate)}));
|
|
206
|
+
})()
|
|
207
|
+
`;
|
|
208
|
+
try {
|
|
209
|
+
const parsed = parseEvalJson(agent.evaluate(script));
|
|
210
|
+
if (!parsed.found) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
return parsed.disabled !== true;
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/** 直接读取 DatePicker input 的值,弥补 snapshot 对受控日期组件状态表达不足的问题。 */
|
|
220
|
+
function verifyDatePickerDomValue(agent, field, expectedDate) {
|
|
221
|
+
const script = `(() => {
|
|
222
|
+
const dateHelper = ${datePickerDomHelperSource()};
|
|
223
|
+
const input = dateHelper.findDateInputByField(${JSON.stringify(field)});
|
|
224
|
+
if (!input) {
|
|
225
|
+
return JSON.stringify({ found: false, value: null });
|
|
226
|
+
}
|
|
227
|
+
return JSON.stringify({ found: true, value: input.value || input.getAttribute('value') || '' });
|
|
228
|
+
})()
|
|
229
|
+
`;
|
|
230
|
+
try {
|
|
231
|
+
const parsed = parseEvalJson(agent.evaluate(script));
|
|
232
|
+
if (!parsed.found || typeof parsed.value !== 'string') {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
return parsed.value.includes(expectedDate);
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function parseEvalJson(raw) {
|
|
242
|
+
const decoded = JSON.parse(raw.trim());
|
|
243
|
+
return typeof decoded === 'string'
|
|
244
|
+
? JSON.parse(decoded)
|
|
245
|
+
: decoded;
|
|
246
|
+
}
|
|
247
|
+
/** 返回在页面上下文执行的日期控件定位和赋值工具源码,优先按表单 label 关联 input。 */
|
|
248
|
+
function datePickerDomHelperSource() {
|
|
249
|
+
return `
|
|
250
|
+
(() => {
|
|
251
|
+
const normalizeBrowserOptDateText = (value) => String(value || '').replace(/[\\s::,,。;*]/g, '').toLowerCase();
|
|
252
|
+
const browserOptDateVisible = (element) => {
|
|
253
|
+
const style = window.getComputedStyle(element);
|
|
254
|
+
const rect = element.getBoundingClientRect();
|
|
255
|
+
return style.visibility !== 'hidden' && style.display !== 'none' && rect.width > 0 && rect.height > 0;
|
|
256
|
+
};
|
|
257
|
+
const browserOptDateInputs = (root = document) => [...root.querySelectorAll('input')]
|
|
258
|
+
.filter((input) => browserOptDateVisible(input))
|
|
259
|
+
.filter((input) => {
|
|
260
|
+
const text = normalizeBrowserOptDateText([input.placeholder, input.id, input.name, input.getAttribute('aria-label')].join(' '));
|
|
261
|
+
const className = String(input.closest('.ant-picker, .datepicker, .date-picker')?.className || '');
|
|
262
|
+
return input.type === 'date' || text.includes('日期') || text.includes('时间') || text.includes('date') || text.includes('time') || className.includes('picker');
|
|
263
|
+
});
|
|
264
|
+
function findDateInputByField(field) {
|
|
265
|
+
const fieldText = normalizeBrowserOptDateText(field);
|
|
266
|
+
if (fieldText) {
|
|
267
|
+
const labels = [...document.querySelectorAll('label')]
|
|
268
|
+
.filter((label) => browserOptDateVisible(label))
|
|
269
|
+
.filter((label) => normalizeBrowserOptDateText([label.textContent, label.title, label.getAttribute('for')].join(' ')).includes(fieldText));
|
|
270
|
+
for (const label of labels) {
|
|
271
|
+
const forId = label.getAttribute('for');
|
|
272
|
+
const byId = forId ? document.getElementById(forId) : null;
|
|
273
|
+
if (byId?.tagName === 'INPUT' && browserOptDateVisible(byId)) {
|
|
274
|
+
return byId;
|
|
275
|
+
}
|
|
276
|
+
const formItem = label.closest('.ant-form-item, .form-item, [class*="form-item"]');
|
|
277
|
+
const scoped = formItem ? browserOptDateInputs(formItem)[0] : null;
|
|
278
|
+
if (scoped) {
|
|
279
|
+
return scoped;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return browserOptDateInputs()[0] || null;
|
|
284
|
+
}
|
|
285
|
+
function setNativeInputValue(input, value) {
|
|
286
|
+
const prototype = Object.getPrototypeOf(input);
|
|
287
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, 'value');
|
|
288
|
+
if (descriptor?.set) {
|
|
289
|
+
descriptor.set.call(input, value);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
input.value = value;
|
|
293
|
+
}
|
|
294
|
+
function clickDateCell(expectedDate) {
|
|
295
|
+
const inspected = inspectDateCell(expectedDate);
|
|
296
|
+
if (!inspected.found) {
|
|
297
|
+
return { clicked: false, reason: 'date cell not found' };
|
|
298
|
+
}
|
|
299
|
+
if (inspected.disabled) {
|
|
300
|
+
return { clicked: false, disabled: true, reason: 'date cell disabled' };
|
|
301
|
+
}
|
|
302
|
+
inspected.clickable.click();
|
|
303
|
+
return { clicked: true, selectedDate: expectedDate };
|
|
304
|
+
}
|
|
305
|
+
function inspectDateCell(expectedDate) {
|
|
306
|
+
const dayText = String(Number(expectedDate.slice(8, 10)));
|
|
307
|
+
const candidates = [
|
|
308
|
+
...document.querySelectorAll(
|
|
309
|
+
'.ant-picker-cell[title], td[title], [data-date], .ant-picker-cell-inner, [role="gridcell"]'
|
|
310
|
+
),
|
|
311
|
+
].filter((element) => browserOptDateVisible(element));
|
|
312
|
+
const exact = candidates.find((element) => {
|
|
313
|
+
const title = element.getAttribute('title') || element.closest('[title]')?.getAttribute('title') || '';
|
|
314
|
+
const dataDate = element.getAttribute('data-date') || element.closest('[data-date]')?.getAttribute('data-date') || '';
|
|
315
|
+
return title === expectedDate || dataDate === expectedDate;
|
|
316
|
+
});
|
|
317
|
+
const fallback = exact || candidates.find((element) => {
|
|
318
|
+
const cell = element.closest('.ant-picker-cell');
|
|
319
|
+
const className = String(cell?.className || element.className || '');
|
|
320
|
+
if (className.includes('ant-picker-cell-disabled') || className.includes('ant-picker-cell-in-view') === false) {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
return normalizeBrowserOptDateText(element.textContent) === dayText;
|
|
324
|
+
});
|
|
325
|
+
if (!fallback) {
|
|
326
|
+
return { found: false, disabled: false, reason: 'date cell not found' };
|
|
327
|
+
}
|
|
328
|
+
const cell = fallback.closest('.ant-picker-cell') || fallback;
|
|
329
|
+
const className = String(cell.className || fallback.className || '');
|
|
330
|
+
const disabled = className.includes('ant-picker-cell-disabled')
|
|
331
|
+
|| fallback.getAttribute('aria-disabled') === 'true'
|
|
332
|
+
|| fallback.closest('[aria-disabled="true"]') !== null;
|
|
333
|
+
const clickable = fallback.querySelector?.('.ant-picker-cell-inner') || fallback;
|
|
334
|
+
return { found: true, disabled, clickable };
|
|
335
|
+
}
|
|
336
|
+
function inspectDatePickerCommitButton() {
|
|
337
|
+
const buttons = [...document.querySelectorAll('.ant-picker-ok button, .ant-picker-footer button')]
|
|
338
|
+
.filter((button) => browserOptDateVisible(button) && /确|ok/i.test(button.textContent || ''));
|
|
339
|
+
if (buttons.length === 0) {
|
|
340
|
+
return { found: false, disabled: false };
|
|
341
|
+
}
|
|
342
|
+
const button = buttons[0];
|
|
343
|
+
return { found: true, disabled: Boolean(button.disabled || button.getAttribute('aria-disabled') === 'true') };
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
browserOptDateVisible,
|
|
347
|
+
clickDateCell,
|
|
348
|
+
findDateInputByField,
|
|
349
|
+
inspectDateCell,
|
|
350
|
+
inspectDatePickerCommitButton,
|
|
351
|
+
setNativeInputValue,
|
|
352
|
+
};
|
|
353
|
+
})()
|
|
354
|
+
`;
|
|
355
|
+
}
|
|
356
|
+
/** 日期字段通常会被自然语言写成“直播时间选择明天”,这里保守限制只接管日期/时间类字段。 */
|
|
357
|
+
function isDateField(field) {
|
|
358
|
+
return Boolean(field && /日期|时间|日程|开播|直播时间|date|time/i.test(field));
|
|
359
|
+
}
|
|
360
|
+
/** 时间类 DatePicker 常要求完整时间格式;日期类则先尝试纯日期。 */
|
|
361
|
+
function buildDateInputCandidates(date, field) {
|
|
362
|
+
return [isTimeLikeDateField(field) ? `${date} 00:00:00` : date];
|
|
363
|
+
}
|
|
364
|
+
/** 字段名含“时间/time”时更可能是 DateTimePicker。 */
|
|
365
|
+
function isTimeLikeDateField(field) {
|
|
366
|
+
return Boolean(field && /时间|开播|time/i.test(field));
|
|
367
|
+
}
|
|
368
|
+
/** 将常见中文和数字日期描述转成 DatePicker 默认可接受的 YYYY-MM-DD。 */
|
|
369
|
+
function normalizeDateOption(option, baseDate = new Date()) {
|
|
370
|
+
const trimmed = option.trim();
|
|
371
|
+
const relativeDays = {
|
|
372
|
+
今天: 0,
|
|
373
|
+
今日: 0,
|
|
374
|
+
明天: 1,
|
|
375
|
+
明日: 1,
|
|
376
|
+
后天: 2,
|
|
377
|
+
大后天: 3,
|
|
378
|
+
};
|
|
379
|
+
if (Object.hasOwn(relativeDays, trimmed)) {
|
|
380
|
+
return formatDate(addDays(baseDate, relativeDays[trimmed] ?? 0));
|
|
381
|
+
}
|
|
382
|
+
const explicit = parseExplicitDate(trimmed, baseDate);
|
|
383
|
+
return explicit ? formatDate(explicit) : null;
|
|
384
|
+
}
|
|
385
|
+
/** 解析 7.1、0701、7月1日、2026-7-1、20260701 等常见口语日期。 */
|
|
386
|
+
function parseExplicitDate(input, baseDate) {
|
|
387
|
+
const normalized = input
|
|
388
|
+
.replace(/[号日]/g, '')
|
|
389
|
+
.replace(/年|\/|\.|-/g, '-')
|
|
390
|
+
.replace(/月/g, '-')
|
|
391
|
+
.trim();
|
|
392
|
+
const compact = input.replace(/[^\d]/g, '');
|
|
393
|
+
const currentYear = baseDate.getFullYear();
|
|
394
|
+
const ymd = normalized.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
|
|
395
|
+
if (ymd) {
|
|
396
|
+
return createValidDate(Number(ymd[1]), Number(ymd[2]), Number(ymd[3]));
|
|
397
|
+
}
|
|
398
|
+
const md = normalized.match(/^(\d{1,2})-(\d{1,2})$/);
|
|
399
|
+
if (md) {
|
|
400
|
+
return createFutureBiasedDate(currentYear, Number(md[1]), Number(md[2]), baseDate);
|
|
401
|
+
}
|
|
402
|
+
if (/^\d{8}$/.test(compact)) {
|
|
403
|
+
return createValidDate(Number(compact.slice(0, 4)), Number(compact.slice(4, 6)), Number(compact.slice(6, 8)));
|
|
404
|
+
}
|
|
405
|
+
if (/^\d{4}$/.test(compact)) {
|
|
406
|
+
return createFutureBiasedDate(currentYear, Number(compact.slice(0, 2)), Number(compact.slice(2, 4)), baseDate);
|
|
407
|
+
}
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
/** 没写年份的日期用于预约场景时,如果已过去则自动滚到下一年。 */
|
|
411
|
+
function createFutureBiasedDate(year, month, day, baseDate) {
|
|
412
|
+
const date = createValidDate(year, month, day);
|
|
413
|
+
if (!date) {
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
const baseDay = new Date(baseDate.getFullYear(), baseDate.getMonth(), baseDate.getDate());
|
|
417
|
+
return date < baseDay ? createValidDate(year + 1, month, day) : date;
|
|
418
|
+
}
|
|
419
|
+
/** 严格构造日期,避免 2 月 31 日被 JS 自动进位后误认为合法输入。 */
|
|
420
|
+
function createValidDate(year, month, day) {
|
|
421
|
+
const date = new Date(year, month - 1, day);
|
|
422
|
+
if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
return date;
|
|
426
|
+
}
|
|
427
|
+
/** 按 AntD DatePicker 默认格式输出日期。 */
|
|
428
|
+
function formatDate(date) {
|
|
429
|
+
const year = date.getFullYear();
|
|
430
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
431
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
432
|
+
return `${year}-${month}-${day}`;
|
|
433
|
+
}
|
|
434
|
+
/** 基于本地时区做自然日加减,避免毫秒相加遇到夏令时边界产生偏移。 */
|
|
435
|
+
function addDays(date, days) {
|
|
436
|
+
const next = new Date(date);
|
|
437
|
+
next.setDate(next.getDate() + days);
|
|
438
|
+
return next;
|
|
439
|
+
}
|
|
440
|
+
/** 下拉选择通常会收起选项列表,只保留字段和值文案,因此补充基于页面文案的确认。 */
|
|
441
|
+
function isSelectedValueVisible(text, field, option) {
|
|
442
|
+
const normalizedText = normalizeVisibleText(text);
|
|
443
|
+
const normalizedOption = normalizeVisibleText(option);
|
|
444
|
+
if (!normalizedOption || !normalizedText.includes(normalizedOption)) {
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
if (!field) {
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
return normalizedText.includes(normalizeVisibleText(field));
|
|
451
|
+
}
|
|
452
|
+
/** AntD DateTimePicker 面板还开着且“确定”禁用时,当前日期值只是临时输入态。 */
|
|
453
|
+
function isDatePickerConfirmDisabled(text) {
|
|
454
|
+
return /button\s+"(?:确\s*定|ok)"\s+\[[^\]]*disabled/i.test(text);
|
|
455
|
+
}
|
|
456
|
+
/** 统一不可选日期的用户侧提示,避免报告里出现“已显示但未提交”的误导信息。 */
|
|
457
|
+
function formatDateUnavailableMessage(field, date) {
|
|
458
|
+
return `日期不可选:${field ?? '日期'}=${date}`;
|
|
459
|
+
}
|
|
460
|
+
/** 归一化页面可见文案,减少空白和标点对选择结果确认的影响。 */
|
|
461
|
+
function normalizeVisibleText(value) {
|
|
462
|
+
return value.toLowerCase().replace(/\s+/g, '').replace(/[::,,。;"'‘’“”]/g, '').trim();
|
|
463
|
+
}
|
|
464
|
+
//# sourceMappingURL=date-action.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-action.js","sourceRoot":"","sources":["../../../../../src/browser-opt/runner/actions/utils/date-action.ts"],"names":[],"mappings":"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"}
|