@reconcrap/boss-recommend-mcp 2.0.3 → 2.0.5
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/README.md +3 -3
- package/config/screening-config.example.json +10 -8
- package/package.json +1 -1
- package/src/chat-mcp.js +18 -10
- package/src/chat-runtime-config.js +28 -1
- package/src/core/browser/index.js +1 -0
- package/src/core/screening/index.js +3 -3
- package/src/core/self-heal/index.js +128 -3
- package/src/core/self-heal/viewport.js +564 -0
- package/src/domains/chat/run-service.js +52 -8
- package/src/domains/recommend/roots.js +4 -2
- package/src/domains/recommend/run-service.js +37 -3
- package/src/domains/recruit/roots.js +2 -1
- package/src/domains/recruit/run-service.js +34 -3
- package/src/index.js +6 -3
- package/src/recommend-mcp.js +22 -7
- package/src/recruit-mcp.js +18 -6
package/README.md
CHANGED
|
@@ -221,10 +221,10 @@ config/screening-config.example.json
|
|
|
221
221
|
|
|
222
222
|
- `openaiOrganization`
|
|
223
223
|
- `openaiProject`
|
|
224
|
-
- `debugPort`
|
|
225
|
-
- `outputDir
|
|
224
|
+
- `debugPort`:未显式传 `port` 时,recommend / search / chat CDP-only MCP run 和健康检查默认连接这个 Chrome 调试端口。
|
|
225
|
+
- `outputDir`:recommend / search / chat 完成后的最终 CSV 与 report JSON 会写入这里;run state / checkpoint 仍保留在各自状态目录,方便 pause/resume/cancel。
|
|
226
226
|
- `llmThinkingLevel`:默认 `low`。可设为 `off/minimal/low/medium/high/auto/current`,用于控制 OpenAI-compatible LLM 的 thinking/reasoning 强度。
|
|
227
|
-
- `humanRestEnabled`:默认 `false
|
|
227
|
+
- `humanRestEnabled`:默认 `false`。当前 CDP-only recommend / search / chat run 尚未实现随机休息层,因此会读取并保留该字段但不改变节奏;如后续重新加入 human rest,应以此字段为默认值。
|
|
228
228
|
|
|
229
229
|
## 常用命令
|
|
230
230
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"baseUrl": "https://api.openai.com/v1",
|
|
3
3
|
"apiKey": "replace-with-openai-api-key",
|
|
4
|
-
"model": "gpt-4.1-mini",
|
|
5
|
-
"llmThinkingLevel": "low",
|
|
6
|
-
"llmTimeoutMs": 60000,
|
|
7
|
-
"llmMaxRetries": 3,
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
4
|
+
"model": "gpt-4.1-mini",
|
|
5
|
+
"llmThinkingLevel": "low",
|
|
6
|
+
"llmTimeoutMs": 60000,
|
|
7
|
+
"llmMaxRetries": 3,
|
|
8
|
+
"debugPort": 9222,
|
|
9
|
+
"outputDir": "",
|
|
10
|
+
"humanRestEnabled": false,
|
|
11
|
+
"openaiOrganization": "optional-org-id",
|
|
12
|
+
"openaiProject": "optional-project-id"
|
|
13
|
+
}
|
package/package.json
CHANGED
package/src/chat-mcp.js
CHANGED
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
getBossChatDataDir,
|
|
46
46
|
getBossChatTargetCountValue,
|
|
47
47
|
normalizeTargetCountInput,
|
|
48
|
+
resolveBossConfiguredOutputDir,
|
|
48
49
|
resolveBossChatRuntimeLayout,
|
|
49
50
|
resolveBossScreeningConfig
|
|
50
51
|
} from "./chat-runtime-config.js";
|
|
@@ -123,12 +124,14 @@ function getChatRunArtifacts(runId) {
|
|
|
123
124
|
const normalized = normalizeRunId(runId);
|
|
124
125
|
if (!normalized) return null;
|
|
125
126
|
const runsDir = getChatRunsDir();
|
|
127
|
+
const outputDir = resolveBossConfiguredOutputDir("", runsDir);
|
|
126
128
|
return {
|
|
127
129
|
runs_dir: runsDir,
|
|
130
|
+
output_dir: outputDir,
|
|
128
131
|
run_state_path: path.join(runsDir, `${normalized}.json`),
|
|
129
132
|
checkpoint_path: path.join(runsDir, `${normalized}.checkpoint.json`),
|
|
130
|
-
output_csv: path.join(
|
|
131
|
-
report_json: path.join(
|
|
133
|
+
output_csv: path.join(outputDir, `${normalized}.results.csv`),
|
|
134
|
+
report_json: path.join(outputDir, `${normalized}.report.json`)
|
|
132
135
|
};
|
|
133
136
|
}
|
|
134
137
|
|
|
@@ -491,7 +494,8 @@ async function waitForHealthyChat(client, config, {
|
|
|
491
494
|
domain: "chat",
|
|
492
495
|
roots: roots.roots,
|
|
493
496
|
selectorProbes: config.selectorProbes,
|
|
494
|
-
accessibilityProbes: config.accessibilityProbes
|
|
497
|
+
accessibilityProbes: config.accessibilityProbes,
|
|
498
|
+
viewportProbes: config.viewportProbes
|
|
495
499
|
});
|
|
496
500
|
if (lastCheck.status === HEALTH_STATUS.HEALTHY) return lastCheck;
|
|
497
501
|
await sleep(intervalMs);
|
|
@@ -633,7 +637,7 @@ async function readChatJobOptionsFromSession(session) {
|
|
|
633
637
|
return readChatJobOptions(session.client, roots.rootNodes.top);
|
|
634
638
|
}
|
|
635
639
|
|
|
636
|
-
function normalizeChatStartInput(args = {}) {
|
|
640
|
+
function normalizeChatStartInput(args = {}, configResolution = null) {
|
|
637
641
|
const target = normalizeTargetCountInput(getBossChatTargetCountValue(args));
|
|
638
642
|
return {
|
|
639
643
|
profile: normalizeText(args.profile) || "default",
|
|
@@ -645,7 +649,10 @@ function normalizeChatStartInput(args = {}) {
|
|
|
645
649
|
targetCount: target.targetCount,
|
|
646
650
|
publicTargetCount: target.publicValue,
|
|
647
651
|
host: normalizeText(args.host) || DEFAULT_CHAT_HOST,
|
|
648
|
-
port: parsePositiveInteger(
|
|
652
|
+
port: parsePositiveInteger(
|
|
653
|
+
args.port,
|
|
654
|
+
configResolution?.ok ? configResolution.config.debugPort : DEFAULT_CHAT_PORT
|
|
655
|
+
),
|
|
649
656
|
targetUrlIncludes: normalizeText(args.target_url_includes) || CHAT_TARGET_URL,
|
|
650
657
|
allowNavigate: args.allow_navigate !== false,
|
|
651
658
|
slowLive: args.slow_live === true
|
|
@@ -800,7 +807,6 @@ function getRunOptions(args, normalized, session, { workspaceRoot = "" } = {}) {
|
|
|
800
807
|
const shouldRequestResume = shouldRequestChatResume(args);
|
|
801
808
|
const useLlm = shouldUseChatLlm(args, shouldRequestResume);
|
|
802
809
|
const configResolution = useLlm ? resolveBossScreeningConfig(workspaceRoot) : { ok: false };
|
|
803
|
-
const configFile = configResolution.ok ? readJsonFile(configResolution.config_path) : null;
|
|
804
810
|
return {
|
|
805
811
|
client: session.client,
|
|
806
812
|
targetUrl: CHAT_TARGET_URL,
|
|
@@ -827,8 +833,7 @@ function getRunOptions(args, normalized, session, { workspaceRoot = "" } = {}) {
|
|
|
827
833
|
maxImagePages: parsePositiveInteger(args.max_image_pages, 8),
|
|
828
834
|
imageWheelDeltaY: parsePositiveInteger(args.image_wheel_delta_y, 650),
|
|
829
835
|
llmConfig: configResolution.ok ? {
|
|
830
|
-
...configResolution.config
|
|
831
|
-
apiKey: configFile?.apiKey || ""
|
|
836
|
+
...configResolution.config
|
|
832
837
|
} : null,
|
|
833
838
|
llmTimeoutMs: parsePositiveInteger(args.llm_timeout_ms, slowLive ? 180000 : 120000),
|
|
834
839
|
llmImageLimit: parsePositiveInteger(args.llm_image_limit, 8),
|
|
@@ -888,7 +893,8 @@ function trackChatRun(runId) {
|
|
|
888
893
|
}
|
|
889
894
|
|
|
890
895
|
async function startBossChatRunInternal(args = {}, { workspaceRoot = "" } = {}) {
|
|
891
|
-
const
|
|
896
|
+
const defaultConfigResolution = resolveBossScreeningConfig(workspaceRoot);
|
|
897
|
+
const normalized = normalizeChatStartInput(args, defaultConfigResolution);
|
|
892
898
|
const missingFields = getMissingChatStartFields(args, normalized);
|
|
893
899
|
if (missingFields.length) {
|
|
894
900
|
return buildNeedInputResponse({
|
|
@@ -987,7 +993,8 @@ async function startBossChatRunInternal(args = {}, { workspaceRoot = "" } = {})
|
|
|
987
993
|
}
|
|
988
994
|
|
|
989
995
|
export async function prepareBossChatRunTool({ workspaceRoot = "", args = {} } = {}) {
|
|
990
|
-
const
|
|
996
|
+
const configResolution = resolveBossScreeningConfig(workspaceRoot);
|
|
997
|
+
const normalized = normalizeChatStartInput(args, configResolution);
|
|
991
998
|
let session;
|
|
992
999
|
try {
|
|
993
1000
|
session = await chatConnectorImpl({
|
|
@@ -1129,6 +1136,7 @@ export async function bossChatHealthCheckTool({ workspaceRoot = "", args = {} }
|
|
|
1129
1136
|
cli_path: null,
|
|
1130
1137
|
config_path: configResolution.config_path || null,
|
|
1131
1138
|
config_dir: configResolution.config_dir || null,
|
|
1139
|
+
output_dir: configResolution.ok ? configResolution.config.outputDir || null : null,
|
|
1132
1140
|
debug_port: port,
|
|
1133
1141
|
shared_llm_config: configResolution.ok === true,
|
|
1134
1142
|
data_dir: runtimeLayout.data_dir,
|
|
@@ -223,6 +223,22 @@ function parsePositiveInteger(raw, fallback = null) {
|
|
|
223
223
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
function parseConfigBoolean(raw, fallback = false) {
|
|
227
|
+
if (typeof raw === "boolean") return raw;
|
|
228
|
+
const normalized = normalizeText(raw).toLowerCase();
|
|
229
|
+
if (["true", "1", "yes", "y", "on", "enabled"].includes(normalized)) return true;
|
|
230
|
+
if (["false", "0", "no", "n", "off", "disabled"].includes(normalized)) return false;
|
|
231
|
+
return fallback;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function resolveConfigPathValue(raw, configDir) {
|
|
235
|
+
const normalized = normalizeText(raw);
|
|
236
|
+
if (!normalized) return "";
|
|
237
|
+
return path.isAbsolute(normalized)
|
|
238
|
+
? path.resolve(normalized)
|
|
239
|
+
: path.resolve(configDir || process.cwd(), normalized);
|
|
240
|
+
}
|
|
241
|
+
|
|
226
242
|
function validateScreeningConfig(config) {
|
|
227
243
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
228
244
|
return {
|
|
@@ -369,8 +385,12 @@ export function resolveBossScreeningConfig(workspaceRoot) {
|
|
|
369
385
|
ok: true,
|
|
370
386
|
config: {
|
|
371
387
|
baseUrl: normalizeText(parsed.baseUrl).replace(/\/+$/, ""),
|
|
388
|
+
apiKey: normalizeText(parsed.apiKey),
|
|
372
389
|
model: normalizeText(parsed.model),
|
|
373
|
-
debugPort: parsePositiveInteger(parsed.debugPort, 9222)
|
|
390
|
+
debugPort: parsePositiveInteger(parsed.debugPort, 9222),
|
|
391
|
+
llmThinkingLevel: normalizeText(parsed.llmThinkingLevel || parsed.thinkingLevel || parsed.reasoningEffort),
|
|
392
|
+
outputDir: resolveConfigPathValue(parsed.outputDir, configDir),
|
|
393
|
+
humanRestEnabled: parseConfigBoolean(parsed.humanRestEnabled, false)
|
|
374
394
|
},
|
|
375
395
|
config_path: configPath,
|
|
376
396
|
config_dir: configDir,
|
|
@@ -378,6 +398,13 @@ export function resolveBossScreeningConfig(workspaceRoot) {
|
|
|
378
398
|
};
|
|
379
399
|
}
|
|
380
400
|
|
|
401
|
+
export function resolveBossConfiguredOutputDir(workspaceRoot, fallbackDir = "") {
|
|
402
|
+
const configResolution = resolveBossScreeningConfig(workspaceRoot);
|
|
403
|
+
const configuredDir = configResolution.ok ? normalizeText(configResolution.config.outputDir) : "";
|
|
404
|
+
if (configuredDir) return configuredDir;
|
|
405
|
+
return fallbackDir ? path.resolve(fallbackDir) : "";
|
|
406
|
+
}
|
|
407
|
+
|
|
381
408
|
function isUnlimitedTargetCountToken(value) {
|
|
382
409
|
const token = normalizeText(value).toLowerCase();
|
|
383
410
|
if (!token) return false;
|
|
@@ -37,7 +37,7 @@ const GENDER_CODE_MAP = {
|
|
|
37
37
|
2: "女"
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
-
const LLM_THINKING_LEVELS = new Set(["off", "low", "medium", "high", "current"]);
|
|
40
|
+
const LLM_THINKING_LEVELS = new Set(["off", "minimal", "low", "medium", "high", "auto", "current"]);
|
|
41
41
|
|
|
42
42
|
function nowIso() {
|
|
43
43
|
return new Date().toISOString();
|
|
@@ -64,9 +64,9 @@ function isVolcengineModel(baseUrl, model) {
|
|
|
64
64
|
|
|
65
65
|
function applyChatCompletionThinking(payload, { baseUrl = "", model = "", thinkingLevel = "" } = {}) {
|
|
66
66
|
const level = normalizeLlmThinkingLevel(thinkingLevel);
|
|
67
|
-
if (!level || level === "current") return payload;
|
|
67
|
+
if (!level || level === "current" || level === "auto") return payload;
|
|
68
68
|
if (isVolcengineModel(baseUrl, model)) {
|
|
69
|
-
if (level === "off") {
|
|
69
|
+
if (level === "off" || level === "minimal") {
|
|
70
70
|
payload.thinking = { type: "disabled" };
|
|
71
71
|
} else {
|
|
72
72
|
payload.thinking = { type: "enabled" };
|
|
@@ -5,6 +5,26 @@ import {
|
|
|
5
5
|
querySelectorAll,
|
|
6
6
|
sleep
|
|
7
7
|
} from "../browser/index.js";
|
|
8
|
+
import {
|
|
9
|
+
compactViewportHealthResult,
|
|
10
|
+
ensureHealthyViewport
|
|
11
|
+
} from "./viewport.js";
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
buildViewportHealthDiagnostics,
|
|
15
|
+
compactViewportHealthResult,
|
|
16
|
+
compactViewportState,
|
|
17
|
+
createViewportRunGuard,
|
|
18
|
+
ensureHealthyViewport,
|
|
19
|
+
getCurrentWindowInfo,
|
|
20
|
+
isListViewportCollapsed,
|
|
21
|
+
readViewportState,
|
|
22
|
+
setWindowStateIfPossible,
|
|
23
|
+
toggleWindowStateForViewportRecovery,
|
|
24
|
+
VIEWPORT_COLLAPSE_MIN_EXPECTED_WIDTH,
|
|
25
|
+
VIEWPORT_COLLAPSE_NEAR_FULLSCREEN_RATIO,
|
|
26
|
+
VIEWPORT_COLLAPSE_RATIO_THRESHOLD
|
|
27
|
+
} from "./viewport.js";
|
|
8
28
|
|
|
9
29
|
export const PROBE_STATUS = Object.freeze({
|
|
10
30
|
PASS: "pass",
|
|
@@ -245,6 +265,26 @@ export function createNetworkProbe({
|
|
|
245
265
|
};
|
|
246
266
|
}
|
|
247
267
|
|
|
268
|
+
export function createViewportCollapseProbe({
|
|
269
|
+
id = "viewport_collapse",
|
|
270
|
+
root = "frame",
|
|
271
|
+
frameOwnerRoot = "frameOwner",
|
|
272
|
+
required = true,
|
|
273
|
+
repair = true,
|
|
274
|
+
description = ""
|
|
275
|
+
} = {}) {
|
|
276
|
+
if (!id) throw new Error("Viewport collapse probe requires an id");
|
|
277
|
+
return {
|
|
278
|
+
type: "viewport",
|
|
279
|
+
id,
|
|
280
|
+
root,
|
|
281
|
+
frameOwnerRoot,
|
|
282
|
+
required: Boolean(required),
|
|
283
|
+
repair: Boolean(repair),
|
|
284
|
+
description
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
248
288
|
export async function runSelectorProbe(client, roots, probe) {
|
|
249
289
|
const nodeId = rootNodeId(roots, probe.root);
|
|
250
290
|
if (!nodeId) {
|
|
@@ -338,6 +378,52 @@ export function runNetworkProbe(networkEvents = [], probe) {
|
|
|
338
378
|
};
|
|
339
379
|
}
|
|
340
380
|
|
|
381
|
+
export async function runViewportCollapseProbe(client, roots, probe) {
|
|
382
|
+
const nodeId = rootNodeId(roots, probe.root);
|
|
383
|
+
if (!nodeId) {
|
|
384
|
+
return {
|
|
385
|
+
...probe,
|
|
386
|
+
ok: !probe.required,
|
|
387
|
+
status: probe.required ? PROBE_STATUS.BLOCKED : PROBE_STATUS.OPTIONAL_ABSENT,
|
|
388
|
+
count: 0,
|
|
389
|
+
collapsed: false,
|
|
390
|
+
recovered: false,
|
|
391
|
+
error: `Root not found: ${probe.root}`
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
try {
|
|
396
|
+
const health = await ensureHealthyViewport(client, {
|
|
397
|
+
roots,
|
|
398
|
+
root: probe.root,
|
|
399
|
+
frameOwnerRoot: probe.frameOwnerRoot,
|
|
400
|
+
reason: probe.id,
|
|
401
|
+
repair: probe.repair
|
|
402
|
+
});
|
|
403
|
+
const ok = Boolean(health.ok);
|
|
404
|
+
return {
|
|
405
|
+
...probe,
|
|
406
|
+
ok: probe.required ? ok : true,
|
|
407
|
+
status: ok ? PROBE_STATUS.PASS : probe.required ? PROBE_STATUS.FAIL : PROBE_STATUS.OPTIONAL_ABSENT,
|
|
408
|
+
count: ok ? 1 : 0,
|
|
409
|
+
collapsed: Boolean(health.collapsed),
|
|
410
|
+
recovered: Boolean(health.recovered),
|
|
411
|
+
viewport_health: compactViewportHealthResult(health),
|
|
412
|
+
error: health.error || null
|
|
413
|
+
};
|
|
414
|
+
} catch (error) {
|
|
415
|
+
return {
|
|
416
|
+
...probe,
|
|
417
|
+
ok: !probe.required,
|
|
418
|
+
status: probe.required ? PROBE_STATUS.ERROR : PROBE_STATUS.OPTIONAL_ABSENT,
|
|
419
|
+
count: 0,
|
|
420
|
+
collapsed: false,
|
|
421
|
+
recovered: false,
|
|
422
|
+
error: error?.message || String(error)
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
341
427
|
export function summarizeProbeResults(probes = []) {
|
|
342
428
|
const required = probes.filter((probe) => probe.required);
|
|
343
429
|
const blocked = required.filter((probe) => probe.status === PROBE_STATUS.BLOCKED);
|
|
@@ -370,6 +456,7 @@ export function buildDriftReport(probes = []) {
|
|
|
370
456
|
expected_min_count: probe.minCount,
|
|
371
457
|
observed_count: probe.count || 0,
|
|
372
458
|
selectors: probe.selectors || [],
|
|
459
|
+
viewport_health: probe.viewport_health || undefined,
|
|
373
460
|
error: probe.error || null
|
|
374
461
|
}));
|
|
375
462
|
}
|
|
@@ -380,6 +467,7 @@ export async function runSelfHealCheck({
|
|
|
380
467
|
roots = {},
|
|
381
468
|
selectorProbes = [],
|
|
382
469
|
accessibilityProbes = [],
|
|
470
|
+
viewportProbes = [],
|
|
383
471
|
networkProbes = [],
|
|
384
472
|
networkEvents = []
|
|
385
473
|
} = {}) {
|
|
@@ -393,8 +481,13 @@ export async function runSelfHealCheck({
|
|
|
393
481
|
accessibilityResults.push(await runAccessibilityProbe(client, probe));
|
|
394
482
|
}
|
|
395
483
|
|
|
484
|
+
const viewportResults = [];
|
|
485
|
+
for (const probe of viewportProbes) {
|
|
486
|
+
viewportResults.push(await runViewportCollapseProbe(client, roots, probe));
|
|
487
|
+
}
|
|
488
|
+
|
|
396
489
|
const networkResults = networkProbes.map((probe) => runNetworkProbe(networkEvents, probe));
|
|
397
|
-
const probes = [...selectorResults, ...accessibilityResults, ...networkResults];
|
|
490
|
+
const probes = [...selectorResults, ...accessibilityResults, ...viewportResults, ...networkResults];
|
|
398
491
|
const summary = summarizeProbeResults(probes);
|
|
399
492
|
|
|
400
493
|
return {
|
|
@@ -507,6 +600,16 @@ export function buildRecommendSelfHealConfig(rules = {}) {
|
|
|
507
600
|
description: "Candidate detail popup may mount inside the recommend frame"
|
|
508
601
|
})
|
|
509
602
|
],
|
|
603
|
+
viewportProbes: [
|
|
604
|
+
createViewportCollapseProbe({
|
|
605
|
+
id: "recommend_viewport_collapse",
|
|
606
|
+
root: "frame",
|
|
607
|
+
frameOwnerRoot: "frameOwner",
|
|
608
|
+
required: true,
|
|
609
|
+
repair: true,
|
|
610
|
+
description: "Recommend frame/list viewport has not collapsed relative to the Chrome window"
|
|
611
|
+
})
|
|
612
|
+
],
|
|
510
613
|
accessibilityProbes: [
|
|
511
614
|
createAccessibilityProbe({
|
|
512
615
|
id: "accessibility_tree",
|
|
@@ -610,6 +713,16 @@ export function buildRecruitSelfHealConfig(rules = {}) {
|
|
|
610
713
|
description: "Candidate detail popup may mount inside the search frame"
|
|
611
714
|
})
|
|
612
715
|
],
|
|
716
|
+
viewportProbes: [
|
|
717
|
+
createViewportCollapseProbe({
|
|
718
|
+
id: "recruit_viewport_collapse",
|
|
719
|
+
root: "frame",
|
|
720
|
+
frameOwnerRoot: "frameOwner",
|
|
721
|
+
required: true,
|
|
722
|
+
repair: true,
|
|
723
|
+
description: "Search frame/list viewport has not collapsed relative to the Chrome window"
|
|
724
|
+
})
|
|
725
|
+
],
|
|
613
726
|
accessibilityProbes: [
|
|
614
727
|
createAccessibilityProbe({
|
|
615
728
|
id: "accessibility_tree",
|
|
@@ -711,6 +824,16 @@ export function buildChatSelfHealConfig(rules = {}) {
|
|
|
711
824
|
description: "Resume iframe appears after the online resume is opened"
|
|
712
825
|
})
|
|
713
826
|
],
|
|
827
|
+
viewportProbes: [
|
|
828
|
+
createViewportCollapseProbe({
|
|
829
|
+
id: "chat_viewport_collapse",
|
|
830
|
+
root: "top",
|
|
831
|
+
frameOwnerRoot: "top",
|
|
832
|
+
required: true,
|
|
833
|
+
repair: true,
|
|
834
|
+
description: "Chat list viewport has not collapsed relative to the Chrome window"
|
|
835
|
+
})
|
|
836
|
+
],
|
|
714
837
|
accessibilityProbes: [
|
|
715
838
|
createAccessibilityProbe({
|
|
716
839
|
id: "accessibility_tree",
|
|
@@ -756,7 +879,8 @@ export async function resolveRecommendSelfHealRoots(client, config = buildRecomm
|
|
|
756
879
|
return {
|
|
757
880
|
roots: {
|
|
758
881
|
top: topRoot.nodeId,
|
|
759
|
-
frame: iframe.documentNodeId
|
|
882
|
+
frame: iframe.documentNodeId,
|
|
883
|
+
frameOwner: iframe.nodeId
|
|
760
884
|
},
|
|
761
885
|
topRoot,
|
|
762
886
|
iframe
|
|
@@ -779,7 +903,8 @@ export async function resolveRecruitSelfHealRoots(client, config = buildRecruitS
|
|
|
779
903
|
return {
|
|
780
904
|
roots: {
|
|
781
905
|
top: topRoot.nodeId,
|
|
782
|
-
frame: iframe.documentNodeId
|
|
906
|
+
frame: iframe.documentNodeId,
|
|
907
|
+
frameOwner: iframe.nodeId
|
|
783
908
|
},
|
|
784
909
|
topRoot,
|
|
785
910
|
iframe
|