From e566da4f8feddad6629606b471265e5692cc9b7a Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Thu, 11 Sep 2025 21:56:51 -0700 Subject: [PATCH] Flatten tags coverage --- src-ui/src/app/utils/flatten-tags.spec.ts | 63 +++++++++++++++++++++++ src-ui/src/app/utils/flatten-tags.ts | 2 +- 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src-ui/src/app/utils/flatten-tags.spec.ts diff --git a/src-ui/src/app/utils/flatten-tags.spec.ts b/src-ui/src/app/utils/flatten-tags.spec.ts new file mode 100644 index 000000000..f39fd47fe --- /dev/null +++ b/src-ui/src/app/utils/flatten-tags.spec.ts @@ -0,0 +1,63 @@ +import type { Tag } from '../data/tag' +import { flattenTags } from './flatten-tags' + +describe('flattenTags', () => { + it('returns empty array for empty input', () => { + expect(flattenTags([])).toEqual([]) + }) + + it('orders roots and children by name (case-insensitive, numeric) and sets depth/orderIndex', () => { + const input: Tag[] = [ + { id: 11, name: 'A-root' }, + { id: 10, name: 'B-root' }, + { id: 101, name: 'Child 10', parent: 11 }, + { id: 102, name: 'child 2', parent: 11 }, + { id: 201, name: 'beta', parent: 10 }, + { id: 202, name: 'Alpha', parent: 10 }, + { id: 103, name: 'Sub 1', parent: 102 }, + ] + + const flat = flattenTags(input) + + const names = flat.map((t) => t.name) + expect(names).toEqual([ + 'A-root', + 'child 2', + 'Sub 1', + 'Child 10', + 'B-root', + 'Alpha', + 'beta', + ]) + + expect(flat.map((t) => t.depth)).toEqual([0, 1, 2, 1, 0, 1, 1]) + expect(flat.map((t) => t.orderIndex)).toEqual([0, 1, 2, 3, 4, 5, 6]) + + // Children are rebuilt + const aRoot = flat.find((t) => t.name === 'A-root')! + expect(new Set(aRoot.children?.map((c) => c.name))).toEqual( + new Set(['child 2', 'Child 10']) + ) + + const bRoot = flat.find((t) => t.name === 'B-root')! + expect(new Set(bRoot.children?.map((c) => c.name))).toEqual( + new Set(['Alpha', 'beta']) + ) + + const child2 = flat.find((t) => t.name === 'child 2')! + expect(new Set(child2.children?.map((c) => c.name))).toEqual( + new Set(['Sub 1']) + ) + }) + + it('excludes orphaned nodes (with missing parent)', () => { + const input: Tag[] = [ + { id: 1, name: 'Root' }, + { id: 2, name: 'Child', parent: 1 }, + { id: 3, name: 'Orphan', parent: 999 }, // missing parent + ] + + const flat = flattenTags(input) + expect(flat.map((t) => t.name)).toEqual(['Root', 'Child']) + }) +}) diff --git a/src-ui/src/app/utils/flatten-tags.ts b/src-ui/src/app/utils/flatten-tags.ts index 6a54add8d..c9758e1eb 100644 --- a/src-ui/src/app/utils/flatten-tags.ts +++ b/src-ui/src/app/utils/flatten-tags.ts @@ -13,7 +13,7 @@ export function flattenTags(all: Tag[]): Tag[] { } const roots = Array.from(map.values()).filter((t) => !t.parent) const sortByName = (a: Tag, b: Tag) => - (a.name || '').localeCompare(b.name || '', undefined, { + a.name.localeCompare(b.name, undefined, { sensitivity: 'base', numeric: true, })