Statistics.test.tsx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. import React from 'react'
  2. import { render, screen } from '@testing-library/react'
  3. import '@testing-library/jest-dom'
  4. import Statistics from '../../src/pages/Statistics/Statistics'
  5. // Mock Taro
  6. jest.mock('@tarojs/taro', () => ({
  7. createCanvasContext: jest.fn(() => ({
  8. draw: jest.fn(),
  9. stroke: jest.fn(),
  10. beginPath: jest.fn(),
  11. closePath: jest.fn(),
  12. moveTo: jest.fn(),
  13. lineTo: jest.fn(),
  14. arc: jest.fn(),
  15. setFillStyle: jest.fn(),
  16. setStrokeStyle: jest.fn(),
  17. setLineWidth: jest.fn(),
  18. fillText: jest.fn(),
  19. setTextAlign: jest.fn(),
  20. setTextBaseline: jest.fn(),
  21. fill: jest.fn(),
  22. translate: jest.fn(),
  23. rotate: jest.fn(),
  24. scale: jest.fn(),
  25. })),
  26. getSystemInfoSync: jest.fn(() => ({
  27. pixelRatio: 2,
  28. windowWidth: 375,
  29. windowHeight: 667,
  30. })),
  31. ENV_TYPE: {
  32. WEAPP: 'WEAPP',
  33. SWAN: 'SWAN',
  34. ALIPAY: 'ALIPAY',
  35. TT: 'TT',
  36. QQ: 'QQ',
  37. JD: 'JD',
  38. },
  39. getEnv: jest.fn(() => 'WEAPP'),
  40. }))
  41. // Mock React Query
  42. jest.mock('@tanstack/react-query', () => ({
  43. useQuery: jest.fn(() => ({
  44. data: null,
  45. isLoading: false,
  46. error: null,
  47. })),
  48. }))
  49. // Mock mini-charts components
  50. jest.mock('@d8d/mini-charts', () => ({
  51. ColumnChart: ({ canvasId, width, height }: any) => (
  52. <div data-testid={`column-chart-${canvasId}`}>
  53. {canvasId} ({width}x{height})
  54. </div>
  55. ),
  56. PieChart: ({ canvasId, width, height, pieType }: any) => (
  57. <div data-testid={`pie-chart-${canvasId}`} data-pie-type={pieType}>
  58. {canvasId} ({width}x{height}) {pieType}
  59. </div>
  60. ),
  61. BarChart: ({ canvasId, width, height }: any) => (
  62. <div data-testid={`bar-chart-${canvasId}`}>
  63. {canvasId} ({width}x{height})
  64. </div>
  65. ),
  66. }))
  67. // Mock layout components
  68. jest.mock('@d8d/yongren-shared-ui/components/YongrenTabBarLayout', () => ({
  69. YongrenTabBarLayout: ({ children, activeKey }: any) => (
  70. <div data-testid="tab-bar-layout" data-active-key={activeKey}>
  71. {children}
  72. </div>
  73. ),
  74. }))
  75. jest.mock('@d8d/mini-shared-ui-components/components/navbar', () => ({
  76. Navbar: ({ title }: any) => <div data-testid="navbar">{title}</div>,
  77. }))
  78. // Mock API client
  79. jest.mock('../../src/api/enterpriseStatisticsClient', () => ({
  80. enterpriseStatisticsClient: {
  81. 'disability-type-distribution': {
  82. $get: jest.fn(),
  83. },
  84. 'gender-distribution': {
  85. $get: jest.fn(),
  86. },
  87. 'age-distribution': {
  88. $get: jest.fn(),
  89. },
  90. 'household-distribution': {
  91. $get: jest.fn(),
  92. },
  93. 'job-status-distribution': {
  94. $get: jest.fn(),
  95. },
  96. 'salary-distribution': {
  97. $get: jest.fn(),
  98. },
  99. },
  100. }))
  101. describe('Statistics Page', () => {
  102. beforeEach(() => {
  103. jest.clearAllMocks()
  104. })
  105. it('应该正确渲染统计页面', () => {
  106. render(<Statistics />)
  107. expect(screen.getByTestId('navbar')).toHaveTextContent('数据统计')
  108. })
  109. it('应该显示统计卡片', () => {
  110. render(<Statistics />)
  111. expect(screen.getByText('在职人数')).toBeInTheDocument()
  112. expect(screen.getByText('平均薪资')).toBeInTheDocument()
  113. expect(screen.getByText('在职率')).toBeInTheDocument()
  114. expect(screen.getByText('新增人数')).toBeInTheDocument()
  115. })
  116. it('应该显示所有图表标题', () => {
  117. render(<Statistics />)
  118. expect(screen.getByText('残疾类型分布')).toBeInTheDocument()
  119. expect(screen.getByText('性别分布')).toBeInTheDocument()
  120. expect(screen.getByText('年龄分布')).toBeInTheDocument()
  121. expect(screen.getByText('户籍省份分布')).toBeInTheDocument()
  122. expect(screen.getByText('在职状态统计')).toBeInTheDocument()
  123. expect(screen.getByText('薪资分布')).toBeInTheDocument()
  124. })
  125. it('应该渲染残疾类型柱状图', () => {
  126. const { useQuery } = require('@tanstack/react-query')
  127. useQuery.mockImplementation(() => ({
  128. data: {
  129. stats: [
  130. { key: '肢体', value: 10, percentage: 35.7 },
  131. { key: '听力', value: 8, percentage: 28.6 },
  132. ],
  133. total: 28,
  134. },
  135. isLoading: false,
  136. }))
  137. render(<Statistics />)
  138. expect(screen.getByTestId('column-chart-disability-type-chart')).toBeInTheDocument()
  139. })
  140. it('应该渲染性别分布柱状图', () => {
  141. const { useQuery } = require('@tanstack/react-query')
  142. useQuery.mockImplementation(() => ({
  143. data: {
  144. stats: [
  145. { key: '男', value: 15, percentage: 60 },
  146. { key: '女', value: 10, percentage: 40 },
  147. ],
  148. total: 25,
  149. },
  150. isLoading: false,
  151. }))
  152. render(<Statistics />)
  153. expect(screen.getByTestId('column-chart-gender-chart')).toBeInTheDocument()
  154. })
  155. it('应该渲染年龄分布饼图', () => {
  156. const { useQuery } = require('@tanstack/react-query')
  157. useQuery.mockImplementation(() => ({
  158. data: {
  159. stats: [
  160. { key: '18-25岁', value: 5, percentage: 20 },
  161. { key: '26-35岁', value: 10, percentage: 40 },
  162. ],
  163. total: 25,
  164. },
  165. isLoading: false,
  166. }))
  167. render(<Statistics />)
  168. expect(screen.getByTestId('pie-chart-age-chart')).toBeInTheDocument()
  169. expect(screen.getByTestId('pie-chart-age-chart')).toHaveAttribute('data-pie-type', 'pie')
  170. })
  171. it('应该渲染户籍省份横向柱状图', () => {
  172. const { useQuery } = require('@tanstack/react-query')
  173. useQuery.mockImplementation(() => ({
  174. data: {
  175. stats: [
  176. { key: '广东', value: 10, percentage: 40 },
  177. { key: '湖南', value: 8, percentage: 32 },
  178. ],
  179. total: 25,
  180. },
  181. isLoading: false,
  182. }))
  183. render(<Statistics />)
  184. expect(screen.getByTestId('bar-chart-household-chart')).toBeInTheDocument()
  185. })
  186. it('应该渲染在职状态环形图', () => {
  187. const { useQuery } = require('@tanstack/react-query')
  188. useQuery.mockImplementation(() => ({
  189. data: {
  190. stats: [
  191. { key: '在职', value: 20, percentage: 80 },
  192. { key: '离职', value: 5, percentage: 20 },
  193. ],
  194. total: 25,
  195. },
  196. isLoading: false,
  197. }))
  198. render(<Statistics />)
  199. expect(screen.getByTestId('pie-chart-job-status-chart')).toBeInTheDocument()
  200. expect(screen.getByTestId('pie-chart-job-status-chart')).toHaveAttribute('data-pie-type', 'ring')
  201. })
  202. it('应该渲染薪资分布横向柱状图', () => {
  203. const { useQuery } = require('@tanstack/react-query')
  204. useQuery.mockImplementation(() => ({
  205. data: {
  206. stats: [
  207. { key: '3000-4000', value: 5, percentage: 20 },
  208. { key: '4000-5000', value: 10, percentage: 40 },
  209. ],
  210. total: 25,
  211. },
  212. isLoading: false,
  213. }))
  214. render(<Statistics />)
  215. expect(screen.getByTestId('bar-chart-salary-chart')).toBeInTheDocument()
  216. })
  217. it('应该显示加载状态', () => {
  218. const { useQuery } = require('@tanstack/react-query')
  219. useQuery.mockImplementation(() => ({
  220. data: null,
  221. isLoading: true,
  222. }))
  223. render(<Statistics />)
  224. expect(screen.getAllByText('加载中...')).toHaveLength(6)
  225. })
  226. it('应该显示暂无数据状态', () => {
  227. const { useQuery } = require('@tanstack/react-query')
  228. useQuery.mockImplementation(() => ({
  229. data: { stats: [], total: 0 },
  230. isLoading: false,
  231. }))
  232. render(<Statistics />)
  233. expect(screen.getAllByText('暂无数据')).toHaveLength(6)
  234. })
  235. })
  236. describe('数据转换函数', () => {
  237. it('convertToColumnData 应该正确转换数据', () => {
  238. const stats = [
  239. { key: '类别A', value: 10 },
  240. { key: '类别B', value: 20 },
  241. ]
  242. const result = {
  243. categories: ['类别A', '类别B'],
  244. series: [{
  245. name: '人数',
  246. data: [10, 20]
  247. }]
  248. }
  249. expect(result.categories).toEqual(['类别A', '类别B'])
  250. expect(result.series[0].data).toEqual([10, 20])
  251. })
  252. it('convertToPieData 应该正确转换数据', () => {
  253. const stats = [
  254. { key: '类别A', value: 10 },
  255. { key: '类别B', value: 20 },
  256. ]
  257. const result = stats.map(item => ({
  258. name: item.key,
  259. data: item.value || 0
  260. }))
  261. expect(result).toEqual([
  262. { name: '类别A', data: 10 },
  263. { name: '类别B', data: 20 }
  264. ])
  265. })
  266. })