FamilyRelationGraph.test.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /**
  2. * Tests for FamilyRelationGraph helper functions
  3. */
  4. import { shallowMount } from '@vue/test-utils'
  5. // --------------- helper functions (extracted from component) ---------------
  6. function getEnergy(energyMap, memberId, dimensionCode) {
  7. const data = energyMap[memberId]
  8. if (!data) return 0
  9. const key = dimensionCode + 'Score'
  10. const val = data[key]
  11. return (typeof val !== 'undefined' && val !== null) ? val : 0
  12. }
  13. function getAvatarSize(energy, isSelf) {
  14. const clamped = Math.max(0, Math.min(100, energy))
  15. const base = 64 + (clamped / 100) * 56
  16. if (isSelf) return Math.max(96, base + 16)
  17. return base
  18. }
  19. function getLayoutMode(memberCount) {
  20. if (memberCount <= 3) return 'row'
  21. return 'multi-row'
  22. }
  23. function getDisplayOrder(members, selfId) {
  24. let self = null
  25. const others = []
  26. for (let i = 0; i < members.length; i++) {
  27. if (members[i].id === selfId) {
  28. self = members[i]
  29. } else {
  30. others.push(members[i])
  31. }
  32. }
  33. if (members.length === 2) return [self, others[0]]
  34. if (members.length === 3 && others.length >= 2) return [others[0], self, others[1]]
  35. return [self].concat(others)
  36. }
  37. function getLineEndPoints(selfCX, selfCY, selfR, otherCX, otherCY, otherR) {
  38. const dx = otherCX - selfCX
  39. const dy = otherCY - selfCY
  40. const dist = Math.sqrt(dx * dx + dy * dy)
  41. if (dist < 1) return null
  42. const ux = dx / dist
  43. const uy = dy / dist
  44. return {
  45. x1: selfCX + ux * selfR,
  46. y1: selfCY + uy * selfR,
  47. x2: otherCX - ux * otherR,
  48. y2: otherCY - uy * otherR
  49. }
  50. }
  51. // --------------- tests ---------------
  52. describe('getAvatarSize', () => {
  53. it('returns min size for other at energy 0', () => {
  54. expect(getAvatarSize(0, false)).toBe(64)
  55. })
  56. it('returns max size for other at energy 100', () => {
  57. expect(getAvatarSize(100, false)).toBe(120)
  58. })
  59. it('returns mid size for other at energy 50', () => {
  60. expect(getAvatarSize(50, false)).toBe(92)
  61. })
  62. it('self min is 96', () => {
  63. expect(getAvatarSize(0, true)).toBe(96)
  64. })
  65. it('self max at energy 100', () => {
  66. expect(getAvatarSize(100, true)).toBe(136)
  67. })
  68. it('clamps negative energy to 0', () => {
  69. expect(getAvatarSize(-10, false)).toBe(64)
  70. })
  71. it('clamps energy > 100 to 100', () => {
  72. expect(getAvatarSize(150, false)).toBe(120)
  73. })
  74. })
  75. describe('getLayoutMode', () => {
  76. it('0 members returns row', () => {
  77. expect(getLayoutMode(0)).toBe('row')
  78. })
  79. it('2 members returns row', () => {
  80. expect(getLayoutMode(2)).toBe('row')
  81. })
  82. it('3 members returns row', () => {
  83. expect(getLayoutMode(3)).toBe('row')
  84. })
  85. it('4 members returns multi-row', () => {
  86. expect(getLayoutMode(4)).toBe('multi-row')
  87. })
  88. it('10 members returns multi-row', () => {
  89. expect(getLayoutMode(10)).toBe('multi-row')
  90. })
  91. })
  92. describe('getDisplayOrder', () => {
  93. it('2-person: self first, other second', () => {
  94. const members = [{ id: 1, nickname: '爸' }, { id: 2, nickname: '我' }]
  95. const order = getDisplayOrder(members, 2)
  96. expect(order[0].id).toBe(2)
  97. expect(order[1].id).toBe(1)
  98. })
  99. it('3-person: others on sides, self center', () => {
  100. const members = [{ id: 1, nickname: '爸' }, { id: 2, nickname: '我' }, { id: 3, nickname: '妈' }]
  101. const order = getDisplayOrder(members, 2)
  102. expect(order[0].id).toBe(1)
  103. expect(order[1].id).toBe(2)
  104. expect(order[2].id).toBe(3)
  105. })
  106. })
  107. describe('getLineEndPoints', () => {
  108. it('calculates correct horizontal line endpoints', () => {
  109. const pts = getLineEndPoints(100, 100, 30, 300, 100, 20)
  110. expect(pts.x1).toBe(130)
  111. expect(pts.x2).toBe(280)
  112. expect(pts.y1).toBe(100)
  113. expect(pts.y2).toBe(100)
  114. })
  115. it('returns null when distance < 1', () => {
  116. const pts = getLineEndPoints(100, 100, 30, 100, 100, 20)
  117. expect(pts).toBeNull()
  118. })
  119. })
  120. describe('getEnergy', () => {
  121. it('retrieves body energy by dimension code', () => {
  122. const energyMap = { 1: { bodyScore: 80, mindScore: 40 } }
  123. expect(getEnergy(energyMap, 1, 'body')).toBe(80)
  124. })
  125. it('retrieves mind energy by dimension code', () => {
  126. const energyMap = { 1: { bodyScore: 80, mindScore: 40 } }
  127. expect(getEnergy(energyMap, 1, 'mind')).toBe(40)
  128. })
  129. it('returns 0 for missing member', () => {
  130. const energyMap = { 1: { bodyScore: 80 } }
  131. expect(getEnergy(energyMap, 2, 'body')).toBe(0)
  132. })
  133. })