/** * Tests for FamilyRelationGraph helper functions */ import { shallowMount } from '@vue/test-utils' // --------------- helper functions (extracted from component) --------------- function getEnergy(energyMap, memberId, dimensionCode) { const data = energyMap[memberId] if (!data) return 0 const key = dimensionCode + 'Score' const val = data[key] return (typeof val !== 'undefined' && val !== null) ? val : 0 } function getAvatarSize(energy, isSelf) { const clamped = Math.max(0, Math.min(100, energy)) const base = 64 + (clamped / 100) * 56 if (isSelf) return Math.max(96, base + 16) return base } function getLayoutMode(memberCount) { if (memberCount <= 3) return 'row' return 'multi-row' } function getDisplayOrder(members, selfId) { let self = null const others = [] for (let i = 0; i < members.length; i++) { if (members[i].id === selfId) { self = members[i] } else { others.push(members[i]) } } if (members.length === 2) return [self, others[0]] if (members.length === 3 && others.length >= 2) return [others[0], self, others[1]] return [self].concat(others) } function getLineEndPoints(selfCX, selfCY, selfR, otherCX, otherCY, otherR) { const dx = otherCX - selfCX const dy = otherCY - selfCY const dist = Math.sqrt(dx * dx + dy * dy) if (dist < 1) return null const ux = dx / dist const uy = dy / dist return { x1: selfCX + ux * selfR, y1: selfCY + uy * selfR, x2: otherCX - ux * otherR, y2: otherCY - uy * otherR } } // --------------- tests --------------- describe('getAvatarSize', () => { it('returns min size for other at energy 0', () => { expect(getAvatarSize(0, false)).toBe(64) }) it('returns max size for other at energy 100', () => { expect(getAvatarSize(100, false)).toBe(120) }) it('returns mid size for other at energy 50', () => { expect(getAvatarSize(50, false)).toBe(92) }) it('self min is 96', () => { expect(getAvatarSize(0, true)).toBe(96) }) it('self max at energy 100', () => { expect(getAvatarSize(100, true)).toBe(136) }) it('clamps negative energy to 0', () => { expect(getAvatarSize(-10, false)).toBe(64) }) it('clamps energy > 100 to 100', () => { expect(getAvatarSize(150, false)).toBe(120) }) }) describe('getLayoutMode', () => { it('0 members returns row', () => { expect(getLayoutMode(0)).toBe('row') }) it('2 members returns row', () => { expect(getLayoutMode(2)).toBe('row') }) it('3 members returns row', () => { expect(getLayoutMode(3)).toBe('row') }) it('4 members returns multi-row', () => { expect(getLayoutMode(4)).toBe('multi-row') }) it('10 members returns multi-row', () => { expect(getLayoutMode(10)).toBe('multi-row') }) }) describe('getDisplayOrder', () => { it('2-person: self first, other second', () => { const members = [{ id: 1, nickname: '爸' }, { id: 2, nickname: '我' }] const order = getDisplayOrder(members, 2) expect(order[0].id).toBe(2) expect(order[1].id).toBe(1) }) it('3-person: others on sides, self center', () => { const members = [{ id: 1, nickname: '爸' }, { id: 2, nickname: '我' }, { id: 3, nickname: '妈' }] const order = getDisplayOrder(members, 2) expect(order[0].id).toBe(1) expect(order[1].id).toBe(2) expect(order[2].id).toBe(3) }) }) describe('getLineEndPoints', () => { it('calculates correct horizontal line endpoints', () => { const pts = getLineEndPoints(100, 100, 30, 300, 100, 20) expect(pts.x1).toBe(130) expect(pts.x2).toBe(280) expect(pts.y1).toBe(100) expect(pts.y2).toBe(100) }) it('returns null when distance < 1', () => { const pts = getLineEndPoints(100, 100, 30, 100, 100, 20) expect(pts).toBeNull() }) }) describe('getEnergy', () => { it('retrieves body energy by dimension code', () => { const energyMap = { 1: { bodyScore: 80, mindScore: 40 } } expect(getEnergy(energyMap, 1, 'body')).toBe(80) }) it('retrieves mind energy by dimension code', () => { const energyMap = { 1: { bodyScore: 80, mindScore: 40 } } expect(getEnergy(energyMap, 1, 'mind')).toBe(40) }) it('returns 0 for missing member', () => { const energyMap = { 1: { bodyScore: 80 } } expect(getEnergy(energyMap, 2, 'body')).toBe(0) }) })