fix(web-test): detect server-side errors via waitForSelector and ancestry-based button grouping

Two problems solved:
1. Server-side exceptions (ВызватьИсключение in ПередЗаписью) produce modal dialogs
   AFTER the DOM stabilizes. clickElement now uses waitForSelector with MutationObserver
   (doesn't block JS event loop) to detect #modalSurface or .balloon appearance.
2. checkErrorsScript used button IDs to determine form ownership, but 1C modal dialog
   buttons often have empty IDs. Now uses closest('[id$="_container"]') ancestry to
   group pressButtons by form, correctly separating modal buttons from background form
   buttons (e.g. "Зачет оплаты" in ERP order form).

Tested with ТестОшибки CFE extension on ERP — error detected in 7.7s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-02-28 13:28:23 +03:00
parent 90ca2a7c4a
commit 75558fe46c
2 changed files with 62 additions and 42 deletions
@@ -969,6 +969,24 @@ export async function clickElement(text, { dblclick } = {}) {
return state;
}
// For buttons that trigger server-side operations (post, write, etc.),
// the DOM may stabilize BEFORE the server response arrives.
// Use waitForSelector to detect error modal — this doesn't block the JS event loop.
if (target.kind === 'button') {
const postForm = await page.evaluate(detectFormScript());
if (postForm === formNum) {
// Form didn't change — server might still be processing.
// waitForSelector uses MutationObserver internally — doesn't block event loop.
try {
await page.waitForSelector(
'#modalSurface:not([style*="display: none"]), .balloon',
{ state: 'visible', timeout: 10000 }
);
} catch {}
await waitForStable();
}
}
// Form may have changed — re-detect
const state = await getFormState();
state.clicked = { kind: target.kind, name: target.name };