mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-24 13:41:01 +03:00
refactor(web-test): извлечён EDD-домен в dom/edd.mjs
Новое в dom/edd.mjs:
- readEddScript — {visible, items:[{name,x,y}]}
- isEddVisibleScript — boolean, лёгкая проверка
- clickEddItemViaDispatchScript — клик по name через dispatchEvent (bypass
div.surface); fuzzy с NBSP/ё/bracket-strip
- clickShowAllInEddScript — "Показать все" в footer
Wrappers в helpers.mjs: readEdd, isEddVisible, clickEddItemViaDispatch,
clickShowAllInEdd. row-fill clickEddItem унифицирован с select-value
вариантом (NBSP/ё normalization теперь работает и для табличных строк).
Метрики: select-value 880 → 827 LOC (−53), row-fill 1065 → 1041 LOC
(−24); evaluates row-fill 20 → 17, select-value 7 → 5. Полный регресс
зелёный.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
340142b0a2
commit
89efcad125
@@ -1,4 +1,4 @@
|
||||
// web-test core/helpers v1.18 — private, cross-cutting helpers used by the
|
||||
// web-test core/helpers v1.19 — private, cross-cutting helpers used by the
|
||||
// public action functions (clickElement/fillFields/selectValue/etc).
|
||||
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
@@ -10,6 +10,10 @@ import {
|
||||
isInputFocusedScript,
|
||||
isInputFocusedInGridScript,
|
||||
findOpenPopupScript,
|
||||
readEddScript,
|
||||
isEddVisibleScript,
|
||||
clickEddItemViaDispatchScript,
|
||||
clickShowAllInEddScript,
|
||||
} from '../../dom.mjs';
|
||||
|
||||
/**
|
||||
@@ -112,18 +116,31 @@ export async function findOpenPopup() {
|
||||
* @returns {Promise<{visible: boolean, items?: Array<{name:string, x:number, y:number}>}>}
|
||||
*/
|
||||
export async function readEdd() {
|
||||
return await page.evaluate(`(() => {
|
||||
const edd = document.getElementById('editDropDown');
|
||||
if (!edd || edd.offsetWidth === 0) return { visible: false };
|
||||
const eddTexts = [...edd.querySelectorAll('.eddText')].filter(el => el.offsetWidth > 0);
|
||||
return {
|
||||
visible: true,
|
||||
items: eddTexts.map(el => {
|
||||
const r = el.getBoundingClientRect();
|
||||
return { name: el.innerText?.trim() || '', x: r.x + r.width / 2, y: r.y + r.height / 2 };
|
||||
})
|
||||
};
|
||||
})()`);
|
||||
return page.evaluate(readEddScript());
|
||||
}
|
||||
|
||||
/**
|
||||
* Thin wrapper: is the EDD popup currently visible?
|
||||
* Lighter than `readEdd` when only presence matters.
|
||||
*/
|
||||
export async function isEddVisible() {
|
||||
return page.evaluate(isEddVisibleScript());
|
||||
}
|
||||
|
||||
/**
|
||||
* Click an EDD item by name via dispatchEvent (bypasses div.surface overlays).
|
||||
* Returns the clicked item's innerText, or `null` if no match.
|
||||
*/
|
||||
export async function clickEddItemViaDispatch(itemName) {
|
||||
return page.evaluate(clickEddItemViaDispatchScript(itemName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Click the "Показать все" / "Show all" link in the EDD footer.
|
||||
* Returns boolean.
|
||||
*/
|
||||
export async function clickShowAllInEdd() {
|
||||
return page.evaluate(clickShowAllInEddScript());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@ import { highlight, unhighlight } from '../recording/highlight.mjs';
|
||||
import {
|
||||
safeClick, findFieldInputId, readEdd,
|
||||
detectNewForm as helperDetectNewForm,
|
||||
clickEddItemViaDispatch, clickShowAllInEdd,
|
||||
} from '../core/helpers.mjs';
|
||||
import { pasteText } from '../core/clipboard.mjs';
|
||||
import { getFormState } from './state.mjs';
|
||||
@@ -711,63 +712,9 @@ export async function selectValue(fieldName, searchText, { type } = {}) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Helper: click EDD item via evaluate (bypasses div.surface overlay from DLB)
|
||||
// page.mouse.click() doesn't work here — surface intercepts pointer events.
|
||||
// Dispatching mousedown directly on the element avoids this.
|
||||
async function clickEddItem(itemName) {
|
||||
return page.evaluate(`(() => {
|
||||
const edd = document.getElementById('editDropDown');
|
||||
if (!edd || edd.offsetWidth === 0) return null;
|
||||
const ny = s => s.replace(/ё/gi, 'е').replace(/\\u00a0/g, ' ');
|
||||
const target = ny(${JSON.stringify(itemName.toLowerCase())});
|
||||
const items = [...edd.querySelectorAll('.eddText')].filter(el => el.offsetWidth > 0);
|
||||
function clickEl(el) {
|
||||
const r = el.getBoundingClientRect();
|
||||
const opts = { bubbles: true, cancelable: true, clientX: r.x + r.width/2, clientY: r.y + r.height/2 };
|
||||
el.dispatchEvent(new MouseEvent('mousedown', opts));
|
||||
el.dispatchEvent(new MouseEvent('mouseup', opts));
|
||||
el.dispatchEvent(new MouseEvent('click', opts));
|
||||
return el.innerText.trim();
|
||||
}
|
||||
// Pass 1: exact match (prefer over partial)
|
||||
for (const el of items) {
|
||||
const t = ny((el.innerText?.trim() || '').toLowerCase());
|
||||
if (t === target) return clickEl(el);
|
||||
const stripped = t.replace(/\\s*\\([^)]*\\)\\s*$/, '');
|
||||
if (stripped === target) return clickEl(el);
|
||||
}
|
||||
// Pass 2: partial match
|
||||
for (const el of items) {
|
||||
const t = ny((el.innerText?.trim() || '').toLowerCase());
|
||||
if (t.includes(target) || target.includes(t.replace(/\\s*\\([^)]*\\)\\s*$/, ''))) return clickEl(el);
|
||||
}
|
||||
return null;
|
||||
})()`);
|
||||
}
|
||||
|
||||
// Helper: click "Показать все" in EDD footer via evaluate
|
||||
async function clickShowAll() {
|
||||
return page.evaluate(`(() => {
|
||||
const edd = document.getElementById('editDropDown');
|
||||
if (!edd || edd.offsetWidth === 0) return false;
|
||||
let el = edd.querySelector('.eddBottom .hyperlink');
|
||||
if (!el || el.offsetWidth === 0) {
|
||||
const candidates = [...edd.querySelectorAll('span, div, a')]
|
||||
.filter(e => e.offsetWidth > 0 && e.children.length === 0);
|
||||
el = candidates.find(e => {
|
||||
const t = (e.innerText?.trim() || '').toLowerCase();
|
||||
return t === 'показать все' || t === 'show all';
|
||||
});
|
||||
}
|
||||
if (!el) return false;
|
||||
const r = el.getBoundingClientRect();
|
||||
const opts = { bubbles: true, cancelable: true, clientX: r.x + r.width/2, clientY: r.y + r.height/2 };
|
||||
el.dispatchEvent(new MouseEvent('mousedown', opts));
|
||||
el.dispatchEvent(new MouseEvent('mouseup', opts));
|
||||
el.dispatchEvent(new MouseEvent('click', opts));
|
||||
return true;
|
||||
})()`);
|
||||
}
|
||||
// Locals → dom-scripts in helpers.mjs (see clickEddItemViaDispatch / clickShowAllInEdd)
|
||||
const clickEddItem = clickEddItemViaDispatch;
|
||||
const clickShowAll = clickShowAllInEdd;
|
||||
|
||||
// 2. Click DLB (handle funcPanel / surface overlay intercept)
|
||||
const dlbSel = `[id="${btn.buttonId}"]`;
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
safeClick, findFieldInputId,
|
||||
detectNewForm as helperDetectNewForm,
|
||||
isInputFocused, isInputFocusedInGrid, findOpenPopup,
|
||||
readEdd, isEddVisible, clickEddItemViaDispatch,
|
||||
} from '../core/helpers.mjs';
|
||||
import { clickElement } from '../core/click.mjs';
|
||||
import {
|
||||
@@ -427,11 +428,7 @@ export async function fillTableRow(fields, { tab, add, row, table } = {}) {
|
||||
await pasteText(info.value, { confirm: ['Control+a', 'Control+v'] });
|
||||
await page.waitForTimeout(400);
|
||||
// Dismiss EDD autocomplete if it appeared
|
||||
const hasEdd = await page.evaluate(`(() => {
|
||||
const edd = document.getElementById('editDropDown');
|
||||
return edd && edd.offsetWidth > 0;
|
||||
})()`);
|
||||
if (hasEdd) {
|
||||
if (await isEddVisible()) {
|
||||
await page.keyboard.press('Escape');
|
||||
await page.waitForTimeout(200);
|
||||
}
|
||||
@@ -741,13 +738,8 @@ export async function fillTableRow(fields, { tab, add, row, table } = {}) {
|
||||
}
|
||||
|
||||
// Check for EDD autocomplete (indicates reference field)
|
||||
const eddItems = await page.evaluate(`(() => {
|
||||
const edd = document.getElementById('editDropDown');
|
||||
if (!edd || edd.offsetWidth === 0) return null;
|
||||
return [...edd.querySelectorAll('.eddText')]
|
||||
.filter(el => el.offsetWidth > 0)
|
||||
.map(el => el.innerText?.trim() || '');
|
||||
})()`);
|
||||
const edd = await readEdd();
|
||||
const eddItems = edd.visible ? edd.items.map(i => i.name) : null;
|
||||
|
||||
if (eddItems && eddItems.length > 0) {
|
||||
// Reference field with autocomplete — click best match
|
||||
@@ -763,23 +755,7 @@ export async function fillTableRow(fields, { tab, add, row, table } = {}) {
|
||||
if (!pick) pick = realItems[0];
|
||||
|
||||
// Click EDD item via dispatchEvent (bypasses div.surface overlay)
|
||||
const pickLower = pick.toLowerCase();
|
||||
await page.evaluate(`(() => {
|
||||
const edd = document.getElementById('editDropDown');
|
||||
if (!edd) return;
|
||||
for (const el of edd.querySelectorAll('.eddText')) {
|
||||
if (el.offsetWidth === 0) continue;
|
||||
if (el.innerText.trim().toLowerCase().includes(${JSON.stringify(pickLower)})) {
|
||||
const r = el.getBoundingClientRect();
|
||||
const opts = { bubbles:true, cancelable:true,
|
||||
clientX: r.x + r.width/2, clientY: r.y + r.height/2 };
|
||||
el.dispatchEvent(new MouseEvent('mousedown', opts));
|
||||
el.dispatchEvent(new MouseEvent('mouseup', opts));
|
||||
el.dispatchEvent(new MouseEvent('click', opts));
|
||||
return;
|
||||
}
|
||||
}
|
||||
})()`);
|
||||
await clickEddItemViaDispatch(pick);
|
||||
await waitForStable();
|
||||
info.filled = true;
|
||||
results.push({ field: matchedKey, cell: cell.fullName, ok: true,
|
||||
|
||||
Reference in New Issue
Block a user