| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- import React from 'react'
- import { renderHook, waitFor } from '@testing-library/react'
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
- import { AuthProvider, useRequireAuth } from '../../src/hooks/useAuth'
- import Taro from '@tarojs/taro'
- // Mock Taro
- jest.mock('@tarojs/taro', () => ({
- showToast: jest.fn(),
- redirectTo: jest.fn(),
- getStorageSync: jest.fn(() => null),
- setStorageSync: jest.fn(),
- removeStorageSync: jest.fn(),
- }))
- // Mock talentAuthClient
- jest.mock('../../src/api', () => ({
- talentAuthClient: {
- me: {
- $get: jest.fn(),
- },
- login: {
- $post: jest.fn(),
- },
- },
- }))
- const mockToast = Taro.showToast as jest.MockedFunction<typeof Taro.showToast>
- const mockRedirectTo = Taro.redirectTo as jest.MockedFunction<typeof Taro.redirectTo>
- describe('useRequireAuth', () => {
- let queryClient: QueryClient
- const wrapper = ({ children }: { children: React.ReactNode }) => (
- <QueryClientProvider client={queryClient}>
- <AuthProvider>{children}</AuthProvider>
- </QueryClientProvider>
- )
- beforeEach(() => {
- queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- retry: false,
- staleTime: Infinity,
- refetchOnWindowFocus: false,
- refetchOnReconnect: false,
- },
- },
- })
- jest.clearAllMocks()
- jest.useFakeTimers()
- })
- afterEach(() => {
- queryClient.clear()
- jest.useRealTimers()
- })
- it('应该在未登录时显示提示并跳转到登录页', async () => {
- // 模拟无token的情况
- ;(Taro.getStorageSync as jest.Mock).mockReturnValue(null)
- renderHook(() => useRequireAuth(), { wrapper })
- // 等待useEffect执行
- await waitFor(() => {
- expect(mockToast).toHaveBeenCalledWith({
- title: '请先登录',
- icon: 'none',
- duration: 1500,
- })
- })
- // 快进1500ms
- jest.advanceTimersByTime(1500)
- // 等待redirectTo被调用
- await waitFor(() => {
- expect(mockRedirectTo).toHaveBeenCalledWith({
- url: '/pages/login/index',
- })
- })
- })
- it('应该在loading状态时不跳转', async () => {
- // 模拟无token但loading中的情况
- ;(Taro.getStorageSync as jest.Mock).mockReturnValue(null)
- const { result } = renderHook(() => useRequireAuth(), { wrapper })
- // 在初始加载期间不应该立即调用redirectTo(需要等待loading结束)
- // 由于我们模拟的token为null,loading会很快结束
- // 这里我们只验证在第一次render时不会调用
- expect(mockRedirectTo).not.toHaveBeenCalled()
- })
- it('应该在已登录时不跳转', async () => {
- // 模拟有token且已登录的情况
- ;(Taro.getStorageSync as jest.Mock).mockReturnValue('valid_token')
- // 模拟API返回用户信息
- const { talentAuthClient } = require('../../src/api')
- talentAuthClient.me.$get.mockResolvedValue({
- status: 200,
- json: async () => ({ id: 1, name: '测试用户' }),
- })
- renderHook(() => useRequireAuth(), { wrapper })
- // 等待查询完成
- await waitFor(() => {
- expect(talentAuthClient.me.$get).toHaveBeenCalled()
- })
- // 已登录状态不应该调用redirectTo
- expect(mockRedirectTo).not.toHaveBeenCalled()
- })
- it('应该在token失效时清除token并跳转', async () => {
- // 模拟有token但API返回错误的情况
- ;(Taro.getStorageSync as jest.Mock).mockReturnValue('invalid_token')
- const { talentAuthClient } = require('../../src/api')
- talentAuthClient.me.$get.mockResolvedValue({
- status: 401,
- })
- renderHook(() => useRequireAuth(), { wrapper })
- // 等待查询完成并验证token被清除
- await waitFor(() => {
- expect(Taro.removeStorageSync).toHaveBeenCalledWith('talent_token')
- expect(Taro.removeStorageSync).toHaveBeenCalledWith('talent_user')
- })
- // 快进1500ms
- jest.advanceTimersByTime(1500)
- // 验证跳转到登录页
- await waitFor(() => {
- expect(mockRedirectTo).toHaveBeenCalledWith({
- url: '/pages/login/index',
- })
- })
- })
- })
|