CartContext.test.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import React from 'react'
  2. import { render } from '@testing-library/react'
  3. import { CartProvider, useCart, CartItem } from '@/contexts/CartContext'
  4. import { mockShowToast, mockGetStorageSync, mockSetStorageSync } from '~/__mocks__/taroMock'
  5. // Mock Taro API
  6. jest.mock('@tarojs/taro', () => jest.requireActual('~/__mocks__/taroMock'))
  7. // 测试组件用于访问购物车hook
  8. const TestComponent = ({ action, item }: { action: string; item?: CartItem }) => {
  9. const cart = useCart()
  10. React.useEffect(() => {
  11. if (action === 'add' && item) {
  12. cart.addToCart(item)
  13. }
  14. }, [action, item, cart])
  15. return (
  16. <div>
  17. <div data-testid="items-count">{cart.cart.items.length}</div>
  18. <div data-testid="total-count">{cart.cart.totalCount}</div>
  19. <div data-testid="total-amount">{cart.cart.totalAmount}</div>
  20. {cart.cart.items.map((item, index) => (
  21. <div key={index} data-testid={`item-${index}`}>
  22. <span data-testid={`item-${index}-id`}>{item.id}</span>
  23. <span data-testid={`item-${index}-name`}>{item.name}</span>
  24. <span data-testid={`item-${index}-spec`}>{item.spec || ''}</span>
  25. <span data-testid={`item-${index}-quantity`}>{item.quantity}</span>
  26. </div>
  27. ))}
  28. </div>
  29. )
  30. }
  31. describe('CartContext - 规格支持', () => {
  32. beforeEach(() => {
  33. mockGetStorageSync.mockReturnValue(null)
  34. mockSetStorageSync.mockClear()
  35. mockShowToast.mockClear()
  36. })
  37. it('应该支持添加父商品到购物车', () => {
  38. const parentGoods: CartItem = {
  39. id: 1001,
  40. name: '测试父商品',
  41. price: 99.9,
  42. image: 'parent.jpg',
  43. stock: 10,
  44. quantity: 2,
  45. }
  46. const { getByTestId } = render(
  47. <CartProvider>
  48. <TestComponent action="add" item={parentGoods} />
  49. </CartProvider>
  50. )
  51. expect(getByTestId('items-count').textContent).toBe('1')
  52. expect(getByTestId('item-0-id').textContent).toBe('1001')
  53. expect(getByTestId('item-0-name').textContent).toBe('测试父商品')
  54. expect(mockSetStorageSync).toHaveBeenCalled()
  55. })
  56. it('应该支持添加子商品(带规格)到购物车', () => {
  57. const childGoods: CartItem = {
  58. id: 2001, // 子商品ID
  59. name: '测试父商品 - 红色/M', // 包含规格信息的完整名称
  60. price: 109.9,
  61. image: 'child.jpg',
  62. stock: 5,
  63. quantity: 1,
  64. spec: '红色/M', // 规格信息
  65. }
  66. const { getByTestId } = render(
  67. <CartProvider>
  68. <TestComponent action="add" item={childGoods} />
  69. </CartProvider>
  70. )
  71. expect(getByTestId('items-count').textContent).toBe('1')
  72. expect(getByTestId('item-0-id').textContent).toBe('2001')
  73. expect(getByTestId('item-0-name').textContent).toBe('测试父商品 - 红色/M')
  74. expect(getByTestId('item-0-spec').textContent).toBe('红色/M')
  75. expect(mockSetStorageSync).toHaveBeenCalled()
  76. })
  77. it('应该支持添加同一子商品多次(数量累加)', () => {
  78. const childGoods1: CartItem = {
  79. id: 3001,
  80. name: '测试商品 - 蓝色/L',
  81. price: 89.9,
  82. image: 'goods.jpg',
  83. stock: 10,
  84. quantity: 1,
  85. spec: '蓝色/L',
  86. }
  87. const childGoods2: CartItem = {
  88. id: 3001, // 同一子商品ID
  89. name: '测试商品 - 蓝色/L',
  90. price: 89.9,
  91. image: 'goods.jpg',
  92. stock: 10,
  93. quantity: 3,
  94. spec: '蓝色/L',
  95. }
  96. const { getByTestId, rerender } = render(
  97. <CartProvider>
  98. <TestComponent action="add" item={childGoods1} />
  99. </CartProvider>
  100. )
  101. expect(getByTestId('items-count').textContent).toBe('1')
  102. expect(getByTestId('item-0-quantity').textContent).toBe('1')
  103. // 重新渲染添加更多数量
  104. rerender(
  105. <CartProvider>
  106. <TestComponent action="add" item={childGoods2} />
  107. </CartProvider>
  108. )
  109. expect(getByTestId('item-0-quantity').textContent).toBe('4') // 1 + 3
  110. })
  111. it('应该限制数量不超过库存', () => {
  112. const childGoods: CartItem = {
  113. id: 4001,
  114. name: '测试商品 - 黑色/XL',
  115. price: 129.9,
  116. image: 'goods.jpg',
  117. stock: 2, // 库存只有2
  118. quantity: 3, // 尝试购买3个
  119. spec: '黑色/XL',
  120. }
  121. const { getByTestId } = render(
  122. <CartProvider>
  123. <TestComponent action="add" item={childGoods} />
  124. </CartProvider>
  125. )
  126. // 应该显示库存不足提示
  127. expect(mockShowToast).toHaveBeenCalledWith(
  128. expect.objectContaining({ title: '库存不足' })
  129. )
  130. // 商品不应被添加
  131. expect(getByTestId('items-count').textContent).toBe('0')
  132. })
  133. it('应该支持同时添加父商品和不同子商品', () => {
  134. const parentGoods: CartItem = {
  135. id: 5001,
  136. name: '测试父商品',
  137. price: 199.9,
  138. image: 'parent.jpg',
  139. stock: 20,
  140. quantity: 1,
  141. }
  142. const childGoods1: CartItem = {
  143. id: 5002, // 子商品ID1
  144. name: '测试父商品 - 规格A',
  145. price: 219.9,
  146. image: 'child1.jpg',
  147. stock: 5,
  148. quantity: 2,
  149. spec: '规格A',
  150. }
  151. const childGoods2: CartItem = {
  152. id: 5003, // 子商品ID2
  153. name: '测试父商品 - 规格B',
  154. price: 229.9,
  155. image: 'child2.jpg',
  156. stock: 3,
  157. quantity: 1,
  158. spec: '规格B',
  159. }
  160. const { getByTestId, rerender } = render(
  161. <CartProvider>
  162. <TestComponent action="add" item={parentGoods} />
  163. </CartProvider>
  164. )
  165. expect(getByTestId('items-count').textContent).toBe('1')
  166. // 添加第一个子商品
  167. rerender(
  168. <CartProvider>
  169. <TestComponent action="add" item={childGoods1} />
  170. </CartProvider>
  171. )
  172. expect(getByTestId('items-count').textContent).toBe('2')
  173. // 添加第二个子商品
  174. rerender(
  175. <CartProvider>
  176. <TestComponent action="add" item={childGoods2} />
  177. </CartProvider>
  178. )
  179. expect(getByTestId('items-count').textContent).toBe('3')
  180. expect(getByTestId('item-0-id').textContent).toBe('5001')
  181. expect(getByTestId('item-1-id').textContent).toBe('5002')
  182. expect(getByTestId('item-2-id').textContent).toBe('5003')
  183. })
  184. })