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
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,
EXT_ID, projectRoot, resolveProjectPath, normYo,
isConnected, ensureConnected, getPage, setPreserveClipboard,
} from './core/state.mjs';
} from './engine/core/state.mjs';
export { isConnected, getPage, setPreserveClipboard, ensureConnected };
export async function saveClipboard() {
@@ -130,27 +130,27 @@ export {
connect, disconnect, attach, detach, getSession,
createContext, setActiveContext, listContexts, getActiveContext,
hasContext, closeContext,
} from './core/session.mjs';
} from './engine/core/session.mjs';
// ============================================================
// Wait + error/modal handling — extracted to core/{wait,errors}.mjs
// ============================================================
import {
waitForStable, waitForCondition, startNetworkMonitor,
} from './core/wait.mjs';
} from './engine/core/wait.mjs';
import {
closeModals, checkForErrors, dismissPendingErrors, fetchErrorStack,
_detectPlatformDialogs, _closePlatformDialogs,
} from './core/errors.mjs';
} from './engine/core/errors.mjs';
import {
safeClick, findFieldInputId, readEdd, returnFormState,
detectNewForm as helperDetectNewForm,
} from './core/helpers.mjs';
import { getGridToggleIcon, shouldClickToggle } from './table/grid-toggle.mjs';
} from './engine/core/helpers.mjs';
import { getGridToggleIcon, shouldClickToggle } from './engine/table/grid-toggle.mjs';
// Re-export only what was publicly exported before the refactor.
// waitForStable/waitForCondition/startNetworkMonitor/closeModals/checkForErrors/
// 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 */
@@ -160,7 +160,7 @@ export { fetchErrorStack } from './core/errors.mjs';
export {
getPageState, getSections, navigateSection, getCommands,
openCommand, switchTab, openFile, navigateLink,
} from './nav/navigation.mjs';
} from './engine/nav/navigation.mjs';
/** Read current form state. Single evaluate call via combined script. */
export async function getFormState() {
@@ -184,50 +184,50 @@ export async function getFormState() {
// ============================================================
// Table reading + SpreadsheetDocument — extracted to table/spreadsheet.mjs
// ============================================================
export { readTable } from './table/grid.mjs';
export { readSpreadsheet } from './table/spreadsheet.mjs';
export { readTable } from './engine/table/grid.mjs';
export { readSpreadsheet } from './engine/table/spreadsheet.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 {
selectValue, pickFromSelectionForm, isTypeDialog, pickFromTypeDialog,
fillReferenceField,
} from './forms/select-value.mjs';
} from './engine/forms/select-value.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
// ============================================================
export { clickElement } from './core/click.mjs';
import { clickElement } from './core/click.mjs';
export { clickElement } from './engine/core/click.mjs';
import { clickElement } from './engine/core/click.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
// ============================================================
export { fillTableRow } from './table/row-fill.mjs';
export { deleteTableRow } from './table/grid.mjs';
export { fillTableRow } from './engine/table/row-fill.mjs';
export { deleteTableRow } from './engine/table/grid.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 {
screenshot, wait, isRecording, startRecording, stopRecording,
} from './recording/capture.mjs';
} from './engine/recording/capture.mjs';
export {
showCaption, hideCaption, getCaptions,
showTitleSlide, hideTitleSlide,
showImage, hideImage,
} from './recording/captions.mjs';
} from './engine/recording/captions.mjs';
export {
highlight, unhighlight, setHighlight, isHighlightMode,
} from './recording/highlight.mjs';
export { addNarration } from './recording/narration.mjs';
} from './engine/recording/highlight.mjs';
export { addNarration } from './engine/recording/narration.mjs';
/* ensureConnected moved to core/state.mjs */
@@ -6,7 +6,7 @@ import {
} from './state.mjs';
import {
detectFormScript, findClickTargetScript, resolveGridScript, readSubmenuScript,
} from '../dom.mjs';
} from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors, fetchErrorStack } from './errors.mjs';
import { waitForStable, startNetworkMonitor } from './wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs';
@@ -16,7 +16,7 @@ import {
clickSpreadsheetCell, findSpreadsheetCellByText,
} from '../table/spreadsheet.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).
* 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
import { page } from './state.mjs';
import { checkErrorsScript } from '../dom.mjs';
import { checkErrorsScript } from '../../dom.mjs';
import { waitForStable } from './wait.mjs';
/**
@@ -4,7 +4,7 @@
import { page } from './state.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:
@@ -17,7 +17,7 @@ import { stopRecording } from '../recording/capture.mjs';
// 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
// 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.
@@ -10,9 +10,9 @@
import { dirname, resolve as pathResolve } from 'path';
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);
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). */
export const resolveProjectPath = (p) => pathResolve(projectRoot, p);
@@ -2,7 +2,7 @@
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
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.
@@ -2,10 +2,10 @@
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
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 { waitForStable } from '../core/wait.mjs';
import { getFormState } from '../browser.mjs';
import { getFormState } from '../../browser.mjs';
/**
* Close the current form/dialog via Escape.
@@ -6,7 +6,7 @@ import {
} from '../core/state.mjs';
import {
detectFormScript, resolveFieldsScript, readFormScript,
} from '../dom.mjs';
} from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs';
import { waitForStable, startNetworkMonitor } from '../core/wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs';
@@ -15,7 +15,7 @@ import {
isTypeDialog, pickFromTypeDialog,
} from './select-value.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. */
export async function fillFields(fields) {
@@ -7,7 +7,7 @@ import {
import {
detectFormScript, findFieldButtonScript, resolveFieldsScript,
readSubmenuScript, checkErrorsScript,
} from '../dom.mjs';
} from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs';
import { waitForStable, waitForCondition } from '../core/wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs';
@@ -16,7 +16,7 @@ import {
detectNewForm as helperDetectNewForm,
} from '../core/helpers.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).
@@ -8,14 +8,14 @@ import {
readSectionsScript, readTabsScript, readCommandsScript,
navigateSectionScript, openCommandScript, switchTabScript,
detectFormScript,
} from '../dom.mjs';
} from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs';
import { waitForStable, waitForCondition } from '../core/wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs';
import { returnFormState } from '../core/helpers.mjs';
// pasteText + getFormState live in browser.mjs (move to forms/ in a later stage).
// 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.
@@ -45,7 +45,7 @@ export async function wait(seconds) {
await page.waitForTimeout(ms);
}
}
const { getFormState } = await import('../browser.mjs');
const { getFormState } = await import('../../browser.mjs');
return await getFormState();
}
@@ -8,7 +8,7 @@ import {
import {
readSubmenuScript, detectFormScript, resolveGridScript,
findClickTargetScript, resolveFieldsScript,
} from '../dom.mjs';
} from '../../dom.mjs';
/**
* Highlight an element on the page (visual accent for video recordings).
@@ -2,14 +2,14 @@
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
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 { waitForStable, waitForCondition } from '../core/wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs';
import { safeClick } from '../core/helpers.mjs';
import { selectValue, fillReferenceField } from '../forms/select-value.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.
@@ -6,12 +6,12 @@
// Отдельно от SpreadsheetDocument (table/spreadsheet.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 { waitForStable } from '../core/wait.mjs';
import { clickElement } from '../core/click.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. */
export async function readTable({ maxRows = 20, offset = 0, table } = {}) {
@@ -6,7 +6,7 @@ import {
} from '../core/state.mjs';
import {
detectFormScript, resolveGridScript, readTableScript,
} from '../dom.mjs';
} from '../../dom.mjs';
import { dismissPendingErrors, checkForErrors } from '../core/errors.mjs';
import { waitForStable, waitForCondition, startNetworkMonitor } from '../core/wait.mjs';
import { highlight, unhighlight } from '../recording/highlight.mjs';
@@ -20,7 +20,7 @@ import {
fillReferenceField, selectValue,
} from '../forms/select-value.mjs';
// 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.
@@ -2,10 +2,10 @@
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
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';
// 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).