|
|
@@ -0,0 +1,276 @@
|
|
|
+import React from 'react'
|
|
|
+import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
|
|
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
|
+import AddressManagePage from '@/pages/address-manage/index'
|
|
|
+
|
|
|
+// 导入Taro mock函数
|
|
|
+import { mockGetCurrentPages, mockNavigateTo, mockShowModal } from '~/__mocks__/taroMock'
|
|
|
+
|
|
|
+// Mock API client
|
|
|
+jest.mock('@/api', () => ({
|
|
|
+ deliveryAddressClient: {
|
|
|
+ $get: jest.fn(),
|
|
|
+ $post: jest.fn(),
|
|
|
+ ':id': {
|
|
|
+ $put: jest.fn(),
|
|
|
+ $delete: jest.fn(),
|
|
|
+ },
|
|
|
+ },
|
|
|
+}))
|
|
|
+
|
|
|
+// Mock auth hook
|
|
|
+jest.mock('@/utils/auth', () => ({
|
|
|
+ useAuth: () => ({
|
|
|
+ user: { id: 1 },
|
|
|
+ }),
|
|
|
+}))
|
|
|
+
|
|
|
+// Mock components
|
|
|
+jest.mock('@/components/ui/navbar', () => ({
|
|
|
+ Navbar: ({ title, onClickLeft }: { title: string; onClickLeft: () => void }) => (
|
|
|
+ <div data-testid="navbar">
|
|
|
+ <span>{title}</span>
|
|
|
+ <button onClick={onClickLeft}>返回</button>
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+}))
|
|
|
+
|
|
|
+jest.mock('@/components/ui/button', () => ({
|
|
|
+ Button: ({ children, onClick, disabled, className }: any) => (
|
|
|
+ <button
|
|
|
+ onClick={onClick}
|
|
|
+ disabled={disabled}
|
|
|
+ className={className}
|
|
|
+ data-testid="button"
|
|
|
+ >
|
|
|
+ {children}
|
|
|
+ </button>
|
|
|
+ ),
|
|
|
+}))
|
|
|
+
|
|
|
+describe('AddressManagePage', () => {
|
|
|
+ let queryClient: QueryClient
|
|
|
+
|
|
|
+ beforeEach(() => {
|
|
|
+ queryClient = new QueryClient({
|
|
|
+ defaultOptions: {
|
|
|
+ queries: { retry: false },
|
|
|
+ mutations: { retry: false },
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ // Reset all mocks
|
|
|
+ jest.clearAllMocks()
|
|
|
+
|
|
|
+ // 设置 getCurrentPages 的默认返回值
|
|
|
+ mockGetCurrentPages.mockReturnValue([{ route: 'pages/address-manage/index' }])
|
|
|
+ })
|
|
|
+
|
|
|
+ const renderWithProviders = (component: React.ReactElement) => {
|
|
|
+ return render(
|
|
|
+ <QueryClientProvider client={queryClient}>
|
|
|
+ {component}
|
|
|
+ </QueryClientProvider>
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ const mockAddresses = [
|
|
|
+ {
|
|
|
+ id: 1,
|
|
|
+ name: '张三',
|
|
|
+ phone: '13812345678',
|
|
|
+ province: { name: '广东省' },
|
|
|
+ city: { name: '深圳市' },
|
|
|
+ district: { name: '南山区' },
|
|
|
+ town: { name: '科技园' },
|
|
|
+ address: '科技大厦A座',
|
|
|
+ isDefault: 1,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 2,
|
|
|
+ name: '李四',
|
|
|
+ phone: '13987654321',
|
|
|
+ province: { name: '北京市' },
|
|
|
+ city: { name: '北京市' },
|
|
|
+ district: { name: '朝阳区' },
|
|
|
+ town: { name: '' },
|
|
|
+ address: '国贸中心',
|
|
|
+ isDefault: 0,
|
|
|
+ },
|
|
|
+ ]
|
|
|
+
|
|
|
+ it('渲染页面标题和布局', async () => {
|
|
|
+ const { deliveryAddressClient } = await import('@/api')
|
|
|
+ ;(deliveryAddressClient.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: [] }),
|
|
|
+ } as any)
|
|
|
+
|
|
|
+ renderWithProviders(<AddressManagePage />)
|
|
|
+
|
|
|
+ expect(screen.getByTestId('navbar')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('收货地址')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('显示地址列表', async () => {
|
|
|
+ const { deliveryAddressClient } = await import('@/api')
|
|
|
+ ;(deliveryAddressClient.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: mockAddresses }),
|
|
|
+ } as any)
|
|
|
+
|
|
|
+ renderWithProviders(<AddressManagePage />)
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('张三')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('李四')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('138****5678')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('139****4321')).toBeInTheDocument()
|
|
|
+ expect(screen.getByText('默认')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('显示空状态', async () => {
|
|
|
+ const { deliveryAddressClient } = await import('@/api')
|
|
|
+ ;(deliveryAddressClient.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: [] }),
|
|
|
+ } as any)
|
|
|
+
|
|
|
+ renderWithProviders(<AddressManagePage />)
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('暂无收货地址')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('显示地址数量限制提示', async () => {
|
|
|
+ const { deliveryAddressClient } = await import('@/api')
|
|
|
+ const addresses = Array.from({ length: 20 }, (_, i) => ({
|
|
|
+ id: i + 1,
|
|
|
+ name: `用户${i + 1}`,
|
|
|
+ phone: '13812345678',
|
|
|
+ province: { name: '广东省' },
|
|
|
+ city: { name: '深圳市' },
|
|
|
+ district: { name: '南山区' },
|
|
|
+ address: '测试地址',
|
|
|
+ isDefault: i === 0 ? 1 : 0,
|
|
|
+ }))
|
|
|
+
|
|
|
+ ;(deliveryAddressClient.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: addresses }),
|
|
|
+ } as any)
|
|
|
+
|
|
|
+ renderWithProviders(<AddressManagePage />)
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('最多可添加20个收货地址')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('点击添加地址按钮', async () => {
|
|
|
+ const { deliveryAddressClient } = await import('@/api')
|
|
|
+ ;(deliveryAddressClient.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: [] }),
|
|
|
+ } as any)
|
|
|
+
|
|
|
+ renderWithProviders(<AddressManagePage />)
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ const addButton = screen.getByText('添加新地址')
|
|
|
+ fireEvent.click(addButton)
|
|
|
+ expect(mockNavigateTo).toHaveBeenCalledWith({
|
|
|
+ url: '/pages/address-edit/index',
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('点击编辑地址按钮', async () => {
|
|
|
+ const { deliveryAddressClient } = await import('@/api')
|
|
|
+ ;(deliveryAddressClient.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: mockAddresses }),
|
|
|
+ } as any)
|
|
|
+
|
|
|
+ renderWithProviders(<AddressManagePage />)
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ const editButtons = screen.getAllByText('编辑')
|
|
|
+ fireEvent.click(editButtons[0])
|
|
|
+ expect(mockNavigateTo).toHaveBeenCalledWith({
|
|
|
+ url: '/pages/address-edit/index?id=1',
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('点击设为默认按钮', async () => {
|
|
|
+ const { deliveryAddressClient } = await import('@/api')
|
|
|
+ ;(deliveryAddressClient.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: mockAddresses }),
|
|
|
+ } as any)
|
|
|
+
|
|
|
+ ;(deliveryAddressClient[':id'].$put as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({}),
|
|
|
+ } as any)
|
|
|
+
|
|
|
+ renderWithProviders(<AddressManagePage />)
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ const setDefaultButtons = screen.getAllByText('设为默认')
|
|
|
+ fireEvent.click(setDefaultButtons[0])
|
|
|
+ expect(deliveryAddressClient[':id'].$put).toHaveBeenCalledWith({
|
|
|
+ param: { id: 2 },
|
|
|
+ json: { isDefault: 1 },
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('点击删除按钮', async () => {
|
|
|
+ const { deliveryAddressClient } = await import('@/api')
|
|
|
+ ;(deliveryAddressClient.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: mockAddresses }),
|
|
|
+ } as any)
|
|
|
+
|
|
|
+ ;(deliveryAddressClient[':id'].$delete as jest.Mock).mockResolvedValue({
|
|
|
+ status: 204,
|
|
|
+ json: async () => ({}),
|
|
|
+ } as any)
|
|
|
+
|
|
|
+ renderWithProviders(<AddressManagePage />)
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ const deleteButtons = screen.getAllByText('删除')
|
|
|
+ fireEvent.click(deleteButtons[0])
|
|
|
+ expect(mockShowModal).toHaveBeenCalled()
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('验证样式类名应用', async () => {
|
|
|
+ const { deliveryAddressClient } = await import('@/api')
|
|
|
+ ;(deliveryAddressClient.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: mockAddresses }),
|
|
|
+ } as any)
|
|
|
+
|
|
|
+ renderWithProviders(<AddressManagePage />)
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ const container = document.querySelector('.address-container')
|
|
|
+ expect(container).toBeInTheDocument()
|
|
|
+
|
|
|
+ const addressList = document.querySelector('.address-list')
|
|
|
+ expect(addressList).toBeInTheDocument()
|
|
|
+
|
|
|
+ const addressItems = document.querySelectorAll('.address-item')
|
|
|
+ expect(addressItems).toHaveLength(2)
|
|
|
+
|
|
|
+ const bottomFixed = document.querySelector('.bottom-fixed')
|
|
|
+ expect(bottomFixed).toBeInTheDocument()
|
|
|
+ })
|
|
|
+ })
|
|
|
+})
|