mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-19 09:09:41 +03:00
refactor(web-test): replace fixed delays with smart waitForCondition polls
Add waitForCondition() utility — polls JS expression every 100ms with timeout fallback. Replace key fixed delays: - fillReferenceField paste: 2000ms → poll for EDD/cloud (max 2s) - fillTableRow add: 1000ms → poll for grid INPUT focus (max 2s) - fillTableRow cell paste: 1500ms → poll for EDD/value (max 1.5s) - fillTableRow Tab skip/commit: 300-1000ms → poll for focus change Benchmark: 31.8s vs 32.0s baseline — no measurable speedup because 1C backend response time (~1.5-2s for autocomplete) is the real bottleneck, not our delay calibration. Code is correct and will benefit from faster backends. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -214,6 +214,20 @@ async function waitForStable(previousFormNum = null) {
|
|||||||
// Fallback: max wait reached
|
// Fallback: max wait reached
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Poll until a JS expression returns truthy, or timeout (ms) expires.
|
||||||
|
* Resolves early — typically within 100-300ms instead of fixed delays.
|
||||||
|
*/
|
||||||
|
async function waitForCondition(evalScript, timeout = 2000) {
|
||||||
|
const start = Date.now();
|
||||||
|
while (Date.now() - start < timeout) {
|
||||||
|
const result = await page.evaluate(evalScript);
|
||||||
|
if (result) return result;
|
||||||
|
await page.waitForTimeout(100);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check for validation errors / diagnostics after an action.
|
* Check for validation errors / diagnostics after an action.
|
||||||
* Detects: inline balloon tooltip, messages panel, modal error dialog.
|
* Detects: inline balloon tooltip, messages panel, modal error dialog.
|
||||||
@@ -565,7 +579,18 @@ async function fillReferenceField(selector, fieldName, value, formNum) {
|
|||||||
// 3. Paste text via clipboard (trusted event → triggers real 1C autocomplete)
|
// 3. Paste text via clipboard (trusted event → triggers real 1C autocomplete)
|
||||||
await page.evaluate(`navigator.clipboard.writeText(${JSON.stringify(text)})`);
|
await page.evaluate(`navigator.clipboard.writeText(${JSON.stringify(text)})`);
|
||||||
await page.keyboard.press('Control+V');
|
await page.keyboard.press('Control+V');
|
||||||
await page.waitForTimeout(2000);
|
// Smart wait: poll for EDD dropdown or "not in list" cloud (max 2s)
|
||||||
|
await waitForCondition(`(() => {
|
||||||
|
const edd = document.getElementById('editDropDown');
|
||||||
|
if (edd && edd.offsetWidth > 0) return true;
|
||||||
|
for (const el of document.querySelectorAll('div')) {
|
||||||
|
if (el.offsetWidth === 0) continue;
|
||||||
|
const s = getComputedStyle(el);
|
||||||
|
if ((s.position === 'absolute' || s.position === 'fixed') &&
|
||||||
|
(parseInt(s.zIndex) || 0) >= 100 && (el.innerText || '').includes('нет в списке')) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})()`, ACTION_WAIT);
|
||||||
|
|
||||||
// 4. Check editDropDown for autocomplete suggestions
|
// 4. Check editDropDown for autocomplete suggestions
|
||||||
const eddState = await page.evaluate(`(() => {
|
const eddState = await page.evaluate(`(() => {
|
||||||
@@ -1217,13 +1242,18 @@ export async function fillTableRow(fields, { tab, add, row } = {}) {
|
|||||||
// 1. Switch tab if requested
|
// 1. Switch tab if requested
|
||||||
if (tab) {
|
if (tab) {
|
||||||
await clickElement(tab);
|
await clickElement(tab);
|
||||||
await page.waitForTimeout(500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Add new row if requested
|
// 2. Add new row if requested
|
||||||
if (add) {
|
if (add) {
|
||||||
await clickElement('Добавить');
|
await clickElement('Добавить');
|
||||||
await page.waitForTimeout(1000);
|
// Smart wait: poll until an INPUT inside a grid gets focus
|
||||||
|
await waitForCondition(`(() => {
|
||||||
|
const f = document.activeElement;
|
||||||
|
if (!f || f.tagName !== 'INPUT') return false;
|
||||||
|
let n = f; while (n) { if (n.classList?.contains('grid')) return true; n = n.parentElement; }
|
||||||
|
return false;
|
||||||
|
})()`, ACTION_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2b. Enter edit mode on existing row by dblclick
|
// 2b. Enter edit mode on existing row by dblclick
|
||||||
@@ -1343,9 +1373,10 @@ export async function fillTableRow(fields, { tab, add, row } = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!matchedKey) {
|
if (!matchedKey) {
|
||||||
// Skip this cell
|
// Skip this cell — Tab + wait for focus to move
|
||||||
|
const skipId = cell.id;
|
||||||
await page.keyboard.press('Tab');
|
await page.keyboard.press('Tab');
|
||||||
await page.waitForTimeout(300);
|
await waitForCondition(`document.activeElement?.id !== '${skipId}'`, 500);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1356,7 +1387,13 @@ export async function fillTableRow(fields, { tab, add, row } = {}) {
|
|||||||
await page.keyboard.press('Control+A');
|
await page.keyboard.press('Control+A');
|
||||||
await page.evaluate(`navigator.clipboard.writeText(${JSON.stringify(text)})`);
|
await page.evaluate(`navigator.clipboard.writeText(${JSON.stringify(text)})`);
|
||||||
await page.keyboard.press('Control+V');
|
await page.keyboard.press('Control+V');
|
||||||
await page.waitForTimeout(1500);
|
// Smart wait: poll for EDD dropdown (reference) or stable input value
|
||||||
|
await waitForCondition(`(() => {
|
||||||
|
const edd = document.getElementById('editDropDown');
|
||||||
|
if (edd && edd.offsetWidth > 0) return true;
|
||||||
|
const f = document.activeElement;
|
||||||
|
return f && f.tagName === 'INPUT' && f.value && f.value.length > 0;
|
||||||
|
})()`, 1500);
|
||||||
|
|
||||||
// Check for EDD autocomplete (indicates reference field)
|
// Check for EDD autocomplete (indicates reference field)
|
||||||
const eddItems = await page.evaluate(`(() => {
|
const eddItems = await page.evaluate(`(() => {
|
||||||
@@ -1411,15 +1448,17 @@ export async function fillTableRow(fields, { tab, add, row } = {}) {
|
|||||||
|
|
||||||
// Done? If so, don't Tab (avoids creating a new row after last cell)
|
// Done? If so, don't Tab (avoids creating a new row after last cell)
|
||||||
if ([...pending.values()].every(p => p.filled)) break;
|
if ([...pending.values()].every(p => p.filled)) break;
|
||||||
// Tab to move to next cell
|
// Tab to move to next cell — wait for focus to change
|
||||||
|
const afterEddId = cell.id;
|
||||||
await page.keyboard.press('Tab');
|
await page.keyboard.press('Tab');
|
||||||
await page.waitForTimeout(500);
|
await waitForCondition(`document.activeElement?.id !== '${afterEddId}'`, 500);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No EDD — press Tab to commit the value
|
// No EDD — press Tab to commit the value, wait for focus change
|
||||||
|
const commitId = cell.id;
|
||||||
await page.keyboard.press('Tab');
|
await page.keyboard.press('Tab');
|
||||||
await page.waitForTimeout(1000);
|
await waitForCondition(`document.activeElement?.id !== '${commitId}'`, 1000);
|
||||||
|
|
||||||
// Check for "нет в списке" cloud popup (reference field, value not found)
|
// Check for "нет в списке" cloud popup (reference field, value not found)
|
||||||
const notInList = await page.evaluate(`(() => {
|
const notInList = await page.evaluate(`(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user