«Удалить строку» на строке программы (GROUP) или проекта (ITEM) ничего не делала: у этих строк нет line_id, окно подтверждения не открывалось, а события program_deleted / project_deleted, которые сервер уже поддерживает, фронт не отправлял. - getDeleteTarget: по выделенной строке выбирает программу, проект или строку бюджета; для непустых программы/проекта сразу показывает причину. - RealtimeContext: deleteProgram / deleteProject и обработка ответов. - useRealtimeData: строка убирается из дерева, пересчёт ROOT/GROUP из ответа сопоставляется по section_code / program_id / project_id (alignNodeRows), а не по sort_order — сервер нумерует строки заново, и у листа без строк бюджета нет ROOT (найдено при проверке на стенде). - Окно подтверждения называет удаляемую программу/проект. - getWsErrorMessage срезает префикс "<class 'asyncpg...'>: " — иначе отказ сервера (программа с проектами у устаревшего клиента) показывался с ним. Refs #303 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
74 lines
4.3 KiB
JavaScript
74 lines
4.3 KiB
JavaScript
import assert from 'node:assert/strict';
|
||
import { test } from 'node:test';
|
||
import { getWsErrorMessage } from './wsErrorUtils.js';
|
||
|
||
test('строка возвращается как есть', () => {
|
||
assert.equal(getWsErrorMessage('Ячейка уже редактируется другим пользователем'), 'Ячейка уже редактируется другим пользователем');
|
||
});
|
||
|
||
test('объект с message возвращает message', () => {
|
||
assert.equal(getWsErrorMessage({ code: 400, field: 'q1.transfer_econ', message: 'Нельзя указать отрицательное значение' }), 'Нельзя указать отрицательное значение');
|
||
});
|
||
|
||
test('объект без message возвращает detail', () => {
|
||
assert.equal(getWsErrorMessage({ detail: 'Ошибка подключения к базе данных' }), 'Ошибка подключения к базе данных');
|
||
});
|
||
|
||
test('объект без message и без detail возвращает дефолтный текст, а не undefined', () => {
|
||
const result = getWsErrorMessage({ code: 500 });
|
||
assert.notEqual(result, undefined);
|
||
assert.equal(typeof result, 'string');
|
||
assert.ok(!result.includes('undefined'));
|
||
});
|
||
|
||
test('префикс computed_field: заменяется человеческим текстом', () => {
|
||
assert.equal(getWsErrorMessage('computed_field: q1.corrected_plan'), 'Это расчётная ячейка, её нельзя изменить');
|
||
assert.equal(getWsErrorMessage({ message: 'computed_field: q1.corrected_plan' }), 'Это расчётная ячейка, её нельзя изменить');
|
||
});
|
||
|
||
test('префикс role_not_allowed: заменяется человеческим текстом', () => {
|
||
assert.equal(getWsErrorMessage('role_not_allowed: data.q1.transfer_econ'), 'Нет прав на изменение этой колонки');
|
||
});
|
||
|
||
test('префикс window_closed: заменяется человеческим текстом', () => {
|
||
assert.equal(getWsErrorMessage('window_closed: data.q1.transfer_econ'), 'Окно ввода для этой колонки закрыто');
|
||
});
|
||
|
||
test('префикс org_not_assigned заменяется человеческим текстом', () => {
|
||
assert.equal(getWsErrorMessage('org_not_assigned'), 'Вы не назначены на эту форму');
|
||
assert.equal(getWsErrorMessage({ message: 'org_not_assigned: form_id=123' }), 'Вы не назначены на эту форму');
|
||
});
|
||
|
||
test('неизвестный текст возвращается без технического префикса Server error:', () => {
|
||
const result = getWsErrorMessage('Database unavailable');
|
||
assert.equal(result, 'Database unavailable');
|
||
assert.ok(!result.startsWith('Server error:'));
|
||
});
|
||
|
||
test('пустая строка и отсутствующая ошибка не превращаются в undefined', () => {
|
||
assert.notEqual(getWsErrorMessage(''), undefined);
|
||
assert.notEqual(getWsErrorMessage(null), undefined);
|
||
assert.notEqual(getWsErrorMessage(undefined), undefined);
|
||
assert.ok(!String(getWsErrorMessage(undefined)).includes('undefined'));
|
||
});
|
||
|
||
// AURORA-1978: map_sqlalchemy_error берёт str(exc.orig), и для RAISE из
|
||
// PL/pgSQL текст приходит как "<class 'asyncpg.exceptions.RaiseError'>: ...".
|
||
// Технический префикс класса в тост не попадает; известные префиксы после него
|
||
// по-прежнему переводятся.
|
||
test('AURORA-1978: префикс класса исключения asyncpg срезается', () => {
|
||
assert.equal(
|
||
getWsErrorMessage({
|
||
code: 400,
|
||
field: '',
|
||
message: "<class 'asyncpg.exceptions.RaiseError'>: Нельзя удалить программу, содержащую проекты",
|
||
}),
|
||
'Нельзя удалить программу, содержащую проекты',
|
||
);
|
||
assert.equal(
|
||
getWsErrorMessage("<class 'asyncpg.exceptions.RaiseError'>: role_not_allowed: колонка plan.q1"),
|
||
'Нет прав на изменение этой колонки',
|
||
);
|
||
assert.equal(getWsErrorMessage("<class 'asyncpg.exceptions.RaiseError'>: "), 'Неизвестная ошибка сервера');
|
||
});
|