CartContext.test.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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. console.log('Item 0 id:', getByTestId('item-0-id').textContent)
  103. console.log('Item 0 name:', getByTestId('item-0-name').textContent)
  104. console.log('Item 0 spec:', getByTestId('item-0-spec').textContent)
  105. const quantityElement = getByTestId('item-0-quantity')
  106. console.log('Quantity element text:', quantityElement.textContent)
  107. expect(quantityElement.textContent).toBe('1')
  108. // 重新渲染添加更多数量
  109. rerender(
  110. <CartProvider>
  111. <TestComponent action="add" item={childGoods2} />
  112. </CartProvider>
  113. )
  114. expect(getByTestId('item-0-quantity').textContent).toBe('4') // 1 + 3
  115. })
  116. it('应该限制数量不超过库存', () => {
  117. const childGoods: CartItem = {
  118. id: 4001,
  119. name: '测试商品 - 黑色/XL',
  120. price: 129.9,
  121. image: 'goods.jpg',
  122. stock: 2, // 库存只有2
  123. quantity: 3, // 尝试购买3个
  124. spec: '黑色/XL',
  125. }
  126. const { getByTestId } = render(
  127. <CartProvider>
  128. <TestComponent action="add" item={childGoods} />
  129. </CartProvider>
  130. )
  131. // 应该显示库存不足提示
  132. expect(mockShowToast).toHaveBeenCalledWith(
  133. expect.objectContaining({ title: '库存不足' })
  134. )
  135. // 商品不应被添加
  136. expect(getByTestId('items-count').textContent).toBe('0')
  137. })
  138. it('应该支持同时添加父商品和不同子商品', () => {
  139. const parentGoods: CartItem = {
  140. id: 5001,
  141. name: '测试父商品',
  142. price: 199.9,
  143. image: 'parent.jpg',
  144. stock: 20,
  145. quantity: 1,
  146. }
  147. const childGoods1: CartItem = {
  148. id: 5002, // 子商品ID1
  149. name: '测试父商品 - 规格A',
  150. price: 219.9,
  151. image: 'child1.jpg',
  152. stock: 5,
  153. quantity: 2,
  154. spec: '规格A',
  155. }
  156. const childGoods2: CartItem = {
  157. id: 5003, // 子商品ID2
  158. name: '测试父商品 - 规格B',
  159. price: 229.9,
  160. image: 'child2.jpg',
  161. stock: 3,
  162. quantity: 1,
  163. spec: '规格B',
  164. }
  165. const { getByTestId, rerender } = render(
  166. <CartProvider>
  167. <TestComponent action="add" item={parentGoods} />
  168. </CartProvider>
  169. )
  170. expect(getByTestId('items-count').textContent).toBe('1')
  171. // 添加第一个子商品
  172. rerender(
  173. <CartProvider>
  174. <TestComponent action="add" item={childGoods1} />
  175. </CartProvider>
  176. )
  177. expect(getByTestId('items-count').textContent).toBe('2')
  178. // 添加第二个子商品
  179. rerender(
  180. <CartProvider>
  181. <TestComponent action="add" item={childGoods2} />
  182. </CartProvider>
  183. )
  184. expect(getByTestId('items-count').textContent).toBe('3')
  185. expect(getByTestId('item-0-id').textContent).toBe('5001')
  186. expect(getByTestId('item-1-id').textContent).toBe('5002')
  187. expect(getByTestId('item-2-id').textContent).toBe('5003')
  188. })
  189. })