test(web-test): M4.A — validation messages + exception modal + error stack

10-validation.test.mjs (3 шага): Сообщить() → state.errors.messages,
ВызватьИсключение → onecError.errors.modal с автоматическим закрытием
fetchErrorStack.

14-errors-stack.test.mjs (3 шага): Path 1 OpenReport автоматически фетчит
стек для серверных исключений (entries[] содержит кадр ОбщиеФункции);
оставленная error modal через raw page.click закрывается closeForm;
платформенный диалог «О программе» виден в state.platformDialogs и
закрывается closeForm.

Покрыто 4 P2-кейса coverage matrix: 10-validation/messages,
10-validation/exception-modal, 14-errors/path1, 14-errors/dismiss-platform
+ бонус dismiss-modal. Открытие обработки ТестовыеОшибки через
navigateLink('Обработка.ТестовыеОшибки') — стандартные команды у
DataProcessor отключены.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-05-11 15:21:11 +03:00
parent 8c7c442705
commit 4af69f1600
2 changed files with 117 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
export const name = 'errors: fetchErrorStack Path 1 + dismiss platform dialogs';
export const tags = ['errors', 'stack'];
export const timeout = 60000;
export default async function({ navigateLink, clickElement, closeForm, getFormState, getPage, assert, step, log }) {
await step('path1: серверное ВызватьИсключение → автоматически фетчится стек через OpenReport', async () => {
await navigateLink('Обработка.ТестовыеОшибки');
let caught = null;
try {
await clickElement('Вызвать исключение');
} catch (e) {
caught = e;
}
assert.ok(caught, 'исключение брошено');
const stack = caught.onecError?.stack;
log(`stack entries: ${stack?.entries?.length}`);
assert.ok(stack, 'onecError.stack присутствует');
assert.ok(stack.timestamp, 'stack.timestamp');
assert.ok(Array.isArray(stack.entries) && stack.entries.length >= 1, 'stack.entries — непустой массив');
const root = stack.entries.find(e => /ОбщиеФункции/.test(e.location));
assert.ok(root, 'в стеке есть кадр из ОбщегоМодуля ОбщиеФункции');
assert.match(root.code, /ВызватьИсключение/, 'кадр содержит строку с ВызватьИсключение');
});
await step('dismiss-modal: оставленная error modal видна в state и закрывается closeForm', async () => {
// Поток внутри wrapper'a clickElement автоматически зовёт fetchErrorStack и
// закрывает модалку. Чтобы получить «висящую» модалку — кликаем напрямую
// через page.click, минуя wrapper.
await navigateLink('Обработка.ТестовыеОшибки');
const page = await getPage();
const btnId = await page.evaluate(() => {
const el = document.querySelector('[id$="ВызватьИсключение_div"]');
return el && el.offsetWidth > 0 ? el.id : null;
});
assert.ok(btnId, 'кнопка «Вызвать исключение» найдена в DOM');
await page.click('#' + btnId);
await page.waitForTimeout(2500);
const withModal = await getFormState();
log(`modal present: ${JSON.stringify(withModal.errors?.modal)}`);
assert.equal(withModal.modal, true, 'state.modal=true пока модалка открыта');
assert.ok(withModal.errors?.modal, 'state.errors.modal присутствует');
assert.equal(withModal.errors.modal.message, 'Тестовое исключение', 'modal.message');
await closeForm();
const after = await getFormState();
log(`after closeForm — modal: ${JSON.stringify(after.errors?.modal)} form: ${after.form}`);
assert.ok(!after.errors?.modal, 'модалка закрыта');
assert.ok(!after.modal, 'state.modal не true');
});
await step('dismiss-platform: открытый «О программе» виден в state.platformDialogs и закрывается closeForm', async () => {
// Форма ТестовыеОшибки осталась открытой после предыдущего шага (модалка ушла сама)
const page = await getPage();
await page.click('#captionbarMore');
await page.waitForTimeout(800);
await page.getByText('О программе...', { exact: true }).click();
await page.waitForTimeout(1500);
const before = await getFormState();
log(`platformDialogs: ${JSON.stringify(before.platformDialogs)}`);
assert.ok(Array.isArray(before.platformDialogs) && before.platformDialogs.length === 1,
'state.platformDialogs — массив с одним элементом');
assert.equal(before.platformDialogs[0].type, 'about', 'тип = about');
await closeForm();
const after = await getFormState();
log(`platformDialogs after closeForm: ${after.platformDialogs?.length || 0}`);
assert.ok(!after.platformDialogs?.length, 'после closeForm нет platformDialogs');
});
await closeForm();
}