fix(web-probe): 对齐新版 MDTODO DOM 合同
This commit is contained in:
@@ -764,7 +764,7 @@ async function selectMdtodoTask(command) {
|
||||
const clicked = await target.locator.evaluate((element) => ({
|
||||
taskRef: element.getAttribute("data-task-ref") || null,
|
||||
taskId: element.getAttribute("data-task-id") || element.getAttribute("data-rxx-id") || null,
|
||||
status: element.getAttribute("data-task-status") || null,
|
||||
status: element.getAttribute("data-task-status") || element.querySelector("[data-state]")?.getAttribute("data-state") || null,
|
||||
selected: element.getAttribute("data-selected") === "true" || element.getAttribute("aria-selected") === "true"
|
||||
})).catch(() => ({ taskRef: target.taskRef || null, taskId: target.taskId || null, status: null }));
|
||||
if (!clicked.selected) {
|
||||
@@ -895,12 +895,22 @@ async function closeMdtodoSourceConfigIfOpen(options = {}) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function mdtodoTestIdCandidates(value) {
|
||||
return (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string" && item.length > 0);
|
||||
}
|
||||
|
||||
function mdtodoTestIdLocator(value) {
|
||||
const candidates = mdtodoTestIdCandidates(value);
|
||||
return page.locator(candidates.map((testId) => '[data-testid="' + cssEscape(testId) + '"]').join(", ")).first();
|
||||
}
|
||||
|
||||
async function fillMdtodoField(testId, value) {
|
||||
if (typeof value !== "string" || !value.trim()) return { testId, filled: false };
|
||||
const locator = page.locator('[data-testid="' + cssEscape(testId) + '"]').first();
|
||||
const locator = mdtodoTestIdLocator(testId);
|
||||
await locator.waitFor({ state: "visible", timeout: 10000 });
|
||||
await locator.fill(value);
|
||||
return { testId, filled: true, value: opaqueIdSummary(value), valuesRedacted: true };
|
||||
const resolvedTestId = await locator.getAttribute("data-testid").catch(() => null);
|
||||
return { testId: resolvedTestId || mdtodoTestIdCandidates(testId)[0] || null, filled: true, value: opaqueIdSummary(value), valuesRedacted: true };
|
||||
}
|
||||
|
||||
async function clickProjectButtonAndMaybeWait(testId, pathPattern) {
|
||||
@@ -1003,7 +1013,7 @@ async function saveMdtodoTaskWithButton(command, type, testId, fields) {
|
||||
if (field.openByDblClickTestId) inlineEditors.push(await ensureMdtodoInlineEditor(field.testId, field.openByDblClickTestId));
|
||||
if (field.kind === "fill") await fillMdtodoField(field.testId, field.value);
|
||||
if (field.kind === "select") {
|
||||
const locator = page.locator('[data-testid="' + cssEscape(field.testId) + '"]').first();
|
||||
const locator = mdtodoTestIdLocator(field.testId);
|
||||
await locator.waitFor({ state: "visible", timeout: 10000 });
|
||||
await selectHtmlOptionByValueOrLabel(locator, field.value);
|
||||
}
|
||||
@@ -1023,9 +1033,9 @@ async function clickProjectButtonAndMaybeWaitAny(testIds, pathPattern) {
|
||||
}
|
||||
|
||||
async function ensureMdtodoInlineEditor(editorTestId, readTestId) {
|
||||
const editor = page.locator('[data-testid="' + cssEscape(editorTestId) + '"]').first();
|
||||
const editor = mdtodoTestIdLocator(editorTestId);
|
||||
if (await visibleLocator(editor)) return { editorTestId, readTestId, opened: false };
|
||||
const read = page.locator('[data-testid="' + cssEscape(readTestId) + '"]').first();
|
||||
const read = mdtodoTestIdLocator(readTestId);
|
||||
await read.waitFor({ state: "visible", timeout: 10000 });
|
||||
await read.dblclick();
|
||||
await editor.waitFor({ state: "visible", timeout: 10000 });
|
||||
@@ -1041,7 +1051,7 @@ async function editMdtodoTaskTitle(command) {
|
||||
async function editMdtodoTaskBody(command) {
|
||||
const body = commandValue(command, ["text", "body", "value"]);
|
||||
if (!body) throw new Error("editMdtodoTaskBody requires --text or --text-stdin");
|
||||
return saveMdtodoTaskWithButton(command, "editMdtodoTaskBody", "mdtodo-edit-body-save", [{ kind: "fill", testId: "mdtodo-edit-body", value: body, openByDblClickTestId: "mdtodo-body-rendered" }]);
|
||||
return saveMdtodoTaskWithButton(command, "editMdtodoTaskBody", ["mdtodo-body-save", "mdtodo-edit-body-save"], [{ kind: "fill", testId: ["mdtodo-body-editor", "mdtodo-edit-body"], value: body, openByDblClickTestId: ["mdtodo-body-read", "mdtodo-body-rendered"] }]);
|
||||
}
|
||||
|
||||
async function toggleMdtodoTaskStatus(command) {
|
||||
@@ -1060,7 +1070,7 @@ async function editMdtodoTaskInline(command) {
|
||||
if (field === "body" || field === "content") {
|
||||
const body = commandValue(command, ["body", "text"]);
|
||||
if (!body) throw new Error("editMdtodoTaskInline --field body requires --body, --text, or --text-stdin");
|
||||
return saveMdtodoTaskWithButton(command, "editMdtodoTaskInline", "mdtodo-edit-body-save", [{ kind: "fill", testId: "mdtodo-edit-body", value: body, openByDblClickTestId: "mdtodo-body-rendered" }]);
|
||||
return saveMdtodoTaskWithButton(command, "editMdtodoTaskInline", ["mdtodo-body-save", "mdtodo-edit-body-save"], [{ kind: "fill", testId: ["mdtodo-body-editor", "mdtodo-edit-body"], value: body, openByDblClickTestId: ["mdtodo-body-read", "mdtodo-body-rendered"] }]);
|
||||
}
|
||||
if (field === "status") {
|
||||
const status = commandValue(command, ["status", "text"]);
|
||||
@@ -1219,7 +1229,9 @@ async function deleteMdtodoTask(command) {
|
||||
const selection = await selectTaskIfCommandTargetsOne(command);
|
||||
const firstClick = await clickProjectButtonAndMaybeWait("mdtodo-delete-task", null);
|
||||
let confirmClick = null;
|
||||
const confirmVisible = await visibleLocator(page.locator('[data-testid="mdtodo-delete-cancel"]').first());
|
||||
const deleteButton = page.locator('[data-testid="mdtodo-delete-task"]').first();
|
||||
const confirmVisible = await visibleLocator(page.locator('[data-testid="mdtodo-delete-cancel"]').first())
|
||||
|| await deleteButton.evaluate((element) => /确认|confirm/iu.test(String(element.textContent || ""))).catch(() => false);
|
||||
if (confirmVisible) confirmClick = await clickProjectButtonAndMaybeWait("mdtodo-delete-task", /^\/v1\/project-management\/mdtodo\/tasks/u);
|
||||
return { beforeUrl, afterUrl: currentPageUrl(), type: "deleteMdtodoTask", selection, firstClick, confirmClick, beforeProject, afterProject: await projectManagementCommandSnapshot(), pageId, valuesRedacted: true };
|
||||
}
|
||||
@@ -1250,7 +1262,7 @@ async function launchWorkbenchFromTask(command) {
|
||||
: null;
|
||||
const providerSelection = await selectMdtodoProviderProfileForLaunch(command);
|
||||
const projectBeforeClick = await projectManagementCommandSnapshot({ includeRaw: true });
|
||||
const button = page.locator('[data-testid="mdtodo-workbench-launch"], [data-action="launch-workbench"]').first();
|
||||
const button = page.locator('[data-testid="mdtodo-workbench-launch"], [data-testid="mdtodo-launch-workbench"], [data-action="launch-workbench"]').first();
|
||||
await button.waitFor({ state: "visible", timeout: 15000 });
|
||||
const buttonState = await button.evaluate((element) => ({
|
||||
disabled: Boolean(element.disabled) || element.getAttribute("aria-disabled") === "true",
|
||||
@@ -1392,8 +1404,8 @@ async function projectManagementCommandSnapshot(options = {}) {
|
||||
selected: option.selected === true
|
||||
})) : [];
|
||||
const selectedFileOption = fileOptions.find((option) => option.selected) || null;
|
||||
const launch = document.querySelector('[data-testid="mdtodo-workbench-launch"], [data-action="launch-workbench"]');
|
||||
const bodyRendered = document.querySelector('[data-testid="mdtodo-body-rendered"]');
|
||||
const launch = document.querySelector('[data-testid="mdtodo-workbench-launch"], [data-testid="mdtodo-launch-workbench"], [data-action="launch-workbench"]');
|
||||
const bodyRendered = document.querySelector('[data-testid="mdtodo-body-rendered"], [data-testid="mdtodo-body-read"]');
|
||||
const reportPreview = document.querySelector('[data-testid="mdtodo-report-preview"]');
|
||||
const reportError = document.querySelector('[data-testid="mdtodo-report-error"]');
|
||||
const reportFullscreen = document.querySelector('[data-testid="mdtodo-report-fullscreen-dialog"]');
|
||||
@@ -1410,11 +1422,11 @@ async function projectManagementCommandSnapshot(options = {}) {
|
||||
fileOptionLabels: fileOptions.map((option) => option.label).filter(Boolean).slice(0, 20),
|
||||
selectedTaskRefRaw: selectedTask?.getAttribute("data-task-ref") || null,
|
||||
selectedTaskId: selectedTask?.getAttribute("data-task-id") || selectedTask?.getAttribute("data-rxx-id") || null,
|
||||
selectedTaskStatus: selectedTask?.getAttribute("data-task-status") || null,
|
||||
selectedTaskStatus: selectedTask?.getAttribute("data-task-status") || selectedTask?.querySelector("[data-state]")?.getAttribute("data-state") || null,
|
||||
sourceSelectVisible: visible(sourceSelect),
|
||||
fileSelectVisible: visible(fileSelect),
|
||||
sourceConfigVisible: visible(document.querySelector('[data-testid="mdtodo-source-form-hwpod"], [data-testid="mdtodo-source-config-dialog"], [role="dialog"]')),
|
||||
taskEditorVisible: visible(document.querySelector('[data-testid="mdtodo-edit-title"], [data-testid="mdtodo-edit-body"]')),
|
||||
taskEditorVisible: visible(document.querySelector('[data-testid="mdtodo-edit-title"], [data-testid="mdtodo-edit-body"], [data-testid="mdtodo-body-editor"]')),
|
||||
taskBodyVisible: visible(bodyRendered),
|
||||
taskBodyText: visible(bodyRendered) ? text(bodyRendered) : "",
|
||||
newTaskDraftVisible: visible(document.querySelector('[data-testid="mdtodo-new-title"], [data-testid="mdtodo-new-body"]')),
|
||||
@@ -1427,7 +1439,7 @@ async function projectManagementCommandSnapshot(options = {}) {
|
||||
launchButtonVisible: visible(launch),
|
||||
launchButtonEnabled: visible(launch) && !launch.disabled && launch.getAttribute("aria-disabled") !== "true",
|
||||
launchButtonText: text(launch),
|
||||
blockerTexts: Array.from(document.querySelectorAll('[data-testid="mdtodo-workbench-launch-blocker"], [data-testid="mdtodo-workbench-launch-error"], [role="alert"]')).filter(visible).map(text).filter(Boolean).slice(0, 8),
|
||||
blockerTexts: Array.from(document.querySelectorAll('[data-testid="mdtodo-workbench-launch-blocker"], [data-testid="mdtodo-workbench-launch-error"], [data-testid="mdtodo-create-blocker"], .launch-blocker, [role="alert"]')).filter(visible).map(text).filter(Boolean).slice(0, 8),
|
||||
workbenchLinkCount: Array.from(document.querySelectorAll('[data-testid="mdtodo-workbench-link-summary"] li, a[href*="/workbench/sessions/"]')).filter(visible).length,
|
||||
valuesRedacted: true
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user