fix(web-test): detect modal errors without #modalSurface dependency

1C platform shows some modal dialogs (e.g. "Не удалось записать") via
ps*win floating windows WITHOUT setting #modalSurface visible. Removed
the modalSurface gate from checkErrorsScript — now scans all small forms
for button patterns regardless of overlay state. The elCount > 100
threshold already filters content forms reliably.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-02-28 13:57:18 +03:00
parent 75558fe46c
commit 5ea6414585
+40 -42
View File
@@ -800,55 +800,53 @@ export function checkErrorsScript() {
// 3+4. Modal dialogs: confirmation (multiple buttons) or error (single pressDefault) // 3+4. Modal dialogs: confirmation (multiple buttons) or error (single pressDefault)
// Uses form container ancestry to group buttons — pressButton elements often lack form-prefixed IDs // Uses form container ancestry to group buttons — pressButton elements often lack form-prefixed IDs
const modalSurface = document.getElementById('modalSurface'); // Note: 1C shows some modals WITHOUT #modalSurface (e.g. "Не удалось записать" uses ps*win floating window)
if (modalSurface && modalSurface.offsetWidth > 0) { // so we always scan for small forms with button patterns, regardless of modalSurface state
// Group visible pressButtons by their form container const formButtons = {};
const formButtons = {}; [...document.querySelectorAll('a.press.pressButton')].forEach(btn => {
[...document.querySelectorAll('a.press.pressButton')].forEach(btn => { if (btn.offsetWidth === 0) return;
if (btn.offsetWidth === 0) return; const container = btn.closest('[id$="_container"]');
const container = btn.closest('[id$="_container"]'); const m = container?.id?.match(/^form(\\d+)_/);
const m = container?.id?.match(/^form(\\d+)_/); if (!m) return;
if (!m) return; const fn = m[1];
const fn = m[1]; if (!formButtons[fn]) formButtons[fn] = [];
if (!formButtons[fn]) formButtons[fn] = []; formButtons[fn].push(btn);
formButtons[fn].push(btn); });
});
for (const [fn, buttons] of Object.entries(formButtons)) {
const p = 'form' + fn + '_';
const elCount = document.querySelectorAll('[id^="' + p + '"]').length;
if (elCount > 100) continue; // Skip large content forms
if (buttons.length > 1) {
// Confirmation dialog (multiple buttons: Да/Нет, OK/Отмена, etc.)
const msgEl = document.getElementById(p + 'Message');
const message = msgEl?.innerText?.trim() || '';
const btnNames = buttons.map(el => {
const b = { name: el.innerText?.trim() || '' };
if (el.classList.contains('pressDefault')) b.default = true;
return b;
}).filter(b => b.name);
result.confirmation = { message, buttons: btnNames.map(b => b.name), formNum: parseInt(fn) };
break;
}
}
// Single-button modal: error dialog with pressDefault + staticText
if (!result.confirmation) {
for (const [fn, buttons] of Object.entries(formButtons)) { for (const [fn, buttons] of Object.entries(formButtons)) {
const p = 'form' + fn + '_'; const p = 'form' + fn + '_';
const elCount = document.querySelectorAll('[id^="' + p + '"]').length; const elCount = document.querySelectorAll('[id^="' + p + '"]').length;
if (elCount > 100) continue; // Skip large content forms if (elCount > 100) continue;
if (buttons.length > 1) { if (buttons.length !== 1 || !buttons[0].classList.contains('pressDefault')) continue;
// Confirmation dialog (multiple buttons: Да/Нет, OK/Отмена, etc.) const texts = [...document.querySelectorAll('[id^="' + p + '"].staticText')]
const msgEl = document.getElementById(p + 'Message'); .filter(el => el.offsetWidth > 0)
const message = msgEl?.innerText?.trim() || ''; .map(el => el.innerText?.trim())
const btnNames = buttons.map(el => { .filter(Boolean);
const b = { name: el.innerText?.trim() || '' }; if (texts.length > 0) {
if (el.classList.contains('pressDefault')) b.default = true; result.modal = { message: texts.join(' '), formNum: parseInt(fn), button: buttons[0].innerText?.trim() || '' };
return b;
}).filter(b => b.name);
result.confirmation = { message, buttons: btnNames.map(b => b.name), formNum: parseInt(fn) };
break; break;
} }
} }
// Single-button modal: error dialog with pressDefault + staticText
if (!result.confirmation) {
for (const [fn, buttons] of Object.entries(formButtons)) {
const p = 'form' + fn + '_';
const elCount = document.querySelectorAll('[id^="' + p + '"]').length;
if (elCount > 100) continue;
if (buttons.length !== 1 || !buttons[0].classList.contains('pressDefault')) continue;
const texts = [...document.querySelectorAll('[id^="' + p + '"].staticText')]
.filter(el => el.offsetWidth > 0)
.map(el => el.innerText?.trim())
.filter(Boolean);
if (texts.length > 0) {
result.modal = { message: texts.join(' '), formNum: parseInt(fn), button: buttons[0].innerText?.trim() || '' };
break;
}
}
}
} }
return (result.balloon || result.messages || result.modal || result.confirmation) ? result : null; return (result.balloon || result.messages || result.modal || result.confirmation) ? result : null;