SettingsPage.test.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /**
  2. * SettingsPage 页面测试
  3. * 使用真实的React Query和RPC类型验证
  4. */
  5. import React from 'react'
  6. import { render, screen, waitFor } from '@testing-library/react'
  7. import '@testing-library/jest-dom'
  8. import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
  9. import Taro from '@tarojs/taro'
  10. import { useRequireAuth } from '@d8d/rencai-auth-ui/hooks'
  11. // Mock auth hooks
  12. jest.mock('@d8d/rencai-auth-ui/hooks', () => ({
  13. useRequireAuth: jest.fn()
  14. }))
  15. // Mock API client - 使用真实的RPC类型
  16. jest.mock('@d8d/rencai-settings-ui/api', () => ({
  17. talentSettingsClient: {
  18. me: {
  19. $get: jest.fn()
  20. },
  21. logout: {
  22. $post: jest.fn()
  23. }
  24. }
  25. }))
  26. // Mock shared components
  27. jest.mock('@d8d/mini-shared-ui-components/components/navbar', () => ({
  28. Navbar: ({ title, children }: any) => <div data-testid="navbar">{title}{children}</div>
  29. }))
  30. jest.mock('@d8d/rencai-shared-ui/components/RencaiTabBarLayout', () => ({
  31. RencaiTabBarLayout: ({ children, activeKey }: any) => (
  32. <div data-testid="tabbar" data-active={activeKey}>{children}</div>
  33. )
  34. }))
  35. import { talentSettingsClient } from '../../../src/api'
  36. import SettingsPage from '../../../src/pages/SettingsPage/SettingsPage'
  37. const createMockResponse = <T,>(status: number, data: T) => ({
  38. status,
  39. ok: status >= 200 && status < 300,
  40. json: async () => data
  41. })
  42. const createTestWrapper = () => {
  43. const queryClient = new QueryClient({
  44. defaultOptions: {
  45. queries: {
  46. retry: false,
  47. staleTime: Infinity,
  48. refetchOnWindowFocus: false
  49. },
  50. mutations: {
  51. retry: false
  52. }
  53. }
  54. })
  55. return ({ children }: { children: React.ReactNode }) => (
  56. <QueryClientProvider client={queryClient}>
  57. {children}
  58. </QueryClientProvider>
  59. )
  60. }
  61. describe('SettingsPage', () => {
  62. beforeEach(() => {
  63. jest.clearAllMocks()
  64. // Mock useRequireAuth to do nothing (user is authenticated)
  65. ;(useRequireAuth as jest.Mock).mockImplementation(() => {})
  66. // Reset Taro API mocks
  67. ;(Taro.showModal as jest.Mock).mockClear()
  68. ;(Taro.showToast as jest.Mock).mockClear()
  69. ;(Taro.navigateTo as jest.Mock).mockClear()
  70. ;(Taro.reLaunch as jest.Mock).mockClear()
  71. ;(Taro.removeStorageSync as jest.Mock).mockClear()
  72. })
  73. it('应该渲染页面标题', async () => {
  74. ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
  75. createMockResponse(200, { id: 1, name: '张明' })
  76. )
  77. const wrapper = createTestWrapper()
  78. render(<SettingsPage />, { wrapper })
  79. await waitFor(() => {
  80. expect(screen.getByText('更多')).toBeInTheDocument()
  81. })
  82. })
  83. it('应该渲染个人信息摘要', async () => {
  84. ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
  85. createMockResponse(200, {
  86. id: 1,
  87. name: '张明',
  88. personInfo: {
  89. disabilityType: '肢体残疾',
  90. disabilityLevel: '三级'
  91. }
  92. })
  93. )
  94. const wrapper = createTestWrapper()
  95. render(<SettingsPage />, { wrapper })
  96. await waitFor(() => {
  97. expect(screen.getByText('张明')).toBeInTheDocument()
  98. })
  99. })
  100. it('应该渲染功能入口列表', async () => {
  101. ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
  102. createMockResponse(200, { id: 1, name: '张明' })
  103. )
  104. const wrapper = createTestWrapper()
  105. render(<SettingsPage />, { wrapper })
  106. await waitFor(() => {
  107. expect(screen.getByText('修改个人信息')).toBeInTheDocument()
  108. expect(screen.getByText('账号与安全')).toBeInTheDocument()
  109. expect(screen.getByText('消息通知设置')).toBeInTheDocument()
  110. })
  111. })
  112. it('应该渲染帮助与支持入口', async () => {
  113. ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
  114. createMockResponse(200, { id: 1, name: '张明' })
  115. )
  116. const wrapper = createTestWrapper()
  117. render(<SettingsPage />, { wrapper })
  118. await waitFor(() => {
  119. expect(screen.getByText('帮助中心')).toBeInTheDocument()
  120. expect(screen.getByText('用户协议')).toBeInTheDocument()
  121. expect(screen.getByText('隐私政策')).toBeInTheDocument()
  122. })
  123. })
  124. it('应该渲染退出登录按钮', async () => {
  125. ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
  126. createMockResponse(200, { id: 1, name: '张明' })
  127. )
  128. const wrapper = createTestWrapper()
  129. render(<SettingsPage />, { wrapper })
  130. await waitFor(() => {
  131. expect(screen.getByText('退出登录')).toBeInTheDocument()
  132. })
  133. })
  134. it('API失败时应该显示错误信息', async () => {
  135. ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
  136. createMockResponse(404, {})
  137. )
  138. const wrapper = createTestWrapper()
  139. render(<SettingsPage />, { wrapper })
  140. await waitFor(() => {
  141. expect(screen.getByText('加载失败,请稍后重试')).toBeInTheDocument()
  142. })
  143. })
  144. it('API返回空数据时应该使用模拟数据', async () => {
  145. ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
  146. createMockResponse(200, null)
  147. )
  148. const wrapper = createTestWrapper()
  149. render(<SettingsPage />, { wrapper })
  150. await waitFor(() => {
  151. expect(screen.getByText('张明')).toBeInTheDocument()
  152. })
  153. })
  154. it('应该渲染加载状态', () => {
  155. ;(talentSettingsClient.me.$get as jest.Mock).mockImplementation(
  156. () => new Promise(() => {}) // 永不resolve
  157. )
  158. const wrapper = createTestWrapper()
  159. render(<SettingsPage />, { wrapper })
  160. expect(screen.getByText('加载中...')).toBeInTheDocument()
  161. })
  162. })