index.test.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. import React from 'react'
  2. import { render, fireEvent } from '@testing-library/react'
  3. import Taro from '@tarojs/taro'
  4. import CartPage from '@/pages/cart/index'
  5. // Mock Taro相关API
  6. jest.mock('@tarojs/taro', () => ({
  7. default: {
  8. navigateBack: jest.fn(),
  9. navigateTo: jest.fn(),
  10. showToast: jest.fn(),
  11. showModal: jest.fn(),
  12. getStorageSync: jest.fn(),
  13. setStorageSync: jest.fn(),
  14. },
  15. }))
  16. // Mock购物车hook
  17. jest.mock('@/utils/cart', () => ({
  18. useCart: () => ({
  19. cart: {
  20. items: [
  21. {
  22. id: 1,
  23. name: '测试商品1',
  24. price: 29.9,
  25. image: 'test-image1.jpg',
  26. stock: 10,
  27. quantity: 2,
  28. spec: '红色/M',
  29. },
  30. {
  31. id: 2,
  32. name: '测试商品2',
  33. price: 49.9,
  34. image: 'test-image2.jpg',
  35. stock: 5,
  36. quantity: 1,
  37. spec: '蓝色/L',
  38. },
  39. ],
  40. totalAmount: 109.7,
  41. totalCount: 3,
  42. },
  43. updateQuantity: jest.fn(),
  44. removeFromCart: jest.fn(),
  45. clearCart: jest.fn(),
  46. isLoading: false,
  47. }),
  48. }))
  49. // Mock布局组件
  50. jest.mock('@/layouts/tab-bar-layout', () => ({
  51. TabBarLayout: ({ children }: any) => <div>{children}</div>,
  52. }))
  53. // Mock导航栏组件
  54. jest.mock('@/components/ui/navbar', () => ({
  55. Navbar: ({ title, onClickRight }: any) => (
  56. <div>
  57. <div>{title}</div>
  58. <button onClick={onClickRight}>清空购物车</button>
  59. </div>
  60. ),
  61. }))
  62. // Mock按钮组件
  63. jest.mock('@/components/ui/button', () => ({
  64. Button: ({ children, onClick, disabled, className }: any) => (
  65. <button onClick={onClick} disabled={disabled} className={className}>
  66. {children}
  67. </button>
  68. ),
  69. }))
  70. // Mock图片组件
  71. jest.mock('@/components/ui/image', () => ({
  72. Image: ({ src, className, mode }: any) => (
  73. <img src={src} className={className} alt="商品图片" />
  74. ),
  75. }))
  76. describe('购物车页面', () => {
  77. beforeEach(() => {
  78. jest.clearAllMocks()
  79. // Mock showModal返回确认
  80. ;(Taro.showModal as any).mockResolvedValue({ confirm: true })
  81. })
  82. it('应该正确渲染购物车页面标题', () => {
  83. const { getByText } = render(<CartPage />)
  84. expect(getByText('购物车')).toBeDefined()
  85. })
  86. it('应该显示购物车中的商品列表', () => {
  87. const { getByText } = render(<CartPage />)
  88. expect(getByText('测试商品1')).toBeDefined()
  89. expect(getByText('测试商品2')).toBeDefined()
  90. expect(getByText('¥29.90')).toBeDefined()
  91. expect(getByText('¥49.90')).toBeDefined()
  92. })
  93. it('应该显示商品规格信息', () => {
  94. const { getByText } = render(<CartPage />)
  95. expect(getByText('红色/M')).toBeDefined()
  96. expect(getByText('蓝色/L')).toBeDefined()
  97. })
  98. it('应该显示商品数量选择器', () => {
  99. const { getByText } = render(<CartPage />)
  100. expect(getByText('2')).toBeDefined() // 商品1的数量
  101. expect(getByText('1')).toBeDefined() // 商品2的数量
  102. })
  103. it('应该显示底部结算栏', () => {
  104. const { getByText } = render(<CartPage />)
  105. expect(getByText('全选')).toBeDefined()
  106. expect(getByText('总计')).toBeDefined()
  107. expect(getByText('去结算(0)')).toBeDefined()
  108. })
  109. it('应该支持全选功能', () => {
  110. const { getByText } = render(<CartPage />)
  111. const selectAllButton = getByText('全选')
  112. fireEvent.click(selectAllButton)
  113. // 检查结算按钮文本变化
  114. expect(getByText('去结算(2)')).toBeDefined()
  115. })
  116. it('应该支持单个商品选择', () => {
  117. const { getByText } = render(<CartPage />)
  118. const selectAllButton = getByText('全选')
  119. fireEvent.click(selectAllButton)
  120. // 再次点击取消全选
  121. fireEvent.click(selectAllButton)
  122. expect(getByText('去结算(0)')).toBeDefined()
  123. })
  124. it('应该显示清空购物车按钮', () => {
  125. const { getByText } = render(<CartPage />)
  126. const clearButton = getByText('清空购物车')
  127. fireEvent.click(clearButton)
  128. expect(Taro.showModal).toHaveBeenCalledWith({
  129. title: '清空购物车',
  130. content: '确定要清空购物车吗?',
  131. success: expect.any(Function),
  132. })
  133. })
  134. it('应该显示删除按钮', () => {
  135. const { getAllByText } = render(<CartPage />)
  136. const deleteButtons = getAllByText('删除')
  137. expect(deleteButtons).toHaveLength(2)
  138. fireEvent.click(deleteButtons[0])
  139. expect(Taro.showModal).toHaveBeenCalledWith({
  140. title: '删除商品',
  141. content: '确定要删除这个商品吗?',
  142. success: expect.any(Function),
  143. })
  144. })
  145. it('应该显示库存不足提示', () => {
  146. const { getByText } = render(<CartPage />)
  147. expect(getByText('仅剩5件')).toBeDefined() // 商品2的库存
  148. })
  149. it('应该显示广告区域', () => {
  150. const { container } = render(<CartPage />)
  151. const adElement = container.querySelector('.cart-advertisement')
  152. expect(adElement).toBeDefined()
  153. })
  154. describe('空购物车状态', () => {
  155. beforeEach(() => {
  156. // Mock空购物车状态
  157. jest.doMock('@/utils/cart', () => ({
  158. useCart: () => ({
  159. cart: {
  160. items: [],
  161. totalAmount: 0,
  162. totalCount: 0,
  163. },
  164. updateQuantity: jest.fn(),
  165. removeFromCart: jest.fn(),
  166. clearCart: jest.fn(),
  167. isLoading: false,
  168. }),
  169. }))
  170. })
  171. it('应该显示空购物车状态', () => {
  172. const { getByText } = render(<CartPage />)
  173. expect(getByText('购物车是空的')).toBeDefined()
  174. expect(getByText('去首页逛逛')).toBeDefined()
  175. })
  176. it('应该隐藏底部结算栏', () => {
  177. const { queryByText } = render(<CartPage />)
  178. expect(queryByText('去结算')).toBeNull()
  179. })
  180. })
  181. describe('结算功能', () => {
  182. it('应该阻止未选择商品时结算', () => {
  183. const { getByText } = render(<CartPage />)
  184. const checkoutButton = getByText('去结算(0)')
  185. fireEvent.click(checkoutButton)
  186. expect(Taro.showToast).toHaveBeenCalledWith({
  187. title: '请选择商品',
  188. icon: 'none',
  189. })
  190. })
  191. it('应该允许选择商品后结算', () => {
  192. const { getByText } = render(<CartPage />)
  193. const selectAllButton = getByText('全选')
  194. const checkoutButton = getByText('去结算(0)')
  195. fireEvent.click(selectAllButton)
  196. fireEvent.click(checkoutButton)
  197. expect(Taro.setStorageSync).toHaveBeenCalledWith('checkoutItems', {
  198. items: expect.any(Array),
  199. totalAmount: expect.any(Number),
  200. })
  201. expect(Taro.navigateTo).toHaveBeenCalledWith({
  202. url: '/pages/order-submit/index',
  203. })
  204. })
  205. })
  206. })