Подпись пустой цели «цель не заполнена», тесты null/null (ревью I-1, M-1, M-2, M-4)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-18 22:55:42 +04:00
parent cb36ec8840
commit 4fb477d5c2
3 changed files with 12 additions and 8 deletions

View File

@ -231,8 +231,9 @@ export interface FailedCheckOut {
/** -1 в GET …/statement и null в теле 409 — нарушение без колонки (P3-60) */ /** -1 в GET …/statement и null в теле 409 — нарушение без колонки (P3-60) */
column_index: number | null; column_index: number | null;
relation: string; relation: string;
/** null — у связи нет строки цели (P3-30) */ /** null — цель соотношения не заполнена при непустых членах (P3-30) */
expected: string | null; expected: string | null;
/** допускает null по OpenAPI ядра (P3-30) */
actual: string | null; actual: string | null;
codes: string[]; codes: string[];
line_ids: string[]; line_ids: string[];

View File

@ -18,11 +18,14 @@ describe('failureText', () => {
it('обычное нарушение с номером колонки', () => { it('обычное нарушение с номером колонки', () => {
expect(failureText(base)).toBe('Колонка 1: 1600 = 1700 — ожидалось 10,00, получено 9,00'); expect(failureText(base)).toBe('Колонка 1: 1600 = 1700 — ожидалось 10,00, получено 9,00');
}); });
it('expected = null: «нет строки цели», без NaN', () => { it('expected = null: «цель не заполнена»', () => {
const text = failureText({ ...base, expected: null }); const text = failureText({ ...base, expected: null });
expect(text).toContain('ожидалось нет строки цели'); expect(text).toBe('Колонка 1: 1600 = 1700 — цель не заполнена, получено 9,00');
expect(text).not.toContain('NaN'); expect(text).not.toContain('NaN');
}); });
it('expected и actual оба null', () => {
expect(failureText({ ...base, expected: null, actual: null })).toContain('цель не заполнена, получено —');
});
it('actual = null показывается прочерком', () => { it('actual = null показывается прочерком', () => {
expect(failureText({ ...base, actual: null })).toContain('получено —'); expect(failureText({ ...base, actual: null })).toContain('получено —');
}); });

View File

@ -1,8 +1,8 @@
import type { FailedCheckOut } from '../../types/api'; import type { FailedCheckOut } from '../../types/api';
import { formatAmount } from '../../utils/money'; import { formatAmount } from '../../utils/money';
/** Подпись пустой цели: expected = null — у связи нет строки-цели (P3-30). */ /** Подпись пустой цели: expected = null — цель соотношения не заполнена при непустых членах (P3-30). */
const NO_TARGET = 'нет строки цели'; const NO_TARGET = 'цель не заполнена';
/** /**
* Есть ли у нарушения колонка. Ядро кодирует «колонки нет» двумя способами: * Есть ли у нарушения колонка. Ядро кодирует «колонки нет» двумя способами:
@ -13,11 +13,11 @@ export const hasColumn = (index: number | null | undefined): index is number =>
export const failureKey = (f: Pick<FailedCheckOut, 'column_index' | 'relation'>): string => export const failureKey = (f: Pick<FailedCheckOut, 'column_index' | 'relation'>): string =>
`${hasColumn(f.column_index) ? f.column_index : 'none'}-${f.relation}`; `${hasColumn(f.column_index) ? f.column_index : 'none'}-${f.relation}`;
const expectedText = (v: string | null): string => (v === null ? NO_TARGET : formatAmount(v));
/** «ожидалось …, получено …» для любых expected/actual, в том числе null. */ /** «ожидалось …, получено …» для любых expected/actual, в том числе null. */
export const expectedActualText = (f: Pick<FailedCheckOut, 'expected' | 'actual'>): string => export const expectedActualText = (f: Pick<FailedCheckOut, 'expected' | 'actual'>): string =>
`ожидалось ${expectedText(f.expected)}, получено ${formatAmount(f.actual)}`; f.expected === null
? `${NO_TARGET}, получено ${formatAmount(f.actual)}`
: `ожидалось ${formatAmount(f.expected)}, получено ${formatAmount(f.actual)}`;
export const failureText = (f: FailedCheckOut): string => { export const failureText = (f: FailedCheckOut): string => {
const where = hasColumn(f.column_index) ? `Колонка ${f.column_index + 1}` : 'Без колонки'; const where = hasColumn(f.column_index) ? `Колонка ${f.column_index + 1}` : 'Без колонки';