mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-11 00:14:56 +03:00
docs(web-test): rewrite SKILL.md following Anthropic best practices
- Structured API reference with signatures, return types, and inline examples - Added readSpreadsheet structured format (title, headers, data, totals) - Added readTable pagination, tree, hierarchy documentation - Added DCS reportSettings and human-readable labels for fillFields/selectValue - Added decision guides (when to use which reading/closing method) - Progressive disclosure: quick start → modes → API → patterns → notes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+286
-197
@@ -12,41 +12,18 @@ allowed-tools:
|
||||
|
||||
# /web-test — Browser automation for 1C web client
|
||||
|
||||
Writes and runs automation scripts for 1C web client via Playwright.
|
||||
Automates user interactions with 1C:Enterprise web client via Playwright — navigating sections, filling forms, reading tables and reports, filtering lists.
|
||||
|
||||
## Usage
|
||||
## Quick start
|
||||
|
||||
```
|
||||
/web-test Открой Платежное поручение, заполни сумму 5000, скриншот
|
||||
/web-test Создай "Поступление товаров", организация "Конфетпром"
|
||||
/web-test Проверь список контрагентов — прочитай таблицу
|
||||
```
|
||||
|
||||
## Setup (first time)
|
||||
|
||||
```bash
|
||||
cd .claude/skills/web-test/scripts && npm install
|
||||
```
|
||||
|
||||
Requires Node.js 18+. `npm install` downloads Playwright and Chromium browser.
|
||||
|
||||
## Workflow
|
||||
|
||||
Runner: `.claude/skills/web-test/scripts/run.mjs`
|
||||
|
||||
Use `RUN` shorthand in all commands:
|
||||
```bash
|
||||
RUN=".claude/skills/web-test/scripts/run.mjs"
|
||||
```
|
||||
|
||||
### Autonomous mode (preferred for complete scenarios)
|
||||
# One-shot: opens browser → runs script → closes browser → exits
|
||||
node $RUN run http://localhost:8081/bpdemo test-scenario.js
|
||||
|
||||
Single command — opens browser, runs script, closes browser, exits:
|
||||
|
||||
```bash
|
||||
node $RUN run <url> test-scenario.js
|
||||
# or pipe from stdin:
|
||||
cat <<'SCRIPT' | node $RUN run <url> -
|
||||
# Or pipe inline:
|
||||
cat <<'SCRIPT' | node $RUN run http://localhost:8081/bpdemo -
|
||||
await navigateSection('Продажи');
|
||||
await openCommand('Заказы клиентов');
|
||||
await clickElement('Создать');
|
||||
@@ -55,221 +32,333 @@ await clickElement('Провести и закрыть');
|
||||
SCRIPT
|
||||
```
|
||||
|
||||
Process exits when done. No session files, no HTTP server. Ideal for subagents and CI.
|
||||
## Setup (first time)
|
||||
|
||||
```bash
|
||||
cd .claude/skills/web-test/scripts && npm install
|
||||
```
|
||||
|
||||
Requires Node.js 18+. `npm install` downloads Playwright and Chromium.
|
||||
|
||||
## URL resolution
|
||||
|
||||
Read `.v8-project.json` from project root. Each database has `id` and optional `webUrl`.
|
||||
Construct URL as `http://localhost:8081/<id>` or use `webUrl` if set.
|
||||
Use `/web-publish` first if the database is not published.
|
||||
|
||||
## Execution modes
|
||||
|
||||
### Autonomous mode (preferred for complete scenarios)
|
||||
|
||||
```bash
|
||||
node $RUN run <url> script.js # exits when done, no session
|
||||
```
|
||||
|
||||
### Interactive mode (step-by-step development)
|
||||
|
||||
```bash
|
||||
# 1. Start browser session (run_in_background=true, prints JSON when ready)
|
||||
# 1. Start session (run_in_background=true, prints JSON when ready)
|
||||
node $RUN start <url>
|
||||
|
||||
# 2. Execute scripts against running session
|
||||
cat <<'SCRIPT' | node $RUN exec -
|
||||
const form = await getFormState();
|
||||
console.log(JSON.stringify(form.fields, null, 2));
|
||||
console.log(JSON.stringify(form, null, 2));
|
||||
SCRIPT
|
||||
|
||||
# 3. Screenshot anytime
|
||||
# 3. Screenshot
|
||||
node $RUN shot result.png
|
||||
|
||||
# 4. Stop when done (logout + close browser)
|
||||
# 4. Stop (logout + close)
|
||||
node $RUN stop
|
||||
```
|
||||
|
||||
`start` outputs "Browser ready" JSON and keeps running (HTTP server). Use `exec`/`shot`/`stop` from other commands.
|
||||
`start` runs an HTTP server in background. Use `exec`/`shot`/`stop` from other shells.
|
||||
|
||||
## URL
|
||||
### Writing exec scripts
|
||||
|
||||
Read `.v8-project.json` from project root. Each database has `id` and optional `webUrl`.
|
||||
Construct URL as `http://localhost:8081/<id>` or use `webUrl` if set.
|
||||
Use `/web-publish` skill first if the database is not published yet.
|
||||
|
||||
## Writing exec scripts
|
||||
|
||||
In `exec` sandbox, all browser.mjs functions are available as globals — no `import` needed.
|
||||
`console.log()` output is captured and returned in the JSON response.
|
||||
`writeFileSync` and `readFileSync` are also available.
|
||||
All browser.mjs exports are globals — no `import` needed.
|
||||
`console.log()` output is captured in the JSON response.
|
||||
`writeFileSync` / `readFileSync` also available.
|
||||
|
||||
## API reference
|
||||
|
||||
### Navigation
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `navigateSection(name)` | Go to section (fuzzy match). Returns `{ sections, commands }` |
|
||||
| `openCommand(name)` | Open command from function panel (fuzzy). Returns form state |
|
||||
| `navigateLink(url)` | Open 1C navigation link via Shift+F11 dialog. Returns form state |
|
||||
| `switchTab(name)` | Switch to open tab/window (fuzzy). Returns form state |
|
||||
|
||||
### Reading
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `getFormState()` | Current form: fields (with `required` flag for unfilled mandatory fields), buttons, tabs, table meta (columns + rowCount), filters |
|
||||
| `readTable({maxRows, offset})` | Table row data: `{ columns, rows: [{col: val}], total }`. Use this to read grid contents |
|
||||
| `readSpreadsheet()` | Read report output (SpreadsheetDocument): `{ rows: string[][], total }`. Use after clicking "Сформировать" |
|
||||
| `getSections()` | Sections + commands of active section |
|
||||
| `getPageState()` | Sections + open tabs |
|
||||
| `getCommands()` | Commands of current section |
|
||||
|
||||
### Actions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `clickElement(text, {dblclick?})` | Click button/link/tab (fuzzy). `{dblclick:true}` to open items from lists. If returns `submenu[]` — click again with item name |
|
||||
| `fillFields({name: value})` | Fill form fields (fuzzy by name or label). Auto-detects checkboxes, radio, reference fields |
|
||||
| `selectValue(field, search)` | Select from reference field via dropdown/selection form |
|
||||
| `fillTableRow(fields, opts)` | Fill table row cells via Tab navigation. See below |
|
||||
| `deleteTableRow(row, {tab?})` | Delete row by 0-based index |
|
||||
| `closeForm({save})` | Close form via Escape. `save: false` auto-clicks "Нет", `save: true` auto-clicks "Да", omit — returns confirmation for caller |
|
||||
| `filterList(text, opts)` | Filter list. Simple (text only) or advanced (text + field). See below |
|
||||
| `unfilterList({field?})` | Clear filters. All or specific badge |
|
||||
|
||||
### Utility
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `screenshot()` | Returns PNG Buffer |
|
||||
| `wait(seconds)` | Wait N seconds, returns form state |
|
||||
| `getPage()` | Raw Playwright Page for advanced scripting |
|
||||
|
||||
## Key patterns
|
||||
|
||||
### Fill fields
|
||||
|
||||
#### `navigateSection(name)` → `{ navigated, sections, commands }`
|
||||
Go to a top-level section (fuzzy match). Returns list of commands in that section.
|
||||
```js
|
||||
await fillFields({
|
||||
'Организация': 'Конфетпром', // reference — auto type-ahead
|
||||
'Сумма': '5000', // plain text — clipboard paste
|
||||
'Оплачено': 'true', // checkbox — "true"/"false"/"да"/"нет"
|
||||
'Вид операции': 'Оплата поставщику' // radio — fuzzy label match
|
||||
});
|
||||
// Returns: { filled: [{ field, ok, value, method }], form: {...} }
|
||||
await navigateSection('Продажи');
|
||||
// { navigated: 'Продажи', sections: [...], commands: ['Заказы клиентов', ...] }
|
||||
```
|
||||
|
||||
### Fill table row
|
||||
|
||||
#### `openCommand(name)` → form state
|
||||
Open a command from the function panel (fuzzy). Returns form state of the opened form.
|
||||
```js
|
||||
await fillTableRow(
|
||||
{ 'Номенклатура': 'Бумага', 'Количество': '10', 'Цена': '100' },
|
||||
{ tab: 'Товары', add: true } // add:true = new row
|
||||
);
|
||||
// Edit existing: { row: 0 } instead of { add: true }
|
||||
const form = await openCommand('Заказы клиентов');
|
||||
```
|
||||
|
||||
- Tab-based sequential navigation — field order set by 1C form config
|
||||
- Fuzzy cell match: "Количество" matches "ТоварыКоличество"
|
||||
- Reference cells auto-detected by autocomplete popup
|
||||
|
||||
### Filter
|
||||
|
||||
```js
|
||||
await filterList('КП00-000018'); // simple — all columns
|
||||
await filterList('Мишка', { field: 'Наименование' }); // advanced — specific column
|
||||
await filterList('Мишка', { field: 'Наименование', exact: true }); // exact match
|
||||
await unfilterList(); // clear all
|
||||
await unfilterList({ field: 'Наименование' }); // clear specific badge
|
||||
```
|
||||
|
||||
### Open item from list
|
||||
|
||||
```js
|
||||
// Double-click to open a document/catalog item from a list
|
||||
await clickElement('0000-000227', { dblclick: true });
|
||||
// Returns the opened form state (fields, table, buttons)
|
||||
```
|
||||
|
||||
Single `clickElement(text)` only selects the row. To open — always use `{dblclick: true}`.
|
||||
|
||||
### Hierarchical lists (catalogs)
|
||||
|
||||
Both simple and advanced search work on hierarchical catalogs (Контрагенты, Номенклатура, etc.):
|
||||
|
||||
```js
|
||||
await filterList('Конфетпром'); // simple search — flattens hierarchical view
|
||||
await filterList('Конфетпром', { field: 'Наименование' }); // advanced — specific column
|
||||
await clickElement('Конфетпром ООО', { dblclick: true }); // open found item
|
||||
await closeForm(); // close item
|
||||
await unfilterList(); // restore hierarchical view
|
||||
```
|
||||
|
||||
Hint: if `readTable()` returns `hierarchical: true`, the list has groups.
|
||||
|
||||
### Closing forms
|
||||
|
||||
| Action | Method |
|
||||
|--------|--------|
|
||||
| Post & close document | `clickElement('Провести и закрыть')` |
|
||||
| Save & close catalog | `clickElement('Записать и закрыть')` |
|
||||
| Close without saving | `closeForm({ save: false })` — auto-dismisses "save changes?" |
|
||||
| Close and save | `closeForm({ save: true })` — auto-confirms save |
|
||||
| Close (manual confirm) | `closeForm()` — returns `confirmation` field if dialog appears |
|
||||
|
||||
`closeForm()` is preferred over `clickElement('×')` — close buttons on tabs are ambiguous.
|
||||
|
||||
### Keyboard shortcuts
|
||||
|
||||
| Key | Context | Action |
|
||||
|-----|---------|--------|
|
||||
| `F8` | Reference field focused | Open creation form for the field's catalog |
|
||||
| `Shift+F4` | Reference field focused | Clear field value |
|
||||
| `F4` | Reference field focused | Open selection form |
|
||||
| `Alt+F` | List/table form | Open advanced search dialog |
|
||||
|
||||
### Navigation links
|
||||
|
||||
#### `navigateLink(url)` → form state
|
||||
Open any 1C object by metadata path (Shift+F11 dialog). Bypasses section/command navigation.
|
||||
```js
|
||||
await navigateLink('Документ.ЗаказКлиента');
|
||||
await navigateLink('РегистрНакопления.ЗаказыКлиентов');
|
||||
await navigateLink('Справочник.Контрагенты');
|
||||
```
|
||||
|
||||
Bypasses section/command navigation. Useful for registers, journals, and any form with a known path.
|
||||
#### `switchTab(name)` → form state
|
||||
Switch to an already-open tab/window (fuzzy match).
|
||||
|
||||
### Submenu navigation
|
||||
### Reading form state
|
||||
|
||||
#### `getFormState()` → `{ fields, buttons, tabs, table, filters, reportSettings? }`
|
||||
Returns current form structure. This is the primary way to understand what's on screen.
|
||||
|
||||
**fields** — each field has: `name`, `value`, `label?`, `actions?` (select, clear, open), `required?` (true for unfilled mandatory fields)
|
||||
|
||||
**table** — summary only: `{ name, columns, rowCount }`. Use `readTable()` for actual data.
|
||||
|
||||
**reportSettings** — for DCS reports: human-readable filter settings instead of raw technical names:
|
||||
```js
|
||||
const form = await getFormState();
|
||||
// form.reportSettings = [
|
||||
// { name: "Склад", enabled: true, value: "Склад бытовой техники", actions: ["select"] },
|
||||
// { name: "Номенклатура", enabled: false, value: "" }
|
||||
// ]
|
||||
```
|
||||
|
||||
**errorModal** — if present, 1C showed an error dialog. Read the message and decide how to proceed.
|
||||
|
||||
**confirmation** — if present, a Yes/No dialog is shown. Call `clickElement('Да')` or `clickElement('Нет')`.
|
||||
|
||||
### Reading data
|
||||
|
||||
#### `readTable({ maxRows?, offset? })` → `{ columns, rows, total, shown, offset }`
|
||||
Read actual grid data with pagination. Each row is `{ columnName: value }`.
|
||||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `maxRows` | 20 | Max rows to return per call |
|
||||
| `offset` | 0 | Skip first N rows |
|
||||
|
||||
Special row fields:
|
||||
- `_kind: 'group'` — hierarchical group row
|
||||
- `_kind: 'parent'` — parent row in hierarchy
|
||||
- `_tree: 'expanded'|'collapsed'` — tree node state
|
||||
- `_level: N` — nesting depth in tree view
|
||||
- `hierarchical: true` — list has groups (on result object)
|
||||
- `viewMode: 'tree'` — tree view active (on result object)
|
||||
|
||||
```js
|
||||
const r = await clickElement('Ещё');
|
||||
// r.submenu = ['Расширенный поиск', 'Настройки', ...]
|
||||
await clickElement('Расширенный поиск'); // click submenu item
|
||||
const t = await readTable({ maxRows: 50 });
|
||||
console.log('Columns:', t.columns);
|
||||
console.log('Rows:', t.rows.length, 'of', t.total);
|
||||
// Pagination:
|
||||
const page2 = await readTable({ maxRows: 50, offset: 50 });
|
||||
```
|
||||
|
||||
## Response format (exec)
|
||||
#### `readSpreadsheet()` → `{ title?, headers?, data?, totals?, rows?, total }`
|
||||
Read report output (SpreadsheetDocument) after clicking "Сформировать".
|
||||
|
||||
Returns structured data when header row is detected:
|
||||
```js
|
||||
await clickElement('Сформировать');
|
||||
await wait(5);
|
||||
const report = await readSpreadsheet();
|
||||
// { title: "Остатки товаров", headers: ["Номенклатура", "Склад", "Количество"],
|
||||
// data: [{ "Номенклатура": "Бумага", "Склад": "Основной", "Количество": "150" }, ...],
|
||||
// totals: { "Количество": "1250" }, total: 42 }
|
||||
```
|
||||
|
||||
Falls back to `{ rows: string[][], total }` when headers can't be detected.
|
||||
|
||||
#### `getSections()` → `{ activeSection, sections, commands }`
|
||||
Read section panel and commands without navigating.
|
||||
|
||||
#### `getCommands()` → `string[]`
|
||||
Commands of the current section.
|
||||
|
||||
#### `getPageState()` → `{ activeSection, activeTab, sections, tabs }`
|
||||
Sections + all open tabs.
|
||||
|
||||
### Actions
|
||||
|
||||
#### `clickElement(text, { dblclick? })` → form state
|
||||
Click button, hyperlink, tab, or grid row (fuzzy match).
|
||||
|
||||
- Single click selects a row in a list. **Double-click opens** the item:
|
||||
```js
|
||||
await clickElement('0000-000227', { dblclick: true }); // opens document
|
||||
```
|
||||
- Returns `submenu[]` when a menu opens — click again with item name:
|
||||
```js
|
||||
const r = await clickElement('Ещё');
|
||||
// r.submenu = ['Расширенный поиск', 'Настройки', ...]
|
||||
await clickElement('Расширенный поиск');
|
||||
```
|
||||
- Handles tree nodes: clicking a tree icon expands/collapses.
|
||||
|
||||
#### `fillFields({ name: value })` → `{ filled, form }`
|
||||
Fill form fields by label (fuzzy match). Auto-detects field type.
|
||||
|
||||
| Value | Field type | Method |
|
||||
|-------|-----------|--------|
|
||||
| `'Конфетпром'` | Reference | Clipboard paste + typeahead |
|
||||
| `'5000'` | Plain text | Clipboard paste |
|
||||
| `'true'` / `'да'` | Checkbox | Toggle |
|
||||
| `'Оплата поставщику'` | Radio | Fuzzy label match |
|
||||
|
||||
**DCS report filters**: use human-readable label names. Checkbox is auto-enabled:
|
||||
```js
|
||||
await fillFields({
|
||||
'Склад': 'Склад бытовой техники', // auto-enables "Склад" checkbox + fills value
|
||||
'Номенклатура': 'Вентилятор' // same: enables checkbox + fills
|
||||
});
|
||||
```
|
||||
|
||||
Returns `{ filled: [{ field, ok, value, method }], form: {...} }`.
|
||||
Method is one of: `'toggle'` | `'radio'` | `'paste'` | `'dropdown'` | `'form'` | `'typeahead'`
|
||||
|
||||
#### `selectValue(field, search)` → form state with `selected`
|
||||
Select a value from reference field via dropdown or selection form. More reliable than `fillFields` for reference fields that need exact selection from a catalog.
|
||||
|
||||
```js
|
||||
await selectValue('Организация', 'Конфетпром');
|
||||
// result.selected = { field: 'Организация', search: 'Конфетпром', method: 'dropdown'|'form' }
|
||||
```
|
||||
|
||||
Also supports DCS labels — auto-enables the paired checkbox.
|
||||
|
||||
#### `fillTableRow(fields, opts)` → form state
|
||||
Fill table row cells via Tab navigation.
|
||||
|
||||
```js
|
||||
// Add new row:
|
||||
await fillTableRow(
|
||||
{ 'Номенклатура': 'Бумага', 'Количество': '10', 'Цена': '100' },
|
||||
{ tab: 'Товары', add: true }
|
||||
);
|
||||
// Edit existing row:
|
||||
await fillTableRow(
|
||||
{ 'Количество': '20' },
|
||||
{ tab: 'Товары', row: 0 }
|
||||
);
|
||||
```
|
||||
|
||||
- Tab-based sequential navigation — field order set by 1C form config
|
||||
- Fuzzy cell match: "Количество" matches "ТоварыКоличество"
|
||||
- Reference cells auto-detected by autocomplete popup
|
||||
|
||||
#### `deleteTableRow(row, { tab? })` → form state
|
||||
Delete row by 0-based index.
|
||||
|
||||
#### `closeForm({ save? })` → form state
|
||||
Close the current form via Escape.
|
||||
|
||||
| Argument | Behavior |
|
||||
|----------|----------|
|
||||
| `{ save: false }` | Auto-clicks "Нет" on confirmation |
|
||||
| `{ save: true }` | Auto-clicks "Да" on confirmation |
|
||||
| `{}` (omitted) | Returns `confirmation` field if dialog appears |
|
||||
|
||||
Preferred over `clickElement('×')` — close buttons on tabs are ambiguous.
|
||||
|
||||
#### `filterList(text, opts?)` → form state
|
||||
Filter list. Simple mode searches all columns, advanced mode targets a specific field.
|
||||
|
||||
```js
|
||||
await filterList('КП00-000018'); // simple — all columns
|
||||
await filterList('Мишка', { field: 'Наименование' }); // advanced — specific column
|
||||
await filterList('Мишка', { field: 'Наименование', exact: true }); // exact match
|
||||
```
|
||||
|
||||
Works on hierarchical catalogs too (flattens the view).
|
||||
|
||||
#### `unfilterList({ field? })` → form state
|
||||
Clear filters. Without arguments clears all, with `{ field }` clears specific badge.
|
||||
|
||||
### Utility
|
||||
|
||||
#### `screenshot()` → PNG Buffer
|
||||
#### `wait(seconds)` → form state
|
||||
#### `getPage()` → Playwright Page (raw, for advanced scripting)
|
||||
|
||||
## Common patterns
|
||||
|
||||
### Create and save a document
|
||||
|
||||
```js
|
||||
await navigateSection('Продажи');
|
||||
await openCommand('Заказы клиентов');
|
||||
await clickElement('Создать');
|
||||
await fillFields({ 'Организация': 'Конфетпром', 'Контрагент': 'Альфа' });
|
||||
await fillTableRow({ 'Номенклатура': 'Бумага', 'Количество': '10' }, { tab: 'Товары', add: true });
|
||||
await clickElement('Провести и закрыть');
|
||||
```
|
||||
|
||||
### Open item from list
|
||||
|
||||
```js
|
||||
await clickElement('КП00-000227', { dblclick: true });
|
||||
// Always use { dblclick: true } — single click only selects the row
|
||||
```
|
||||
|
||||
### Work with hierarchical lists
|
||||
|
||||
```js
|
||||
await filterList('Конфетпром'); // flatten + search
|
||||
await clickElement('Конфетпром ООО', { dblclick: true }); // open
|
||||
await closeForm();
|
||||
await unfilterList(); // restore hierarchy
|
||||
```
|
||||
|
||||
### Generate and read a report
|
||||
|
||||
```js
|
||||
// Fill report filters using readable labels
|
||||
await fillFields({ 'Склад': 'Основной склад' });
|
||||
await clickElement('Сформировать');
|
||||
await wait(5);
|
||||
const report = await readSpreadsheet();
|
||||
console.log('Title:', report.title);
|
||||
console.log('Data rows:', report.data?.length);
|
||||
```
|
||||
|
||||
### Keyboard shortcuts (via `page.keyboard.press`)
|
||||
|
||||
| Key | Context | Action |
|
||||
|-----|---------|--------|
|
||||
| `F8` | Reference field focused | Create new catalog item |
|
||||
| `Shift+F4` | Reference field focused | Clear field value |
|
||||
| `F4` | Reference field focused | Open selection form |
|
||||
| `Alt+F` | List/table form | Open advanced search dialog |
|
||||
|
||||
### Closing forms — which method to use
|
||||
|
||||
| Goal | Method |
|
||||
|------|--------|
|
||||
| Post & close document | `clickElement('Провести и закрыть')` |
|
||||
| Save & close catalog | `clickElement('Записать и закрыть')` |
|
||||
| Close without saving | `closeForm({ save: false })` |
|
||||
| Close and save | `closeForm({ save: true })` |
|
||||
| Close (manual confirm) | `closeForm()` — returns `confirmation` if dialog appears |
|
||||
|
||||
## Exec response format
|
||||
|
||||
Success:
|
||||
```json
|
||||
{ "ok": true, "output": "...console.log...", "elapsed": 3.2 }
|
||||
{ "ok": true, "output": "...console.log output...", "elapsed": 3.2 }
|
||||
```
|
||||
|
||||
Error (with auto-screenshot):
|
||||
On error (auto-screenshot taken):
|
||||
```json
|
||||
{ "ok": false, "error": "Element not found", "output": "...", "screenshot": "error-shot.png", "elapsed": 1.5 }
|
||||
```
|
||||
|
||||
## Script template
|
||||
|
||||
```js
|
||||
// Navigate to section and open list
|
||||
await navigateSection('Банк и касса');
|
||||
await openCommand('Платежные поручения');
|
||||
|
||||
// Create new document
|
||||
await clickElement('Создать');
|
||||
|
||||
// Fill and save
|
||||
await fillFields({ 'Организация': 'Конфетпром', 'Сумма': '5000' });
|
||||
await clickElement('Провести и закрыть');
|
||||
|
||||
console.log('done');
|
||||
```
|
||||
|
||||
Run: `node $RUN run http://localhost:8081/bpdemo script.js`
|
||||
|
||||
## Important
|
||||
## Important notes
|
||||
|
||||
- **Headed mode** — 1C requires visible browser, no headless
|
||||
- **1C loads 30-60s** on initial connect (wait is built into `start`)
|
||||
- **Fuzzy match** — all name lookups use fuzzy search (exact > startsWith > includes)
|
||||
- **errorModal** — if response contains `errorModal`, 1C showed an error dialog
|
||||
- **Clipboard paste** — all fields filled via Ctrl+V (triggers 1C events properly)
|
||||
- **Stdin pipe for Cyrillic** — use `cat <<'SCRIPT' | node $RUN exec -` to avoid bash escaping
|
||||
- **Startup time** — 1C loads 30-60s on initial connect (built into `start`)
|
||||
- **Fuzzy matching** — all name lookups: exact > startsWith > includes
|
||||
- **Clipboard paste** — all text fields filled via Ctrl+V (triggers 1C events properly)
|
||||
- **Cyrillic in bash** — use `cat <<'SCRIPT' | node $RUN exec -` to avoid escaping issues
|
||||
- **Non-breaking spaces** — 1C uses `\u00a0` instead of regular spaces. All matching is normalized internally
|
||||
|
||||
Reference in New Issue
Block a user