Simplify conflict scheduling and lifecycle subscriptions

This commit is contained in:
vorotamoroz
2026-09-04 05:15:45 +00:00
parent ad91776ad9
commit 84be444689
8 changed files with 206 additions and 75 deletions
+22 -13
View File
@@ -287,19 +287,28 @@ export async function captureObsidianElement(
await mkdir(dirname(screenshotPath), { recursive: true });
await withObsidianPage(port, async (page) => {
try {
const element = await resolveElement(page);
await element.waitFor({ state: "visible", timeout: timeoutMs });
await element.screenshot({
path: screenshotPath,
animations: "disabled",
style: ".notice-container { visibility: hidden !important; }",
});
} catch (error) {
const failurePath = screenshotPath.replace(/\.png$/u, ".failure.png");
await page.screenshot({ path: failurePath, fullPage: true });
console.error(`UI element failure screenshot: ${failurePath}`);
throw error;
for (let attempt = 0; attempt < 3; attempt++) {
try {
const element = await resolveElement(page);
await element.waitFor({ state: "visible", timeout: timeoutMs });
await element.screenshot({
path: screenshotPath,
animations: "disabled",
style: ".notice-container { visibility: hidden !important; }",
});
return;
} catch (error) {
const detachedDuringCapture =
error instanceof Error && error.message.includes("not attached to the DOM");
if (detachedDuringCapture && attempt < 2) {
await page.waitForTimeout(50);
continue;
}
const failurePath = screenshotPath.replace(/\.png$/u, ".failure.png");
await page.screenshot({ path: failurePath, fullPage: true });
console.error(`UI element failure screenshot: ${failurePath}`);
throw error;
}
}
});
@@ -423,7 +423,17 @@ async function main(): Promise<void> {
state: "visible",
timeout: uiTimeoutMs,
});
const actionButtonBounds = await modal.locator(".conflict-action-button").evaluateAll((buttons) =>
});
const firstDialogueScreenshot = await captureObsidianElement(
session.remoteDebuggingPort,
"conflict-dialog-three-versions.png",
(page) => conflictDialogue(page).locator(".modal").first()
);
await withObsidianPage(session.remoteDebuggingPort, async (page) => {
const modal = conflictDialogue(page);
const actionButtons = modal.locator(".conflict-action-button");
await actionButtons.nth(3).waitFor({ state: "visible", timeout: uiTimeoutMs });
const actionButtonBounds = await actionButtons.evaluateAll((buttons) =>
buttons.map((button) => {
const bounds = button.getBoundingClientRect();
return { top: bounds.top, bottom: bounds.bottom };
@@ -435,16 +445,20 @@ async function main(): Promise<void> {
(bounds, index) => index > 0 && bounds.top < actionButtonBounds[index - 1].bottom
)
) {
const buttonDetails = await modal.locator("button").evaluateAll((buttons) =>
buttons.map((button) => ({
text: button.textContent,
className: button.className,
}))
);
throw new Error(
`Conflict action buttons are not stacked vertically: ${JSON.stringify(actionButtonBounds)}`
`Conflict action buttons are not stacked vertically: ${JSON.stringify({
actionButtonBounds,
buttonDetails,
})}`
);
}
});
const firstDialogueScreenshot = await captureObsidianElement(
session.remoteDebuggingPort,
"conflict-dialog-three-versions.png",
(page) => conflictDialogue(page).locator(".modal").first()
);
await withObsidianPage(session.remoteDebuggingPort, async (page) => {
const modal = conflictDialogue(page);
await modal.getByRole("button", { name: "Concat both", exact: true }).click({ timeout: uiTimeoutMs });