feat(meta-info): выводить «Представление типа» для ссылочных объектов

В шапке ссылочных объектов (справочники, документы, перечисления, ПВХ/ПВР,
планы счетов, планы обмена, бизнес-процессы, задачи) теперь выводится строка
«Представление типа» — имя ссылочного типа в диалогах выбора типа, с fallback
ObjectPresentation -> Synonym -> Name. В режиме full дополнительно выводятся
заданные сырые представления (объекта/списка и расширенные).

Тесты: раннер принимает stdoutContains строкой или массивом, добавлен
stdoutNotContains. Добавлены кейсы meta-info (ед.ч. ПВХ, full со всеми
представлениями, fallback на синоним) и негативная проверка у регистра.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-01 15:40:17 +03:00
co-authored by Claude Opus 4.8
parent 7c9769c644
commit b188d338f9
8 changed files with 131 additions and 9 deletions
+15 -1
View File
@@ -108,6 +108,20 @@ node tests/skills/verify-snapshots.mjs --help # полный
`params` — параметры для навыка. Используются через `case.<field>` и `workPath` в `_skill.json`.
`expect.stdoutContains` / `expect.stdoutNotContains` — строка **или массив строк**. Каждая подстрока проверяется на наличие (`stdoutContains`) или отсутствие (`stdoutNotContains`) в stdout навыка. Удобно для info-навыков: проверить, что нужная строка есть, а лишней — нет.
```json
{
"name": "Представление типа у ПВХ",
"setup": "external:C:/WS/tasks/cfsrc/erp_8.3.24",
"params": { "objectPath": "ChartsOfCharacteristicTypes/ВидыСубконтоХозрасчетные" },
"expect": {
"stdoutContains": ["Представление типа: Вид субконто", "Представление объекта: Вид субконто"],
"stdoutNotContains": "Представление списка:"
}
}
```
### С дополнительными CLI-аргументами
```json
@@ -175,7 +189,7 @@ node tests/skills/verify-snapshots.mjs --help # полный
| `outputPath` | нет | Относительный путь для навыков с `-OutputPath` |
| `args_extra` | нет | Массив дополнительных CLI-аргументов |
| `preRun` | нет | Массив шагов подготовки (создание объектов и т.п.) |
| `expect` | нет | Дополнительные проверки: `files`, `stdoutContains` |
| `expect` | нет | Дополнительные проверки: `files`, `stdoutContains` (строка/массив), `stdoutNotContains` (строка/массив) |
| `expectError` | нет | `true` или строка — ожидается ошибка |
## Эталоны (snapshots)
@@ -0,0 +1,14 @@
{
"name": "Представления объекта/списка/расширенные в full — БП СтатьиДвиженияДенежныхСредств",
"setup": "external:C:/WS/tasks/cfsrc/acc_8.3.24",
"params": { "objectPath": "Catalogs/СтатьиДвиженияДенежныхСредств" },
"args_extra": ["-Mode", "full"],
"expect": {
"stdoutContains": [
"Представление типа: Статья движения ден. средств",
"Представление объекта: Статья движения ден. средств",
"Расширенное представление объекта: Статья движения денежных средств",
"Представление списка: Статьи движения денежных средств"
]
}
}
@@ -2,5 +2,8 @@
"name": "Реальный регистр бухгалтерии Хозрасчетный (БП)",
"setup": "external:C:/WS/tasks/cfsrc/acc_8.3.24",
"params": { "objectPath": "AccountingRegisters/Хозрасчетный" },
"expect": { "stdoutContains": "Хозрасчетный" }
"expect": {
"stdoutContains": "Хозрасчетный",
"stdoutNotContains": "Представление типа:"
}
}
@@ -0,0 +1,10 @@
{
"name": "Представление типа = синоним при пустом ObjectPresentation — ERP СтатьиБюджетов",
"setup": "external:C:/WS/tasks/cfsrc/erp_8.3.24",
"params": { "objectPath": "Catalogs/СтатьиБюджетов" },
"args_extra": ["-Mode", "full"],
"expect": {
"stdoutContains": "Представление типа: Статьи бюджетов",
"stdoutNotContains": "Представление объекта:"
}
}
@@ -0,0 +1,8 @@
{
"name": "Представление типа (ед.ч.) у ПВХ — ERP ВидыСубконтоХозрасчетные",
"setup": "external:C:/WS/tasks/cfsrc/erp_8.3.24",
"params": { "objectPath": "ChartsOfCharacteristicTypes/ВидыСубконтоХозрасчетные" },
"expect": {
"stdoutContains": "Представление типа: Вид субконто"
}
}
+23 -5
View File
@@ -588,8 +588,17 @@ async function runCaseAsync(testCase, opts) {
}
}
if (caseData.expect?.stdoutContains) {
if (!stdout.includes(caseData.expect.stdoutContains)) {
errors.push(`stdout does not contain "${caseData.expect.stdoutContains}"`);
const needles = Array.isArray(caseData.expect.stdoutContains)
? caseData.expect.stdoutContains : [caseData.expect.stdoutContains];
for (const needle of needles) {
if (!stdout.includes(needle)) errors.push(`stdout does not contain "${needle}"`);
}
}
if (caseData.expect?.stdoutNotContains) {
const needles = Array.isArray(caseData.expect.stdoutNotContains)
? caseData.expect.stdoutNotContains : [caseData.expect.stdoutNotContains];
for (const needle of needles) {
if (stdout.includes(needle)) errors.push(`stdout unexpectedly contains "${needle}"`);
}
}
if (errors.length === 0 && !caseData.expectError && !workspace.readOnly) {
@@ -754,10 +763,19 @@ function runCase(testCase, opts) {
}
}
// expect.stdoutContains
// expect.stdoutContains / stdoutNotContains (string or array)
if (caseData.expect?.stdoutContains) {
if (!stdout.includes(caseData.expect.stdoutContains)) {
errors.push(`stdout does not contain "${caseData.expect.stdoutContains}"`);
const needles = Array.isArray(caseData.expect.stdoutContains)
? caseData.expect.stdoutContains : [caseData.expect.stdoutContains];
for (const needle of needles) {
if (!stdout.includes(needle)) errors.push(`stdout does not contain "${needle}"`);
}
}
if (caseData.expect?.stdoutNotContains) {
const needles = Array.isArray(caseData.expect.stdoutNotContains)
? caseData.expect.stdoutNotContains : [caseData.expect.stdoutNotContains];
for (const needle of needles) {
if (stdout.includes(needle)) errors.push(`stdout unexpectedly contains "${needle}"`);
}
}