refactor(web-test): структура — engine/ wrapper для внутренних модулей

Перенос всей внутрянки движка под scripts/engine/:
  - core/, forms/, nav/, table/, recording/ → engine/<same>/

Публичные entry-точки остаются в scripts/ корне без изменений:
  - browser.mjs, dom.mjs, run.mjs — компат не ломаем.

Симметричный layout, легко читать с первого взгляда:
  scripts/
    browser.mjs, dom.mjs, run.mjs    ← публичные entries
    engine/                          ← внутренности движка
    (dom/, cli/ — место под будущий распил dom.mjs / run.mjs)

Технические правки после переезда:
  - browser.mjs: ./core/... → ./engine/core/... (23 импорта)
  - engine/*/* модули: ../browser.mjs → ../../browser.mjs (11 импортов)
  - engine/*/* модули: ../dom.mjs → ../../dom.mjs (12 импортов)
  - engine/recording/capture.mjs: dynamic import('../browser.mjs')
    → import('../../browser.mjs')
  - engine/core/state.mjs: projectRoot пересчитан (5 → 6 уровней вверх)
  - Git rename detection срабатывает — история файлов сохраняется

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-05-26 16:03:20 +03:00
co-authored by Claude Opus 4.7
parent f31770d79c
commit 8739d1d15c
21 changed files with 49 additions and 49 deletions
+23 -23
View File
@@ -35,7 +35,7 @@ import {
LOAD_TIMEOUT, INIT_TIMEOUT, ACTION_WAIT, MAX_WAIT, POLL_INTERVAL, STABLE_CYCLES, LOAD_TIMEOUT, INIT_TIMEOUT, ACTION_WAIT, MAX_WAIT, POLL_INTERVAL, STABLE_CYCLES,
EXT_ID, projectRoot, resolveProjectPath, normYo, EXT_ID, projectRoot, resolveProjectPath, normYo,
isConnected, ensureConnected, getPage, setPreserveClipboard, isConnected, ensureConnected, getPage, setPreserveClipboard,
} from './core/state.mjs'; } from './engine/core/state.mjs';
export { isConnected, getPage, setPreserveClipboard, ensureConnected }; export { isConnected, getPage, setPreserveClipboard, ensureConnected };
export async function saveClipboard() { export async function saveClipboard() {
@@ -130,27 +130,27 @@ export {
connect, disconnect, attach, detach, getSession, connect, disconnect, attach, detach, getSession,
createContext, setActiveContext, listContexts, getActiveContext, createContext, setActiveContext, listContexts, getActiveContext,
hasContext, closeContext, hasContext, closeContext,
} from './core/session.mjs'; } from './engine/core/session.mjs';
// ============================================================ // ============================================================
// Wait + error/modal handling — extracted to core/{wait,errors}.mjs // Wait + error/modal handling — extracted to core/{wait,errors}.mjs
// ============================================================ // ============================================================
import { import {
waitForStable, waitForCondition, startNetworkMonitor, waitForStable, waitForCondition, startNetworkMonitor,
} from './core/wait.mjs'; } from './engine/core/wait.mjs';
import { import {
closeModals, checkForErrors, dismissPendingErrors, fetchErrorStack, closeModals, checkForErrors, dismissPendingErrors, fetchErrorStack,
_detectPlatformDialogs, _closePlatformDialogs, _detectPlatformDialogs, _closePlatformDialogs,
} from './core/errors.mjs'; } from './engine/core/errors.mjs';
import { import {
safeClick, findFieldInputId, readEdd, returnFormState, safeClick, findFieldInputId, readEdd, returnFormState,
detectNewForm as helperDetectNewForm, detectNewForm as helperDetectNewForm,
} from './core/helpers.mjs'; } from './engine/core/helpers.mjs';
import { getGridToggleIcon, shouldClickToggle } from './table/grid-toggle.mjs'; import { getGridToggleIcon, shouldClickToggle } from './engine/table/grid-toggle.mjs';
// Re-export only what was publicly exported before the refactor. // Re-export only what was publicly exported before the refactor.
// waitForStable/waitForCondition/startNetworkMonitor/closeModals/checkForErrors/ // waitForStable/waitForCondition/startNetworkMonitor/closeModals/checkForErrors/
// dismissPendingErrors are internal helpers — imported above for local use only. // dismissPendingErrors are internal helpers — imported above for local use only.
export { fetchErrorStack } from './core/errors.mjs'; export { fetchErrorStack } from './engine/core/errors.mjs';
/* getPage moved to core/state.mjs */ /* getPage moved to core/state.mjs */
@@ -160,7 +160,7 @@ export { fetchErrorStack } from './core/errors.mjs';
export { export {
getPageState, getSections, navigateSection, getCommands, getPageState, getSections, navigateSection, getCommands,
openCommand, switchTab, openFile, navigateLink, openCommand, switchTab, openFile, navigateLink,
} from './nav/navigation.mjs'; } from './engine/nav/navigation.mjs';
/** Read current form state. Single evaluate call via combined script. */ /** Read current form state. Single evaluate call via combined script. */
export async function getFormState() { export async function getFormState() {
@@ -184,50 +184,50 @@ export async function getFormState() {
// ============================================================ // ============================================================
// Table reading + SpreadsheetDocument — extracted to table/spreadsheet.mjs // Table reading + SpreadsheetDocument — extracted to table/spreadsheet.mjs
// ============================================================ // ============================================================
export { readTable } from './table/grid.mjs'; export { readTable } from './engine/table/grid.mjs';
export { readSpreadsheet } from './table/spreadsheet.mjs'; export { readSpreadsheet } from './engine/table/spreadsheet.mjs';
// ============================================================ // ============================================================
// Value selection (DLB/CB) — extracted to forms/select-value.mjs // Value selection (DLB/CB) — extracted to forms/select-value.mjs
// ============================================================ // ============================================================
export { selectValue } from './forms/select-value.mjs'; export { selectValue } from './engine/forms/select-value.mjs';
import { import {
selectValue, pickFromSelectionForm, isTypeDialog, pickFromTypeDialog, selectValue, pickFromSelectionForm, isTypeDialog, pickFromTypeDialog,
fillReferenceField, fillReferenceField,
} from './forms/select-value.mjs'; } from './engine/forms/select-value.mjs';
// ============================================================ // ============================================================
// Fill fields — extracted to forms/fill.mjs // Fill fields — extracted to forms/fill.mjs
// ============================================================ // ============================================================
export { fillFields, fillField } from './forms/fill.mjs'; export { fillFields, fillField } from './engine/forms/fill.mjs';
// ============================================================ // ============================================================
// clickElement dispatcher — extracted to core/click.mjs // clickElement dispatcher — extracted to core/click.mjs
// ============================================================ // ============================================================
export { clickElement } from './core/click.mjs'; export { clickElement } from './engine/core/click.mjs';
import { clickElement } from './core/click.mjs'; import { clickElement } from './engine/core/click.mjs';
// ============================================================ // ============================================================
// Close form — extracted to forms/close.mjs // Close form — extracted to forms/close.mjs
// ============================================================ // ============================================================
export { closeForm } from './forms/close.mjs'; export { closeForm } from './engine/forms/close.mjs';
// ============================================================ // ============================================================
// fillTableRow / deleteTableRow — extracted to table/{row-fill,grid}.mjs // fillTableRow / deleteTableRow — extracted to table/{row-fill,grid}.mjs
// ============================================================ // ============================================================
export { fillTableRow } from './table/row-fill.mjs'; export { fillTableRow } from './engine/table/row-fill.mjs';
export { deleteTableRow } from './table/grid.mjs'; export { deleteTableRow } from './engine/table/grid.mjs';
// ============================================================ // ============================================================
// List filters — extracted to table/filter.mjs // List filters — extracted to table/filter.mjs
// ============================================================ // ============================================================
export { filterList, unfilterList } from './table/filter.mjs'; export { filterList, unfilterList } from './engine/table/filter.mjs';
// ============================================================ // ============================================================
@@ -235,15 +235,15 @@ export { filterList, unfilterList } from './table/filter.mjs';
// ============================================================ // ============================================================
export { export {
screenshot, wait, isRecording, startRecording, stopRecording, screenshot, wait, isRecording, startRecording, stopRecording,
} from './recording/capture.mjs'; } from './engine/recording/capture.mjs';
export { export {
showCaption, hideCaption, getCaptions, showCaption, hideCaption, getCaptions,
showTitleSlide, hideTitleSlide, showTitleSlide, hideTitleSlide,
showImage, hideImage, showImage, hideImage,
} from './recording/captions.mjs'; } from './engine/recording/captions.mjs';
export { export {
highlight, unhighlight, setHighlight, isHighlightMode, highlight, unhighlight, setHighlight, isHighlightMode,
} from './recording/highlight.mjs'; } from './engine/recording/highlight.mjs';
export { addNarration } from './recording/narration.mjs'; export { addNarration } from './engine/recording/narration.mjs';
/* ensureConnected moved to core/state.mjs */ /* ensureConnected moved to core/state.mjs */
@@ -6,7 +6,7 @@ import {
} from './state.mjs'; } from './state.mjs';
import { import {
detectFormScript, findClickTargetScript, resolveGridScript, readSubmenuScript, detectFormScript, findClickTargetScript, resolveGridScript, readSubmenuScript,
} from '../dom.mjs'; } from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors, fetchErrorStack } from './errors.mjs'; import { dismissPendingErrors, checkForErrors, fetchErrorStack } from './errors.mjs';
import { waitForStable, startNetworkMonitor } from './wait.mjs'; import { waitForStable, startNetworkMonitor } from './wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs'; import { highlight, unhighlight } from '../recording/highlight.mjs';
@@ -16,7 +16,7 @@ import {
clickSpreadsheetCell, findSpreadsheetCellByText, clickSpreadsheetCell, findSpreadsheetCellByText,
} from '../table/spreadsheet.mjs'; } from '../table/spreadsheet.mjs';
// getFormState still in browser.mjs. // getFormState still in browser.mjs.
import { getFormState } from '../browser.mjs'; import { getFormState } from '../../browser.mjs';
/** Click a button/hyperlink/tab on the current form. Use {dblclick: true} to double-click (open items from lists). /** Click a button/hyperlink/tab on the current form. Use {dblclick: true} to double-click (open items from lists).
* First argument can also be an object { row, column } to click a SpreadsheetDocument cell. */ * First argument can also be an object { row, column } to click a SpreadsheetDocument cell. */
@@ -2,7 +2,7 @@
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills // Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { page } from './state.mjs'; import { page } from './state.mjs';
import { checkErrorsScript } from '../dom.mjs'; import { checkErrorsScript } from '../../dom.mjs';
import { waitForStable } from './wait.mjs'; import { waitForStable } from './wait.mjs';
/** /**
@@ -4,7 +4,7 @@
import { page } from './state.mjs'; import { page } from './state.mjs';
import { dismissPendingErrors, checkForErrors } from './errors.mjs'; import { dismissPendingErrors, checkForErrors } from './errors.mjs';
import { getFormState } from '../browser.mjs'; import { getFormState } from '../../browser.mjs';
/** /**
* page.click with the standard "intercepts pointer events" retry ladder: * page.click with the standard "intercepts pointer events" retry ladder:
@@ -17,7 +17,7 @@ import { stopRecording } from '../recording/capture.mjs';
// getPageState lives in browser.mjs (moves to nav/navigation.mjs in a later stage). // getPageState lives in browser.mjs (moves to nav/navigation.mjs in a later stage).
// Static import is a deliberate ESM cycle — fine because the binding is used at // Static import is a deliberate ESM cycle — fine because the binding is used at
// call time (inside async connect/createContext), not at module evaluation time. // call time (inside async connect/createContext), not at module evaluation time.
import { getPageState } from '../browser.mjs'; import { getPageState } from '../../browser.mjs';
/** /**
* Find the 1C browser extension in Chrome/Edge user profiles. * Find the 1C browser extension in Chrome/Edge user profiles.
@@ -10,9 +10,9 @@
import { dirname, resolve as pathResolve } from 'path'; import { dirname, resolve as pathResolve } from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
// Project root: 4 levels up from .claude/skills/web-test/scripts/core/state.mjs // Project root: 6 levels up from .claude/skills/web-test/scripts/engine/core/state.mjs
const __fn_state = fileURLToPath(import.meta.url); const __fn_state = fileURLToPath(import.meta.url);
export const projectRoot = pathResolve(dirname(__fn_state), '..', '..', '..', '..', '..'); export const projectRoot = pathResolve(dirname(__fn_state), '..', '..', '..', '..', '..', '..');
/** Resolve a user-provided path relative to the project root (not cwd). */ /** Resolve a user-provided path relative to the project root (not cwd). */
export const resolveProjectPath = (p) => pathResolve(projectRoot, p); export const resolveProjectPath = (p) => pathResolve(projectRoot, p);
@@ -2,7 +2,7 @@
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills // Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { page, MAX_WAIT, POLL_INTERVAL, STABLE_CYCLES } from './state.mjs'; import { page, MAX_WAIT, POLL_INTERVAL, STABLE_CYCLES } from './state.mjs';
import { detectFormScript } from '../dom.mjs'; import { detectFormScript } from '../../dom.mjs';
/** /**
* Smart wait: poll until DOM is stable and no loading indicators are visible. * Smart wait: poll until DOM is stable and no loading indicators are visible.
@@ -2,10 +2,10 @@
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills // Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { page, recorder, ensureConnected } from '../core/state.mjs'; import { page, recorder, ensureConnected } from '../core/state.mjs';
import { detectFormScript } from '../dom.mjs'; import { detectFormScript } from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors, _detectPlatformDialogs, _closePlatformDialogs } from '../core/errors.mjs'; import { dismissPendingErrors, checkForErrors, _detectPlatformDialogs, _closePlatformDialogs } from '../core/errors.mjs';
import { waitForStable } from '../core/wait.mjs'; import { waitForStable } from '../core/wait.mjs';
import { getFormState } from '../browser.mjs'; import { getFormState } from '../../browser.mjs';
/** /**
* Close the current form/dialog via Escape. * Close the current form/dialog via Escape.
@@ -6,7 +6,7 @@ import {
} from '../core/state.mjs'; } from '../core/state.mjs';
import { import {
detectFormScript, resolveFieldsScript, readFormScript, detectFormScript, resolveFieldsScript, readFormScript,
} from '../dom.mjs'; } from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs'; import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs';
import { waitForStable, startNetworkMonitor } from '../core/wait.mjs'; import { waitForStable, startNetworkMonitor } from '../core/wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs'; import { highlight, unhighlight } from '../recording/highlight.mjs';
@@ -15,7 +15,7 @@ import {
isTypeDialog, pickFromTypeDialog, isTypeDialog, pickFromTypeDialog,
} from './select-value.mjs'; } from './select-value.mjs';
// pasteText + getFormState live in browser.mjs. // pasteText + getFormState live in browser.mjs.
import { pasteText, getFormState } from '../browser.mjs'; import { pasteText, getFormState } from '../../browser.mjs';
/** Fill fields on the current form via Playwright page.fill(). Returns fill results + updated form. */ /** Fill fields on the current form via Playwright page.fill(). Returns fill results + updated form. */
export async function fillFields(fields) { export async function fillFields(fields) {
@@ -7,7 +7,7 @@ import {
import { import {
detectFormScript, findFieldButtonScript, resolveFieldsScript, detectFormScript, findFieldButtonScript, resolveFieldsScript,
readSubmenuScript, checkErrorsScript, readSubmenuScript, checkErrorsScript,
} from '../dom.mjs'; } from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs'; import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs';
import { waitForStable, waitForCondition } from '../core/wait.mjs'; import { waitForStable, waitForCondition } from '../core/wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs'; import { highlight, unhighlight } from '../recording/highlight.mjs';
@@ -16,7 +16,7 @@ import {
detectNewForm as helperDetectNewForm, detectNewForm as helperDetectNewForm,
} from '../core/helpers.mjs'; } from '../core/helpers.mjs';
// pasteText + getFormState live in browser.mjs. // pasteText + getFormState live in browser.mjs.
import { pasteText, getFormState } from '../browser.mjs'; import { pasteText, getFormState } from '../../browser.mjs';
/** /**
* Scan visible grid rows for a text match (exact startsWith includes). * Scan visible grid rows for a text match (exact startsWith includes).
@@ -8,14 +8,14 @@ import {
readSectionsScript, readTabsScript, readCommandsScript, readSectionsScript, readTabsScript, readCommandsScript,
navigateSectionScript, openCommandScript, switchTabScript, navigateSectionScript, openCommandScript, switchTabScript,
detectFormScript, detectFormScript,
} from '../dom.mjs'; } from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs'; import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs';
import { waitForStable, waitForCondition } from '../core/wait.mjs'; import { waitForStable, waitForCondition } from '../core/wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs'; import { highlight, unhighlight } from '../recording/highlight.mjs';
import { returnFormState } from '../core/helpers.mjs'; import { returnFormState } from '../core/helpers.mjs';
// pasteText + getFormState live in browser.mjs (move to forms/ in a later stage). // pasteText + getFormState live in browser.mjs (move to forms/ in a later stage).
// Static import — ESM cycle that resolves at call time. // Static import — ESM cycle that resolves at call time.
import { pasteText, getFormState } from '../browser.mjs'; import { pasteText, getFormState } from '../../browser.mjs';
/** /**
* Get current page state: active section, tabs. * Get current page state: active section, tabs.
@@ -45,7 +45,7 @@ export async function wait(seconds) {
await page.waitForTimeout(ms); await page.waitForTimeout(ms);
} }
} }
const { getFormState } = await import('../browser.mjs'); const { getFormState } = await import('../../browser.mjs');
return await getFormState(); return await getFormState();
} }
@@ -8,7 +8,7 @@ import {
import { import {
readSubmenuScript, detectFormScript, resolveGridScript, readSubmenuScript, detectFormScript, resolveGridScript,
findClickTargetScript, resolveFieldsScript, findClickTargetScript, resolveFieldsScript,
} from '../dom.mjs'; } from '../../dom.mjs';
/** /**
* Highlight an element on the page (visual accent for video recordings). * Highlight an element on the page (visual accent for video recordings).
@@ -2,14 +2,14 @@
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills // Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { page, ensureConnected, normYo, highlightMode, ACTION_WAIT } from '../core/state.mjs'; import { page, ensureConnected, normYo, highlightMode, ACTION_WAIT } from '../core/state.mjs';
import { detectFormScript, resolveGridScript } from '../dom.mjs'; import { detectFormScript, resolveGridScript } from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs'; import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs';
import { waitForStable, waitForCondition } from '../core/wait.mjs'; import { waitForStable, waitForCondition } from '../core/wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs'; import { highlight, unhighlight } from '../recording/highlight.mjs';
import { safeClick } from '../core/helpers.mjs'; import { safeClick } from '../core/helpers.mjs';
import { selectValue, fillReferenceField } from '../forms/select-value.mjs'; import { selectValue, fillReferenceField } from '../forms/select-value.mjs';
// pasteText + getFormState + clickElement still in browser.mjs. // pasteText + getFormState + clickElement still in browser.mjs.
import { pasteText, getFormState, clickElement } from '../browser.mjs'; import { pasteText, getFormState, clickElement } from '../../browser.mjs';
/** /**
* Filter the current list by field value, or search via search bar. * Filter the current list by field value, or search via search bar.
@@ -6,12 +6,12 @@
// Отдельно от SpreadsheetDocument (table/spreadsheet.mjs). // Отдельно от SpreadsheetDocument (table/spreadsheet.mjs).
import { page, ensureConnected } from '../core/state.mjs'; import { page, ensureConnected } from '../core/state.mjs';
import { detectFormScript, readTableScript, resolveGridScript } from '../dom.mjs'; import { detectFormScript, readTableScript, resolveGridScript } from '../../dom.mjs';
import { dismissPendingErrors } from '../core/errors.mjs'; import { dismissPendingErrors } from '../core/errors.mjs';
import { waitForStable } from '../core/wait.mjs'; import { waitForStable } from '../core/wait.mjs';
import { clickElement } from '../core/click.mjs'; import { clickElement } from '../core/click.mjs';
// getFormState lives in browser.mjs. // getFormState lives in browser.mjs.
import { getFormState } from '../browser.mjs'; import { getFormState } from '../../browser.mjs';
/** Read structured table data with pagination. Returns columns, rows, total count. */ /** Read structured table data with pagination. Returns columns, rows, total count. */
export async function readTable({ maxRows = 20, offset = 0, table } = {}) { export async function readTable({ maxRows = 20, offset = 0, table } = {}) {
@@ -6,7 +6,7 @@ import {
} from '../core/state.mjs'; } from '../core/state.mjs';
import { import {
detectFormScript, resolveGridScript, readTableScript, detectFormScript, resolveGridScript, readTableScript,
} from '../dom.mjs'; } from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs'; import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs';
import { waitForStable, waitForCondition, startNetworkMonitor } from '../core/wait.mjs'; import { waitForStable, waitForCondition, startNetworkMonitor } from '../core/wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs'; import { highlight, unhighlight } from '../recording/highlight.mjs';
@@ -20,7 +20,7 @@ import {
fillReferenceField, selectValue, fillReferenceField, selectValue,
} from '../forms/select-value.mjs'; } from '../forms/select-value.mjs';
// pasteText + getFormState still in browser.mjs (cycle). // pasteText + getFormState still in browser.mjs (cycle).
import { pasteText, getFormState } from '../browser.mjs'; import { pasteText, getFormState } from '../../browser.mjs';
/** /**
* Fill cells in the current table row via Tab navigation. * Fill cells in the current table row via Tab navigation.
@@ -2,10 +2,10 @@
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills // Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { page, ensureConnected, normYo } from '../core/state.mjs'; import { page, ensureConnected, normYo } from '../core/state.mjs';
import { detectFormScript, readTableScript, resolveGridScript } from '../dom.mjs'; import { detectFormScript, readTableScript, resolveGridScript } from '../../dom.mjs';
import { waitForStable } from '../core/wait.mjs'; import { waitForStable } from '../core/wait.mjs';
// getFormState still in browser.mjs (cycle resolves at call time). // getFormState still in browser.mjs (cycle resolves at call time).
import { getFormState } from '../browser.mjs'; import { getFormState } from '../../browser.mjs';
// readTable moved to table/grid.mjs (form-grid операции отделены от SpreadsheetDocument). // readTable moved to table/grid.mjs (form-grid операции отделены от SpreadsheetDocument).