|
|
@@ -0,0 +1,195 @@
|
|
|
+/**
|
|
|
+ * SettingsPage 页面测试
|
|
|
+ * 使用真实的React Query和RPC类型验证
|
|
|
+ */
|
|
|
+import React from 'react'
|
|
|
+import { render, screen, waitFor } from '@testing-library/react'
|
|
|
+import '@testing-library/jest-dom'
|
|
|
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
|
+import Taro from '@tarojs/taro'
|
|
|
+import { useRequireAuth } from '@d8d/rencai-auth-ui/hooks'
|
|
|
+
|
|
|
+// Mock auth hooks
|
|
|
+jest.mock('@d8d/rencai-auth-ui/hooks', () => ({
|
|
|
+ useRequireAuth: jest.fn()
|
|
|
+}))
|
|
|
+
|
|
|
+// Mock API client - 使用真实的RPC类型
|
|
|
+jest.mock('@d8d/rencai-settings-ui/api', () => ({
|
|
|
+ talentSettingsClient: {
|
|
|
+ me: {
|
|
|
+ $get: jest.fn()
|
|
|
+ },
|
|
|
+ logout: {
|
|
|
+ $post: jest.fn()
|
|
|
+ }
|
|
|
+ }
|
|
|
+}))
|
|
|
+
|
|
|
+// Mock shared components
|
|
|
+jest.mock('@d8d/mini-shared-ui-components/components/navbar', () => ({
|
|
|
+ Navbar: ({ title, children }: any) => <div data-testid="navbar">{title}{children}</div>
|
|
|
+}))
|
|
|
+
|
|
|
+jest.mock('@d8d/rencai-shared-ui/components/RencaiTabBarLayout', () => ({
|
|
|
+ RencaiTabBarLayout: ({ children, activeKey }: any) => (
|
|
|
+ <div data-testid="tabbar" data-active={activeKey}>{children}</div>
|
|
|
+ )
|
|
|
+}))
|
|
|
+
|
|
|
+import { talentSettingsClient } from '../../../src/api'
|
|
|
+import SettingsPage from '../../../src/pages/SettingsPage/SettingsPage'
|
|
|
+
|
|
|
+const createMockResponse = <T,>(status: number, data: T) => ({
|
|
|
+ status,
|
|
|
+ ok: status >= 200 && status < 300,
|
|
|
+ json: async () => data
|
|
|
+})
|
|
|
+
|
|
|
+const createTestWrapper = () => {
|
|
|
+ const queryClient = new QueryClient({
|
|
|
+ defaultOptions: {
|
|
|
+ queries: {
|
|
|
+ retry: false,
|
|
|
+ staleTime: Infinity,
|
|
|
+ refetchOnWindowFocus: false
|
|
|
+ },
|
|
|
+ mutations: {
|
|
|
+ retry: false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ return ({ children }: { children: React.ReactNode }) => (
|
|
|
+ <QueryClientProvider client={queryClient}>
|
|
|
+ {children}
|
|
|
+ </QueryClientProvider>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+describe('SettingsPage', () => {
|
|
|
+ beforeEach(() => {
|
|
|
+ jest.clearAllMocks()
|
|
|
+ // Mock useRequireAuth to do nothing (user is authenticated)
|
|
|
+ ;(useRequireAuth as jest.Mock).mockImplementation(() => {})
|
|
|
+ // Reset Taro API mocks
|
|
|
+ ;(Taro.showModal as jest.Mock).mockClear()
|
|
|
+ ;(Taro.showToast as jest.Mock).mockClear()
|
|
|
+ ;(Taro.navigateTo as jest.Mock).mockClear()
|
|
|
+ ;(Taro.reLaunch as jest.Mock).mockClear()
|
|
|
+ ;(Taro.removeStorageSync as jest.Mock).mockClear()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该渲染页面标题', async () => {
|
|
|
+ ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
|
|
|
+ createMockResponse(200, { id: 1, name: '张明' })
|
|
|
+ )
|
|
|
+
|
|
|
+ const wrapper = createTestWrapper()
|
|
|
+ render(<SettingsPage />, { wrapper })
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('更多')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该渲染个人信息摘要', async () => {
|
|
|
+ ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
|
|
|
+ createMockResponse(200, {
|
|
|
+ id: 1,
|
|
|
+ name: '张明',
|
|
|
+ personInfo: {
|
|
|
+ disabilityType: '肢体残疾',
|
|
|
+ disabilityLevel: '三级'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ )
|
|
|
+
|
|
|
+ const wrapper = createTestWrapper()
|
|
|
+ render(<SettingsPage />, { wrapper })
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('张明')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该渲染功能入口列表', async () => {
|
|
|
+ ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
|
|
|
+ createMockResponse(200, { id: 1, name: '张明' })
|
|
|
+ )
|
|
|
+
|
|
|
+ const wrapper = createTestWrapper()
|
|
|
+ render(<SettingsPage />, { wrapper })
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('修改个人信息')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('账号与安全')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('消息通知设置')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该渲染帮助与支持入口', async () => {
|
|
|
+ ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
|
|
|
+ createMockResponse(200, { id: 1, name: '张明' })
|
|
|
+ )
|
|
|
+
|
|
|
+ const wrapper = createTestWrapper()
|
|
|
+ render(<SettingsPage />, { wrapper })
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('帮助中心')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('用户协议')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('隐私政策')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该渲染退出登录按钮', async () => {
|
|
|
+ ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
|
|
|
+ createMockResponse(200, { id: 1, name: '张明' })
|
|
|
+ )
|
|
|
+
|
|
|
+ const wrapper = createTestWrapper()
|
|
|
+ render(<SettingsPage />, { wrapper })
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('退出登录')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('API失败时应该显示错误信息', async () => {
|
|
|
+ ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
|
|
|
+ createMockResponse(404, {})
|
|
|
+ )
|
|
|
+
|
|
|
+ const wrapper = createTestWrapper()
|
|
|
+ render(<SettingsPage />, { wrapper })
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('加载失败,请稍后重试')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('API返回空数据时应该使用模拟数据', async () => {
|
|
|
+ ;(talentSettingsClient.me.$get as jest.Mock).mockResolvedValue(
|
|
|
+ createMockResponse(200, null)
|
|
|
+ )
|
|
|
+
|
|
|
+ const wrapper = createTestWrapper()
|
|
|
+ render(<SettingsPage />, { wrapper })
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('张明')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该渲染加载状态', () => {
|
|
|
+ ;(talentSettingsClient.me.$get as jest.Mock).mockImplementation(
|
|
|
+ () => new Promise(() => {}) // 永不resolve
|
|
|
+ )
|
|
|
+
|
|
|
+ const wrapper = createTestWrapper()
|
|
|
+ render(<SettingsPage />, { wrapper })
|
|
|
+
|
|
|
+ expect(screen.getByText('加载中...')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+})
|