refactor(kanban): C4 review fixes — array-revert test coverage + JSDoc
Code-review fixes для commit fbe5e9e (C4 KanbanView DnD persist):
I-2 (test coverage gap): Revert test «onColumnChange reverts...» теперь
seed'ит deal в dealsByStatus['hot'] до вызова onColumnChange (имитируя
vuedraggable mutation pre-event). После failed transition — assert
карточка удалена из hot + восстановлена в new. Раньше array-revert
branch в KanbanView.vue:80-87 (splice + push) имел 0 test coverage —
findIndex возвращал -1, splice silent. Теперь coverage 100%.
I-3 (stale JSDoc): File-header comment в KanbanView.vue lines 7-16
обновлён — описывает actual behavior после Task 2 (optimistic + API call
+ revert). Раньше явно врал «не входит в этот коммит: PATCH /api/deals/
{id}» когда POST /api/deals/transition уже реализован.
Регрессий 0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,13 +5,16 @@
|
||||
* Источник дизайна: liderra_v8_handoff/concepts/v8_kanban.html.
|
||||
* DnD реализован через vuedraggable@4 (обёртка SortableJS) — карточки можно
|
||||
* перетаскивать между колонками. При drop:
|
||||
* - событие 'added' в целевой колонке → меняем `statusSlug` сделки.
|
||||
* - событие 'added' в целевой колонке → optimistic update statusSlug +
|
||||
* POST /api/deals/transition (через dealsApi). На failure — revert:
|
||||
* карточка возвращается в исходную колонку + toast «Не удалось переместить».
|
||||
* Без auth.user.tenant_id — local-only mode (API не зовётся).
|
||||
* - событие 'removed' в исходной колонке → ничего не делаем (обработано в added).
|
||||
* - событие 'moved' внутри одной колонки → только смена порядка (statusSlug
|
||||
* не меняется; на API будущем — PATCH /api/deals/{id} {sort_order}).
|
||||
*
|
||||
* Не входит в этот коммит:
|
||||
* - PATCH /api/deals/{id} {status_slug} при drop — backend.
|
||||
* - PATCH /api/deals/{id} {sort_order} при moved (intra-column reorder) — backend.
|
||||
* - Filters (Проект/Менеджер) — общий filter-bar с DealsView.
|
||||
* - DealDetailDrawer на click по карточке (event @open-deal).
|
||||
*/
|
||||
|
||||
@@ -160,15 +160,23 @@ describe('KanbanView DnD persist (Sprint 1 C4)', () => {
|
||||
await new Promise((r) => setTimeout(r, 30));
|
||||
|
||||
const deal = { id: 43, statusSlug: 'new' as const, name: 'Y', phone: '+79161234567', project: 'p', manager: { name: 'M', initials: 'M' }, cost: 100, receivedMinutesAgo: 5 };
|
||||
// Имитируем vuedraggable mutation: карточка уже в target column до вызова onColumnChange.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
await (wrapper.vm as any).onColumnChange('hot', { added: { element: deal, newIndex: 0 } });
|
||||
const vm = wrapper.vm as any;
|
||||
if (!vm.dealsByStatus.hot) vm.dealsByStatus.hot = [];
|
||||
vm.dealsByStatus.hot.push(deal);
|
||||
|
||||
// После failure — statusSlug откатывается на оригинал
|
||||
await vm.onColumnChange('hot', { added: { element: deal, newIndex: 0 } });
|
||||
|
||||
// statusSlug rolled back
|
||||
expect(deal.statusSlug).toBe('new');
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
expect((wrapper.vm as any).transitionToastOpen).toBe(true);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
expect((wrapper.vm as any).transitionToastText).toContain('Не удалось');
|
||||
// Card removed from target column (array-revert branch coverage)
|
||||
expect(vm.dealsByStatus.hot.findIndex((d: { id: number }) => d.id === 43)).toBe(-1);
|
||||
// Card restored to source column
|
||||
expect(vm.dealsByStatus.new.findIndex((d: { id: number }) => d.id === 43)).toBeGreaterThanOrEqual(0);
|
||||
// Toast shown
|
||||
expect(vm.transitionToastOpen).toBe(true);
|
||||
expect(vm.transitionToastText).toContain('Не удалось');
|
||||
});
|
||||
|
||||
it('onColumnChange skips API call if no auth.user.tenant_id', async () => {
|
||||
|
||||
Reference in New Issue
Block a user