/** * Tests for cfc-frontend utils/team-tree.js * * Tests the pure function that converts flat /api/commission/team/tree nodes * (as returned by the backend) into preorder rows usable by the tree view. * These are pure functions - no uni mock needed. */ describe('team-tree.js', () => { let teamTree beforeAll(() => { teamTree = require('@/utils/team-tree') }) describe('buildTeamTreeRows', () => { const nodes = [ { userId: 101, nickname: '直推A', level: 1, parentId: 100, memberConsumption: 32000, myCfEarnedFromMember: 9600 }, { userId: 102, nickname: '间推B', level: 2, parentId: 101, memberConsumption: 8000, myCfEarnedFromMember: 2400 }, { userId: 103, nickname: '直推C', level: 1, parentId: 100, memberConsumption: 15000, myCfEarnedFromMember: 4500 } ] test('builds preorder rows with depth from flat nodes', () => { const rows = teamTree.buildTeamTreeRows(nodes) expect(rows.map(r => r.node.userId)).toEqual([101, 102, 103]) expect(rows.map(r => r.depth)).toEqual([0, 1, 0]) }) test('marks hasChildren and collapsed flags', () => { const rows = teamTree.buildTeamTreeRows(nodes) expect(rows[0].hasChildren).toBe(true) expect(rows[0].collapsed).toBe(false) expect(rows[1].hasChildren).toBe(false) expect(rows[2].hasChildren).toBe(false) }) test('collapsed node hides its descendants only', () => { const rows = teamTree.buildTeamTreeRows(nodes, [101]) expect(rows.map(r => r.node.userId)).toEqual([101, 103]) expect(rows[0].collapsed).toBe(true) }) test('treats nodes with unknown parentId as roots', () => { const rows = teamTree.buildTeamTreeRows(nodes) expect(rows.filter(r => r.depth === 0).length).toBe(2) }) test('prefers referrerId over parentId for immediate parent (materialized tree)', () => { // /api/commission/team/tree 物化表查询结果中 parentId 恒为根节点,referrerId 才是直接上级 const materialized = [ { userId: 101, referrerId: 100, parentId: 100, level: 1 }, { userId: 102, referrerId: 101, parentId: 100, level: 2 } ] const rows = teamTree.buildTeamTreeRows(materialized) expect(rows.map(r => r.node.userId)).toEqual([101, 102]) expect(rows.map(r => r.depth)).toEqual([0, 1]) expect(rows[0].hasChildren).toBe(true) expect(rows[1].hasChildren).toBe(false) }) test('rootUserId shifts root depth so "self" row can sit at depth 0', () => { // team.vue 自造根行(depth=0),传入 rootUserId 后 L1 成员 depth 从 1 开始 const materialized = [ { userId: 101, referrerId: 100, parentId: 100, level: 1 }, { userId: 102, referrerId: 101, parentId: 100, level: 2 } ] const rows = teamTree.buildTeamTreeRows(materialized, [], 100) expect(rows.map(r => r.node.userId)).toEqual([101, 102]) expect(rows.map(r => r.depth)).toEqual([1, 2]) }) test('returns empty array for empty nodes', () => { expect(teamTree.buildTeamTreeRows([])).toEqual([]) expect(teamTree.buildTeamTreeRows(null)).toEqual([]) expect(teamTree.buildTeamTreeRows(undefined)).toEqual([]) }) test('guards against self-referencing cycles', () => { const cyclic = [ { userId: 201, nickname: 'A', level: 1, parentId: 201 } ] const rows = teamTree.buildTeamTreeRows(cyclic) expect(rows.length).toBe(1) expect(rows[0].depth).toBe(0) }) }) })