mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-22 15:06:32 +00:00
6dc8699bd1
The to-do filters, counts, sort order and categories move from the phone listsModel into todoListModel. useTaskForm holds the name, the fields, the load and the save of a task for the desktop detail and new task panes and for MTaskSheet. Each side keeps its own guard and error wording.
173 lines
5.8 KiB
TypeScript
173 lines
5.8 KiB
TypeScript
// FE-W4TDM-001 to FE-W4TDM-013
|
|
import { describe, expect, it } from 'vitest';
|
|
import { buildTodoItem } from '../../../tests/helpers/factories';
|
|
import {
|
|
KAT_COLORS,
|
|
PRIO_CONFIG,
|
|
TODO_SMART_FILTERS,
|
|
blankTaskFields,
|
|
compareTodoDue,
|
|
compareTodoPriority,
|
|
filterTodoItems,
|
|
filterTodoItemsByCategory,
|
|
isTodoSmartFilter,
|
|
katColor,
|
|
taskFieldsOf,
|
|
taskUpdatePayload,
|
|
} from './todoListModel';
|
|
|
|
describe('katColor', () => {
|
|
it('FE-W4TDM-001: gives a known category the palette colour at its index', () => {
|
|
const cats = ['Docs', 'Gear', 'Food'];
|
|
|
|
expect(katColor('Docs', cats)).toBe(KAT_COLORS[0]);
|
|
expect(katColor('Gear', cats)).toBe(KAT_COLORS[1]);
|
|
expect(katColor('Food', cats)).toBe(KAT_COLORS[2]);
|
|
});
|
|
|
|
it('FE-W4TDM-002: wraps around when there are more categories than colours', () => {
|
|
const cats = Array.from({ length: 12 }, (_, i) => `c${i}`);
|
|
|
|
expect(katColor('c10', cats)).toBe(KAT_COLORS[0]);
|
|
expect(katColor('c11', cats)).toBe(KAT_COLORS[1]);
|
|
});
|
|
|
|
it('FE-W4TDM-003: hashes an unlisted category into the palette', () => {
|
|
const color = katColor('Ad-hoc', []);
|
|
|
|
expect(KAT_COLORS).toContain(color);
|
|
expect(katColor('Ad-hoc', [])).toBe(color);
|
|
});
|
|
|
|
it('FE-W4TDM-004: gives different unlisted categories different colours', () => {
|
|
const seen = new Set(['Alpha', 'Bravo', 'Charlie', 'Delta'].map((c) => katColor(c, [])));
|
|
expect(seen.size).toBeGreaterThan(1);
|
|
});
|
|
|
|
it('FE-W4TDM-005: handles an empty category name without going out of range', () => {
|
|
expect(KAT_COLORS).toContain(katColor('', []));
|
|
});
|
|
});
|
|
|
|
describe('PRIO_CONFIG', () => {
|
|
it('FE-W4TDM-006: maps the three priorities to labels and colours', () => {
|
|
expect(PRIO_CONFIG[1]).toEqual({ label: 'P1', color: '#ef4444' });
|
|
expect(PRIO_CONFIG[2].label).toBe('P2');
|
|
expect(PRIO_CONFIG[3].label).toBe('P3');
|
|
expect(PRIO_CONFIG[4]).toBeUndefined();
|
|
expect(KAT_COLORS).toHaveLength(10);
|
|
});
|
|
});
|
|
|
|
describe('todo order shared by both lists', () => {
|
|
it('FE-W4TDM-007: compareTodoPriority puts P1 first and tasks without a priority last', () => {
|
|
const p2 = buildTodoItem({ id: 1, priority: 2 });
|
|
const none = buildTodoItem({ id: 2, priority: 0 });
|
|
const p1 = buildTodoItem({ id: 3, priority: 1 });
|
|
expect([p2, none, p1].sort(compareTodoPriority).map((i) => i.id)).toEqual([3, 1, 2]);
|
|
expect(compareTodoPriority(p2, buildTodoItem({ priority: 2 }))).toBe(0);
|
|
});
|
|
|
|
it('FE-W4TDM-008: compareTodoDue puts the nearest date first and undated tasks last, ties untouched', () => {
|
|
const later = buildTodoItem({ id: 1, due_date: '2026-07-20' });
|
|
const undated = buildTodoItem({ id: 2 });
|
|
const sooner = buildTodoItem({ id: 3, due_date: '2026-07-16' });
|
|
const sameDay = buildTodoItem({ id: 4, due_date: '2026-07-20' });
|
|
const undated2 = buildTodoItem({ id: 5 });
|
|
expect([later, undated, sooner, sameDay, undated2].sort(compareTodoDue).map((i) => i.id)).toEqual([3, 1, 4, 2, 5]);
|
|
expect(compareTodoDue(undated, undated2)).toBe(0);
|
|
expect(compareTodoDue(undated, sooner)).toBe(1);
|
|
expect(compareTodoDue(sooner, undated)).toBe(-1);
|
|
});
|
|
|
|
it('FE-W4TDM-009: filterTodoItems reads a name it does not know as a category, as the desktop sidebar does', () => {
|
|
const items = [buildTodoItem({ id: 1, category: 'my' }), buildTodoItem({ id: 2, category: 'Gear' })];
|
|
expect(filterTodoItems(items, 'Gear', 7, '2026-07-15').map((i) => i.id)).toEqual([2]);
|
|
expect(filterTodoItemsByCategory(items, 'my').map((i) => i.id)).toEqual([1]);
|
|
});
|
|
});
|
|
|
|
describe('task form fields', () => {
|
|
it('FE-W4TDM-010: taskFieldsOf reads a saved task with empty strings for what it lacks', () => {
|
|
expect(
|
|
taskFieldsOf(
|
|
buildTodoItem({ description: null, priority: 0, category: null, due_date: null, assigned_user_id: null })
|
|
)
|
|
).toEqual({
|
|
desc: '',
|
|
priority: 0,
|
|
category: '',
|
|
dueDate: '',
|
|
assignedUserId: null,
|
|
});
|
|
expect(
|
|
taskFieldsOf(
|
|
buildTodoItem({
|
|
description: 'Ask',
|
|
priority: 2,
|
|
category: 'Docs',
|
|
due_date: '2026-07-01',
|
|
assigned_user_id: 4,
|
|
})
|
|
)
|
|
).toEqual({
|
|
desc: 'Ask',
|
|
priority: 2,
|
|
category: 'Docs',
|
|
dueDate: '2026-07-01',
|
|
assignedUserId: 4,
|
|
});
|
|
});
|
|
|
|
it('FE-W4TDM-011: blankTaskFields files a new task in the given list, or in none', () => {
|
|
expect(blankTaskFields('Docs')).toEqual({
|
|
desc: '',
|
|
priority: 0,
|
|
category: 'Docs',
|
|
dueDate: '',
|
|
assignedUserId: null,
|
|
});
|
|
expect(blankTaskFields(null).category).toBe('');
|
|
expect(blankTaskFields().category).toBe('');
|
|
});
|
|
|
|
it('FE-W4TDM-012: taskUpdatePayload trims the name and sends every emptied field as null', () => {
|
|
expect(
|
|
taskUpdatePayload(' Visa ', { desc: '', priority: 0, category: '', dueDate: '', assignedUserId: null })
|
|
).toEqual({
|
|
name: 'Visa',
|
|
description: null,
|
|
due_date: null,
|
|
category: null,
|
|
assigned_user_id: null,
|
|
priority: 0,
|
|
});
|
|
expect(
|
|
taskUpdatePayload('Visa', {
|
|
desc: 'Form',
|
|
priority: 1,
|
|
category: 'Docs',
|
|
dueDate: '2026-07-01',
|
|
assignedUserId: 3,
|
|
})
|
|
).toEqual({
|
|
name: 'Visa',
|
|
description: 'Form',
|
|
due_date: '2026-07-01',
|
|
category: 'Docs',
|
|
assigned_user_id: 3,
|
|
priority: 1,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('built-in filters', () => {
|
|
it('FE-W4TDM-013: lists the four built-ins and tells them apart from category names', () => {
|
|
expect(TODO_SMART_FILTERS).toEqual(['all', 'my', 'overdue', 'done']);
|
|
for (const f of TODO_SMART_FILTERS) expect(isTodoSmartFilter(f)).toBe(true);
|
|
expect(isTodoSmartFilter('Docs')).toBe(false);
|
|
expect(isTodoSmartFilter('All')).toBe(false);
|
|
expect(isTodoSmartFilter('')).toBe(false);
|
|
});
|
|
});
|